diff --git a/0readmeAsynchIO.txt b/0readmeAsynchIO.txt new file mode 100644 index 00000000..b41cf4f9 --- /dev/null +++ b/0readmeAsynchIO.txt @@ -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. + diff --git a/ALTAIR/altair_cpu.c b/ALTAIR/altair_cpu.c index 740d66f7..4a837c8b 100644 --- a/ALTAIR/altair_cpu.c +++ b/ALTAIR/altair_cpu.c @@ -141,7 +141,7 @@ device addresses, if a device is plugged to a port it's routine address is here, 'nulldev' means no device is available */ struct idev { - int32 (*routine)(); + int32 (*routine)(int32, int32); }; struct idev dev_table[256] = { {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 000 */ diff --git a/ALTAIR/altair_sio.c b/ALTAIR/altair_sio.c index abe4cd9a..a60927de 100644 --- a/ALTAIR/altair_sio.c +++ b/ALTAIR/altair_sio.c @@ -122,7 +122,7 @@ DEVICE ptp_dev = { /* service routine - actually gets char & places in buffer */ -int32 sio_svc (UNIT *uptr) +t_stat sio_svc (UNIT *uptr) { int32 temp; @@ -139,12 +139,12 @@ int32 sio_svc (UNIT *uptr) } -int32 ptr_svc (UNIT *uptr) +t_stat ptr_svc (UNIT *uptr) { return SCPE_OK; } -int32 ptp_svc (UNIT *uptr) +t_stat ptp_svc (UNIT *uptr) { return SCPE_OK; } @@ -152,7 +152,7 @@ int32 ptp_svc (UNIT *uptr) /* Reset routine */ -int32 sio_reset (DEVICE *dptr) +t_stat sio_reset (DEVICE *dptr) { sio_unit.buf = 0; /* Data */ sio_unit.u3 = 0x02; /* Status */ @@ -161,7 +161,7 @@ int32 sio_reset (DEVICE *dptr) } -int32 ptr_reset (DEVICE *dptr) +t_stat ptr_reset (DEVICE *dptr) { ptr_unit.buf = 0; ptr_unit.u3 = 0x02; @@ -169,7 +169,7 @@ int32 ptr_reset (DEVICE *dptr) return SCPE_OK; } -int32 ptp_reset (DEVICE *dptr) +t_stat ptp_reset (DEVICE *dptr) { ptp_unit.buf = 0; ptp_unit.u3 = 0x02; diff --git a/AltairZ80/altairZ80_sio.c b/AltairZ80/altairZ80_sio.c index 1f255a16..6249546d 100644 --- a/AltairZ80/altairZ80_sio.c +++ b/AltairZ80/altairZ80_sio.c @@ -506,10 +506,10 @@ typedef struct { int32 sio_can_read; /* bit mask to indicate that one can read from this port */ int32 sio_cannot_read; /* bit mask to indicate that one cannot read from this port */ int32 sio_can_write; /* bit mask to indicate that one can write to this port */ - int32 hasReset; /* TRUE iff SIO has reset command */ + t_bool hasReset; /* TRUE iff SIO has reset command */ int32 sio_reset; /* reset command */ - int32 hasOUT; /* TRUE iff port supports OUT command */ - int32 isBuiltin; /* TRUE iff mapping is built in */ + t_bool hasOUT; /* TRUE iff port supports OUT command */ + t_bool isBuiltin; /* TRUE iff mapping is built in */ } SIO_PORT_INFO; static SIO_PORT_INFO port_table[PORT_TABLE_SIZE] = { diff --git a/AltairZ80/altairz80_hdsk.c b/AltairZ80/altairz80_hdsk.c index 009fb0e5..e90bc90e 100644 --- a/AltairZ80/altairz80_hdsk.c +++ b/AltairZ80/altairz80_hdsk.c @@ -632,8 +632,8 @@ static int32 doWrite(void) { hdskbuf[i] = GetBYTEWrapper(selectedDMA + i); rtn = sim_fwrite(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref); if (rtn != (size_t)(uptr -> HDSK_SECTOR_SIZE)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write Sector=%02d Track=%04d Result=%zd." NLP, - selectedDisk, PCX, selectedSector, selectedTrack, rtn)); + TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write Sector=%02d Track=%04d Result=%d." NLP, + selectedDisk, PCX, selectedSector, selectedTrack, (int)rtn)); return CPM_ERROR; } } diff --git a/AltairZ80/i8272.c b/AltairZ80/i8272.c index 5a11ad4a..0d21de52 100644 --- a/AltairZ80/i8272.c +++ b/AltairZ80/i8272.c @@ -475,8 +475,8 @@ static char *messages[0x20] = { uint8 I8272_Write(const uint32 Addr, uint8 cData) { I8272_DRIVE_INFO *pDrive; - unsigned int flags = 0; - unsigned int readlen; + uint32 flags = 0; + uint32 readlen; uint8 disk_read = 0; int32 i; diff --git a/AltairZ80/mfdc.c b/AltairZ80/mfdc.c index bc6f3531..5ac79053 100644 --- a/AltairZ80/mfdc.c +++ b/AltairZ80/mfdc.c @@ -421,8 +421,8 @@ static uint8 MFDC_Read(const uint32 Addr) if(mfdc_info->datacount == 0) { unsigned int i, checksum; unsigned long sec_offset; - unsigned int flags; - unsigned int readlen; + uint32 flags; + uint32 readlen; /* Clear out unused portion of sector. */ memset(&sdata.u.unused[0], 0x00, 10); @@ -524,8 +524,8 @@ static uint8 MFDC_Read(const uint32 Addr) static uint8 MFDC_Write(const uint32 Addr, uint8 cData) { unsigned int sec_offset; - unsigned int flags = 0; - unsigned int writelen; + uint32 flags = 0; + uint32 writelen; MFDC_DRIVE_INFO *pDrive; pDrive = &mfdc_info->drive[mfdc_info->sel_drive]; diff --git a/AltairZ80/vfdhd.c b/AltairZ80/vfdhd.c index df021b87..11db5b54 100644 --- a/AltairZ80/vfdhd.c +++ b/AltairZ80/vfdhd.c @@ -547,7 +547,7 @@ static void VFDHD_Command(void) if(vfdhd_info->read == 1) { /* Perform a Read operation */ unsigned int i, checksum; - unsigned int readlen; + uint32 readlen; TRACE_PRINT(RD_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " RD: Drive=%d, Track=%d, Head=%d, Sector=%d" NLP, PCX, @@ -619,7 +619,7 @@ static void VFDHD_Command(void) } } else { /* Perform a Write operation */ - unsigned int writelen; + uint32 writelen; TRACE_PRINT(WR_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " WR: Drive=%d, Track=%d, Head=%d, Sector=%d" NLP, PCX, diff --git a/AltairZ80/wd179x.c b/AltairZ80/wd179x.c index e0f77454..743e779a 100644 --- a/AltairZ80/wd179x.c +++ b/AltairZ80/wd179x.c @@ -445,8 +445,8 @@ uint8 WD179X_Read(const uint32 Addr) { uint8 cData; WD179X_DRIVE_INFO *pDrive; - unsigned int flags = 0; - unsigned int readlen; + uint32 flags = 0; + uint32 readlen; int status; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { @@ -578,8 +578,8 @@ static uint8 Do1793Command(uint8 cCommand) { uint8 result = 0; WD179X_DRIVE_INFO *pDrive; - unsigned int flags = 0; - unsigned int readlen; + uint32 flags = 0; + uint32 readlen; int status; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { @@ -955,8 +955,8 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) { WD179X_DRIVE_INFO *pDrive; /* uint8 disk_read = 0; */ - unsigned int flags = 0; - unsigned int writelen; + uint32 flags = 0; + uint32 writelen; if(wd179x_info->sel_drive >= WD179X_MAX_DRIVES) { return 0xFF; diff --git a/Ibm1130/ibm1130_cpu.c b/Ibm1130/ibm1130_cpu.c index 1db5600f..d35bbcbd 100644 --- a/Ibm1130/ibm1130_cpu.c +++ b/Ibm1130/ibm1130_cpu.c @@ -197,7 +197,7 @@ int32 int_mask; /* current active interrupt mask (ipl sensitive) */ int32 mem_mask; /* mask for memory address bits based on current memory size */ int32 cpu_dsw = 0; /* CPU device status word */ int32 ibkpt_addr = -1; /* breakpoint addr */ -int32 sim_gui = TRUE; /* enable gui */ +t_bool sim_gui = TRUE; /* enable gui */ t_bool running = FALSE; /* TRUE if CPU is running */ t_bool power = TRUE; /* TRUE if CPU power is on */ t_bool cgi = FALSE; /* TRUE if we are running as a CGI program */ @@ -222,7 +222,7 @@ t_stat cpu_set_type (UNIT *uptr, int32 value, char *cptr, void *desc); void calc_ints (void); extern t_stat ts_wr (int32 data, int32 addr, int32 access); -extern t_stat detach_cmd (int flags, char *cptr); +extern t_stat detach_cmd (int32 flags, char *cptr); extern UNIT cr_unit; extern int32 sim_switches; @@ -230,7 +230,7 @@ extern int32 sim_switches; static void archive_backtrace(char *inst); static void reset_backtrace (void); static void show_backtrace (int nshow); - static t_stat backtrace_cmd (int flag, char *cptr); + static t_stat backtrace_cmd (int32 flag, char *cptr); #else #define archive_backtrace(inst) #define reset_backtrace() @@ -245,7 +245,7 @@ extern int32 sim_switches; static void init_console_window (void); static void destroy_console_window (void); -static t_stat view_cmd (int flag, char *cptr); +static t_stat view_cmd (int32 flag, char *cptr); static t_stat cpu_attach (UNIT *uptr, char *cptr); static t_bool bsctest (int32 DSPLC, t_bool reset_V); static void exit_irq (void); @@ -1556,7 +1556,7 @@ static void show_backtrace (int nshow) putchar('\n'); } -static t_stat backtrace_cmd (int flag, char *cptr) +static t_stat backtrace_cmd (int32 flag, char *cptr) { int n; @@ -1854,7 +1854,7 @@ void debug_print (char *fmt, ...) /* view_cmd - let user view and/or edit a file (e.g. a printer output file, script, or source deck) */ -static t_stat view_cmd (int flag, char *cptr) +static t_stat view_cmd (int32 flag, char *cptr) { #ifdef _WIN32 char cmdline[256]; diff --git a/Ibm1130/ibm1130_cr.c b/Ibm1130/ibm1130_cr.c index 61014b71..c45205a8 100644 --- a/Ibm1130/ibm1130_cr.c +++ b/Ibm1130/ibm1130_cr.c @@ -951,7 +951,7 @@ t_stat load_cr_boot (int drvno, int switches) return SCPE_OK; } -t_stat cr_boot (int unitno, DEVICE *dptr) +t_stat cr_boot (int32 unitno, DEVICE *dptr) { t_stat rval; int i; diff --git a/Ibm1130/ibm1130_defs.h b/Ibm1130/ibm1130_defs.h index 36963a6a..d4f925b3 100644 --- a/Ibm1130/ibm1130_defs.h +++ b/Ibm1130/ibm1130_defs.h @@ -47,7 +47,7 @@ extern int cgi; /* TRUE if we are running as a CGI program */ extern int cgiwritable; /* TRUE if we can write the disk images back to the image file in CGI mode */ -extern int sim_gui; +extern t_bool sim_gui; extern uint16 M[]; /* core memory, up to 32Kwords (note: don't even think about trying 64K) */ extern uint16 ILSW[]; /* interrupt level status words */ @@ -269,7 +269,7 @@ void xio_error (char *msg); void bail (char *msg); t_stat load_cr_boot (int drv, int switches); -t_stat cr_boot (int unitno, DEVICE *dptr); +t_stat cr_boot (int32 unitno, DEVICE *dptr); t_stat cr_rewind (void); t_stat cr_detach (UNIT *uptr); void calc_ints (void); /* recalculate interrupt bitmask */ diff --git a/Ibm1130/ibm1130_disk.c b/Ibm1130/ibm1130_disk.c index 52dc8525..4b776470 100644 --- a/Ibm1130/ibm1130_disk.c +++ b/Ibm1130/ibm1130_disk.c @@ -43,9 +43,9 @@ extern int32 sim_switches; extern int32 sim_quiet; static int trace_dms = 0; static void tracesector (int iswrite, int nwords, int addr, int sector); -static t_stat where_cmd (int flag, char *ptr); -static t_stat phdebug_cmd (int flag, char *ptr); -static t_stat fdump_cmd (int flags, char *cptr); +static t_stat where_cmd (int32 flag, char *ptr); +static t_stat phdebug_cmd (int32 flag, char *ptr); +static t_stat fdump_cmd (int32 flags, char *cptr); static void enable_dms_tracing (int newsetting); #endif @@ -91,7 +91,7 @@ static t_stat dsk_svc (UNIT *uptr); static t_stat dsk_reset (DEVICE *dptr); static t_stat dsk_attach (UNIT *uptr, char *cptr); static t_stat dsk_detach (UNIT *uptr); -static t_stat dsk_boot (int unitno, DEVICE *dptr); +static t_stat dsk_boot (int32 unitno, DEVICE *dptr); static void diskfail (UNIT *uptr, int dswflag, int unitflag, t_bool do_interrupt); @@ -571,7 +571,7 @@ static t_stat dsk_detach (UNIT *uptr) /* boot routine - if they type BOOT DSK, load the standard boot card. */ -static t_stat dsk_boot (int unitno, DEVICE *dptr) +static t_stat dsk_boot (int32 unitno, DEVICE *dptr) { t_stat rval; @@ -644,7 +644,7 @@ char * saywhere (int addr) static int phdebug_lo = -1, phdebug_hi = -1; -static t_stat phdebug_cmd (int flag, char *ptr) +static t_stat phdebug_cmd (int32 flag, char *ptr) { int val1, val2; @@ -671,7 +671,7 @@ static t_stat phdebug_cmd (int flag, char *ptr) return SCPE_OK; } -static t_stat where_cmd (int flag, char *ptr) +static t_stat where_cmd (int32 flag, char *ptr) { int addr; char *where; @@ -836,7 +836,7 @@ done: savesector(addr, offset, nwords, phid, name); } -static t_stat fdump_cmd (int flags, char *cptr) +static t_stat fdump_cmd (int32 flags, char *cptr) { int addr = 0x7a24; /* address of next statement */ int sofst = 0x7a26, symaddr; diff --git a/Ibm1130/ibm1130_prt.c b/Ibm1130/ibm1130_prt.c index 30fe258c..90103b8f 100644 --- a/Ibm1130/ibm1130_prt.c +++ b/Ibm1130/ibm1130_prt.c @@ -637,7 +637,7 @@ static t_stat prt1403_svc(UNIT *uptr) /* delete_cmd - SCP command to delete a file */ -static t_stat delete_cmd (int flag, char *cptr) +static t_stat delete_cmd (int32 flag, char *cptr) { char gbuf[CBUFSIZE]; int status; diff --git a/Ibm1130/ibm1130_ptrp.c b/Ibm1130/ibm1130_ptrp.c index 71498e3c..c24a27d4 100644 --- a/Ibm1130/ibm1130_ptrp.c +++ b/Ibm1130/ibm1130_ptrp.c @@ -37,7 +37,7 @@ static t_stat ptr_svc (UNIT *uptr); static t_stat ptr_reset (DEVICE *dptr); static t_stat ptr_attach (UNIT *uptr, char *cptr); static t_stat ptr_detach (UNIT *uptr); -static t_stat ptr_boot (int unitno, DEVICE *dptr); +static t_stat ptr_boot (int32 unitno, DEVICE *dptr); static t_stat ptp_svc (UNIT *uptr); static t_stat ptp_reset (DEVICE *dptr); static t_stat ptp_attach (UNIT *uptr, char *cptr); @@ -228,7 +228,7 @@ static t_stat ptr_detach (UNIT *uptr) /* ptr_attach - perform paper tape initial program load */ -static t_stat ptr_boot (int unitno, DEVICE *dptr) +static t_stat ptr_boot (int32 unitno, DEVICE *dptr) { int ch, nch, val, addr; t_bool leader = TRUE, start = FALSE; diff --git a/NOVA/eclipse_cpu.c b/NOVA/eclipse_cpu.c index 7802a1a8..50f0bfcf 100644 --- a/NOVA/eclipse_cpu.c +++ b/NOVA/eclipse_cpu.c @@ -5957,12 +5957,12 @@ int32 Debug_Entry(int32 PC, int32 inst, int32 inst2, int32 AC0, int32 AC1, int32 return 0; } -int32 Debug_Dump(UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat Debug_Dump(UNIT *uptr, int32 val, char *cptr, void *desc) { return SCPE_OK; } -int32 Dump_History (FILE *st, UNIT *uptr, int32 val, void *desc) +t_stat Dump_History (FILE *st, UNIT *uptr, int32 val, void *desc) { char debmap[4], debion[4]; t_value simeval[20]; diff --git a/NOVA/nova_defs.h b/NOVA/nova_defs.h index b21d573a..1dabed0e 100644 --- a/NOVA/nova_defs.h +++ b/NOVA/nova_defs.h @@ -228,14 +228,14 @@ struct ndev { int32 mask; /* done/busy mask */ int32 pi; /* assigned pi bit */ - int32 (*routine)(); /* dispatch routine */ + int32 (*routine)(int32, int32, int32); /* dispatch routine */ }; typedef struct { int32 dnum; /* device number */ int32 mask; /* done/busy mask */ int32 pi; /* assigned pi bit */ - int32 (*routine)(); /* dispatch routine */ + int32 (*routine)(int32, int32, int32); /* dispatch routine */ } DIB; /* Device flags (simulator representation) diff --git a/NOVA/nova_sys.c b/NOVA/nova_sys.c index 0dab680b..4b066f54 100644 --- a/NOVA/nova_sys.c +++ b/NOVA/nova_sys.c @@ -861,7 +861,8 @@ return SCPE_ARG; char *get_addr (char *cptr, t_addr addr, t_bool ext, int32 cflag, int32 *val) { -int32 d, r, x, pflag; +int32 d, x, pflag; +t_stat r; char gbuf[CBUFSIZE]; int32 dmax, dsign; diff --git a/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c index 652341d8..b73e88c0 100644 --- a/PDP10/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -446,24 +446,24 @@ const d10 bytemask[64] = { 0, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES }; -static t_bool (*io700d[16])() = { +static t_bool (*io700d[16])(a10, int32) = { &aprid, NULL, NULL, NULL, &wrapr, &rdapr, &czapr, &coapr, NULL, NULL, NULL, NULL, &wrpi, &rdpi, &czpi, &copi }; -static t_bool (*io701d[16])() = { +static t_bool (*io701d[16])(a10, int32) = { NULL, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -static t_bool (*io702d[16])() = { +static t_bool (*io702d[16])(a10, int32) = { &rdspb, &rdcsb, &rdpur, &rdcstm, &rdtim, &rdint, &rdhsb, NULL, &wrspb, &wrcsb, &wrpur, &wrcstm, &wrtim, &wrint, &wrhsb, NULL }; #define io700i io700d -static t_bool (*io701i[16])() = { +static t_bool (*io701i[16])(a10, int32) = { &clrcsh, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL, NULL, &rdpcst, NULL, &wrpcst, NULL, NULL, NULL, NULL }; -static t_bool (*io702i[16])() = { +static t_bool (*io702i[16])(a10, int32) = { &sdbr1, &sdbr2, &sdbr3, &sdbr4, &rdtim, &rdint, &rdhsb, &spm, &ldbr1, &ldbr2, &ldbr3, &ldbr4, &wrtim, &wrint, &wrhsb, &lpmr }; @@ -697,7 +697,7 @@ for ( ;; ) { /* loop until ABORT */ int32 op, ac, i, st, xr, xct_cnt, its_2pr, pflgs; a10 ea; d10 inst, mb, indrct, rs[2]; -t_bool (*fptr)(); +t_bool (*fptr)(int32, int32); pager_PC = PC; /* update pager PC */ pager_tc = FALSE; /* not in trap cycle */ diff --git a/PDP11/pdp11_mscp.h b/PDP11/pdp11_mscp.h index 4e3c9698..9dd07c90 100644 --- a/PDP11/pdp11_mscp.h +++ b/PDP11/pdp11_mscp.h @@ -84,6 +84,7 @@ #define MD_ACL 0x0002 /* t avl: all class NI */ #define MD_NXU 0x0001 /* b gus: next unit */ #define MD_RIP 0x0001 /* d onl: allow rip NI */ +#define MD_SPD 0x0001 /* d avl: spin-down */ /* End flags */ diff --git a/PDP11/pdp11_rp.c b/PDP11/pdp11_rp.c index 1ae0bbe7..f3503cc7 100644 --- a/PDP11/pdp11_rp.c +++ b/PDP11/pdp11_rp.c @@ -25,6 +25,10 @@ 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 21-Nov-05 RMS Enable/disable device also enables/disables Massbus adapter 12-Nov-05 RMS Fixed DriveClear, does not clear disk address @@ -65,6 +69,7 @@ #endif +#include "sim_disk.h" #include #define RP_CTRL 0 /* ctrl is RP */ @@ -93,6 +98,9 @@ /* Parameters in the unit descriptor */ #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 */ @@ -319,19 +327,20 @@ struct drvtyp { int32 size; /* #blocks */ int32 devtype; /* device type */ int32 ctrl; /* ctrl type */ + char *name; /* device type name */ }; static struct drvtyp drv_tab[] = { - { RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV, RM_CTRL }, - { RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV, RP_CTRL }, - { RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV, RM_CTRL }, - { RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV, RP_CTRL }, - { RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV, RM_CTRL }, - { RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_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" }, + { 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" }, + { 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" }, { 0 } }; -uint16 *rpxb = NULL; /* xfer buffer */ +uint16 *rpxb[RP_NUMDR] = { 0 }; /* xfer buffer */ uint16 rpcs1[RP_NUMDR] = { 0 }; /* control/status 1 */ uint16 rpda[RP_NUMDR] = { 0 }; /* track/sector */ 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 rpec2[RP_NUMDR] = { 0 }; /* ECC correction 2 */ 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 */ static const char *rp_fname[CS1_N_FNC] = { "NOP", "UNLD", "SEEK", "RECAL", "DCLR", "RLS", "OFFS", "RETN", @@ -767,6 +776,15 @@ int32 rp_abort (void) 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 Complete movement or data transfer command @@ -791,96 +809,127 @@ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ rp_update_ds (DS_ATA, drv); /* set attn */ 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 */ - rp_update_ds (DS_OFM | DS_ATA, drv); - break; + case FNC_OFFSET: /* offset */ + rp_update_ds (DS_OFM | DS_ATA, drv); + break; - case FNC_RETURN: /* return to centerline */ - rpds[drv] = rpds[drv] & ~DS_OFM; /* clear offset, set attn */ - rp_update_ds (DS_ATA, drv); - break; + case FNC_RETURN: /* return to centerline */ + rpds[drv] = rpds[drv] & ~DS_OFM; /* clear offset, set attn */ + rp_update_ds (DS_ATA, drv); + break; - case FNC_UNLOAD: /* unload */ - rp_detach (uptr); /* detach unit */ - break; + case FNC_UNLOAD: /* unload */ + rp_detach (uptr); /* detach unit */ + break; - case FNC_RECAL: /* recalibrate */ - case FNC_SEARCH: /* search */ - case FNC_SEEK: /* seek */ - rp_update_ds (DS_ATA, drv); - break; + case FNC_RECAL: /* recalibrate */ + case FNC_SEARCH: /* search */ + case FNC_SEEK: /* seek */ + rp_update_ds (DS_ATA, drv); + break; - case FNC_WRITE: /* write */ - if (uptr->flags & UNIT_WPRT) { /* write locked? */ - rp_set_er (ER1_WLE, drv); /* set drive error */ - mba_set_exc (rp_dib.ba); /* set exception */ - rp_update_ds (DS_ATA, drv); /* set attn */ - return SCPE_OK; - } - case FNC_WCHK: /* write check */ - case FNC_READ: /* read */ - case FNC_READH: /* read headers */ - err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); - mbc = mba_get_bc (rp_dib.ba); /* get byte count */ - wc = (mbc + 1) >> 1; /* convert to words */ - if ((da + wc) > drv_tab[dtype].size) { /* disk overrun? */ - rp_set_er (ER1_AOE, drv); /* set err */ - wc = drv_tab[dtype].size - da; /* trim xfer */ - mbc = wc << 1; /* trim mb count */ - if (da >= drv_tab[dtype].size) { /* none left? */ + case FNC_WRITE: /* write */ + if (uptr->flags & UNIT_WPRT) { /* write locked? */ + rp_set_er (ER1_WLE, drv); /* set drive error */ mba_set_exc (rp_dib.ba); /* set exception */ rp_update_ds (DS_ATA, drv); /* set attn */ - break; + return SCPE_OK; } - } - if (fnc == FNC_WRITE) { /* write? */ - abc = mba_rdbufW (rp_dib.ba, mbc, rpxb); /* get buffer */ - wc = (abc + 1) >> 1; /* actual # wds */ - awc = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); - for (i = wc; i < awc; i++) /* fill buf */ - rpxb[i] = 0; - if (wc && !err) { /* write buf */ - fxwrite (rpxb, sizeof (uint16), awc, uptr->fileref); - err = ferror (uptr->fileref); + 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 ((da + wc) > drv_tab[dtype].size) { /* disk overrun? */ + rp_set_er (ER1_AOE, drv); /* set err */ + wc = drv_tab[dtype].size - da; /* trim xfer */ + mbc = wc << 1; /* trim mb count */ + if (da >= drv_tab[dtype].size) { /* none left? */ + mba_set_exc (rp_dib.ba); /* set exception */ + rp_update_ds (DS_ATA, drv); /* set attn */ + break; + } } - } /* end if wr */ - else { /* read or wchk */ - awc = fxread (rpxb, sizeof (uint16), wc, uptr->fileref); - err = ferror (uptr->fileref); - for (i = awc; i < wc; i++) /* fill buf */ - rpxb[i] = 0; - if (fnc == FNC_WCHK) /* write check? */ - mba_chbufW (rp_dib.ba, mbc, rpxb); /* check vs mem */ - else mba_wrbufW (rp_dib.ba, mbc, rpxb); /* store in mem */ - } /* end if read */ - da = da + wc + (RP_NUMWD - 1); - if (da >= drv_tab[dtype].size) - rpds[drv] = rpds[drv] | DS_LST; - da = da / RP_NUMWD; - rpda[drv] = da % drv_tab[dtype].sect; - da = da / drv_tab[dtype].sect; - rpda[drv] = rpda[drv] | ((da % drv_tab[dtype].surf) << DA_V_SF); - rpdc[drv] = da / drv_tab[dtype].surf; - uptr->CYL = rpdc[drv]; + if (fnc == FNC_WRITE) { /* write? */ + abc = mba_rdbufW (rp_dib.ba, mbc, rpxb[drv]);/* get buffer */ + wc = (abc + 1) >> 1; /* actual # wds */ + awc = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); + for (i = wc; i < awc; i++) /* fill buf */ + rpxb[drv][i] = 0; + sim_disk_wrsect_a (uptr, da/RP_NUMWD, (void *)rpxb[drv], NULL, awc/RP_NUMWD, rp_io_complete); + return SCPE_OK; + } /* end if wr */ + else { /* read or wchk */ + awc = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); + 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 */ - if (err != 0) { /* error? */ - rp_set_er (ER1_PAR, drv); /* set drive error */ - mba_set_exc (rp_dib.ba); /* set exception */ - rp_update_ds (DS_ATA, drv); - perror ("RP I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } + 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; - 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 */ + 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 */ + rpxb[drv][i] = 0; + if (fnc == FNC_WCHK) /* write check? */ + mba_chbufW (rp_dib.ba, mbc, rpxb[drv]); /* check vs mem */ + else mba_wrbufW (rp_dib.ba, mbc, rpxb[drv]);/* store in mem */ + } /* end if read */ + da = da + wc + (RP_NUMWD - 1); + if (da >= drv_tab[dtype].size) + rpds[drv] = rpds[drv] | DS_LST; + da = da / RP_NUMWD; + rpda[drv] = da % drv_tab[dtype].sect; + da = da / drv_tab[dtype].sect; + rpda[drv] = rpda[drv] | ((da % drv_tab[dtype].surf) << DA_V_SF); + rpdc[drv] = da / drv_tab[dtype].surf; + uptr->CYL = rpdc[drv]; + + if (err != 0) { /* error? */ + rp_set_er (ER1_PAR, drv); /* set drive error */ + mba_set_exc (rp_dib.ba); /* set exception */ + rp_update_ds (DS_ATA, drv); + perror ("RP I/O error"); + return SCPE_IOERR; + } + + mba_set_don (rp_dib.ba); /* set done */ + rp_update_ds (0, drv); /* update ds */ + break; + } /* end case func */ + } +rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */ if (DEBUG_PRS (rp_dev)) 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; rmmr2[i] = 0; rmhr[i] = 0; + if (rpxb[i] == NULL) + rpxb[i] = (uint16 *) calloc (RP_MAXFR, sizeof (uint16)); + if (rpxb[i] == NULL) + return SCPE_MEM; } -if (rpxb == NULL) - rpxb = (uint16 *) calloc (RP_MAXFR, sizeof (uint16)); -if (rpxb == NULL) - return SCPE_MEM; return SCPE_OK; } @@ -979,7 +1028,9 @@ int32 drv, i, p; t_stat r; 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? */ return r; 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; 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? */ return SCPE_OK; +p = (int32)sim_disk_size (uptr); for (i = 0; drv_tab[i].sect != 0; i++) { if (p <= (drv_tab[i].size * (int) sizeof (int16))) { 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 */ rpds[drv] = rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OFM); rp_update_ds (DS_ATA, drv); /* request intr */ -return detach_unit (uptr); +return sim_disk_detach (uptr); } /* Set size command validation routine */ diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index 89da0cb5..8bd6044e 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -26,6 +26,19 @@ 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 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread 31-Oct-05 RMS Fixed address width for large files @@ -97,6 +110,7 @@ extern int32 cpu_opt; #include "pdp11_uqssp.h" #include "pdp11_mscp.h" +#include "sim_disk.h" #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_DTYPE (UNIT_V_UF + 3) /* drive type */ #define UNIT_M_DTYPE 0x1F +#define UNIT_V_NOAUTO (UNIT_V_UF + 8) /* noautosize */ #define UNIT_ONL (1 << UNIT_V_ONL) #define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_ATP (1 << UNIT_V_ATP) +#define UNIT_NOAUTO (1 << UNIT_V_NOAUTO) #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) #define cpkt u3 /* current packet */ #define pktq u4 /* packet queue */ #define uf buf /* settable unit flags */ #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 RQ_RMV(u) ((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RMV)? \ UF_RMV: 0) #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_WR 1 /* stage 1 wrap */ @@ -567,7 +586,6 @@ extern FILE *sim_deb; extern uint32 sim_taddr_64; extern int32 sim_switches; -uint16 *rqxb = NULL; /* xfer buffer */ int32 rq_itime = 200; /* init time, except */ int32 rq_itime4 = 10; /* stage 4 */ int32 rq_qtime = RQ_QTIME; /* queue time */ @@ -597,7 +615,56 @@ typedef struct { struct rqpkt pak[RQ_NPKTS]; /* packet queue */ } 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_wr (int32 data, int32 PA, int32 access); @@ -686,9 +753,11 @@ REG rq_reg[] = { { GRDATA (SAW, rq_ctx.saw, DEV_RDX, 16, 0) }, { GRDATA (S1DAT, rq_ctx.s1dat, DEV_RDX, 16, 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 (CQLNT, rq_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, { 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 (RQLNT, rq_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (RQIDX, rq_ctx.rq.idx, DEV_RDX, 8, 2) }, @@ -774,6 +843,10 @@ MTAB rq_mod[] = { &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, 0, "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) { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", &set_addr, &show_addr, NULL }, @@ -793,7 +866,8 @@ DEVICE rq_dev = { RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, NULL, NULL, &rq_reset, &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 @@ -829,9 +903,11 @@ REG rqb_reg[] = { { GRDATA (SAW, rqb_ctx.saw, DEV_RDX, 16, 0) }, { GRDATA (S1DAT, rqb_ctx.s1dat, DEV_RDX, 16, 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 (CQLNT, rqb_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, { 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 (RQLNT, rqb_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, { 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 (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 (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 (DEVVEC, rqb_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { NULL } @@ -862,7 +938,8 @@ DEVICE rqb_dev = { RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, NULL, NULL, &rq_reset, &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 @@ -898,9 +975,11 @@ REG rqc_reg[] = { { GRDATA (SAW, rqc_ctx.saw, DEV_RDX, 16, 0) }, { GRDATA (S1DAT, rqc_ctx.s1dat, DEV_RDX, 16, 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 (CQLNT, rqc_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, { 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 (RQLNT, rqc_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, { 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 (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 (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 (DEVVEC, rqc_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { NULL } @@ -931,7 +1010,8 @@ DEVICE rqc_dev = { RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, NULL, NULL, &rq_reset, &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 @@ -967,9 +1047,11 @@ REG rqd_reg[] = { { GRDATA (SAW, rqd_ctx.saw, DEV_RDX, 16, 0) }, { GRDATA (S1DAT, rqd_ctx.s1dat, DEV_RDX, 16, 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 (CQLNT, rqd_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, { 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 (RQLNT, rqd_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, { 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 (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 (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 (DEVVEC, rqd_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { NULL } @@ -1000,7 +1082,8 @@ DEVICE rqd_dev = { RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, NULL, NULL, &rq_reset, &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] = { @@ -1023,6 +1106,8 @@ int32 cidx = rq_map_pa ((uint32) PA); MSC *cp = rq_ctxmap[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) return SCPE_IERR; 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? */ rq_step4 (cp); else if (cp->csta == CST_UP) { /* if up */ - if (DEBUG_PRD (dptr)) - fprintf (sim_deb, ">>RQ%c: poll started, PC=%X\n", - 'A' + cp->cnum, OLDPC); + sim_debug (DBG_REQ, dptr, "poll started, PC=%X\n", OLDPC); cp->pip = 1; /* poll host */ sim_activate (dptr->units + RQ_QUEUE, rq_qtime); } @@ -1044,7 +1127,6 @@ switch ((PA >> 1) & 01) { /* decode PA<1> */ *data = cp->sa; break; } - return SCPE_OK; } @@ -1056,13 +1138,14 @@ DEVICE *dptr = rq_devmap[cidx]; if (cidx < 0) 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> */ case 0: /* IP */ rq_reset (rq_devmap[cidx]); /* init device */ - if (DEBUG_PRD (dptr)) - fprintf (sim_deb, ">>RQ%c: initialization started\n", - 'A' + cp->cnum); + sim_debug (DBG_REQ, dptr, "initialization started\n"); break; case 1: /* SA */ @@ -1147,7 +1230,12 @@ MSC *cp = rq_ctxmap[uptr->cnum]; DEVICE *dptr = rq_devmap[uptr->cnum]; DIB *dibp = (DIB *) dptr->ctxt; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_quesvc\n"); + 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? */ case CST_S1: /* need S1 reply */ @@ -1197,8 +1285,7 @@ if (cp->csta < CST_UP) { /* still init? */ case CST_S4: /* need S4 reply */ if (cp->saw & SA_S4H_GO) { /* go set? */ - if (DEBUG_PRD (dptr)) - fprintf (sim_deb, ">>RQ%c: initialization complete\n", 'A' + cp->cnum); + sim_debug (DBG_REQ, dptr, "initialization complete\n"); cp->csta = CST_UP; /* we're up */ cp->sa = 0; /* clear SA */ 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 */ return SCPE_OK; if (pkt) { /* got one? */ - if (DEBUG_PRD (dptr)) { - fprintf (sim_deb, ">>RQ%c: cmd=%04X, mod=%04X, unit=%d, ", - 'A' + cp->cnum, cp->pak[pkt].d[CMD_OPC], - 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", + sim_debug (DBG_REQ, dptr, "cmd=%04X(%3s), mod=%04X, unit=%d, bc=%04X%04X, ma=%04X%04X, lbn=%04X%04X\n", + cp->pak[pkt].d[CMD_OPC], rq_cmdname[cp->pak[pkt].d[CMD_OPC]&0x3f], + cp->pak[pkt].d[CMD_MOD], cp->pak[pkt].d[CMD_UN], 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_LBNH], cp->pak[pkt].d[RW_LBNL]); - } if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */ return rq_fatal (cp, PE_PIE); /* no, term thread */ 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 */ if (!rq_putpkt (cp, pkt, FALSE)) /* send to host */ return SCPE_OK; + sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_quesvc - rq_putpkt failed - 1\n"); } /* end if resp q */ if (pkt) /* more to do? */ sim_activate (uptr, rq_qtime); @@ -1268,6 +1353,7 @@ UNIT *nuptr; MSC *cp = rq_ctxmap[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 */ for (i = 0; i < RQ_NUMDR; i++) { /* poll */ 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); +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_mscp - %s\n", q? "Queue" : "No Queue"); + switch (cmd) { case OP_ABO: /* abort */ @@ -1351,6 +1439,8 @@ int32 tpkt, prv; UNIT *uptr; DEVICE *dptr = rq_devmap[cp->cnum]; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_abo\n"); + tpkt = 0; /* set no mtch */ if (uptr = rq_getucb (cp, lu)) { /* get unit */ 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 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ +uint32 mdf = cp->pak[pkt].d[CMD_MOD]; /* modifier */ uint32 sts; UNIT *uptr; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_avl\n"); + if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ if (q && uptr->cpkt) { /* need to queue? */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */ return OK; } 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 */ sts = ST_SUC; /* success */ } @@ -1417,6 +1512,8 @@ uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */ int32 tpkt; UNIT *uptr; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_gcs\n"); + if ((uptr = rq_getucb (cp, lu)) && /* valid lu? */ (tpkt = uptr->cpkt) && /* queued pkt? */ (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */ @@ -1441,6 +1538,8 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 dtyp, sts, rbpar; 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 (lu >= (cp->ubase + RQ_NUMDR)) { /* end of range? */ lu = 0; /* reset to 0 */ @@ -1482,6 +1581,8 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 sts; UNIT *uptr; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_onl\n"); + if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ if (q && uptr->cpkt) { /* need to queue? */ 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 */ else if (uptr->flags & UNIT_ONL) /* already online? */ sts = ST_SUC | SB_SUC_ON; - else { /* mark online */ + else if (sim_disk_isavailable (uptr)) + { /* mark online */ sts = ST_SUC; uptr->flags = uptr->flags | UNIT_ONL; 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 */ } else sts = ST_OFL; /* offline */ @@ -1511,6 +1615,8 @@ t_bool rq_scc (MSC *cp, int32 pkt, t_bool q) { int32 sts, cmd; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_scc\n"); + if (cp->pak[pkt].d[SCC_MSV]) { /* MSCP ver = 0? */ sts = ST_CMD | I_VRSN; /* no, lose */ cmd = 0; @@ -1547,6 +1653,8 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 sts; UNIT *uptr; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_suc\n"); + if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ if (q && uptr->cpkt) { /* need to queue? */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */ @@ -1576,6 +1684,8 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 sts; UNIT *uptr; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_fmt\n"); + if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ if (q && uptr->cpkt) { /* need to queue? */ rq_enqt (cp, &uptr->pktq, pkt); /* do later */ @@ -1610,8 +1720,11 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 sts; 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 (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 */ 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_WBLL] = cp->pak[pkt].d[RW_LBNL]; 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 */ } } @@ -1674,12 +1789,28 @@ if ((cmd == OP_WR) || (cmd == OP_ERS)) { /* write op? */ 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 */ t_stat rq_svc (UNIT *uptr) { MSC *cp = rq_ctxmap[uptr->cnum]; - uint32 i, t, tbc, abc, wwc; uint32 err = 0; 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 bc = GETP32 (pkt, RW_WBCL); /* byte count */ 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??? */ return STOP_RQ; @@ -1713,77 +1847,85 @@ if ((cmd == OP_ERS) || (cmd == OP_WR)) { /* write op? */ } } -if (cmd == OP_ERS) { /* erase? */ - wwc = ((tbc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; - for (i = 0; i < wwc; i++) /* clr buf */ - rqxb[i] = 0; - err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */ - if (!err) - sim_fwrite (rqxb, sizeof (int16), wwc, uptr->fileref); - err = ferror (uptr->fileref); /* end if 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; + memset (uptr->rqxb, 0, wwc * sizeof(uint16)); /* clr buf */ + 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_disk_wrsect_a (uptr, bl, uptr->rqxb, NULL, (wwc << 1) / RQ_NUMBY, rq_io_complete); + } -else if (cmd == OP_WR) { /* write? */ - t = Map_ReadW (ba, tbc, rqxb); /* fetch buffer */ - if (abc = tbc - t) { /* any xfer? */ - wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; - for (i = (abc >> 1); i < wwc; i++) - rqxb[i] = 0; - err = sim_fseek (uptr->fileref, da, SEEK_SET); - if (!err) - sim_fwrite (rqxb, sizeof (int16), wwc, uptr->fileref); - err = ferror (uptr->fileref); - } - if (t) { /* nxm? */ - PUTP32 (pkt, RW_WBCL, bc - abc); /* adj bc */ - PUTP32 (pkt, RW_WBAL, ba + abc); /* adj ba */ - if (rq_hbe (cp, uptr)) /* post err log */ - rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); - return SCPE_OK; /* end else wr */ - } - } - -else { - err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */ - 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 (t = Map_WriteW (ba, tbc, rqxb)) { /* store, nxm? */ - PUTP32 (pkt, RW_WBCL, bc - (tbc - t)); /* adj bc */ - PUTP32 (pkt, RW_WBAL, ba + (tbc - t)); /* adj ba */ - if (rq_hbe (cp, uptr)) /* post err log */ - rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); - return SCPE_OK; + else if (cmd == OP_WR) { /* write? */ + t = Map_ReadW (ba, tbc, uptr->rqxb); /* fetch buffer */ + if (abc = tbc - t) { /* any xfer? */ + wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; + for (i = (abc >> 1); i < wwc; i++) + ((uint16 *)(uptr->rqxb))[i] = 0; + sim_disk_data_trace(uptr, uptr->rqxb, bl, wwc << 1, "sim_disk_wrsect-WR", DBG_DAT & rq_devmap[cp->cnum]->dctrl, DBG_REQ); + err = sim_disk_wrsect_a (uptr, bl, uptr->rqxb, NULL, (wwc << 1) / RQ_NUMBY, rq_io_complete); } } - else if ((cmd == OP_CMP) && !err) { /* compare? */ - uint8 dby, mby; - for (i = 0; i < tbc; i++) { /* loop */ - if (Map_ReadB (ba + i, 1, &mby)) { /* fetch, nxm? */ - PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ - PUTP32 (pkt, RW_WBAL, bc - i); /* adj ba */ + + 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? */ + PUTP32 (pkt, RW_WBCL, bc - abc); /* adj bc */ + PUTP32 (pkt, RW_WBAL, ba + abc); /* adj ba */ + if (rq_hbe (cp, uptr)) /* post err log */ + rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); + return SCPE_OK; /* end else wr */ + } + } + + else { + sim_disk_data_trace(uptr, uptr->rqxb, bl, tbc, "sim_disk_rdsect", DBG_DAT & rq_devmap[cp->cnum]->dctrl, DBG_REQ); + if ((cmd == OP_RD) && !err) { /* read? */ + if (t = Map_WriteW (ba, tbc, uptr->rqxb)) { /* store, nxm? */ + PUTP32 (pkt, RW_WBCL, bc - (tbc - t)); /* adj bc */ + PUTP32 (pkt, RW_WBAL, ba + (tbc - t)); /* adj ba */ if (rq_hbe (cp, uptr)) /* post err log */ - 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; } - dby = (rqxb[i >> 1] >> ((i & 1)? 8: 0)) & 0xFF; - if (mby != dby) { /* cmp err? */ - PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ - rq_rw_end (cp, uptr, 0, ST_CMP); /* done */ - return SCPE_OK; /* exit */ - } /* end if */ - } /* end for */ - } /* end else if */ - } /* end else read */ + } + else if ((cmd == OP_CMP) && !err) { /* compare? */ + uint8 dby, mby; + for (i = 0; i < tbc; i++) { /* loop */ + if (Map_ReadB (ba + i, 1, &mby)) { /* fetch, nxm? */ + PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ + PUTP32 (pkt, RW_WBAL, bc - i); /* adj ba */ + if (rq_hbe (cp, uptr)) /* post err log */ + rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); + return SCPE_OK; + } + dby = (((uint16 *)(uptr->rqxb))[i >> 1] >> ((i & 1)? 8: 0)) & 0xFF; + if (mby != dby) { /* cmp err? */ + PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ + rq_rw_end (cp, uptr, 0, ST_CMP); /* done */ + return SCPE_OK; /* exit */ + } /* end if */ + } /* end for */ + } /* end else if */ + } /* end else read */ + } /* end else bottom end */ if (err != 0) { /* error? */ if (rq_dte (cp, uptr, ST_DRV)) /* post err log */ rq_rw_end (cp, uptr, EF_LOG, ST_DRV); /* if ok, report err */ perror ("RQ I/O error"); - clearerr (uptr->fileref); + if (!(uptr->flags | UNIT_RAW)) + clearerr (uptr->fileref); return SCPE_IOERR; } ba = ba + tbc; /* incr bus addr */ @@ -1793,7 +1935,7 @@ PUTP32 (pkt, RW_WBAL, ba); /* update pkt */ PUTP32 (pkt, RW_WBCL, bc); PUTP32 (pkt, RW_WBLL, bl); if (bc) /* more? resched */ - sim_activate (uptr, rq_xtime); + sim_activate (uptr, 0); else rq_rw_end (cp, uptr, 0, ST_SUC); /* done! */ return SCPE_OK; } @@ -1808,6 +1950,8 @@ uint32 bc = GETP32 (pkt, RW_BCL); /* init bc */ uint32 wbc = GETP32 (pkt, RW_WBCL); /* work bc */ DEVICE *dptr = rq_devmap[uptr->cnum]; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_rw_end\n"); + uptr->cpkt = 0; /* done */ PUTP32 (pkt, RW_BCL, bc - wbc); /* bytes processed */ 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; 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? */ return OK; if (!rq_deqf (cp, &pkt)) /* get log pkt */ @@ -1883,6 +2029,8 @@ t_bool rq_hbe (MSC *cp, UNIT *uptr) { int32 pkt, tpkt; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_hbe\n"); + if ((cp->cflgs & CF_THS) == 0) /* logging? */ return OK; if (!rq_deqf (cp, &pkt)) /* get log pkt */ @@ -1912,6 +2060,8 @@ t_bool rq_plf (MSC *cp, uint32 err) { int32 pkt; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_plf\n"); + if (!rq_deqf (cp, &pkt)) /* get log pkt */ return ERR; cp->pak[pkt].d[ELP_REFL] = 0; /* ref = 0 */ @@ -1933,12 +2083,13 @@ return rq_putpkt (cp, pkt, TRUE); /* Unit now available attention packet */ -int32 rq_una (MSC *cp, int32 un) +t_bool rq_una (MSC *cp, int32 un) { int32 pkt; uint32 lu = cp->ubase + un; UNIT *uptr = rq_getucb (cp, lu); +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_una (Unit=%d)\n", lu); if (uptr == NULL) /* huh? */ return OK; if (!rq_deqf (cp, &pkt)) /* get log pkt */ @@ -2039,9 +2190,8 @@ DEVICE *dptr = rq_devmap[cp->cnum]; if (pkt == 0) /* any packet? */ return OK; -if (DEBUG_PRD (dptr)) - 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]); +sim_debug (DBG_REQ, dptr, "rsp=%04X, sts=%04X\n", + cp->pak[pkt].d[RSP_OPF], cp->pak[pkt].d[RSP_STS]); if (!rq_getdesc (cp, &cp->rq, &desc)) /* get rsp desc */ return ERR; if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */ @@ -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 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_UFL] = uptr->uf | UF_RPL | RQ_WPH (uptr) | RQ_RMV (uptr); cp->pak[pkt].d[ONL_RSVL] = 0; /* reserved */ @@ -2205,6 +2357,8 @@ return; void rq_setint (MSC *cp) { +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_setint\n"); + cp->irq = 1; /* set ctrl int */ SET_INT (RQ); /* set master int */ return; @@ -2217,6 +2371,8 @@ void rq_clrint (MSC *cp) int32 i; MSC *ncp; +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_clrint\n"); + cp->irq = 0; /* clr ctrl int */ for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrls */ ncp = rq_ctxmap[i]; /* get context */ @@ -2256,8 +2412,9 @@ t_bool rq_fatal (MSC *cp, uint32 err) { DEVICE *dptr = rq_devmap[cp->cnum]; -if (DEBUG_PRD (dptr)) - fprintf (sim_deb, ">>RQ%c: fatal err=%X\n", 'A' + cp->cnum, err); +sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_fatal\n"); + +sim_debug (DBG_REQ, dptr, "fatal err=%X\n", err); rq_reset (rq_devmap[cp->cnum]); /* reset device */ cp->sa = SA_ER | err; /* SA = dead code */ cp->csta = CST_DEAD; /* state = dead */ @@ -2330,10 +2487,11 @@ t_stat rq_attach (UNIT *uptr, char *cptr) MSC *cp = rq_ctxmap[uptr->cnum]; 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) return r; -if (cp->csta == CST_UP) + +if ((cp->csta == CST_UP) && sim_disk_isavailable (uptr)) uptr->flags = uptr->flags | UNIT_ATP; return SCPE_OK; } @@ -2344,7 +2502,7 @@ t_stat rq_detach (UNIT *uptr) { t_stat r; -r = detach_unit (uptr); /* detach unit */ +r = sim_disk_detach (uptr); /* detach unit */ if (r != SCPE_OK) return r; uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP); /* clr onl, atn pend */ @@ -2361,6 +2519,8 @@ UNIT *uptr; MSC *cp; 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 */ if (rq_devmap[i] == dptr) 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->uf = 0; /* clr unit flags */ uptr->cpkt = uptr->pktq = 0; /* clr pkt q's */ + uptr->rqxb = (uint16 *) realloc (uptr->rqxb, (RQ_MAXFR >> 1) * sizeof (uint16)); + if (uptr->rqxb == NULL) + return SCPE_MEM; } -if (rqxb == NULL) - rqxb = (uint16 *) calloc (RQ_MAXFR >> 1, sizeof (uint16)); -if (rqxb == NULL) - return SCPE_MEM; return auto_config (0, 0); /* run autoconfig */ } diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c index 73d60a39..bba47ec4 100644 --- a/PDP11/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -130,7 +130,7 @@ t_stat rx_wr (int32 data, int32 PA, int32 access); t_stat rx_svc (UNIT *uptr); t_stat rx_reset (DEVICE *dptr); t_stat rx_boot (int32 unitno, DEVICE *dptr); -void rx_done (int esr_flags, int new_ecode); +void rx_done (int32 esr_flags, int32 new_ecode); /* RX11 data structures diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c index 23a86595..5d69ae0f 100644 --- a/PDP11/pdp11_ry.c +++ b/PDP11/pdp11_ry.c @@ -161,7 +161,7 @@ t_stat ry_wr (int32 data, int32 PA, int32 access); t_stat ry_svc (UNIT *uptr); t_stat ry_reset (DEVICE *dptr); t_stat ry_boot (int32 unitno, DEVICE *dptr); -void ry_done (int esr_flags, int new_ecode); +void ry_done (int32 esr_flags, int32 new_ecode); t_stat ry_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat ry_attach (UNIT *uptr, char *cptr); diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index 27be77e5..ce1d79f8 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -25,20 +25,23 @@ 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 + 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 + 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. - - Added textual display of the command being performed - 23-Dec-10 RMS Fixed comments about register addresses + 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 16-Feb-06 RMS Revised for new magtape capacity checking 31-Oct-05 RMS Fixed address width for large files @@ -115,7 +118,10 @@ extern int32 cpu_opt; #define pktq u4 /* packet queue */ #define uf buf /* settable unit flags */ #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 results up7 /* xfer buffer & results */ #define CST_S1 0 /* init stage 1 */ #define CST_S1_WR 1 /* stage 1 wrap */ @@ -240,7 +246,6 @@ extern int32 tmr_poll, clk_tps; extern FILE *sim_deb; extern uint32 sim_taddr_64; -uint8 *tqxb = NULL; /* xfer buffer */ uint32 tq_sa = 0; /* status, addr */ uint32 tq_saw = 0; /* written data */ uint32 tq_s1dat = 0; /* S1 data */ @@ -340,7 +345,7 @@ DEVICE tq_dev; t_stat tq_rd (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_tmrsvc (UNIT *uptr); t_stat tq_quesvc (UNIT *uptr); @@ -374,12 +379,10 @@ t_bool tq_dte (UNIT *uptr, uint32 err); t_bool tq_hbe (UNIT *uptr, uint32 ba); t_bool tq_una (UNIT *uptr); uint32 tq_map_status (UNIT *uptr, t_stat st); -uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec); -uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped); -uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc); -uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec); -uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped); -uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc); +void tq_rdbuff_top (UNIT *uptr, t_mtrlnt *tbc); +uint32 tq_rdbuff_bottom (UNIT *uptr, t_mtrlnt *tbc); +void tq_rdbufr_top (UNIT *uptr, t_mtrlnt *tbc); +uint32 tq_rdbufr_bottom (UNIT *uptr, t_mtrlnt *tbc); t_bool tq_deqf (int32 *pkt); int32 tq_deqh (int32 *lh); void tq_enqh (int32 *lh, int32 pkt); @@ -429,9 +432,11 @@ REG tq_reg[] = { { GRDATA (SA, tq_sa, DEV_RDX, 16, 0) }, { GRDATA (SAW, tq_saw, 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 (CQLNT, tq_cq.lnt, DEV_RDX, 8, 2), REG_NZ }, { 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 (TQLNT, tq_rq.lnt, DEV_RDX, 8, 2), REG_NZ }, { GRDATA (TQIDX, tq_rq.idx, DEV_RDX, 8, 2) }, @@ -504,12 +509,44 @@ MTAB tq_mod[] = { { 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 = { "TQ", tq_unit, tq_reg, tq_mod, TQ_NUMDR + 2, 10, T_ADDR_W, 1, DEV_RDX, 8, NULL, NULL, &tq_reset, &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 17774500 - 17774502 @@ -520,6 +557,8 @@ DEVICE tq_dev = { 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> */ case 0: /* IP */ *data = 0; /* reads zero */ @@ -541,13 +580,13 @@ return SCPE_OK; 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> */ case 0: /* IP */ tq_reset (&tq_dev); /* init device */ - if (DEBUG_PRS (tq_dev)) - fprintf (sim_deb, ">>TQ: initialization started, time=%.0f\n", - sim_gtime ()); + sim_debug (DBG_REQ, &tq_dev, "initialization started\n"); break; case 1: /* SA */ @@ -611,9 +650,12 @@ int32 i, cnid; int32 pkt = 0; UNIT *nuptr; -if (tq_csta < CST_UP) { /* still init? */ - switch (tq_csta) { /* controller state? */ +sim_debug(DBG_TRC, &tq_dev, "tq_quesvc\n"); +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 */ if (tq_saw & SA_S1H_VL) { /* valid? */ if (tq_saw & SA_S1H_WR) { /* wrap? */ @@ -661,8 +703,7 @@ if (tq_csta < CST_UP) { /* still init? */ case CST_S4: /* need S4 reply */ if (tq_saw & SA_S4H_GO) { /* go set? */ - if (DEBUG_PRS (tq_dev)) - fprintf (sim_deb, ">>TQ: initialization complete\n"); + sim_debug (DBG_REQ, &tq_dev, "initialization complete\n"); tq_csta = CST_UP; /* we're up */ tq_sa = 0; /* clear SA */ sim_activate (&tq_unit[TQ_TIMER], tmr_poll * clk_tps); @@ -687,21 +728,22 @@ if ((pkt == 0) && tq_pip) { /* polling? */ if (!tq_getpkt (&pkt)) /* get host pkt */ return SCPE_OK; if (pkt) { /* got one? */ - if (DEBUG_PRS (tq_dev)) { - UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); - fprintf (sim_deb, ">>TQ: cmd=%04X(%3s), mod=%04X, unit=%d, ", - 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]); - fprintf (sim_deb, "bc=%04X%04X, ma=%04X%04X", - tq_pkt[pkt].d[RW_BCH], tq_pkt[pkt].d[RW_BCL], - tq_pkt[pkt].d[RW_BAH], tq_pkt[pkt].d[RW_BAL]); - if (up) { - fprintf (sim_deb, ", pos="); - fprint_val (sim_deb, up->pos, 10, T_ADDR_W, PV_LEFT); - fprintf (sim_deb, ", obj=%d\n", up->objp); - } - else fprintf (sim_deb, "\n"); - fflush (sim_deb); - } + UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); + + if (up) + 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_BAH], tq_pkt[pkt].d[RW_BAL]); + if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */ return tq_fatal (PE_PIE); /* no, term thread */ cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */ @@ -735,6 +777,8 @@ t_stat tq_tmrsvc (UNIT *uptr) int32 i; UNIT *nuptr; +sim_debug(DBG_TRC, &tq_dev, "tq_tmrsvc\n"); + sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */ for (i = 0; i < TQ_NUMDR; i++) { /* poll */ nuptr = tq_dev.units + i; @@ -762,6 +806,8 @@ uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_mscp\n"); + if ((cmd >= 64) || (tq_cmf[cmd] == 0)) { /* invalid cmd? */ cmd = OP_END; /* set end op */ sts = ST_CMD | I_OPCD; /* ill op */ @@ -785,6 +831,7 @@ else { /* valid cmd */ /* uptr->flags = uptr->flags & ~UNIT_CDL; */ if ((mdf & MD_CSE) && (uptr->flags & UNIT_SXC)) /* clr ser exc? */ uptr->flags = uptr->flags & ~UNIT_SXC; + memset (uptr->results, 0, sizeof (struct tq_req_results)); /* init request state */ } switch (cmd) { @@ -852,6 +899,8 @@ uint32 ref = GETP32 (pkt, ABO_REFL); /* cmd ref # */ int32 tpkt, prv; UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_abo\n"); + tpkt = 0; /* set no mtch */ if (uptr = tq_getucb (lu)) { /* get unit */ if (uptr->cpkt && /* curr pkt? */ @@ -895,6 +944,8 @@ uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifiers */ uint32 sts; UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_avl\n"); + if (uptr = tq_getucb (lu)) { /* unit exist? */ if (uptr->flags & UNIT_SXC) /* ser exc pending? */ sts = ST_SXC; @@ -924,6 +975,8 @@ uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */ int32 tpkt; UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_gcs\n"); + if ((uptr = tq_getucb (lu)) && /* valid lu? */ (tpkt = uptr->cpkt) && /* queued pkt? */ (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */ @@ -944,6 +997,8 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ uint32 sts; UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_gus\n"); + if (tq_pkt[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */ if (lu >= TQ_NUMDR) { /* end of range? */ lu = 0; /* reset to 0 */ @@ -975,6 +1030,8 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ uint32 sts; UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_onl\n"); + if (uptr = tq_getucb (lu)) { /* unit exist? */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ sts = ST_OFL | SB_OFL_NV; /* offl no vol */ @@ -999,6 +1056,8 @@ return tq_putpkt (pkt, TRUE); 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? */ tq_putr (pkt, 0, 0, ST_CMD | I_VRSN, SCC_LNT, UQ_TYP_SEQ); else { @@ -1028,6 +1087,8 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ uint32 sts; UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_suc\n"); + if (uptr = tq_getucb (lu)) { /* unit exist? */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ sts = ST_OFL | SB_OFL_NV; /* offl no vol */ @@ -1050,6 +1111,8 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ uint32 sts; UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_flu\n"); + if (uptr = tq_getucb (lu)) /* unit exist? */ sts = tq_mot_valid (uptr, OP_FLU); /* validate req */ else sts = ST_OFL; /* offline */ @@ -1066,11 +1129,14 @@ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 sts; UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_erase\n"); + if (uptr = tq_getucb (lu)) { /* unit exist? */ sts = tq_mot_valid (uptr, cmd); /* validity checks */ if (sts == ST_SUC) { /* ok? */ uptr->cpkt = pkt; /* op in progress */ - sim_activate (uptr, tq_xtime); /* activate */ + uptr->iostarttime = sim_grtime(); + sim_activate (uptr, 0); /* activate */ return OK; /* done */ } } @@ -1087,12 +1153,15 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ uint32 sts, objp = 0; UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_wtm\n"); + if (uptr = tq_getucb (lu)) { /* unit exist? */ objp = uptr->objp; /* position op */ sts = tq_mot_valid (uptr, OP_WTM); /* validity checks */ if (sts == ST_SUC) { /* ok? */ uptr->cpkt = pkt; /* op in progress */ - sim_activate (uptr, tq_xtime); /* activate */ + uptr->iostarttime = sim_grtime(); + sim_activate (uptr, 0); /* activate */ return OK; /* done */ } } @@ -1110,6 +1179,8 @@ uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ uint32 sts, objp = 0; UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_pos\n"); + if (uptr = tq_getucb (lu)) { /* unit exist? */ objp = uptr->objp; /* position op */ sts = tq_mot_valid (uptr, OP_POS); /* validity checks */ @@ -1119,8 +1190,10 @@ if (uptr = tq_getucb (lu)) { /* unit exist? */ 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 */ - sim_activate (uptr, tq_xtime); /* use normal execute time */ + else { /* otherwise */ + uptr->iostarttime = sim_grtime(); + sim_activate (uptr, 0); /* use normal execute time */ + } return OK; /* done */ } } @@ -1142,6 +1215,8 @@ uint32 bc = GETP32 (pkt, RW_BCL); /* byte count */ uint32 sts, objp = 0; UNIT *uptr; +sim_debug(DBG_TRC, &tq_dev, "tq_rw\n"); + if (uptr = tq_getucb (lu)) { /* unit exist? */ objp = uptr->objp; /* position op */ sts = tq_mot_valid (uptr, cmd); /* validity checks */ @@ -1152,7 +1227,8 @@ if (uptr = tq_getucb (lu)) { /* unit exist? */ } else { uptr->cpkt = pkt; /* op in progress */ - sim_activate (uptr, tq_xtime); /* activate */ + uptr->iostarttime = sim_grtime(); + sim_activate (uptr, 0); /* activate */ return OK; /* done */ } } @@ -1169,6 +1245,8 @@ return tq_putpkt (pkt, TRUE); 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? */ return ST_SXC; if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ @@ -1190,10 +1268,28 @@ return ST_SUC; /* success! */ /* 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) { -uint32 t, sts, sktmk, skrec; -t_mtrlnt i, tbc, wbc; +uint32 t; +t_mtrlnt wbc; int32 pkt = uptr->cpkt; /* get packet */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */ uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */ @@ -1201,7 +1297,14 @@ uint32 ba = GETP32 (pkt, RW_BAL); /* buf addr */ t_mtrlnt bc = GETP32 (pkt, RW_BCL); /* byte count */ uint32 nrec = GETP32 (pkt, POS_RCL); /* #rec to skip */ 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??? */ return SCPE_IERR; if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ @@ -1221,60 +1324,71 @@ if (tq_cmf[cmd] & CMF_WR) { /* write op? */ return SCPE_OK; } } -sts = ST_SUC; /* assume success */ -tbc = 0; /* assume zero rec */ +if (!io_complete) { + res->sts = ST_SUC; /* assume success */ + res->tbc = 0; /* assume zero rec */ + } switch (cmd) { /* case on command */ case OP_RD:case OP_ACC:case OP_CMP: /* read-like op */ - if (mdf & MD_REV) /* read record */ - sts = tq_rdbufr (uptr, &tbc); - else sts = tq_rdbuff (uptr, &tbc); - if (sts == ST_DRV) { /* read error? */ - PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */ - return tq_mot_err (uptr, tbc); /* log, done */ + if (!io_complete) { + if (mdf & MD_REV) /* read record */ + tq_rdbufr_top (uptr, &res->tbc); + else + tq_rdbuff_top (uptr, &res->tbc); + return SCPE_OK; } - if ((sts != ST_SUC) || (cmd == OP_ACC)) { /* error or access? */ - if (sts == ST_TMK) + 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 */ break; } - if (tbc > bc) { /* tape rec > buf? */ + if (res->tbc > bc) { /* tape rec > buf? */ uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ - sts = ST_RDT; /* data truncated */ + res->sts = ST_RDT; /* data truncated */ wbc = bc; /* set working bc */ } - else wbc = tbc; + else wbc = res->tbc; 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 */ 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 */ } } /* end if read */ else { /* compare */ uint8 mby, dby; uint32 mba; + t_mtrlnt i; for (i = 0; i < wbc; i++) { /* loop */ if (mdf & MD_REV) { /* reverse? */ mba = ba + bc - 1 - i; /* mem addr */ - dby = tqxb[tbc - 1 - i]; /* byte */ + dby = ((uint8 *)res->tqxb)[res->tbc - 1 - i]; /* byte */ } else { mba = ba + i; - dby = tqxb[i]; + dby = ((uint8 *)res->tqxb)[i]; } if (Map_ReadB (mba, 1, &mby)) { /* fetch, nxm? */ PUTP32 (pkt, RW_BCL, i); /* adj bc */ 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; } if (mby != dby) { /* cmp err? */ uptr->flags = uptr->flags | UNIT_SXC; /* ser exc */ 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 */ } } /* end for */ @@ -1283,23 +1397,31 @@ switch (cmd) { /* case on command */ break; case OP_WR: /* write */ - if (t = Map_ReadB (ba, bc, tqxb)) { /* fetch buf, nxm? */ - PUTP32 (pkt, RW_BCL, 0); /* no bytes xfer'd */ - if (tq_hbe (uptr, ba + bc - t)) /* post err log */ - tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc); - return SCPE_OK; /* end else wr */ - } - if (sim_tape_wrrecf (uptr, tqxb, bc)) /* write rec fwd, err? */ + 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 */ + if (tq_hbe (uptr, ba + bc - t)) /* post err log */ + tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc); + return SCPE_OK; /* end else wr */ + } + 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 */ uptr->objp = uptr->objp + 1; /* upd obj pos */ if (TEST_EOT (uptr)) /* EOT on write? */ uptr->flags = uptr->flags | UNIT_SXC; uptr->flags = uptr->flags & ~UNIT_TMK; /* disable LEOT */ - tbc = bc; /* RW_BC is ok */ + res->tbc = bc; /* RW_BC is ok */ break; 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 */ uptr->objp = uptr->objp + 1; /* incr obj cnt */ case OP_ERG: /* erase gap */ @@ -1309,51 +1431,47 @@ switch (cmd) { /* case on command */ break; 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 */ - sim_tape_rewind (uptr); /* rewind */ uptr->objp = 0; uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL); break; case OP_POS: /* position */ - sktmk = skrec = 0; /* clr skipped */ - if (mdf & MD_RWD) { /* rewind? */ - sim_tape_rewind (uptr); - uptr->objp = 0; /* clr flags */ - uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL); - } - if (mdf & MD_OBC) { /* skip obj? */ - if (mdf & MD_REV) /* reverse? */ - sts = tq_spacer (uptr, nrec, &skrec, FALSE); - else sts = tq_spacef (uptr, nrec, &skrec, FALSE); - } - else { /* skip tmk, rec */ - if (mdf & MD_REV) - sts = tq_skipfr (uptr, ntmk, &sktmk); - else sts = tq_skipff (uptr, ntmk, &sktmk); - if (sts == ST_SUC) { /* tmk succeed? */ - if (mdf & MD_REV) /* reverse? */ - sts = tq_spacer (uptr, nrec, &skrec, TRUE); - else sts = tq_spacef (uptr, nrec, &skrec, TRUE); - if (sts == ST_TMK) - sktmk = sktmk + 1; + if (!io_complete) { /* Top half processing */ + res->sktmk = res->skrec = 0; /* clr skipped */ + if (mdf & MD_RWD) { /* rewind? */ + uptr->objp = 0; /* clr flags */ + uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL); } + sim_tape_position_a (uptr, + ((mdf & MD_RWD) ? MTPOS_M_REW : 0) | + ((mdf & MD_REV) ? MTPOS_M_REV : 0) | + ((mdf & MD_OBC) ? MTPOS_M_OBJ : 0) , + nrec, &res->skrec, ntmk, &res->sktmk, (uint32 *)&res->objupd, tq_io_complete); + return SCPE_OK; } - PUTP32 (pkt, POS_RCL, skrec); /* #rec skipped */ - PUTP32 (pkt, POS_TMCL, sktmk); /* #tmk skipped */ - if (DEBUG_PRS (tq_dev)) { - fprintf (sim_deb, ">>TQ: Position Done: mdf=%04X, nrec=%04X, ntmk=%04X, skrec=%04X, sktmk=%04X\n", - mdf, nrec, ntmk, skrec, sktmk); - fflush (sim_deb); - } + 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) + uptr->objp = uptr->objp - res->objupd; + else + uptr->objp = uptr->objp + res->objupd; + PUTP32 (pkt, POS_RCL, res->skrec); /* #rec skipped */ + PUTP32 (pkt, POS_TMCL, res->sktmk); /* #tmk skipped */ break; default: return SCPE_IERR; } -tq_mot_end (uptr, 0, sts, tbc); /* done */ +tq_mot_end (uptr, 0, res->sts, res->tbc); /* done */ return SCPE_OK; } @@ -1445,90 +1563,21 @@ switch (st) { 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 */ -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; +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? */ uptr->flags = uptr->flags | UNIT_SXC | UNIT_TMK; /* serious exc */ uptr->objp = uptr->objp + 1; /* update obj cnt */ @@ -1541,11 +1590,19 @@ uptr->objp = uptr->objp + 1; /* upd obj cnt */ 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; +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? */ uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ uptr->objp = uptr->objp - 1; /* update obj cnt */ @@ -1645,7 +1702,7 @@ return tq_putpkt (pkt, TRUE); /* Unit now available attention packet */ -int32 tq_una (UNIT *uptr) +t_bool tq_una (UNIT *uptr) { int32 pkt; uint32 lu; @@ -1744,21 +1801,17 @@ return tq_putdesc (&tq_cq, desc); /* release desc */ t_bool tq_putpkt (int32 pkt, t_bool qt) { uint32 addr, desc, lnt, cr; +UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); if (pkt == 0) /* any packet? */ return OK; -if (DEBUG_PRS (tq_dev)) { - UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); - fprintf (sim_deb, ">>TQ: rsp=%04X, sts=%04X", - tq_pkt[pkt].d[RSP_OPF], tq_pkt[pkt].d[RSP_STS]); - if (up) { - fprintf (sim_deb, ", pos="); - fprint_val (sim_deb, up->pos, 10, T_ADDR_W, PV_LEFT); - fprintf (sim_deb, ", obj=%d\n", up->objp); - } - else fprintf (sim_deb, "\n"); - fflush (sim_deb); - } +if (up) + sim_debug (DBG_REQ, &tq_dev, "rsp=%04X, sts=%04X, rszl=%04X, obj=%d, pos=%d\n", + 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]); if (!tq_getdesc (&tq_rq, &desc)) /* get rsp desc */ return ERR; if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */ @@ -1944,8 +1997,9 @@ return tq_dib.vec; /* prog vector */ t_bool tq_fatal (uint32 err) { -if (DEBUG_PRS (tq_dev)) - fprintf (sim_deb, ">>TQ: fatal err=%X\n", err); +sim_debug (DBG_TRC, &tq_dev, "tq_fatal\n"); + +sim_debug (DBG_REQ, &tq_dev, "fatal err=%X\n", err); tq_reset (&tq_dev); /* reset device */ tq_sa = SA_ER | err; /* SA = dead code */ tq_csta = CST_DEAD; /* state = dead */ @@ -1959,7 +2013,7 @@ t_stat tq_attach (UNIT *uptr, char *cptr) { t_stat r; -r = sim_tape_attach (uptr, cptr); +r = sim_tape_attach_ex (uptr, cptr, DBG_TAP); if (r != SCPE_OK) return r; if (tq_csta == CST_UP) @@ -2020,11 +2074,11 @@ for (i = 0; i < TQ_NUMDR + 2; i++) { /* init units */ ~(UNIT_ONL|UNIT_ATP|UNIT_SXC|UNIT_POL|UNIT_TMK); uptr->uf = 0; /* clr unit flags */ uptr->cpkt = uptr->pktq = 0; /* clr pkt q's */ + if (uptr->results == NULL) + uptr->results = calloc (1, sizeof (struct tq_req_results)); + if (uptr->results == NULL) + return SCPE_MEM; } -if (tqxb == NULL) - tqxb = (uint8 *) calloc (TQ_MAXFR, sizeof (uint8)); -if (tqxb == NULL) - return SCPE_MEM; return SCPE_OK; } diff --git a/PDP11/pdp11_tu.c b/PDP11/pdp11_tu.c index 91d86198..f933a7c0 100644 --- a/PDP11/pdp11_tu.c +++ b/PDP11/pdp11_tu.c @@ -598,7 +598,7 @@ return MBE_GOE; /* Abort transfer */ -t_stat tu_abort (void) +int32 tu_abort (void) { return tu_reset (&tu_dev); } diff --git a/PDP11/pdp11_xq.h b/PDP11/pdp11_xq.h index f3b9210a..16327504 100644 --- a/PDP11/pdp11_xq.h +++ b/PDP11/pdp11_xq.h @@ -294,7 +294,7 @@ struct xq_device { ETH_PACK read_buffer; ETH_PACK write_buffer; ETH_QUE ReadQ; - uint32 idtmr; /* countdown for ID Timer */ + int32 idtmr; /* countdown for ID Timer */ uint32 must_poll; /* receiver must poll instead of counting on asynch polls */ }; diff --git a/PDP18B/pdp18b_cpu.c b/PDP18B/pdp18b_cpu.c index cfce154c..9545390e 100644 --- a/PDP18B/pdp18b_cpu.c +++ b/PDP18B/pdp18b_cpu.c @@ -1989,7 +1989,7 @@ else *ea = (PC & BLKMASK) | (t & IAMASK); /* within 32K */ return sta; } -t_stat Incr_addr (int32 ma) +int32 Incr_addr (int32 ma) { if (memm) return ((ma & B_EPCMASK) | ((ma + 1) & B_DAMASK)); diff --git a/PDP18B/pdp18b_fpp.c b/PDP18B/pdp18b_fpp.c index becbbe24..1a22c4c2 100644 --- a/PDP18B/pdp18b_fpp.c +++ b/PDP18B/pdp18b_fpp.c @@ -159,7 +159,7 @@ t_stat fp15_fmul (int32 ir, UFP *a, UFP *b); t_stat fp15_fdiv (int32 ir, UFP *a, UFP *b); t_stat fp15_fix (int32 ir, UFP *a); t_stat fp15_norm (int32 ir, UFP *a, UFP *b, t_bool rnd); -t_stat fp15_exc (int32 sta); +t_stat fp15_exc (t_stat sta); void fp15_asign (int32 ir, UFP *a); void dp_add (UFP *a, UFP *b); void dp_sub (UFP *a, UFP *b); diff --git a/S3/s3_cpu.c b/S3/s3_cpu.c index 4655773f..0574d15b 100644 --- a/S3/s3_cpu.c +++ b/S3/s3_cpu.c @@ -398,13 +398,13 @@ extern t_stat sim_activate (UNIT *uptr, int32 delay); extern int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); int32 nulldev (int32 opcode, int32 m, int32 n, int32 data); -int add_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2); +int32 add_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2); int32 subtract_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2); static int32 compare(int32 byte1, int32 byte2, int32 cond); static int32 condition(int32 qbyte); static void store_decimal (int32 addr, int32 len, uint8 *dec, int sign); -static void load_decimal (int32 addr, int32 len, uint8 *result, int32 *count, int32 *sign); -static void add_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int32 *count); +static void load_decimal (int32 addr, int32 len, uint8 *result, int *count, int *sign); +static void add_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int *count); static void subtract_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int *count, int *sign); int32 GetMem(int32 addr); int32 PutMem(int32 addr, int32 data); @@ -1541,7 +1541,7 @@ int sign1, sign2, sign3; /* Sign of operands & result */ /* This field is set to zero if the result is all zero, */ /* or to MAX_DECIMAL_DIGITS+1 if overflow occurred. */ /*-------------------------------------------------------------------*/ -static void add_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int32 *count) +static void add_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int *count) { int d; /* Decimal digit */ int i; /* Array subscript */ @@ -1684,7 +1684,7 @@ uint8 *lower; /* -> Lower value operand */ /* exception, or if the operand causes a data exception */ /* because of invalid decimal digits or sign. */ /*-------------------------------------------------------------------*/ -static void load_decimal (int32 addr, int32 len, uint8 *result, int32 *count, int32 *sign) +static void load_decimal (int32 addr, int32 len, uint8 *result, int *count, int *sign) { int h; /* Hexadecimal digit */ int i, j; /* Array subscripts */ diff --git a/S3/s3_defs.h b/S3/s3_defs.h index b218e509..3bb0a93d 100644 --- a/S3/s3_defs.h +++ b/S3/s3_defs.h @@ -67,7 +67,7 @@ struct ndev { int32 level; /* interrupt level */ int32 pri; /* Device priority */ - int32 (*routine)(); /* dispatch routine */ + int32 (*routine)(int32, int32, int32, int32); /* dispatch routine */ }; /* Structure to define operation codes */ diff --git a/VAX/vax780_fload.c b/VAX/vax780_fload.c index d8c2ed3e..b4f94c08 100644 --- a/VAX/vax780_fload.c +++ b/VAX/vax780_fload.c @@ -88,7 +88,7 @@ uint32 rtfile_find (uint32 block, uint32 sector); /* FLOAD file_name {file_origin} */ -t_stat vax780_fload (int flag, char *cptr) +t_stat vax780_fload (int32 flag, char *cptr) { char gbuf[CBUFSIZE]; uint16 file_name[3], blkbuf[BLK_SIZE]; diff --git a/VAX/vax780_sbi.c b/VAX/vax780_sbi.c index df49c22c..e7f4bf23 100644 --- a/VAX/vax780_sbi.c +++ b/VAX/vax780_sbi.c @@ -28,6 +28,7 @@ sbi bus controller 21-Mar-2011 RMS Added autoreboot capability (from Mark Pizzalato) + 04-Feb-2011 MP Added RQB, RQC, and RQD as bootable controllers 31-May-2008 RMS Fixed machine_check calling sequence (found by Peter Schorn) 03-May-2006 RMS Fixed writes to ACCS 28-May-2008 RMS Inlined physical memory routines @@ -111,6 +112,9 @@ static struct boot_dev boot_tab[] = { { "HK", BOOT_HK, 0 }, { "RL", BOOT_RL, 0 }, { "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 }, { NULL } }; diff --git a/VAX/vax780_stddev.c b/VAX/vax780_stddev.c index ae5da61c..9c9b09ce 100644 --- a/VAX/vax780_stddev.c +++ b/VAX/vax780_stddev.c @@ -287,6 +287,10 @@ REG clk_reg[] = { { DRDATA (TODR, todr_reg, 32), PV_LEFT }, { DRDATA (TIME, clk_unit.wait, 24), 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 } }; @@ -573,6 +577,7 @@ t_stat clk_svc (UNIT *uptr) tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ sim_activate (&clk_unit, tmr_poll); /* reactivate unit */ 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 */ if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */ tmr_incr (TMR_INC); /* do timer service */ diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index b0465784..1918494c 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -26,6 +26,7 @@ cpu VAX central processor 23-Mar-11 RMS Revised for new idle design (from Mark Pizzolato) + 05-Jan-11 MP Added Asynch I/O support 24-Apr-10 RMS Added OLDVMS idle timer option Fixed bug in SET CPU IDLE 21-May-08 RMS Removed inline support @@ -612,6 +613,7 @@ for ( ;; ) { } fault_PC = PC; recqptr = 0; /* clr recovery q */ + AIO_CHECK_EVENT; if (sim_interval <= 0) { /* chk clock queue */ temp = sim_process_event (); if (temp) diff --git a/VAX/vax_stddev.c b/VAX/vax_stddev.c index fb092607..881fcefb 100644 --- a/VAX/vax_stddev.c +++ b/VAX/vax_stddev.c @@ -27,6 +27,7 @@ tto terminal output clk 100Hz and TODR clock + 05-Jan-11 MP Added Asynch I/O support 17-Aug-08 RMS Resync TODR on any clock reset 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 @@ -178,6 +179,10 @@ REG clk_reg[] = { { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, { DRDATA (POLL, tmr_poll, 24), REG_NZ + PV_LEFT + REG_HRO }, { 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 } }; diff --git a/Visual Studio Projects/0ReadMe_Projects.txt b/Visual Studio Projects/0ReadMe_Projects.txt new file mode 100644 index 00000000..fa304799 --- /dev/null +++ b/Visual Studio Projects/0ReadMe_Projects.txt @@ -0,0 +1,33 @@ +This dirctory contains a set of Visual Studio 2008 build projects for the current simh code base. When used (with Visual Studio Express 2008 or Visual Studio Express 2010) it populates a directory tree under the BIN directory of the Simh distribution for temporary build files and produces resulting executables in the BIN/NT/Win32-Debug or BIN/NT/Win32-Release directories (depending on whether you target a Debug or Release build). It expects that a winpcap developer pack zip file is expanded in a directory parallel to the simh directory. + +For Example, the directory structure should look like: + + .../simh/simhv38-2-rc1/VAX/vax_cpu.c + .../simh/simhv38-2-rc1/scp.c + .../simh/simhv38-2-rc1/Visual Studio Projects/simh.sln + .../simh/simhv38-2-rc1/Visual Studio Projects/VAX.vcproj + .../simh/simhv38-2-rc1/BIN/Nt/Win32-Release/vax.exe + .../simh/winpcap/WpdPack/Include/pcap.h + + +The winpcap developer pack can be found at: + http://www.winpcap.org/devel.htm + + +Some features can be enabled if the pthreads API is available and contained also in a parallel place in the directory structure. + + + .../simh/pthreads/Pre-built.2/include/include/pthreads.h + + +To install pthreads API, create the directory: + + .../simh/pthreads/ + +download the file: ftp://sourceware.org/pub/pthreads-win32/pthreads-w32-2-8-0-release.exe +to that directory and execute it. Click on the Extract button. +Once installed, When running a simulator with pthreads support enabled, you will need a copy of the DLL file (simh\pthreads\Pre-built.2\lib\pthreadVC2.dll) to exist in either the %windir%\System32 directory or your working directory while running a simh simulator. The default working directory for included project files is the "Visual Studio Projects" directory. + + +Only network devices are capable of using pthreads to enhance their performance. Build the desire simulator with USE_READER_THREAD defined. The relevant simulators which have network support are VAX, VAX780, PDP11 and PDP10. + diff --git a/Visual Studio Projects/ALTAIR.vcproj b/Visual Studio Projects/ALTAIR.vcproj new file mode 100644 index 00000000..59fa3bd7 --- /dev/null +++ b/Visual Studio Projects/ALTAIR.vcproj @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/AltairZ80.vcproj b/Visual Studio Projects/AltairZ80.vcproj new file mode 100644 index 00000000..b5681a54 --- /dev/null +++ b/Visual Studio Projects/AltairZ80.vcproj @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/ECLIPSE.vcproj b/Visual Studio Projects/ECLIPSE.vcproj new file mode 100644 index 00000000..d92daee7 --- /dev/null +++ b/Visual Studio Projects/ECLIPSE.vcproj @@ -0,0 +1,322 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/GRI.vcproj b/Visual Studio Projects/GRI.vcproj new file mode 100644 index 00000000..811cd8aa --- /dev/null +++ b/Visual Studio Projects/GRI.vcproj @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/H316.vcproj b/Visual Studio Projects/H316.vcproj new file mode 100644 index 00000000..226ea7a8 --- /dev/null +++ b/Visual Studio Projects/H316.vcproj @@ -0,0 +1,306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/HP2100.vcproj b/Visual Studio Projects/HP2100.vcproj new file mode 100644 index 00000000..052039da --- /dev/null +++ b/Visual Studio Projects/HP2100.vcproj @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/I1401.vcproj b/Visual Studio Projects/I1401.vcproj new file mode 100644 index 00000000..d1f8f561 --- /dev/null +++ b/Visual Studio Projects/I1401.vcproj @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/I1620.vcproj b/Visual Studio Projects/I1620.vcproj new file mode 100644 index 00000000..f24ac970 --- /dev/null +++ b/Visual Studio Projects/I1620.vcproj @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/I7094.vcproj b/Visual Studio Projects/I7094.vcproj new file mode 100644 index 00000000..c96b4579 --- /dev/null +++ b/Visual Studio Projects/I7094.vcproj @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/IBM1130.vcproj b/Visual Studio Projects/IBM1130.vcproj new file mode 100644 index 00000000..cec64ded --- /dev/null +++ b/Visual Studio Projects/IBM1130.vcproj @@ -0,0 +1,354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/ID16.vcproj b/Visual Studio Projects/ID16.vcproj new file mode 100644 index 00000000..162a6fac --- /dev/null +++ b/Visual Studio Projects/ID16.vcproj @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/ID32.vcproj b/Visual Studio Projects/ID32.vcproj new file mode 100644 index 00000000..237c2e7c --- /dev/null +++ b/Visual Studio Projects/ID32.vcproj @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/NOVA.vcproj b/Visual Studio Projects/NOVA.vcproj new file mode 100644 index 00000000..22cb8bc2 --- /dev/null +++ b/Visual Studio Projects/NOVA.vcproj @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/PDP1.vcproj b/Visual Studio Projects/PDP1.vcproj new file mode 100644 index 00000000..57431cb4 --- /dev/null +++ b/Visual Studio Projects/PDP1.vcproj @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/PDP10.vcproj b/Visual Studio Projects/PDP10.vcproj new file mode 100644 index 00000000..eff6841a --- /dev/null +++ b/Visual Studio Projects/PDP10.vcproj @@ -0,0 +1,344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/PDP11.vcproj b/Visual Studio Projects/PDP11.vcproj new file mode 100644 index 00000000..30e71620 --- /dev/null +++ b/Visual Studio Projects/PDP11.vcproj @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/PDP15.vcproj b/Visual Studio Projects/PDP15.vcproj new file mode 100644 index 00000000..fb326065 --- /dev/null +++ b/Visual Studio Projects/PDP15.vcproj @@ -0,0 +1,322 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/PDP18B.vcproj b/Visual Studio Projects/PDP18B.vcproj new file mode 100644 index 00000000..5d829a55 --- /dev/null +++ b/Visual Studio Projects/PDP18B.vcproj @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/PDP4.vcproj b/Visual Studio Projects/PDP4.vcproj new file mode 100644 index 00000000..3a5fa23d --- /dev/null +++ b/Visual Studio Projects/PDP4.vcproj @@ -0,0 +1,322 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/PDP7.vcproj b/Visual Studio Projects/PDP7.vcproj new file mode 100644 index 00000000..dce8d70e --- /dev/null +++ b/Visual Studio Projects/PDP7.vcproj @@ -0,0 +1,322 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/PDP8.vcproj b/Visual Studio Projects/PDP8.vcproj new file mode 100644 index 00000000..26335916 --- /dev/null +++ b/Visual Studio Projects/PDP8.vcproj @@ -0,0 +1,350 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/PDP9.vcproj b/Visual Studio Projects/PDP9.vcproj new file mode 100644 index 00000000..7bec5514 --- /dev/null +++ b/Visual Studio Projects/PDP9.vcproj @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/S3.vcproj b/Visual Studio Projects/S3.vcproj new file mode 100644 index 00000000..fba7a787 --- /dev/null +++ b/Visual Studio Projects/S3.vcproj @@ -0,0 +1,302 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/SDS.vcproj b/Visual Studio Projects/SDS.vcproj new file mode 100644 index 00000000..d1c3ff9c --- /dev/null +++ b/Visual Studio Projects/SDS.vcproj @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/SWTP.vcproj b/Visual Studio Projects/SWTP.vcproj new file mode 100644 index 00000000..ca490ae2 --- /dev/null +++ b/Visual Studio Projects/SWTP.vcproj @@ -0,0 +1,294 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/Simh.sln b/Visual Studio Projects/Simh.sln new file mode 100644 index 00000000..0b5fe2da --- /dev/null +++ b/Visual Studio Projects/Simh.sln @@ -0,0 +1,182 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VAX", "VAX.vcproj", "{D5D873F7-D286-43E7-958A-3D838FAA0856}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VAX780", "VAX780.vcproj", "{D5D873F7-D286-43E7-958A-3D83DEADBEEF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AltairZ80", "AltairZ80.vcproj", "{BC7F37AD-7414-43C3-829D-214CD1113D67}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Altair", "ALTAIR.vcproj", "{1C602310-C406-4446-85C3-E5AE0E836120}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GRI", "GRI.vcproj", "{611E140C-8403-4FD8-AF53-CE01C8452B34}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HP2100", "HP2100.vcproj", "{7A9428F5-593C-4217-B8FE-980E249D3DB9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "H316", "H316.vcproj", "{C915B408-80D8-4925-BF7B-0469436B33BF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ID16", "ID16.vcproj", "{D90C77B3-A3E7-40D3-BB88-18A4EF1C001D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ID32", "ID32.vcproj", "{324EF17B-1683-48B5-824D-FACF17AEB27B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP8", "PDP8.vcproj", "{5EB65E13-1E6A-46A4-B7FE-EC87F8702067}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP10", "PDP10.vcproj", "{A39C0AFE-BDE5-4236-B740-AC710FCA1DA2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "S3", "S3.vcproj", "{927C3BD9-BD0C-4A23-99F9-573A40236509}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDS", "SDS.vcproj", "{750762C6-A2AF-40BA-A006-5E68002C1E87}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP11", "PDP11.vcproj", "{49499E1B-5019-4B98-9DC7-2E73306D5578}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP1", "PDP1.vcproj", "{CB017838-5DC5-4B9D-A8F7-7B36AA4A3331}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "I1401", "I1401.vcproj", "{C92737AD-07CC-492F-AA76-D169CEF5BBAB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "I1620", "I1620.vcproj", "{089C9C0B-C4F7-4923-86C4-F14BF5D61821}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IBM1130", "IBM1130.vcproj", "{D593C954-5115-4D15-ABDB-01B66006FF6F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP18B", "PDP18B.vcproj", "{0A3FD54C-E497-4B2D-AD32-D83EAF996D59}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP15", "PDP15.vcproj", "{44C07AA4-6D56-45ED-8393-18A23E76B758}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP9", "PDP9.vcproj", "{9D589BCA-9E10-4FFA-B43F-DDFA91C1C098}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP7", "PDP7.vcproj", "{0F8B9E39-56A7-45BE-A68F-04F7EB8EF8A3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDP4", "PDP4.vcproj", "{C51841F3-BD47-41C3-946C-20F893FB5A23}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NOVA", "NOVA.vcproj", "{9B55ACBB-C29A-40EB-98BF-D1047912389E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ECLIPSE", "ECLIPSE.vcproj", "{FF632F3D-9F62-481D-A5C7-AD090F46143C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lgp", "lgp.vcproj", "{927C3BD9-BD0C-4A23-99F9-5ABC40236509}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "I7094", "I7094.vcproj", "{927C3BD9-BD0C-4A23-99F9-DEAD402BEEF9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SWTP", "SWTP.vcproj", "{0ABAF350-853E-4A8F-8435-B583E29FB78C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D5D873F7-D286-43E7-958A-3D838FAA0856}.Debug|Win32.ActiveCfg = Debug|Win32 + {D5D873F7-D286-43E7-958A-3D838FAA0856}.Debug|Win32.Build.0 = Debug|Win32 + {D5D873F7-D286-43E7-958A-3D838FAA0856}.Release|Win32.ActiveCfg = Release|Win32 + {D5D873F7-D286-43E7-958A-3D838FAA0856}.Release|Win32.Build.0 = Release|Win32 + {D5D873F7-D286-43E7-958A-3D83DEADBEEF}.Debug|Win32.ActiveCfg = Debug|Win32 + {D5D873F7-D286-43E7-958A-3D83DEADBEEF}.Debug|Win32.Build.0 = Debug|Win32 + {D5D873F7-D286-43E7-958A-3D83DEADBEEF}.Release|Win32.ActiveCfg = Release|Win32 + {D5D873F7-D286-43E7-958A-3D83DEADBEEF}.Release|Win32.Build.0 = Release|Win32 + {BC7F37AD-7414-43C3-829D-214CD1113D67}.Debug|Win32.ActiveCfg = Debug|Win32 + {BC7F37AD-7414-43C3-829D-214CD1113D67}.Debug|Win32.Build.0 = Debug|Win32 + {BC7F37AD-7414-43C3-829D-214CD1113D67}.Release|Win32.ActiveCfg = Release|Win32 + {BC7F37AD-7414-43C3-829D-214CD1113D67}.Release|Win32.Build.0 = Release|Win32 + {1C602310-C406-4446-85C3-E5AE0E836120}.Debug|Win32.ActiveCfg = Debug|Win32 + {1C602310-C406-4446-85C3-E5AE0E836120}.Debug|Win32.Build.0 = Debug|Win32 + {1C602310-C406-4446-85C3-E5AE0E836120}.Release|Win32.ActiveCfg = Release|Win32 + {1C602310-C406-4446-85C3-E5AE0E836120}.Release|Win32.Build.0 = Release|Win32 + {611E140C-8403-4FD8-AF53-CE01C8452B34}.Debug|Win32.ActiveCfg = Debug|Win32 + {611E140C-8403-4FD8-AF53-CE01C8452B34}.Debug|Win32.Build.0 = Debug|Win32 + {611E140C-8403-4FD8-AF53-CE01C8452B34}.Release|Win32.ActiveCfg = Release|Win32 + {611E140C-8403-4FD8-AF53-CE01C8452B34}.Release|Win32.Build.0 = Release|Win32 + {7A9428F5-593C-4217-B8FE-980E249D3DB9}.Debug|Win32.ActiveCfg = Debug|Win32 + {7A9428F5-593C-4217-B8FE-980E249D3DB9}.Debug|Win32.Build.0 = Debug|Win32 + {7A9428F5-593C-4217-B8FE-980E249D3DB9}.Release|Win32.ActiveCfg = Release|Win32 + {7A9428F5-593C-4217-B8FE-980E249D3DB9}.Release|Win32.Build.0 = Release|Win32 + {C915B408-80D8-4925-BF7B-0469436B33BF}.Debug|Win32.ActiveCfg = Debug|Win32 + {C915B408-80D8-4925-BF7B-0469436B33BF}.Debug|Win32.Build.0 = Debug|Win32 + {C915B408-80D8-4925-BF7B-0469436B33BF}.Release|Win32.ActiveCfg = Release|Win32 + {C915B408-80D8-4925-BF7B-0469436B33BF}.Release|Win32.Build.0 = Release|Win32 + {D90C77B3-A3E7-40D3-BB88-18A4EF1C001D}.Debug|Win32.ActiveCfg = Debug|Win32 + {D90C77B3-A3E7-40D3-BB88-18A4EF1C001D}.Debug|Win32.Build.0 = Debug|Win32 + {D90C77B3-A3E7-40D3-BB88-18A4EF1C001D}.Release|Win32.ActiveCfg = Release|Win32 + {D90C77B3-A3E7-40D3-BB88-18A4EF1C001D}.Release|Win32.Build.0 = Release|Win32 + {324EF17B-1683-48B5-824D-FACF17AEB27B}.Debug|Win32.ActiveCfg = Debug|Win32 + {324EF17B-1683-48B5-824D-FACF17AEB27B}.Debug|Win32.Build.0 = Debug|Win32 + {324EF17B-1683-48B5-824D-FACF17AEB27B}.Release|Win32.ActiveCfg = Release|Win32 + {324EF17B-1683-48B5-824D-FACF17AEB27B}.Release|Win32.Build.0 = Release|Win32 + {5EB65E13-1E6A-46A4-B7FE-EC87F8702067}.Debug|Win32.ActiveCfg = Debug|Win32 + {5EB65E13-1E6A-46A4-B7FE-EC87F8702067}.Debug|Win32.Build.0 = Debug|Win32 + {5EB65E13-1E6A-46A4-B7FE-EC87F8702067}.Release|Win32.ActiveCfg = Release|Win32 + {5EB65E13-1E6A-46A4-B7FE-EC87F8702067}.Release|Win32.Build.0 = Release|Win32 + {A39C0AFE-BDE5-4236-B740-AC710FCA1DA2}.Debug|Win32.ActiveCfg = Debug|Win32 + {A39C0AFE-BDE5-4236-B740-AC710FCA1DA2}.Debug|Win32.Build.0 = Debug|Win32 + {A39C0AFE-BDE5-4236-B740-AC710FCA1DA2}.Release|Win32.ActiveCfg = Release|Win32 + {A39C0AFE-BDE5-4236-B740-AC710FCA1DA2}.Release|Win32.Build.0 = Release|Win32 + {927C3BD9-BD0C-4A23-99F9-573A40236509}.Debug|Win32.ActiveCfg = Debug|Win32 + {927C3BD9-BD0C-4A23-99F9-573A40236509}.Debug|Win32.Build.0 = Debug|Win32 + {927C3BD9-BD0C-4A23-99F9-573A40236509}.Release|Win32.ActiveCfg = Release|Win32 + {927C3BD9-BD0C-4A23-99F9-573A40236509}.Release|Win32.Build.0 = Release|Win32 + {750762C6-A2AF-40BA-A006-5E68002C1E87}.Debug|Win32.ActiveCfg = Debug|Win32 + {750762C6-A2AF-40BA-A006-5E68002C1E87}.Debug|Win32.Build.0 = Debug|Win32 + {750762C6-A2AF-40BA-A006-5E68002C1E87}.Release|Win32.ActiveCfg = Release|Win32 + {750762C6-A2AF-40BA-A006-5E68002C1E87}.Release|Win32.Build.0 = Release|Win32 + {49499E1B-5019-4B98-9DC7-2E73306D5578}.Debug|Win32.ActiveCfg = Debug|Win32 + {49499E1B-5019-4B98-9DC7-2E73306D5578}.Debug|Win32.Build.0 = Debug|Win32 + {49499E1B-5019-4B98-9DC7-2E73306D5578}.Release|Win32.ActiveCfg = Release|Win32 + {49499E1B-5019-4B98-9DC7-2E73306D5578}.Release|Win32.Build.0 = Release|Win32 + {CB017838-5DC5-4B9D-A8F7-7B36AA4A3331}.Debug|Win32.ActiveCfg = Debug|Win32 + {CB017838-5DC5-4B9D-A8F7-7B36AA4A3331}.Debug|Win32.Build.0 = Debug|Win32 + {CB017838-5DC5-4B9D-A8F7-7B36AA4A3331}.Release|Win32.ActiveCfg = Release|Win32 + {CB017838-5DC5-4B9D-A8F7-7B36AA4A3331}.Release|Win32.Build.0 = Release|Win32 + {C92737AD-07CC-492F-AA76-D169CEF5BBAB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C92737AD-07CC-492F-AA76-D169CEF5BBAB}.Debug|Win32.Build.0 = Debug|Win32 + {C92737AD-07CC-492F-AA76-D169CEF5BBAB}.Release|Win32.ActiveCfg = Release|Win32 + {C92737AD-07CC-492F-AA76-D169CEF5BBAB}.Release|Win32.Build.0 = Release|Win32 + {089C9C0B-C4F7-4923-86C4-F14BF5D61821}.Debug|Win32.ActiveCfg = Debug|Win32 + {089C9C0B-C4F7-4923-86C4-F14BF5D61821}.Debug|Win32.Build.0 = Debug|Win32 + {089C9C0B-C4F7-4923-86C4-F14BF5D61821}.Release|Win32.ActiveCfg = Release|Win32 + {089C9C0B-C4F7-4923-86C4-F14BF5D61821}.Release|Win32.Build.0 = Release|Win32 + {D593C954-5115-4D15-ABDB-01B66006FF6F}.Debug|Win32.ActiveCfg = Debug|Win32 + {D593C954-5115-4D15-ABDB-01B66006FF6F}.Debug|Win32.Build.0 = Debug|Win32 + {D593C954-5115-4D15-ABDB-01B66006FF6F}.Release|Win32.ActiveCfg = Release|Win32 + {D593C954-5115-4D15-ABDB-01B66006FF6F}.Release|Win32.Build.0 = Release|Win32 + {0A3FD54C-E497-4B2D-AD32-D83EAF996D59}.Debug|Win32.ActiveCfg = Debug|Win32 + {0A3FD54C-E497-4B2D-AD32-D83EAF996D59}.Debug|Win32.Build.0 = Debug|Win32 + {0A3FD54C-E497-4B2D-AD32-D83EAF996D59}.Release|Win32.ActiveCfg = Release|Win32 + {0A3FD54C-E497-4B2D-AD32-D83EAF996D59}.Release|Win32.Build.0 = Release|Win32 + {44C07AA4-6D56-45ED-8393-18A23E76B758}.Debug|Win32.ActiveCfg = Debug|Win32 + {44C07AA4-6D56-45ED-8393-18A23E76B758}.Debug|Win32.Build.0 = Debug|Win32 + {44C07AA4-6D56-45ED-8393-18A23E76B758}.Release|Win32.ActiveCfg = Release|Win32 + {44C07AA4-6D56-45ED-8393-18A23E76B758}.Release|Win32.Build.0 = Release|Win32 + {9D589BCA-9E10-4FFA-B43F-DDFA91C1C098}.Debug|Win32.ActiveCfg = Debug|Win32 + {9D589BCA-9E10-4FFA-B43F-DDFA91C1C098}.Debug|Win32.Build.0 = Debug|Win32 + {9D589BCA-9E10-4FFA-B43F-DDFA91C1C098}.Release|Win32.ActiveCfg = Release|Win32 + {9D589BCA-9E10-4FFA-B43F-DDFA91C1C098}.Release|Win32.Build.0 = Release|Win32 + {0F8B9E39-56A7-45BE-A68F-04F7EB8EF8A3}.Debug|Win32.ActiveCfg = Debug|Win32 + {0F8B9E39-56A7-45BE-A68F-04F7EB8EF8A3}.Debug|Win32.Build.0 = Debug|Win32 + {0F8B9E39-56A7-45BE-A68F-04F7EB8EF8A3}.Release|Win32.ActiveCfg = Release|Win32 + {0F8B9E39-56A7-45BE-A68F-04F7EB8EF8A3}.Release|Win32.Build.0 = Release|Win32 + {C51841F3-BD47-41C3-946C-20F893FB5A23}.Debug|Win32.ActiveCfg = Debug|Win32 + {C51841F3-BD47-41C3-946C-20F893FB5A23}.Debug|Win32.Build.0 = Debug|Win32 + {C51841F3-BD47-41C3-946C-20F893FB5A23}.Release|Win32.ActiveCfg = Release|Win32 + {C51841F3-BD47-41C3-946C-20F893FB5A23}.Release|Win32.Build.0 = Release|Win32 + {9B55ACBB-C29A-40EB-98BF-D1047912389E}.Debug|Win32.ActiveCfg = Debug|Win32 + {9B55ACBB-C29A-40EB-98BF-D1047912389E}.Debug|Win32.Build.0 = Debug|Win32 + {9B55ACBB-C29A-40EB-98BF-D1047912389E}.Release|Win32.ActiveCfg = Release|Win32 + {9B55ACBB-C29A-40EB-98BF-D1047912389E}.Release|Win32.Build.0 = Release|Win32 + {FF632F3D-9F62-481D-A5C7-AD090F46143C}.Debug|Win32.ActiveCfg = Debug|Win32 + {FF632F3D-9F62-481D-A5C7-AD090F46143C}.Debug|Win32.Build.0 = Debug|Win32 + {FF632F3D-9F62-481D-A5C7-AD090F46143C}.Release|Win32.ActiveCfg = Release|Win32 + {FF632F3D-9F62-481D-A5C7-AD090F46143C}.Release|Win32.Build.0 = Release|Win32 + {927C3BD9-BD0C-4A23-99F9-5ABC40236509}.Debug|Win32.ActiveCfg = Debug|Win32 + {927C3BD9-BD0C-4A23-99F9-5ABC40236509}.Debug|Win32.Build.0 = Debug|Win32 + {927C3BD9-BD0C-4A23-99F9-5ABC40236509}.Release|Win32.ActiveCfg = Release|Win32 + {927C3BD9-BD0C-4A23-99F9-5ABC40236509}.Release|Win32.Build.0 = Release|Win32 + {927C3BD9-BD0C-4A23-99F9-DEAD402BEEF9}.Debug|Win32.ActiveCfg = Debug|Win32 + {927C3BD9-BD0C-4A23-99F9-DEAD402BEEF9}.Debug|Win32.Build.0 = Debug|Win32 + {927C3BD9-BD0C-4A23-99F9-DEAD402BEEF9}.Release|Win32.ActiveCfg = Release|Win32 + {927C3BD9-BD0C-4A23-99F9-DEAD402BEEF9}.Release|Win32.Build.0 = Release|Win32 + {0ABAF350-853E-4A8F-8435-B583E29FB78C}.Debug|Win32.ActiveCfg = Debug|Win32 + {0ABAF350-853E-4A8F-8435-B583E29FB78C}.Debug|Win32.Build.0 = Debug|Win32 + {0ABAF350-853E-4A8F-8435-B583E29FB78C}.Release|Win32.ActiveCfg = Release|Win32 + {0ABAF350-853E-4A8F-8435-B583E29FB78C}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Visual Studio Projects/VAX.vcproj b/Visual Studio Projects/VAX.vcproj new file mode 100644 index 00000000..3c980a12 --- /dev/null +++ b/Visual Studio Projects/VAX.vcproj @@ -0,0 +1,421 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/VAX780.vcproj b/Visual Studio Projects/VAX780.vcproj new file mode 100644 index 00000000..7ce43838 --- /dev/null +++ b/Visual Studio Projects/VAX780.vcproj @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/lgp.vcproj b/Visual Studio Projects/lgp.vcproj new file mode 100644 index 00000000..cf6d7156 --- /dev/null +++ b/Visual Studio Projects/lgp.vcproj @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/descrip.mms b/descrip.mms index 1dd77ed7..4982b9b0 100644 --- a/descrip.mms +++ b/descrip.mms @@ -2,13 +2,13 @@ # Written By: Robert Alan Byer / byer@mail.ourservers.net # Modified By: Mark Pizzolato / mark@infocomm.com # Norman Lastovica / norman.lastovica@oracle.com -# Camiel Vanderhoeven / camiel@camicom.com +# Camiel Vanderhoeven / camiel@camicom.com # # This MMS/MMK build script is used to compile the various simulators in # the SIMH package for OpenVMS using DEC C v6.0-001(AXP), v6.5-001(AXP), -# HP C V7.2-001 (IA64) and v6.4-005(VAX). +# HP C V7.3-009-48GBT (AXP), HP C V7.2-001 (IA64) and v6.4-005(VAX). # -# Notes: On VAX, the PDP-10 and Eclipse simulators will not be built +# Notes: On VAX, the PDP-10and IBM 7094 simulators will not be built # due to the fact that INT64 is required for that simulator. # # This build script will accept the following build options. @@ -23,6 +23,7 @@ # HP2100 Just Build The Hewlett-Packard HP-2100. # I1401 Just Build The IBM 1401. # I1620 Just Build The IBM 1620. +# I7094 Just Build The IBM 7094. # IBM1130 Just Build The IBM 1130. # ID16 Just Build The Interdata 16-bit CPU. # ID32 Just Build The Interdata 32-bit CPU. @@ -37,6 +38,7 @@ # PDP15 Just Build The DEC PDP-15. # S3 Just Build The IBM System 3. # SDS Just Build The SDS 940. +# SWTP Just Build The SWTP. # VAX Just Build The DEC VAX. # VAX780 Just Build The DEC VAX780. # CLEAN Will Clean Files Back To Base Kit. @@ -46,6 +48,11 @@ # # MMK/MACRO=(DEBUG=1) # +# To build on older Alpha VMS platforms, SIM_ASYNCH_IO must be disabled. +# use.. +# +# MMK/MACRO=(NOASYNCH=1) +# # This will produce an executable named {Simulator}-{I64|VAX|AXP}-DBG.EXE # @@ -62,19 +69,23 @@ CC_OPTIMIZE = /NOOPTIMIZE .IFDEF MMSALPHA ALPHA_OR_IA64 = 1 CC_FLAGS = /PREF=ALL -ARCH = AXP-DBG +.IFDEF NOASYNCH +ARCH = AXP-NOASYNCH-DBG CC_DEFS = "_LARGEFILE" +.ELSE +ARCH = AXP-DBG +CC_DEFS = "_LARGEFILE","SIM_ASYNCH_IO=1" +.ENDIF .ENDIF .IFDEF MMSIA64 ALPHA_OR_IA64 = 1 CC_FLAGS = /PREF=ALL ARCH = I64-DBG -CC_DEFS = "_LARGEFILE" +CC_DEFS = "_LARGEFILE","SIM_ASYNCH_IO=1" .ENDIF .IFDEF MMSVAX -ALPHA_OR_IA64 = 0 CC_FLAGS = $(CC_FLAGS) ARCH = VAX-DBG CC_DEFS = "__VAX" @@ -87,8 +98,13 @@ LINK_DEBUG = /NODEBUG/NOTRACEBACK ALPHA_OR_IA64 = 1 CC_OPTIMIZE = /OPT=(LEV=5)/ARCH=HOST CC_FLAGS = /PREF=ALL -ARCH = AXP +.IFDEF NOASYNCH +ARCH = AXP-NOASYNCH CC_DEFS = "_LARGEFILE" +.ELSE +ARCH = AXP +CC_DEFS = "_LARGEFILE","SIM_ASYNCH_IO=1" +.ENDIF LINK_SECTION_BINDING = /SECTION_BINDING .ENDIF @@ -97,11 +113,10 @@ ALPHA_OR_IA64 = 1 CC_OPTIMIZE = /OPT=(LEV=5) CC_FLAGS = /PREF=ALL ARCH = I64 -CC_DEFS = "_LARGEFILE" +CC_DEFS = "_LARGEFILE","SIM_ASYNCH_IO=1" .ENDIF .IFDEF MMSVAX -ALPHA_OR_IA64 = 0 CC_OPTIMIZE = /OPTIMIZE CC_FLAGS = $(CC_FLAGS) ARCH = VAX @@ -120,15 +135,18 @@ CC = CC/DECC$(OUR_CC_FLAGS) # Define The platform specific Build Directory Where The Objects Will Go. # BIN_DIR = SYS$DISK:[.BIN] -LIB_DIR = SYS$DISK:[.LIB] -BLD_DIR = SYS$DISK:[.LIB.BLD-$(ARCH)] +LIB_DIR = SYS$DISK:[.BIN.VMS.LIB] +BLD_DIR = SYS$DISK:[.BIN.VMS.LIB.BLD-$(ARCH)] # Check To Make Sure We Have SYS$DISK:[.BIN] & SYS$DISK:[.LIB] Directory. # .FIRST + @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(F$GETSYI("VERSION").LES."V8.0").AND.("$(NOASYNCH)".EQS."")) THEN WRITE SYS$OUTPUT "*** WARNING **** Build should be invoked with /MACRO=NOASYNCH=1 on this platform" + @ IF ((F$GETSYI("ARCH_NAME").EQS."Alpha").AND.(F$GETSYI("VERSION").LES."V8.0").AND.("$(NOASYNCH)".EQS."")) THEN EXIT %x10000000 @ IF (F$SEARCH("SYS$DISK:[]BIN.DIR").EQS."") THEN CREATE/DIRECTORY $(BIN_DIR) - @ IF (F$SEARCH("SYS$DISK:[]LIB.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) - @ IF (F$SEARCH("SYS$DISK:[.LIB]BLD-$(ARCH).DIR").EQS."") THEN CREATE/DIRECTORY $(BLD_DIR) + @ IF (F$SEARCH("SYS$DISK:[.BIN]VMS.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) + @ IF (F$SEARCH("SYS$DISK:[.BIN.VMS]LIB.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) + @ IF (F$SEARCH("SYS$DISK:[.BIN.VMS.LIB]BLD-$(ARCH).DIR").EQS."") THEN CREATE/DIRECTORY $(BLD_DIR) @ IF (F$SEARCH("$(BLD_DIR)*.*").NES."") THEN DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.*;* @ IF "".NES."''CC'" THEN DELETE/SYMBOL/GLOBAL CC @@ -139,7 +157,11 @@ SIMH_LIB = $(LIB_DIR)SIMH-$(ARCH).OLB SIMH_SOURCE = $(SIMH_DIR)SIM_CONSOLE.C,$(SIMH_DIR)SIM_SOCK.C,\ $(SIMH_DIR)SIM_TMXR.C,$(SIMH_DIR)SIM_ETHER.C,\ $(SIMH_DIR)SIM_TAPE.C,$(SIMH_DIR)SIM_FIO.C,\ - $(SIMH_DIR)SIM_TIMER.C + $(SIMH_DIR)SIM_TIMER.C,$(SIMH_DIR)SIM_DISK.C +SIMH_MAIN = SCP.C +.IFDEF ALPHA_OR_IA64 +SIMH_LIB64 = $(LIB_DIR)SIMH64-$(ARCH).OLB +.ENDIF # VMS PCAP File Definitions. # @@ -227,7 +249,7 @@ ECLIPSE_SOURCE = $(NOVA_DIR)ECLIPSE_CPU.C,$(NOVA_DIR)ECLIPSE_TT.C,\ $(NOVA_DIR)NOVA_PT.C,$(NOVA_DIR)NOVA_CLK.C,\ $(NOVA_DIR)NOVA_TT1.C,$(NOVA_DIR)NOVA_QTY.C ECLIPSE_OPTIONS = /INCL=($(SIMH_DIR),$(NOVA_DIR))\ - /DEF=($(CC_DEFS),"USE_INT64=1","ECLIPSE=1") + /DEF=($(CC_DEFS),"ECLIPSE=1") # # GRI Corporation GRI-909 Simulator Definitions. @@ -275,7 +297,7 @@ HP2100_SOURCE1 = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.C,\ HP2100_LIB2 = $(LIB_DIR)HP2100L2-$(ARCH).OLB HP2100_SOURCE2 = $(HP2100_DIR)HP2100_FP1.C,$(HP2100_DIR)HP2100_BACI.C,\ $(HP2100_DIR)HP2100_MPX.C,$(HP2100_DIR)HP2100_PIF.C -.IF ALPHA_OR_IA64 +.IFDEF ALPHA_OR_IA64 HP2100_OPTIONS = /INCL=($(SIMH_DIR),$(HP2100_DIR))\ /DEF=($(CC_DEFS),"HAVE_INT64=1") .ELSE @@ -453,6 +475,15 @@ SDS_SOURCE = $(SDS_DIR)SDS_CPU.C,$(SDS_DIR)SDS_DRM.C,$(SDS_DIR)SDS_DSK.C,\ $(SDS_DIR)SDS_SYS.C SDS_OPTIONS = /INCL=($(SIMH_DIR),$(SDS_DIR))/DEF=($(CC_DEFS)) +# +# SWTP 6800 +# +SWTP_DIR = SYS$DISK:[.SWTP] +SWTP_LIB = $(LIB_DIR)SWTP-$(ARCH).OLB +SWTP_SOURCE = $(SWTP_DIR)SWTP_CPU.C,$(SWTP_DIR)SWTP_DSK.C,$(SWTP_DIR)SWTP_SIO.C,\ + $(SWTP_DIR)SWTP_SYS.C +SWTP_OPTIONS = /INCL=($(SIMH_DIR),$(SWTP_DIR))/DEF=($(CC_DEFS)) + # # Digital Equipment VAX Simulator Definitions. # @@ -470,8 +501,15 @@ VAX_SOURCE = $(VAX_DIR)VAX_CIS.C,$(VAX_DIR)VAX_CMODE.C,\ $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ $(PDP11_DIR)PDP11_XQ.C,$(PDP11_DIR)PDP11_CR.C,\ $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_VH.C +.IFDEF ALPHA_OR_IA64 +VAX_OPTIONS = /INCL=($(SIMH_DIR),$(VAX_DIR),$(PDP11_DIR)$(PCAP_INC))\ + /DEF=($(CC_DEFS),"VM_VAX=1","USE_ADDR64=1","USE_INT64=1"$(PCAP_DEFS)) +VAX_SIMH_LIB = $(SIMH_LIB64) +.ELSE VAX_OPTIONS = /INCL=($(SIMH_DIR),$(VAX_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEF=($(CC_DEFS),"VM_VAX=1"$(PCAP_DEFS)) +VAX_SIMH_LIB = $(SIMH_LIB) +.ENDIF # Digital Equipment VAX780 Simulator Definitions. # @@ -493,8 +531,15 @@ VAX780_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_RP.C,\ $(PDP11_DIR)PDP11_TU.C,$(PDP11_DIR)PDP11_HK.C,\ $(PDP11_DIR)PDP11_IO_LIB.C +.IFDEF ALPHA_OR_IA64 +VAX780_OPTIONS = /INCL=($(SIMH_DIR),$(VAX780_DIR),$(PDP11_DIR)$(PCAP_INC))\ + /DEF=($(CC_DEFS),"VM_VAX=1","USE_ADDR64=1","USE_INT64=1"$(PCAP_DEFS),"VAX_780=1") +VAX780_SIMH_LIB = $(SIMH_LIB64) +.ELSE VAX780_OPTIONS = /INCL=($(SIMH_DIR),$(VAX780_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEF=($(CC_DEFS),"VM_VAX=1"$(PCAP_DEFS),"VAX_780=1") +VAX780_SIMH_LIB = $(SIMH_LIB) +.ENDIF # IBM 7094 Simulator Definitions. # @@ -510,17 +555,17 @@ I7094_OPTIONS = /INCL=($(SIMH_DIR),$(I7094_DIR))/DEF=($(CC_DEFS)) # If we're not a VAX, Build Everything # -.IF ALPHA_OR_IA64 +.IFDEF ALPHA_OR_IA64 ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI LGP H316 HP2100 I1401 I1620 IBM1130 ID16 \ ID32 NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP10 PDP11 PDP15 S3 VAX VAX780 SDS \ - I7094 + I7094 SWTP $! No further actions necessary .ELSE # # Else We Are On VAX And Build Everything EXCEPT the 64b simulators # -ALL : ALTAIR ALTAIRZ80 GRI H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \ - NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP11 PDP15 S3 VAX VAX780 SDS +ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \ + NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP11 PDP15 S3 VAX VAX780 SDS SWTP $! No further actions necessary .ENDIF @@ -553,6 +598,19 @@ $(SIMH_LIB) : $(SIMH_SOURCE) $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* +.IFDEF ALPHA_OR_IA64 +$(SIMH_LIB64) : $(SIMH_SOURCE) + $! + $! Building The $(SIMH_LIB64) Library. + $! + $ $(CC)/DEF=($(CC_DEFS)$(PCAP_DEFS),"USE_ADDR64=1","USE_INT64=1")$(PCAP_SIMH_INC) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* +.ENDIF + $(ALTAIR_LIB) : $(ALTAIR_SOURCE) $! $! Building The $(ALTAIR_LIB) Library. @@ -586,10 +644,6 @@ $(ALTAIRZ80_LIB2) : $(ALTAIRZ80_SOURCE2) $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -# -# If Not On VAX, Build The Eclipse Library. -# -.IF ALPHA_OR_IA64 $(ECLIPSE_LIB) : $(ECLIPSE_SOURCE) $! $! Building The $(ECLIPSE_LIB) Library. @@ -600,16 +654,6 @@ $(ECLIPSE_LIB) : $(ECLIPSE_SOURCE) LIBRARY/CREATE $(MMS$TARGET) $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -.ELSE -# -# We Are On VAX And Due To The Use of INT64 We Can't Build It. -# -$(ECLIPSE_LIB) : - $! - $! Due To The Use Of INT64 We Can't Build The - $! $(LIB_DIR)ECLIPSE-$(ARCH).OLB Library On VAX. - $! -.ENDIF $(GRI_LIB) : $(GRI_SOURCE) $! @@ -790,7 +834,7 @@ $(PDP9_LIB) : $(PDP18B_SOURCE) # # If Not On VAX, Build The PDP-10 Library. # -.IF ALPHA_OR_IA64 +.IFDEF ALPHA_OR_IA64 $(PDP10_LIB) : $(PDP10_SOURCE) $! $! Building The $(PDP10_LIB) Library. @@ -807,7 +851,7 @@ $(PDP10_LIB) : $(PDP10_SOURCE) # $(PDP10_LIB) : $! Due To The Use Of INT64 We Can't Build The - $! $(LIB_DIR)PDP10-$(ARCH).OLB Library On VAX. + $! $(MMS$TARGET) Library On VAX. .ENDIF $(PDP11_LIB1) : $(PDP11_SOURCE1) @@ -865,6 +909,17 @@ $(SDS_LIB) : $(SDS_SOURCE) $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* +$(SWTP_LIB) : $(SWTP_SOURCE) + $! + $! Building The $(SWTP_LIB) Library. + $! + $ $(CC)$(SWTP_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + $(VAX_LIB) : $(VAX_SOURCE) $! $! Building The $(VAX_LIB) Library. @@ -913,7 +968,7 @@ $(PCAP_LIB) : $(PCAP_SOURCE) # # If Not On VAX, Build The IBM 7094 Library. # -.IF ALPHA_OR_IA64 +.IFDEF ALPHA_OR_IA64 $(I7094_LIB) : $(I7094_SOURCE) $! $! Building The $(I7094_LIB) Library. @@ -930,13 +985,16 @@ $(I7094_LIB) : $(I7094_SOURCE) # $(I7094_LIB) : $! Due To The Use Of INT64 We Can't Build The - $! $(LIB_DIR)I7094-$(ARCH).OLB Library On VAX. + $! $(MMS$TARGET) Library On VAX. .ENDIF # # Individual Simulator Builds. # -ALTAIR : $(SIMH_LIB) $(ALTAIR_LIB) +ALTAIR : $(BIN_DIR)ALTAIR-$(ARCH).EXE + $! ALTAIR done + +$(BIN_DIR)ALTAIR-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(ALTAIR_LIB) $! $! Building The $(BIN_DIR)ALTAIR-$(ARCH).EXE Simulator. $! @@ -945,7 +1003,10 @@ ALTAIR : $(SIMH_LIB) $(ALTAIR_LIB) $(BLD_DIR)SCP.OBJ,$(ALTAIR_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -ALTAIRZ80 : $(SIMH_LIB) $(ALTAIRZ80_LIB1) $(ALTAIRZ80_LIB2) +ALTAIRZ80 : $(BIN_DIR)ALTAIRZ80-$(ARCH).EXE + $! ALTAIRZ80 done + +$(BIN_DIR)ALTAIRZ80-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(ALTAIRZ80_LIB1) $(ALTAIRZ80_LIB2) $! $! Building The $(BIN_DIR)ALTAIRZ80-$(ARCH).EXE Simulator. $! @@ -955,11 +1016,10 @@ ALTAIRZ80 : $(SIMH_LIB) $(ALTAIRZ80_LIB1) $(ALTAIRZ80_LIB2) $(ALTAIRZ80_LIB2)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -# -# If Not On VAX, Build The PDP-10 Simulator. -# -.IF ALPHA_OR_IA64 -ECLIPSE : $(SIMH_LIB) $(ECLIPSE_LIB) +ECLIPSE : $(BIN_DIR)ECLIPSE-$(ARCH).EXE + $! ECLIPSE done + +$(BIN_DIR)ECLIPSE-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(ECLIPSE_LIB) $! $! Building The $(BIN_DIR)ECLIPSE-$(ARCH).EXE Simulator. $! @@ -967,17 +1027,11 @@ ECLIPSE : $(SIMH_LIB) $(ECLIPSE_LIB) $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ECLIPSE-$(ARCH).EXE - $(BLD_DIR)SCP.OBJ,$(ECLIPSE_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -.ELSE -# -# Else We Are On VAX And Tell The User We Can't Build On VAX -# Due To The Use Of INT64. -# -ECLIPSE : - $! Sorry, Can't Build $(BIN_DIR)ECLIPSE-$(ARCH).EXE Simulator - $! Because It Requires The Use Of INT64. -.ENDIF -GRI : $(SIMH_LIB) $(GRI_LIB) +GRI : $(BIN_DIR)GRI-$(ARCH).EXE + $! GRI done + +$(BIN_DIR)GRI-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(GRI_LIB) $! $! Building The $(BIN_DIR)GRI-$(ARCH).EXE Simulator. $! @@ -986,7 +1040,10 @@ GRI : $(SIMH_LIB) $(GRI_LIB) $(BLD_DIR)SCP.OBJ,$(GRI_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -LGP : $(SIMH_LIB) $(LGP_LIB) +LGP : $(BIN_DIR)LGP-$(ARCH).EXE + $! LGP done + +$(BIN_DIR)LGP-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(LGP_LIB) $! $! Building The $(BIN_DIR)LGP-$(ARCH).EXE Simulator. $! @@ -995,7 +1052,10 @@ LGP : $(SIMH_LIB) $(LGP_LIB) $(BLD_DIR)SCP.OBJ,$(LGP_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -H316 : $(SIMH_LIB) $(H316_LIB) +H316 : $(BIN_DIR)H316-$(ARCH).EXE + $! H316 done + +$(BIN_DIR)H316-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(H316_LIB) $! $! Building The $(BIN_DIR)H316-$(ARCH).EXE Simulator. $! @@ -1004,7 +1064,10 @@ H316 : $(SIMH_LIB) $(H316_LIB) $(BLD_DIR)SCP.OBJ,$(H316_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -HP2100 : $(SIMH_LIB) $(HP2100_LIB1) $(HP2100_LIB2) +HP2100 : $(BIN_DIR)HP2100-$(ARCH).EXE + $! HP2100 done + +$(BIN_DIR)HP2100-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(HP2100_LIB1) $(HP2100_LIB2) $! $! Building The $(BIN_DIR)HP2100-$(ARCH).EXE Simulator. $! @@ -1014,7 +1077,10 @@ HP2100 : $(SIMH_LIB) $(HP2100_LIB1) $(HP2100_LIB2) $(HP2100_LIB2)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -I1401 : $(SIMH_LIB) $(I1401_LIB) +I1401 : $(BIN_DIR)I1401-$(ARCH).EXE + $! I1401 done + +$(BIN_DIR)I1401-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(I1401_LIB) $! $! Building The $(BIN_DIR)I1401-$(ARCH).EXE Simulator. $! @@ -1023,7 +1089,10 @@ I1401 : $(SIMH_LIB) $(I1401_LIB) $(BLD_DIR)SCP.OBJ,$(I1401_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -I1620 : $(SIMH_LIB) $(I1620_LIB) +I1620 : $(BIN_DIR)I1620-$(ARCH).EXE + $! I1620 done + +$(BIN_DIR)I1620-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(I1620_LIB) $! $! Building The $(BIN_DIR)I1620-$(ARCH).EXE Simulator. $! @@ -1032,7 +1101,10 @@ I1620 : $(SIMH_LIB) $(I1620_LIB) $(BLD_DIR)SCP.OBJ,$(I1620_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -IBM1130 : $(SIMH_LIB) $(IBM1130_LIB) +IBM1130 : $(BIN_DIR)IBM1130-$(ARCH).EXE + $! IBM1130 done + +$(BIN_DIR)IBM1130-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(IBM1130_LIB) $! $! Building The $(BIN_DIR)IBM1130-$(ARCH).EXE Simulator. $! @@ -1041,7 +1113,10 @@ IBM1130 : $(SIMH_LIB) $(IBM1130_LIB) $(BLD_DIR)SCP.OBJ,$(IBM1130_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -ID16 : $(SIMH_LIB) $(ID16_LIB) +ID16 : $(BIN_DIR)ID16-$(ARCH).EXE + $! ID16 done + +$(BIN_DIR)ID16-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(ID16_LIB) $! $! Building The $(BIN_DIR)ID16-$(ARCH).EXE Simulator. $! @@ -1050,7 +1125,10 @@ ID16 : $(SIMH_LIB) $(ID16_LIB) $(BLD_DIR)SCP.OBJ,$(ID16_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -ID32 : $(SIMH_LIB) $(ID32_LIB) +ID32 : $(BIN_DIR)ID32-$(ARCH).EXE + $! ID32 done + +$(BIN_DIR)ID32-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(ID32_LIB) $! $! Building The $(BIN_DIR)ID32-$(ARCH).EXE Simulator. $! @@ -1059,7 +1137,10 @@ ID32 : $(SIMH_LIB) $(ID32_LIB) $(BLD_DIR)SCP.OBJ,$(ID32_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -NOVA : $(SIMH_LIB) $(NOVA_LIB) +NOVA : $(BIN_DIR)NOVA-$(ARCH).EXE + $! NOVA done + +$(BIN_DIR)NOVA-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(NOVA_LIB) $! $! Building The $(BIN_DIR)NOVA-$(ARCH).EXE Simulator. $! @@ -1068,7 +1149,10 @@ NOVA : $(SIMH_LIB) $(NOVA_LIB) $(BLD_DIR)SCP.OBJ,$(NOVA_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -PDP1 : $(SIMH_LIB) $(PDP1_LIB) +PDP1 : $(BIN_DIR)PDP1-$(ARCH).EXE + $! PDP1 done + +$(BIN_DIR)PDP1-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(PDP1_LIB) $! $! Building The $(BIN_DIR)PDP1-$(ARCH).EXE Simulator. $! @@ -1077,7 +1161,10 @@ PDP1 : $(SIMH_LIB) $(PDP1_LIB) $(BLD_DIR)SCP.OBJ,$(PDP1_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -PDP4 : $(SIMH_LIB) $(PDP4_LIB) +PDP4 : $(BIN_DIR)PDP4-$(ARCH).EXE + $! PDP4 done + +$(BIN_DIR)PDP4-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(PDP4_LIB) $! $! Building The $(BIN_DIR)PDP4-$(ARCH).EXE Simulator. $! @@ -1086,7 +1173,10 @@ PDP4 : $(SIMH_LIB) $(PDP4_LIB) $(BLD_DIR)SCP.OBJ,$(PDP4_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -PDP7 : $(SIMH_LIB) $(PDP7_LIB) +PDP7 : $(BIN_DIR)PDP7-$(ARCH).EXE + $! PDP7 done + +$(BIN_DIR)PDP7-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(PDP7_LIB) $! $! Building The $(BIN_DIR)PDP7-$(ARCH).EXE Simulator. $! @@ -1095,7 +1185,10 @@ PDP7 : $(SIMH_LIB) $(PDP7_LIB) $(BLD_DIR)SCP.OBJ,$(PDP7_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -PDP8 : $(SIMH_LIB) $(PDP8_LIB) +PDP8 : $(BIN_DIR)PDP8-$(ARCH).EXE + $! PDP8 done + +$(BIN_DIR)PDP8-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(PDP8_LIB) $! $! Building The $(BIN_DIR)PDP8-$(ARCH).EXE Simulator. $! @@ -1104,7 +1197,10 @@ PDP8 : $(SIMH_LIB) $(PDP8_LIB) $(BLD_DIR)SCP.OBJ,$(PDP8_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -PDP9 : $(SIMH_LIB) $(PDP9_LIB) +PDP9 : $(BIN_DIR)PDP9-$(ARCH).EXE + $! PDP9 done + +$(BIN_DIR)PDP9-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(PDP9_LIB) $! $! Building The $(BIN_DIR)PDP9-$(ARCH).EXE Simulator. $! @@ -1116,8 +1212,11 @@ PDP9 : $(SIMH_LIB) $(PDP9_LIB) # # If Not On VAX, Build The PDP-10 Simulator. # -.IF ALPHA_OR_IA64 -PDP10 : $(SIMH_LIB) $(PCAP_LIBD) $(PDP10_LIB) $(PCAP_EXECLET) +.IFDEF ALPHA_OR_IA64 +PDP10 : $(BIN_DIR)PDP10-$(ARCH).EXE + $! PDP10 done + +$(BIN_DIR)PDP10-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(PCAP_LIBD) $(PDP10_LIB) $(PCAP_EXECLET) $! $! Building The $(BIN_DIR)PDP10-$(ARCH).EXE Simulator. $! @@ -1135,7 +1234,10 @@ PDP10 : $! Because It Requires The Use Of INT64. .ENDIF -PDP11 : $(SIMH_LIB) $(PCAP_LIBD) $(PDP11_LIB1) $(PDP11_LIB2) $(PCAP_EXECLET) +PDP11 : $(BIN_DIR)PDP11-$(ARCH).EXE + $! PDP11 done + +$(BIN_DIR)PDP11-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(PCAP_LIBD) $(PDP11_LIB1) $(PDP11_LIB2) $(PCAP_EXECLET) $! $! Building The $(BIN_DIR)PDP11-$(ARCH).EXE Simulator. $! @@ -1144,7 +1246,10 @@ PDP11 : $(SIMH_LIB) $(PCAP_LIBD) $(PDP11_LIB1) $(PDP11_LIB2) $(PCAP_EXECLET) $(BLD_DIR)SCP.OBJ,$(PDP11_LIB1)/LIBRARY,$(PDP11_LIB2)/LIBRARY,$(SIMH_LIB)/LIBRARY$(PCAP_LIBR) $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -PDP15 : $(SIMH_LIB) $(PDP15_LIB) +PDP15 : $(BIN_DIR)PDP15-$(ARCH).EXE + $! PDP15 done + +$(BIN_DIR)PDP15-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(PDP15_LIB) $! $! Building The $(BIN_DIR)PDP15-$(ARCH).EXE Simulator. $! @@ -1153,7 +1258,10 @@ PDP15 : $(SIMH_LIB) $(PDP15_LIB) $(BLD_DIR)SCP.OBJ,$(PDP15_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -S3 : $(SIMH_LIB) $(S3_LIB) +S3 : $(BIN_DIR)S3-$(ARCH).EXE + $! S3 done + +$(BIN_DIR)S3-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(S3_LIB) $! $! Building The $(BIN_DIR)S3-$(ARCH).EXE Simulator. $! @@ -1162,7 +1270,10 @@ S3 : $(SIMH_LIB) $(S3_LIB) $(BLD_DIR)SCP.OBJ,$(S3_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -SDS : $(SIMH_LIB) $(SDS_LIB) +SDS : $(BIN_DIR)SDS-$(ARCH).EXE + $! SDS done + +$(BIN_DIR)SDS-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(SDS_LIB) $! $! Building The $(BIN_DIR)SDS-$(ARCH).EXE Simulator. $! @@ -1171,7 +1282,22 @@ SDS : $(SIMH_LIB) $(SDS_LIB) $(BLD_DIR)SCP.OBJ,$(SDS_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -VAX : $(SIMH_LIB) $(PCAP_LIBD) $(VAX_LIB) $(PCAP_EXECLET) +SWTP : $(BIN_DIR)SWTP-$(ARCH).EXE + $! SWTP done + +$(BIN_DIR)SWTP-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(SWTP_LIB) + $! + $! Building The $(BIN_DIR)SWTP-$(ARCH).EXE Simulator. + $! + $ $(CC)$(SWTP_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)SWTP-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,$(SWTP_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +VAX : $(BIN_DIR)VAX-$(ARCH).EXE + $! VAX done + +$(BIN_DIR)VAX-$(ARCH).EXE : $(SIMH_MAIN) $(VAX_SIMH_LIB) $(PCAP_LIBD) $(VAX_LIB) $(PCAP_EXECLET) $! $! Building The $(BIN_DIR)VAX-$(ARCH).EXE Simulator. $! @@ -1179,10 +1305,13 @@ VAX : $(SIMH_LIB) $(PCAP_LIBD) $(VAX_LIB) $(PCAP_EXECLET) $ LINK $(LINK_DEBUG)$(LINK_SECTION_BINDING)- /EXE=$(BIN_DIR)VAX-$(ARCH).EXE - $(BLD_DIR)SCP.OBJ,$(VAX_LIB)/LIBRARY,- - $(SIMH_LIB)/LIBRARY$(PCAP_LIBR) + $(VAX_SIMH_LIB)/LIBRARY$(PCAP_LIBR) $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -VAX780 : $(SIMH_LIB) $(PCAP_LIBD) $(VAX780_LIB1) $(VAX780_LIB2) $(PCAP_EXECLET) +VAX780 : $(BIN_DIR)VAX780-$(ARCH).EXE + $! VAX780 done + +$(BIN_DIR)VAX780-$(ARCH).EXE : $(SIMH_MAIN) $(VAX780_SIMH_LIB) $(PCAP_LIBD) $(VAX780_LIB1) $(VAX780_LIB2) $(PCAP_EXECLET) $! $! Building The $(BIN_DIR)VAX780-$(ARCH).EXE Simulator. $! @@ -1191,14 +1320,17 @@ VAX780 : $(SIMH_LIB) $(PCAP_LIBD) $(VAX780_LIB1) $(VAX780_LIB2) $(PCAP_EXECLET) /EXE=$(BIN_DIR)VAX780-$(ARCH).EXE - $(BLD_DIR)SCP.OBJ,- $(VAX780_LIB1)/LIBRARY,$(VAX780_LIB2)/LIBRARY,- - $(SIMH_LIB)/LIBRARY$(PCAP_LIBR) + $(VAX780_SIMH_LIB)/LIBRARY$(PCAP_LIBR) $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* # # If Not On VAX, Build The IBM 7094 Simulator. # -.IF ALPHA_OR_IA64 -I7094 : $(SIMH_LIB) $(I7094_LIB) +.IFDEF ALPHA_OR_IA64 +I7094 : $(BIN_DIR)I7094-$(ARCH).EXE + $! I7094 done + +$(BIN_DIR)I7094-$(ARCH).EXE : $(SIMH_MAIN) $(SIMH_LIB) $(I7094_LIB) $! $! Building The $(BIN_DIR)I7094-$(ARCH).EXE Simulator. $! diff --git a/makefile b/makefile index 2f9f3abd..1b8a0f74 100644 --- a/makefile +++ b/makefile @@ -1,62 +1,117 @@ # -# CC Command +# This GMU make makefile has been tested on: +# Linux (x86 & Sparc) +# OS X +# Solaris (x86 & Sparc) +# OpenBSD +# NetBSD +# FreeBSD +# Windows (MinGW & cygwin) +# +# +# CC Command (and platform available options). (Poor man's autoconf) # ifeq ($(WIN32),) - #Unix Environments - ifneq (,$(findstring solaris,$(OSTYPE))) - OS_CCDEFS = -lm -lsocket -lnsl -lrt -lpthread -D_GNU_SOURCE + #*nix Environments (&& cygwin) + ifeq (SunOS,$(shell uname)) + TEST = /bin/test else - ifneq (,$(findstring darwin,$(OSTYPE))) - OS_CCDEFS = -D_GNU_SOURCE - else - ifeq (librt,$(shell if test -e /usr/lib/librt.a; then echo librt; fi)) - OS_CCDEFS = -lrt -lm -D_GNU_SOURCE - else - OS_CCDEFS = -lm -D_GNU_SOURCE - endif - endif + TEST = test endif - ifeq (readline,$(shell if test -e /usr/lib/libreadline.a; then echo readline; fi)) + ifeq (Darwin,$(shell uname)) + LIBEXT = dylib + else + LIBEXT = a + endif + OS_CCDEFS = -D_GNU_SOURCE + ifeq (libm,$(shell if $(TEST) -e /usr/lib/libm.$(LIBEXT); then echo libm; fi)) + OS_LDFLAGS += -lm + endif + ifeq (SunOS,$(shell uname)) + OS_CCDEFS += -I/opt/sfw/include + OS_LDFLAGS += -lsocket -lnsl -lrt -lm -lpthread -L/opt/sfw/lib -R/opt/sfw/lib + endif + ifeq (cygwin,$(findstring cygwin,$(OSTYPE))) + OS_CCDEFS += -O2 + endif + ifeq (librt,$(shell if $(TEST) -e /usr/lib/librt.$(LIBEXT); then echo librt; fi)) + OS_LDFLAGS += -lrt + endif + ifeq (libpthread,$(shell if $(TEST) -e /usr/lib/libpthread.$(LIBEXT); then echo libpthread; fi)) + OS_CCDEFS += -DSIM_ASYNCH_IO -DUSE_READER_THREAD + OS_LDFLAGS += -lpthread + endif + ifeq (readline,$(shell if $(TEST) -e /usr/lib/libreadline.$(LIBEXT) -o -e /opt/sfw/lib/libreadline.a; then echo readline; fi)) # Use Locally installed and available readline support - ifeq (ncurses,$(shell if test -e /usr/lib/libncurses.a; then echo ncurses; fi)) - READLINE_CCDEFS = -DHAVE_READLINE -lreadline -lncurses + ifeq (ncurses,$(shell if $(TEST) -e /usr/lib/libncurses.$(LIBEXT) -o -e /opt/sfw/lib/libncurses.a; then echo ncurses; fi)) + OS_CCDEFS += -DHAVE_READLINE + OS_LDFLAGS += -lreadline -lncurses else - READLINE_CCDEFS = -DHAVE_READLINE -lreadline + OS_CCDEFS += -DHAVE_READLINE + OS_LDFLAGS += -lreadline endif endif - ifeq (pcap,$(shell if test -e /usr/lib/libpcap.a; then echo pcap; fi)) + ifeq (pcap,$(shell if $(TEST) -e /usr/include/pcap.h -o -e /opt/sfw/include/pcap.h; then echo pcap; fi)) # Use Locally installed and available pcap support - NETWORK_CCDEFS = -DUSE_NETWORK -lpcap + NETWORK_CCDEFS = -DUSE_NETWORK + NETWORK_LDFLAGS = -lpcap endif - ifeq (tuntap,$(shell if test -e /usr/include/linux/if_tun.h; then echo tuntap; fi)) + ifeq (tuntap,$(shell if $(TEST) -e /usr/include/linux/if_tun.h; then echo tuntap; fi)) # Provide support for Tap networking on Linux NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK endif - ifeq (bsdtuntap,$(shell if test -e /usr/include/net/if_tun.h; then echo bsdtuntap; fi)) + ifeq (bsdtuntap,$(shell if $(TEST) -e /usr/include/net/if_tun.h; then echo bsdtuntap; fi)) # Provide support for Tap networking NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP endif - CC = gcc -std=c99 -U__STRICT_ANSI__ -g $(OS_CCDEFS) -I . $(READLINE_CCDEFS) $(NETWORK_CCDEFS) $(NETWORK_TAP_CCDEFS) + ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi)) + MKDIRBIN = if $(TEST) ! -e BIN; then mkdir BIN; fi + endif ifneq ($(USE_NETWORK),) # Assume built from tcpdump.org sources with default install target NETWORK_OPT = -DUSE_NETWORK -isystem /usr/local/include /usr/local/lib/libpcap.a endif else - #Win32 Environments - LDFLAGS = -lm -lwsock32 -lwinmm - CC = gcc -std=c99 -U__STRICT_ANSI__ -O2 -I. + #Win32 Environments (via MinGW32) + GCC_Path := $(dir $(shell where gcc.exe)) + ifeq (pthreads,$(shell if exist ..\pthreads\Pre-built.2\include\pthread.h echo pthreads)) + PTHREADS_CCDEFS = -DSIM_ASYNCH_IO -DUSE_READER_THREAD -I../pthreads/Pre-built.2/include + PTHREADS_LDFLAGS = -lpthreadVC2 -L..\pthreads\Pre-built.2\lib + NETWORK_OPT = -DUSE_SHARED + ifeq (pthreads,$(shell if exist $(dir $(GCC_Path))..\include\pthread.h echo pthreads)) + PTHREADS_CCDEFS = -DSIM_ASYNCH_IO -DUSE_READER_THREAD + PTHREADS_LDFLAGS = -lpthreads + endif + endif + ifeq (pcap,$(shell if exist ..\winpcap\Wpdpack\include\pcap.h echo pcap)) + PCAP_CCDEFS = -I../winpcap/Wpdpack/include -DUSE_SHARED + NETWORK_LDFLAGS = + else + ifeq (pcap,$(shell if exist $(dir $(GCC_Path))..\include\pcap.h echo pcap)) + PCAP_CCDEFS = -DUSE_SHARED + NETWORK_LDFLAGS = + endif + endif + OS_CCDEFS = -fms-extensions -O2 $(PTHREADS_CCDEFS) $(PCAP_CCDEFS) + OS_LDFLAGS = -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) EXE = .exe + ifneq (binexists,$(shell if exist BIN echo binexists)) + MKDIRBIN = if not exist BIN mkdir BIN + endif ifneq ($(USE_NETWORK),) NETWORK_OPT = -DUSE_SHARED endif endif +CC = gcc -std=c99 -U__STRICT_ANSI__ -g -I . $(NETWORK_CCDEFS) $(NETWORK_TAP_CCDEFS) $(OS_CCDEFS) +LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS) + # # Common Libraries # BIN = BIN/ SIM = scp.c sim_console.c sim_fio.c sim_timer.c sim_sock.c \ - sim_tmxr.c sim_ether.c sim_tape.c + sim_tmxr.c sim_ether.c sim_tape.c sim_disk.c # @@ -81,7 +136,7 @@ ECLIPSE = ${NOVAD}/eclipse_cpu.c ${NOVAD}/eclipse_tt.c ${NOVAD}/nova_sys.c \ ${NOVAD}/nova_dkp.c ${NOVAD}/nova_dsk.c ${NOVAD}/nova_lp.c \ ${NOVAD}/nova_mta.c ${NOVAD}/nova_plt.c ${NOVAD}/nova_pt.c \ ${NOVAD}/nova_clk.c ${NOVAD}/nova_tt1.c ${NOVAD}/nova_qty.c -ECLIPSE_OPT = -I ${NOVAD} -DECLIPSE +ECLIPSE_OPT = -I ${NOVAD} -DECLIPSE PDP18BD = PDP18B @@ -304,134 +359,161 @@ endif pdp1 : ${BIN}pdp1${EXE} ${BIN}pdp1${EXE} : ${PDP1} ${SIM} + ${MKDIRBIN} ${CC} ${PDP1} ${SIM} ${PDP1_OPT} -o $@ ${LDFLAGS} pdp4 : ${BIN}pdp4${EXE} ${BIN}pdp4${EXE} : ${PDP18B} ${SIM} + ${MKDIRBIN} ${CC} ${PDP18B} ${SIM} ${PDP4_OPT} -o $@ ${LDFLAGS} pdp7 : ${BIN}pdp7${EXE} ${BIN}pdp7${EXE} : ${PDP18B} ${SIM} + ${MKDIRBIN} ${CC} ${PDP18B} ${SIM} ${PDP7_OPT} -o $@ ${LDFLAGS} pdp8 : ${BIN}pdp8${EXE} ${BIN}pdp8${EXE} : ${PDP8} ${SIM} + ${MKDIRBIN} ${CC} ${PDP8} ${SIM} ${PDP8_OPT} -o $@ ${LDFLAGS} pdp9 : ${BIN}pdp9${EXE} ${BIN}pdp9${EXE} : ${PDP18B} ${SIM} + ${MKDIRBIN} ${CC} ${PDP18B} ${SIM} ${PDP9_OPT} -o $@ ${LDFLAGS} pdp15 : ${BIN}pdp15${EXE} ${BIN}pdp15${EXE} : ${PDP18B} ${SIM} + ${MKDIRBIN} ${CC} ${PDP18B} ${SIM} ${PDP15_OPT} -o $@ ${LDFLAGS} pdp10 : ${BIN}pdp10${EXE} ${BIN}pdp10${EXE} : ${PDP10} ${SIM} + ${MKDIRBIN} ${CC} ${PDP10} ${SIM} ${PDP10_OPT} -o $@ ${LDFLAGS} pdp11 : ${BIN}pdp11${EXE} ${BIN}pdp11${EXE} : ${PDP11} ${SIM} + ${MKDIRBIN} ${CC} ${PDP11} ${SIM} ${PDP11_OPT} -o $@ ${LDFLAGS} vax : ${BIN}vax${EXE} ${BIN}vax${EXE} : ${VAX} ${SIM} + ${MKDIRBIN} ${CC} ${VAX} ${SIM} ${VAX_OPT} -o $@ ${LDFLAGS} vax780 : ${BIN}vax780${EXE} ${BIN}vax780${EXE} : ${VAX780} ${SIM} + ${MKDIRBIN} ${CC} ${VAX780} ${SIM} ${VAX780_OPT} -o $@ ${LDFLAGS} nova : ${BIN}nova${EXE} ${BIN}nova${EXE} : ${NOVA} ${SIM} + ${MKDIRBIN} ${CC} ${NOVA} ${SIM} ${NOVA_OPT} -o $@ ${LDFLAGS} eclipse : ${BIN}eclipse${EXE} ${BIN}eclipse${EXE} : ${ECLIPSE} ${SIM} + ${MKDIRBIN} ${CC} ${ECLIPSE} ${SIM} ${ECLIPSE_OPT} -o $@ ${LDFLAGS} h316 : ${BIN}h316${EXE} ${BIN}h316${EXE} : ${H316} ${SIM} + ${MKDIRBIN} ${CC} ${H316} ${SIM} ${H316_OPT} -o $@ ${LDFLAGS} hp2100 : ${BIN}hp2100${EXE} ${BIN}hp2100${EXE} : ${HP2100} ${SIM} + ${MKDIRBIN} ${CC} ${HP2100} ${SIM} ${HP2100_OPT} -o $@ ${LDFLAGS} i1401 : ${BIN}i1401${EXE} ${BIN}i1401${EXE} : ${I1401} ${SIM} + ${MKDIRBIN} ${CC} ${I1401} ${SIM} ${I1401_OPT} -o $@ ${LDFLAGS} i1620 : ${BIN}i1620${EXE} ${BIN}i1620${EXE} : ${I1620} ${SIM} + ${MKDIRBIN} ${CC} ${I1620} ${SIM} ${I1620_OPT} -o $@ ${LDFLAGS} i7094 : ${BIN}i7094${EXE} ${BIN}i7094${EXE} : ${I7094} ${SIM} + ${MKDIRBIN} ${CC} ${I7094} ${SIM} ${I7094_OPT} -o $@ ${LDFLAGS} ibm1130 : ${BIN}ibm1130${EXE} ${BIN}ibm1130${EXE} : ${IBM1130} + ${MKDIRBIN} ${CC} ${IBM1130} ${SIM} ${IBM1130_OPT} -o $@ ${LDFLAGS} s3 : ${BIN}s3${EXE} ${BIN}s3${EXE} : ${S3} ${SIM} + ${MKDIRBIN} ${CC} ${S3} ${SIM} ${S3_OPT} -o $@ ${LDFLAGS} altair : ${BIN}altair${EXE} ${BIN}altair${EXE} : ${ALTAIR} ${SIM} + ${MKDIRBIN} ${CC} ${ALTAIR} ${SIM} ${ALTAIR_OPT} -o $@ ${LDFLAGS} altairz80 : ${BIN}altairz80${EXE} ${BIN}altairz80${EXE} : ${ALTAIRZ80} ${SIM} + ${MKDIRBIN} ${CC} ${ALTAIRZ80} ${SIM} ${ALTAIRZ80_OPT} -o $@ ${LDFLAGS} gri : ${BIN}gri${EXE} ${BIN}gri${EXE} : ${GRI} ${SIM} + ${MKDIRBIN} ${CC} ${GRI} ${SIM} ${GRI_OPT} -o $@ ${LDFLAGS} lgp : ${BIN}lgp${EXE} ${BIN}lgp${EXE} : ${LGP} ${SIM} + ${MKDIRBIN} ${CC} ${LGP} ${SIM} ${LGP_OPT} -o $@ ${LDFLAGS} id16 : ${BIN}id16${EXE} ${BIN}id16${EXE} : ${ID16} ${SIM} + ${MKDIRBIN} ${CC} ${ID16} ${SIM} ${ID16_OPT} -o $@ ${LDFLAGS} id32 : ${BIN}id32${EXE} ${BIN}id32${EXE} : ${ID32} ${SIM} + ${MKDIRBIN} ${CC} ${ID32} ${SIM} ${ID32_OPT} -o $@ ${LDFLAGS} sds : ${BIN}sds${EXE} ${BIN}sds${EXE} : ${SDS} ${SIM} + ${MKDIRBIN} ${CC} ${SDS} ${SIM} ${SDS_OPT} -o $@ ${LDFLAGS} swtp : ${BIN}swtp${EXE} ${BIN}swtp${EXE} : ${SWTP} ${SIM} - ${CC} ${SWTP} ${SIM} ${SWTP_OPT} -o $@ ${LDFLAGS} \ No newline at end of file + ${MKDIRBIN} + ${CC} ${SWTP} ${SIM} ${SWTP_OPT} -o $@ ${LDFLAGS} diff --git a/scp.c b/scp.c index f0d8ef3f..76ffd840 100644 --- a/scp.c +++ b/scp.c @@ -23,6 +23,11 @@ used in advertising or otherwise to promote the sale, use or other dealings 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 22-Jan-11 MP Added SET ON, SET NOON, ON, GOTO and RETURN command support 13-Jan-11 MP Added "SHOW SHOW" and "SHOW SHOW" commands 05-Jan-11 RMS Fixed bug in deposit stride for numeric input (John Dundas) @@ -253,6 +258,17 @@ else if (sim_switches & SWMASK ('H')) val = 16; \ 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 */ extern char sim_name[]; @@ -657,6 +673,7 @@ for (i = 1; i < argc; i++) { /* loop thru args */ } /* end for */ sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */ +AIO_INIT; /* init Asynch I/O */ if (sim_vm_init != NULL) /* call once only */ (*sim_vm_init)(); sim_finit (); /* init fio package */ @@ -742,6 +759,7 @@ sim_set_deboff (0, NULL); /* close debug */ sim_set_logoff (0, NULL); /* close log */ sim_set_notelnet (0, NULL); /* close Telnet */ sim_ttclose (); /* close console */ +AIO_CLEANUP; /* Asynch I/O */ return 0; } @@ -1766,6 +1784,26 @@ for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) { fprintf (st, " at %d\n", 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; } @@ -2895,14 +2933,6 @@ r = sim_instr(); sim_is_running = 0; /* flag idle */ sim_ttcmd (); /* restore console */ 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 */ fflush (sim_log); if (sim_deb) /* flush debug log */ @@ -2912,12 +2942,24 @@ for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* flush attached files uptr = dptr->units + j; if ((uptr->flags & UNIT_ATT) && /* attached, */ !(uptr->flags & UNIT_BUF) && /* not buffered, */ - (uptr->fileref) && /* real file, */ - !(uptr->flags & UNIT_RAW) && /* not raw, */ - !(uptr->flags & UNIT_RO)) /* not read only? */ - fflush (uptr->fileref); + (uptr->fileref)) /* real file, */ + 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? */ + 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) printf ("\n"); #endif @@ -4457,6 +4499,7 @@ t_stat reason; if (stop_cpu) /* stop CPU? */ return SCPE_STOP; +AIO_UPDATE_QUEUE; if (sim_clock_queue == NULL) { /* queue empty? */ UPDATE_SIM_TIME (noqueue_time); /* update sim time */ sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */ @@ -4495,8 +4538,7 @@ t_stat sim_activate (UNIT *uptr, int32 event_time) UNIT *cptr, *prvptr; int32 accum; -if (event_time < 0) - return SCPE_IERR; +AIO_ACTIVATE (sim_activate, uptr, event_time); if (sim_is_active (uptr)) /* already active? */ return SCPE_OK; if (sim_clock_queue == NULL) { @@ -4540,6 +4582,7 @@ return SCPE_OK; t_stat sim_activate_abs (UNIT *uptr, int32 event_time) { +AIO_ACTIVATE (sim_activate_abs, uptr, event_time); sim_cancel (uptr); return sim_activate (uptr, event_time); } @@ -4557,6 +4600,7 @@ t_stat sim_cancel (UNIT *uptr) { UNIT *cptr, *nptr; +AIO_VALIDATE; if (sim_clock_queue == NULL) return SCPE_OK; UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */ @@ -4594,6 +4638,7 @@ int32 sim_is_active (UNIT *uptr) UNIT *cptr; int32 accum; +AIO_VALIDATE; accum = 0; for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { if (cptr == sim_clock_queue) { @@ -5002,7 +5047,7 @@ return SCPE_OK; /* Debug printout routines, from Dave Hittner */ const char* debug_bstates = "01_^"; -const char* debug_fmt = "DBG> %s %s: "; +const char* debug_fmt = "DBG(%.0f)> %s %s: "; int32 debug_unterm = 0; /* Finds debug phrase matching bitmask from from device DEBTAB table */ @@ -5032,7 +5077,7 @@ static void sim_debug_prefix (uint32 dbits, DEVICE* dptr) { if (!debug_unterm) { 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); } } @@ -5060,7 +5105,7 @@ if (sim_deb && (dptr->dctrl & dbits)) { #if defined (_WIN32) #define vsnprintf _vsnprintf #endif -#if defined (__DECC) && defined (__VMS) +#if defined (__DECC) && defined (__VMS) && defined (__VAX) #define NO_vsnprintf #endif #if defined( NO_vsnprintf) @@ -5073,9 +5118,12 @@ if (sim_deb && (dptr->dctrl & dbits)) { set and the bitmask matches the current device debug options. Extra returns are added for un*x systems, since the output device is set into 'raw' mode when the cpu is booted, - and the extra returns don't hurt any other systems. */ - -void sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...) + 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, ...) { if (sim_deb && (dptr->dctrl & dbits)) { @@ -5084,9 +5132,9 @@ if (sim_deb && (dptr->dctrl & dbits)) { char *buf = stackbuf; va_list arglist; int32 i, j, len; + char* debug_type = get_dbg_verb (dbits, dptr); buf[bufsize-1] = '\0'; - sim_debug_prefix(dbits, dptr); /* print prefix if required */ while (1) { /* format passed string, args */ va_start (arglist, fmt); @@ -5132,10 +5180,14 @@ if (sim_deb && (dptr->dctrl & dbits)) { for (i = j = 0; i < len; ++i) { if ('\n' == buf[i]) { - if (i > j) - fwrite (&buf[j], 1, i-j, sim_deb); - j = i; - fputc('\r', sim_deb); + if (i > j) { + if (debug_unterm) + fprintf (sim_deb, "%.*s\r\n", i-j, &buf[j]); + 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) diff --git a/scp.h b/scp.h index cb22baa0..6c5aae9e 100644 --- a/scp.h +++ b/scp.h @@ -23,6 +23,7 @@ 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. + 05-Dec-10 MP Added macro invocation of sim_debug 09-Aug-06 JDB Added assign_device and deassign_device 14-Jul-06 RMS Added sim_activate_abs 06-Jan-06 RMS Added fprint_stopped_gen @@ -121,7 +122,14 @@ t_stat sim_string_to_stat (char *cptr, t_stat *cond); t_stat sim_cancel_step (void); void sim_debug_u16 (uint32 dbits, DEVICE* dptr, const char* const* bitdefs, 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, ...); +#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); #endif diff --git a/sim_console.c b/sim_console.c index 8b35cf66..2422dbdf 100644 --- a/sim_console.c +++ b/sim_console.c @@ -555,7 +555,7 @@ if (strcmp (gbuf, "LOG") == 0) { /* output to log? */ ++(*pref)->refcount; } else if (strcmp (gbuf, "DEBUG") == 0) { /* output to debug? */ - if (sim_debug == NULL) /* any debug? */ + if (sim_deb == NULL) /* any debug? */ return SCPE_ARG; *pf = sim_deb; *pref = sim_deb_ref; diff --git a/sim_defs.h b/sim_defs.h index 9b192c88..91abc4ef 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 05-Jan-11 MP Added Asynch I/O support 18-Jan-11 MP Added log file reference count support 21-Jul-08 RMS Removed inlining support 28-May-08 RMS Added inlining support @@ -119,12 +120,16 @@ /* Length specific integer declarations */ +#if defined (VMS) +#include +#else typedef signed char int8; typedef signed short int16; typedef signed int int32; typedef unsigned char uint8; typedef unsigned short uint16; -typedef unsigned int uint32; +typedef unsigned int uint32; +#endif typedef int t_stat; /* status */ typedef int t_bool; /* boolean */ @@ -349,12 +354,23 @@ struct sim_unit { uint32 flags; /* flags */ t_addr capac; /* capacity */ 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 wait; /* wait */ int32 u3; /* device specific */ int32 u4; /* device specific */ int32 u5; /* 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 */ @@ -539,4 +555,157 @@ typedef struct sim_fileref FILEREF; #include "sim_timer.h" #include "sim_fio.h" +/* Asynch/Threaded I/O support */ + +#if defined (SIM_ASYNCH_IO) +#include + +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 +#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 diff --git a/sim_disk.c b/sim_disk.c new file mode 100644 index 00000000..b6768525 --- /dev/null +++ b/sim_disk.c @@ -0,0 +1,3272 @@ +/* sim_disk.c: simulator disk support library + + 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 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 Mark Pizzolato. + + + + This is the place which hides processing of various disk formats, + as well as OS-specific direct hardware access. + + 25-Jan-11 MP Initial Implemementation + +Public routines: + + sim_disk_attach attach disk unit + sim_disk_detach detach disk unit + sim_disk_rdsect read disk sectors + sim_disk_rdsect_a read disk sectors asynchronously + sim_disk_wrsect write disk sectors + sim_disk_wrsect_a write disk sectors asynchronously + sim_disk_unload unload or detach a disk as needed + sim_disk_reset reset unit + sim_disk_wrp TRUE if write protected + sim_disk_isavailable TRUE if available for I/O + sim_disk_size get disk size + sim_disk_set_fmt set disk format + sim_disk_show_fmt show disk format + sim_disk_set_capac set disk capacity + sim_disk_show_capac show disk capacity + sim_disk_set_async enable asynchronous operation + sim_disk_clr_async disable asynchronous operation + sim_disk_data_trace debug support + +Internal routines: + + sim_os_disk_open_raw platform specific open raw device + sim_os_disk_close_raw platform specific close raw device + sim_os_disk_size_raw platform specific raw device size + sim_os_disk_unload_raw platform specific disk unload/eject + sim_os_disk_rdsect platform specific read sectors + sim_os_disk_wrsect platform specific write sectors + + sim_vhd_disk_open platform independent open virtual disk file + sim_vhd_disk_create platform independent create virtual disk file + sim_vhd_disk_create_diff platform independent create differencing virtual disk file + sim_vhd_disk_close platform independent close virtual disk file + sim_vhd_disk_size platform independent virtual disk size + sim_vhd_disk_rdsect platform independent read virtual disk sectors + sim_vhd_disk_wrsect platform independent write virtual disk sectors + + +*/ + +#include "sim_defs.h" +#include "sim_disk.h" +#include +#include + +#ifdef _WIN32 +#include +#endif +#if defined SIM_ASYNCH_IO +#include +#endif + +extern FILE *sim_log; /* log file */ +extern int32 sim_switches; +extern int32 sim_quiet; +extern uint32 sim_taddr_64; +extern int32 sim_end; + +struct disk_context { + DEVICE *dptr; /* Device for unit (access to debug flags) */ + uint32 dbit; /* debugging bit */ + uint32 sector_size; /* Disk Sector Size (of the pseudo disk) */ + uint32 xfer_element_size; /* Disk Bus Transfer size (1 - byte, 2 - word, 4 - longword) */ + uint32 storage_sector_size;/* Sector size of the containing storage */ + uint32 removable; /* Removable device flag */ + uint32 auto_format; /* Format determined dynamically */ +#if defined _WIN32 + HANDLE disk_handle; /* OS specific Raw device handle */ +#endif +#if defined SIM_ASYNCH_IO + int asynch_io; /* Asynchronous Interrupt scheduling enabled */ + int asynch_io_latency; /* instructions to delay pending interrupt */ + pthread_mutex_t lock; + pthread_t io_thread; /* I/O Thread Id */ + pthread_mutex_t io_lock; + pthread_cond_t io_cond; + int io_dop; + uint8 *buf; + t_seccnt *rsects; + t_seccnt sects; + t_lba lba; + DISK_PCALLBACK callback; + t_stat io_status; +#endif + }; + +#define disk_ctx up8 /* Field in Unit structure which points to the disk_context */ + +#if defined SIM_ASYNCH_IO +#define AIO_CALLSETUP \ +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; \ + \ +if ((!callback) || !ctx->asynch_io) + +#define AIO_CALL(op, _lba, _buf, _rsects, _sects, _callback) \ + if (1) { \ + struct disk_context *ctx = \ + (struct disk_context *)uptr->disk_ctx; \ + \ + pthread_mutex_lock (&ctx->io_lock); \ + \ + sim_debug (ctx->dbit, ctx->dptr, \ + "sim_disk AIO_CALL(op=%d, unit=%d, lba=0x%X, sects=%d)\n",\ + op, uptr-ctx->dptr->units, _lba, _sects); \ + \ + if (ctx->callback) \ + abort(); /* horrible mistake, stop */ \ + ctx->io_dop = op; \ + ctx->lba = _lba; \ + ctx->buf = _buf; \ + ctx->sects = _sects; \ + ctx->rsects = _rsects; \ + ctx->callback = _callback; \ + pthread_cond_signal (&ctx->io_cond); \ + pthread_mutex_unlock (&ctx->io_lock); \ + } + + +#define DOP_DONE 0 /* close */ +#define DOP_RSEC 1 /* sim_disk_rdsect_a */ +#define DOP_WSEC 2 /* sim_disk_wrsect_a */ +#define DOP_IAVL 3 /* sim_disk_isavailable_a */ + +static void * +_disk_io(void *arg) +{ +UNIT* volatile uptr = (UNIT*)arg; +int sched_policy; +struct sched_param sched_priority; +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; + +/* Boost Priority for this I/O thread vs the CPU instruction execution + thread which in general won't be readily yielding the processor when + this thread needs to run */ +pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); +++sched_priority.sched_priority; +pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); + +sim_debug (ctx->dbit, ctx->dptr, "_disk_io(unit=%d) starting\n", uptr-ctx->dptr->units); + +pthread_mutex_lock (&ctx->io_lock); +while (ctx->asynch_io) { + pthread_cond_wait (&ctx->io_cond, &ctx->io_lock); + if (ctx->io_dop == DOP_DONE) + break; + pthread_mutex_unlock (&ctx->io_lock); + switch (ctx->io_dop) { + case DOP_RSEC: + ctx->io_status = sim_disk_rdsect (uptr, ctx->lba, ctx->buf, ctx->rsects, ctx->sects); + break; + case DOP_WSEC: + ctx->io_status = sim_disk_wrsect (uptr, ctx->lba, ctx->buf, ctx->rsects, ctx->sects); + break; + case DOP_IAVL: + ctx->io_status = sim_disk_isavailable (uptr); + break; + } + pthread_mutex_lock (&ctx->io_lock); + ctx->io_dop = DOP_DONE; + sim_activate (uptr, ctx->asynch_io_latency); + } +pthread_mutex_unlock (&ctx->io_lock); + +sim_debug (ctx->dbit, ctx->dptr, "_disk_io(unit=%d) exiting\n", uptr-ctx->dptr->units); + +return NULL; +} + +/* This routine is called in the context of the main simulator thread before + processing events for any unit. It is only called when an asynchronous + thread has called sim_activate() to activate a unit. The job of this + routine is to put the unit in proper condition to digest what may have + occurred in the asynchrcondition thread. + + Since disk processing only handles a single I/O at a time to a + particular disk device (due to using stdio for the SimH Disk format + and stdio doesn't have an atomic seek+(read|write) operation), + we have the opportunity to possibly detect improper attempts to + issue multiple concurrent I/O requests. */ +static void _disk_completion_dispatch (UNIT *uptr) +{ +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +DISK_PCALLBACK callback = ctx->callback; + +sim_debug (ctx->dbit, ctx->dptr, "_disk_completion_dispatch(unit=%d, dop=%d, callback=%p)\n", uptr-ctx->dptr->units, ctx->io_dop, ctx->callback); + +if (ctx->io_dop != DOP_DONE) + abort(); /* horribly wrong, stop */ + +if (ctx->callback && ctx->io_dop == DOP_DONE) { + ctx->callback = NULL; + callback (uptr, ctx->io_status); + } +} +#else +#define AIO_CALLSETUP +#define AIO_CALL(op, _lba, _buf, _rsects, _sects, _callback) \ + if (_callback) \ + (_callback) (uptr, r); +#endif + +/* Forward declarations */ + +static t_stat sim_vhd_disk_implemented (void); +static FILE *sim_vhd_disk_open (const char *rawdevicename, const char *openmode); +static FILE *sim_vhd_disk_create (const char *szVHDPath, t_addr desiredsize); +static FILE *sim_vhd_disk_create_diff (const char *szVHDPath, const char *szParentVHDPath); +static int sim_vhd_disk_close (FILE *f); +static void sim_vhd_disk_flush (FILE *f); +static t_addr sim_vhd_disk_size (FILE *f); +static t_stat sim_vhd_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects); +static t_stat sim_vhd_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects); +static t_stat sim_vhd_disk_set_dtype (FILE *f, const char *dtype); +static const char *sim_vhd_disk_get_dtype (FILE *f); +static t_stat sim_os_disk_implemented_raw (void); +static FILE *sim_os_disk_open_raw (const char *rawdevicename, const char *openmode); +static int sim_os_disk_close_raw (FILE *f); +static void sim_os_disk_flush_raw (FILE *f); +static t_addr sim_os_disk_size_raw (FILE *f); +static t_stat sim_os_disk_unload_raw (FILE *f); +static t_bool sim_os_disk_isavailable_raw (FILE *f); +static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects); +static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects); +static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable); +static t_stat sim_disk_pdp11_bad_block (UNIT *uptr, int32 sec); + +struct sim_disk_fmt { + char *name; /* name */ + int32 uflags; /* unit flags */ + int32 fmtval; /* Format type value */ + t_stat (*impl_fnc)(void); /* Implemented Test Function */ + }; + +static struct sim_disk_fmt fmts[DKUF_N_FMT] = { + { "SIMH", 0, DKUF_F_STD, NULL}, + { "RAW", 0, DKUF_F_RAW, sim_os_disk_implemented_raw}, + { "VHD", 0, DKUF_F_VHD, sim_vhd_disk_implemented}, + { NULL, 0, 0} + }; + +/* Set disk format */ + +t_stat sim_disk_set_fmt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 f; + +if (uptr == NULL) + return SCPE_IERR; +if (cptr == NULL) + return SCPE_ARG; +for (f = 0; f < DKUF_N_FMT && fmts[f].name; f++) { + if (fmts[f].name && (strcmp (cptr, fmts[f].name) == 0)) { + if ((fmts[f].impl_fnc) && (fmts[f].impl_fnc() != SCPE_OK)) + return SCPE_NOFNC; + uptr->flags = (uptr->flags & ~DKUF_FMT) | + (fmts[f].fmtval << DKUF_V_FMT) | fmts[f].uflags; + return SCPE_OK; + } + } +return SCPE_ARG; +} + +/* Show disk format */ + +t_stat sim_disk_show_fmt (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, f = DK_GET_FMT (uptr); + +for (i = 0; i < DKUF_N_FMT; i++) + if (fmts[i].fmtval == f) { + fprintf (st, "%s format", fmts[i].name); + return SCPE_OK; + } +fprintf (st, "invalid format"); +return SCPE_OK; +} + +/* Set disk capacity */ + +t_stat sim_disk_set_capac (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +t_addr cap; +t_stat r; + +if ((cptr == NULL) || (*cptr == 0)) + return SCPE_ARG; +if (uptr->flags & UNIT_ATT) + return SCPE_ALATT; +cap = (t_addr) get_uint (cptr, 10, sim_taddr_64? 2000000: 2000, &r); +if (r != SCPE_OK) + return SCPE_ARG; +uptr->capac = cap * ((t_addr) 1000000); +return SCPE_OK; +} + +/* Show disk capacity */ + +t_stat sim_disk_show_capac (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (uptr->capac) { + if (uptr->capac >= (t_addr) 1000000) + fprintf (st, "capacity=%dMB", (uint32) (uptr->capac / ((t_addr) 1000000))); + else if (uptr->capac >= (t_addr) 1000) + fprintf (st, "capacity=%dKB", (uint32) (uptr->capac / ((t_addr) 1000))); + else fprintf (st, "capacity=%dB", (uint32) uptr->capac); + } +else fprintf (st, "undefined capacity"); +return SCPE_OK; +} + +/* Test for available */ + +t_bool sim_disk_isavailable (UNIT *uptr) +{ +if (!(uptr->flags & UNIT_ATT)) /* attached? */ + return FALSE; +switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_STD: /* SIMH format */ + return TRUE; + case DKUF_F_VHD: /* VHD format */ + return TRUE; + break; + case DKUF_F_RAW: /* Raw Physical Disk Access */ + return sim_os_disk_isavailable_raw (uptr->fileref); + break; + default: + return FALSE; + } +} + +t_bool sim_disk_isavailable_a (UNIT *uptr, DISK_PCALLBACK callback) +{ +t_bool r = FALSE; +AIO_CALLSETUP + r = sim_disk_isavailable (uptr); +AIO_CALL(DOP_IAVL, 0, NULL, NULL, 0, callback); +return r; +} + +/* Test for write protect */ + +t_bool sim_disk_wrp (UNIT *uptr) +{ +return (uptr->flags & DKUF_WRP)? TRUE: FALSE; +} + +/* Get Disk size */ + +t_addr sim_disk_size (UNIT *uptr) +{ +switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_STD: /* SIMH format */ + return sim_fsize_ex (uptr->fileref); + case DKUF_F_VHD: /* VHD format */ + return sim_vhd_disk_size (uptr->fileref); + break; + case DKUF_F_RAW: /* Raw Physical Disk Access */ + return sim_os_disk_size_raw (uptr->fileref); + break; + default: + return (t_addr)-1; + } +} + +/* Enable asynchronous operation */ + +t_stat sim_disk_set_async (UNIT *uptr, int latency) +{ +#if !defined(SIM_ASYNCH_IO) +char *msg = "Disk: can't operate asynchronously\r\n"; +printf ("%s", msg); +if (sim_log) fprintf (sim_log, "%s", msg); +return SCPE_NOFNC; +#else +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +pthread_attr_t attr; + +ctx->asynch_io = 1; +ctx->asynch_io_latency = latency; +pthread_mutex_init (&ctx->io_lock, NULL); +pthread_cond_init (&ctx->io_cond, NULL); +pthread_attr_init(&attr); +pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); +pthread_create (&ctx->io_thread, &attr, _disk_io, (void *)uptr); +pthread_attr_destroy(&attr); +uptr->a_check_completion = _disk_completion_dispatch; +#endif +return SCPE_OK; +} + +/* Disable asynchronous operation */ + +t_stat sim_disk_clr_async (UNIT *uptr) +{ +#if !defined(SIM_ASYNCH_IO) +return SCPE_NOFNC; +#else +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; + +/* make sure device exists */ +if (!ctx) return SCPE_UNATT; + +if (ctx->asynch_io) { + pthread_mutex_lock (&ctx->io_lock); + ctx->asynch_io = 0; + pthread_cond_signal (&ctx->io_cond); + pthread_mutex_unlock (&ctx->io_lock); + pthread_join (ctx->io_thread, NULL); + pthread_mutex_destroy (&ctx->io_lock); + pthread_cond_destroy (&ctx->io_cond); + } +return SCPE_OK; +#endif +} + +/* Read Sectors */ + +static t_stat _sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects) +{ +t_addr da; +uint32 err, tbc; +size_t i; +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; + +sim_debug (ctx->dbit, ctx->dptr, "_sim_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); + +da = ((t_addr)lba) * ctx->sector_size; +tbc = sects * ctx->sector_size; +if (sectsread) + *sectsread = 0; +err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */ +if (!err) { + i = sim_fread (buf, ctx->xfer_element_size, tbc/ctx->xfer_element_size, uptr->fileref); + if (i < tbc/ctx->xfer_element_size) /* fill */ + memset (&buf[i*ctx->xfer_element_size], 0, tbc-(i*ctx->xfer_element_size)); + err = ferror (uptr->fileref); + if ((!err) && (sectsread)) + *sectsread = (i*ctx->xfer_element_size+ctx->sector_size-1)/ctx->sector_size; + } +return err; +} + +t_stat sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects) +{ +t_stat r; +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +t_seccnt sread; + +sim_debug (ctx->dbit, ctx->dptr, "sim_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); + +if ((sects == 1) && /* Single sector reads */ + (lba >= uptr->capac/ctx->sector_size)) { /* beyond the end of the disk */ + memset (buf, '\0', ctx->sector_size); /* are bad block management efforts - zero buffer */ + if (sectsread) + *sectsread = 1; + return SCPE_OK; /* return success */ + } + +if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) || /* Sector Aligned & whole sector transfers */ + ((0 == ((lba*ctx->sector_size) & (ctx->storage_sector_size - 1))) && + (0 == ((sects*ctx->sector_size) & (ctx->storage_sector_size - 1))))) { + switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_STD: /* SIMH format */ + return _sim_disk_rdsect (uptr, lba, buf, sectsread, sects); + case DKUF_F_VHD: /* VHD format */ + r = sim_vhd_disk_rdsect (uptr, lba, buf, &sread, sects); + break; + case DKUF_F_RAW: /* Raw Physical Disk Access */ + r = sim_os_disk_rdsect (uptr, lba, buf, &sread, sects); + break; + default: + return SCPE_NOFNC; + } + if (sectsread) + *sectsread = sread; + if (r != SCPE_OK) + return r; + sim_buf_swap_data (buf, ctx->xfer_element_size, (sread * ctx->sector_size) / ctx->xfer_element_size); + return r; + } +else { /* Unaligned and/or partial sector transfers */ + uint8 *tbuf = malloc (sects*ctx->sector_size + 2*ctx->storage_sector_size); + t_lba sspsts = ctx->storage_sector_size/ctx->sector_size; /* sim sectors in a storage sector */ + t_lba tlba = lba & ~(sspsts - 1); + t_seccnt tsects = sects + (lba - tlba); + + tsects = (tsects + (sspsts - 1)) & ~(sspsts - 1); + if (sectsread) + *sectsread = 0; + if (tbuf == NULL) + return SCPE_MEM; + switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_STD: /* SIMH format */ + r = _sim_disk_rdsect (uptr, tlba, tbuf, &sread, tsects); + break; + case DKUF_F_VHD: /* VHD format */ + r = sim_vhd_disk_rdsect (uptr, tlba, tbuf, &sread, tsects); + if (r == SCPE_OK) + sim_buf_swap_data (tbuf, ctx->xfer_element_size, (sread * ctx->sector_size) / ctx->xfer_element_size); + break; + case DKUF_F_RAW: /* Raw Physical Disk Access */ + r = sim_os_disk_rdsect (uptr, tlba, tbuf, &sread, tsects); + if (r == SCPE_OK) + sim_buf_swap_data (tbuf, ctx->xfer_element_size, (sread * ctx->sector_size) / ctx->xfer_element_size); + break; + default: + free (tbuf); + return SCPE_NOFNC; + } + if (r == SCPE_OK) { + memcpy (buf, tbuf + ((lba - tlba) * ctx->sector_size), sects * ctx->sector_size); + if (sectsread) { + *sectsread = sread - (lba - tlba); + if (*sectsread > sects) + *sectsread = sects; + } + } + free (tbuf); + return r; + } +} + +t_stat sim_disk_rdsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects, DISK_PCALLBACK callback) +{ +t_stat r = SCPE_OK; +AIO_CALLSETUP + r = sim_disk_rdsect (uptr, lba, buf, sectsread, sects); +AIO_CALL(DOP_RSEC, lba, buf, sectsread, sects, callback); +return r; +} + +/* Write Sectors */ + +static t_stat _sim_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects) +{ +t_addr da; +uint32 err, tbc; +size_t i; +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; + +sim_debug (ctx->dbit, ctx->dptr, "_sim_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); + +da = ((t_addr)lba) * ctx->sector_size; +tbc = sects * ctx->sector_size; +if (sectswritten) + *sectswritten = 0; +err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */ +if (!err) { + i = sim_fwrite (buf, ctx->xfer_element_size, tbc/ctx->xfer_element_size, uptr->fileref); + err = ferror (uptr->fileref); + if ((!err) && (sectswritten)) + *sectswritten = (i*ctx->xfer_element_size+ctx->sector_size-1)/ctx->sector_size; + } +return err; +} + +t_stat sim_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects) +{ +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +uint32 f = DK_GET_FMT (uptr); +t_stat r; +uint8 *tbuf = NULL; + +sim_debug (ctx->dbit, ctx->dptr, "sim_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); + +if (f == DKUF_F_STD) + return _sim_disk_wrsect (uptr, lba, buf, sectswritten, sects); +if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) || /* Sector Aligned & whole sector transfers */ + ((0 == ((lba*ctx->sector_size) & (ctx->storage_sector_size - 1))) && + (0 == ((sects*ctx->sector_size) & (ctx->storage_sector_size - 1))))) { + + if (sim_end || (ctx->xfer_element_size == sizeof (char))) + switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_VHD: /* VHD format */ + return sim_vhd_disk_wrsect (uptr, lba, buf, sectswritten, sects); + case DKUF_F_RAW: /* Raw Physical Disk Access */ + return sim_os_disk_wrsect (uptr, lba, buf, sectswritten, sects); + default: + return SCPE_NOFNC; + } + + tbuf = malloc (sects * ctx->sector_size); + if (NULL == tbuf) + return SCPE_MEM; + sim_buf_copy_swapped (tbuf, buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size); + + switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_VHD: /* VHD format */ + r = sim_vhd_disk_wrsect (uptr, lba, tbuf, sectswritten, sects); + break; + case DKUF_F_RAW: /* Raw Physical Disk Access */ + r = sim_os_disk_wrsect (uptr, lba, tbuf, sectswritten, sects); + break; + default: + r = SCPE_NOFNC; + break; + } + } +else { /* Unaligned and/or partial sector transfers */ + t_lba sspsts = ctx->storage_sector_size/ctx->sector_size; /* sim sectors in a storage sector */ + t_lba tlba = lba & ~(sspsts - 1); + t_seccnt tsects = sects + (lba - tlba); + + tbuf = malloc (sects*ctx->sector_size + 2*ctx->storage_sector_size); + tsects = (tsects + (sspsts - 1)) & ~(sspsts - 1); + if (sectswritten) + *sectswritten = 0; + if (tbuf == NULL) + return SCPE_MEM; + /* Partial Sector writes require a read-modify-write sequence for the partial sectors */ + if ((lba & (sspsts - 1)) || + (sects < sspsts)) + switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_VHD: /* VHD format */ + sim_vhd_disk_rdsect (uptr, tlba, tbuf, NULL, sspsts); + break; + case DKUF_F_RAW: /* Raw Physical Disk Access */ + sim_os_disk_rdsect (uptr, tlba, tbuf, NULL, sspsts); + break; + default: + r = SCPE_NOFNC; + break; + } + if ((tsects > sspsts) && + ((sects + lba - tlba) & (sspsts - 1))) + switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_VHD: /* VHD format */ + sim_vhd_disk_rdsect (uptr, tlba + tsects - sspsts, + tbuf + (tsects - sspsts) * ctx->sector_size, + NULL, sspsts); + break; + case DKUF_F_RAW: /* Raw Physical Disk Access */ + sim_os_disk_rdsect (uptr, tlba + tsects - sspsts, + tbuf + (tsects - sspsts) * ctx->sector_size, + NULL, sspsts); + break; + default: + r = SCPE_NOFNC; + break; + } + sim_buf_copy_swapped (tbuf + (lba & (sspsts - 1)) * ctx->sector_size, + buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size); + switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_VHD: /* VHD format */ + r = sim_vhd_disk_wrsect (uptr, tlba, tbuf, sectswritten, tsects); + break; + case DKUF_F_RAW: /* Raw Physical Disk Access */ + r = sim_os_disk_wrsect (uptr, tlba, tbuf, sectswritten, tsects); + break; + default: + r = SCPE_NOFNC; + break; + } + if ((r == SCPE_OK) && sectswritten) { + *sectswritten -= (lba - tlba); + if (*sectswritten > sects) + *sectswritten = sects; + } + } +free (tbuf); +return r; +} + +t_stat sim_disk_wrsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects, DISK_PCALLBACK callback) +{ +t_stat r = SCPE_OK; +AIO_CALLSETUP + r = sim_disk_wrsect (uptr, lba, buf, sectswritten, sects); +AIO_CALL(DOP_WSEC, lba, buf, sectswritten, sects, callback); +return r; +} + +t_stat sim_disk_unload (UNIT *uptr) +{ +switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_STD: /* Simh */ + case DKUF_F_VHD: /* VHD format */ + return sim_disk_detach (uptr); + case DKUF_F_RAW: /* Raw Physical Disk Access */ + return sim_os_disk_unload_raw (uptr->fileref); /* remove/eject disk */ + break; + default: + return SCPE_NOFNC; + } +} + +static void _sim_disk_io_flush (UNIT *uptr) +{ +uint32 f = DK_GET_FMT (uptr); + +#if defined (SIM_ASYNCH_IO) +sim_disk_clr_async (uptr); +sim_disk_set_async (uptr, 0); +#endif +switch (f) { /* case on format */ + case DKUF_F_STD: /* Simh */ + fflush (uptr->fileref); + break; + case DKUF_F_VHD: /* Virtual Disk */ + sim_vhd_disk_flush (uptr->fileref); + break; + case DKUF_F_RAW: /* Physical */ + sim_os_disk_flush_raw (uptr->fileref); + break; + } +} + +static t_stat _err_return (UNIT *uptr, t_stat stat) +{ +free (uptr->filename); +uptr->filename = NULL; +free (uptr->disk_ctx); +uptr->disk_ctx = NULL; +return stat; +} + + +t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize, uint32 dbit, const char *dtype, uint32 pdp11tracksize) +{ +struct disk_context *ctx; +DEVICE *dptr; +FILE *(*open_function)(const char *filename, const char *mode) = sim_fopen; +FILE *(*create_function)(const char *filename, t_addr desiredsize) = NULL; +t_addr (*size_function)(FILE *file); +t_stat (*storage_function)(FILE *file, uint32 *sector_size, uint32 *removable) = NULL; +t_bool created = FALSE; +t_bool auto_format = FALSE; +t_addr capac; + +if (uptr->flags & UNIT_DIS) /* disabled? */ + return SCPE_UDIS; +if (!(uptr->flags & UNIT_ATTABLE)) /* not attachable? */ + return SCPE_NOATT; +if ((dptr = find_dev_from_unit (uptr)) == NULL) + return SCPE_NOATT; +if (sim_switches & SWMASK ('F')) { /* format spec? */ + char gbuf[CBUFSIZE]; + cptr = get_glyph (cptr, gbuf, 0); /* get spec */ + if (*cptr == 0) /* must be more */ + return SCPE_2FARG; + if (sim_disk_set_fmt (uptr, 0, gbuf, NULL) != SCPE_OK) + return SCPE_ARG; + } +if (sim_switches & SWMASK ('D')) { /* create difference disk? */ + char gbuf[CBUFSIZE]; + FILE *vhd; + + sim_switches = sim_switches & ~(SWMASK ('D')); + cptr = get_glyph_nc (cptr, gbuf, 0); /* get spec */ + if (*cptr == 0) /* must be more */ + return SCPE_2FARG; + vhd = sim_vhd_disk_create_diff (gbuf, cptr); + if (vhd) { + sim_vhd_disk_close (vhd); + return sim_disk_attach (uptr, gbuf, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize); + } + return SCPE_ARG; + } +if (sim_switches & SWMASK ('C')) { /* create vhd disk & copy contents? */ + char gbuf[CBUFSIZE]; + FILE *vhd; + int saved_sim_switches = sim_switches; + int32 saved_sim_quiet = sim_quiet; + t_stat r; + + sim_switches = sim_switches & ~(SWMASK ('C')); + cptr = get_glyph_nc (cptr, gbuf, 0); /* get spec */ + if (*cptr == 0) /* must be more */ + return SCPE_2FARG; + sim_switches |= SWMASK ('R') | SWMASK ('E'); + sim_quiet = TRUE; + /* First open the source of the copy operation */ + r = sim_disk_attach (uptr, cptr, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize); + sim_quiet = saved_sim_quiet; + if (r != SCPE_OK) { + sim_switches = saved_sim_switches; + return r; + } + if (!sim_quiet) + printf ("%s%d: creating new virtual disk '%s'\n", sim_dname (dptr), (int)(uptr-dptr->units), gbuf); + vhd = sim_vhd_disk_create (gbuf, uptr->capac); + if (!vhd) { + if (!sim_quiet) + printf ("%s%d: can't create virtual disk '%s'\n", sim_dname (dptr), (int)(uptr-dptr->units), gbuf); + return SCPE_OPENERR; + } + else { + uint8 *copy_buf = malloc (1024*1024); + t_lba lba; + t_seccnt sectors_per_buffer = (1024*1024)/sector_size; + t_lba total_sectors = (t_lba)(uptr->capac/sector_size); + t_seccnt sects = sectors_per_buffer; + + if (!copy_buf) { + remove (gbuf); + return SCPE_MEM; + } + for (lba = 0; (lba < total_sectors) && (r == SCPE_OK); lba += sects) { + if (!sim_quiet) + printf ("%s%d: Copied %dMB. %d%% complete.\r", sim_dname (dptr), (int)(uptr-dptr->units), (int)(((t_addr)lba*sector_size)/1000000), (int)((lba*100)/total_sectors)); + sects = sectors_per_buffer; + if (lba + sects > total_sectors) + sects = total_sectors - lba; + r = sim_disk_rdsect (uptr, lba, copy_buf, NULL, sects); + if (r == SCPE_OK) { + uint32 saved_unit_flags = uptr->flags; + FILE *save_unit_fileref = uptr->fileref; + + sim_disk_set_fmt (uptr, 0, "VHD", NULL); + uptr->fileref = vhd; + r = sim_disk_wrsect (uptr, lba, copy_buf, NULL, sects); + uptr->fileref = save_unit_fileref; + uptr->flags = saved_unit_flags; + } + } + if (!sim_quiet) + printf ("\n%s%d: Copied %dMB. Done.\n", sim_dname (dptr), (int)(uptr-dptr->units), (int)(((t_addr)lba*sector_size)/1000000)); + free (copy_buf); + created = TRUE; + sim_vhd_disk_close (vhd); + sim_disk_detach (uptr); + strcpy (cptr, gbuf); + sim_disk_set_fmt (uptr, 0, "VHD", NULL); + sim_switches = saved_sim_switches; + /* fall through and open/return the newly created & copied vhd */ + } + } +switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_STD: /* SIMH format */ + if (NULL == (uptr->fileref = sim_vhd_disk_open (cptr, "rb"))) { + open_function = sim_fopen; + size_function = sim_fsize_ex; + break; + } + sim_disk_set_fmt (uptr, 0, "VHD", NULL); /* set file format to VHD */ + sim_vhd_disk_close (uptr->fileref); /* close vhd file*/ + auto_format = TRUE; + uptr->fileref = NULL; + /* Fall through to normal VHD processing */ + case DKUF_F_VHD: /* VHD format */ + open_function = sim_vhd_disk_open; + create_function = sim_vhd_disk_create; + size_function = sim_vhd_disk_size; + break; + case DKUF_F_RAW: /* Raw Physical Disk Access */ + open_function = sim_os_disk_open_raw; + size_function = sim_os_disk_size_raw; + storage_function = sim_os_disk_info_raw; + break; + default: + return SCPE_IERR; + } +uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));/* alloc name buf */ +uptr->disk_ctx = ctx = (struct disk_context *)calloc(1, sizeof(struct disk_context)); +if ((uptr->filename == NULL) || (uptr->disk_ctx == NULL)) + return _err_return (uptr, SCPE_MEM); +strncpy (uptr->filename, cptr, CBUFSIZE); /* save name */ +ctx->sector_size = sector_size; /* save sector_size */ +ctx->xfer_element_size = xfer_element_size; /* save xfer_element_size */ +ctx->dptr = dptr; /* save DEVICE pointer */ +ctx->dbit = dbit; /* save debug bit */ +ctx->auto_format = auto_format; /* save that we auto selected format */ +ctx->storage_sector_size = sector_size; /* Default */ +if (sim_switches & SWMASK ('R')) { /* read only? */ + if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */ + return _err_return (uptr, SCPE_NORO); /* no, error */ + uptr->fileref = open_function (cptr, "rb"); /* open rd only */ + if (uptr->fileref == NULL) /* open fail? */ + return _err_return (uptr, SCPE_OPENERR); /* yes, error */ + uptr->flags = uptr->flags | UNIT_RO; /* set rd only */ + if (!sim_quiet) + printf ("%s%d: unit is read only\n", sim_dname (dptr), (int)(uptr-dptr->units)); + } +else { /* normal */ + uptr->fileref = open_function (cptr, "rb+"); /* open r/w */ + if (uptr->fileref == NULL) { /* open fail? */ + if ((errno == EROFS) || (errno == EACCES)) { /* read only? */ + if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */ + return _err_return (uptr, SCPE_NORO); /* no error */ + uptr->fileref = open_function (cptr, "rb"); /* open rd only */ + if (uptr->fileref == NULL) /* open fail? */ + return _err_return (uptr, SCPE_OPENERR);/* yes, error */ + uptr->flags = uptr->flags | UNIT_RO; /* set rd only */ + if (!sim_quiet) + printf ("%s%d: unit is read only\n", sim_dname (dptr), (int)(uptr-dptr->units)); + } + else { /* doesn't exist */ + if (sim_switches & SWMASK ('E')) /* must exist? */ + return _err_return (uptr, SCPE_OPENERR); /* yes, error */ + if (create_function) + uptr->fileref = create_function (cptr, uptr->capac);/* create new file */ + else + uptr->fileref = open_function (cptr, "wb+");/* open new file */ + if (uptr->fileref == NULL) /* open fail? */ + return _err_return (uptr, SCPE_OPENERR);/* yes, error */ + if (!sim_quiet) + printf ("%s%d: creating new file\n", sim_dname (dptr), (int)(uptr-dptr->units)); + created = TRUE; + } + } /* end if null */ + } /* end else */ +if (DK_GET_FMT (uptr) == DKUF_F_VHD) { + if ((created) && dtype) + sim_vhd_disk_set_dtype (uptr->fileref, dtype); + if (dtype && strcmp (dtype, sim_vhd_disk_get_dtype (uptr->fileref))) { + char cmd[32]; + + sprintf (cmd, "%s%d %s", dptr->name, (int)(uptr-dptr->units), sim_vhd_disk_get_dtype (uptr->fileref)); + set_cmd (0, cmd); + } + } +uptr->flags = uptr->flags | UNIT_ATT; +uptr->pos = 0; + +/* Get Device attributes if they are available */ +if (storage_function) + storage_function (uptr->fileref, &ctx->storage_sector_size, &ctx->removable); + +if (created) { + t_stat r = SCPE_OK; + uint8 *secbuf = calloc (1, ctx->sector_size); /* alloc temp sector buf */ + + /* + On a newly created disk, we write a zero sector to the last and the + first sectors. This serves 3 purposes: + 1) it avoids strange allocation delays writing newly allocated + storage at the end of the disk during simulator operation + 2) it allocates storage for the whole disk at creation time to + avoid strange failures which may happen during simulator execution + if the containing disk is full + 3) it leaves a Sinh Format disk at the intended size so it may + subsequently be autosized with the correct size. + */ + if (secbuf == NULL) + r = SCPE_MEM; + if (r == SCPE_OK) + r = sim_disk_wrsect (uptr, (t_lba)((uptr->capac - ctx->sector_size)/ctx->sector_size), secbuf, NULL, 1); /* Write Last Sector */ + if (r == SCPE_OK) + r = sim_disk_wrsect (uptr, (t_lba)(0), secbuf, NULL, 1); /* Write First Sector */ + free (secbuf); + if (r != SCPE_OK) { + sim_disk_detach (uptr); /* report error now */ + remove (cptr); /* remove the create file */ + return SCPE_OPENERR; + } + if (pdp11tracksize) + sim_disk_pdp11_bad_block (uptr, pdp11tracksize); + } + +capac = size_function (uptr->fileref); +if (capac && (capac != (t_addr)-1)) + if (dontautosize) { + if ((capac < uptr->capac) && (DKUF_F_STD != DK_GET_FMT (uptr))) { + if (!sim_quiet) { + printf ("%s%d: non expandable disk %s is smaller than simulated device (", sim_dname (dptr), (int)(uptr-dptr->units), cptr); + fprint_val (stdout, capac, 10, T_ADDR_W, PV_LEFT); + printf (" < "); + fprint_val (stdout, uptr->capac, 10, T_ADDR_W, PV_LEFT); + printf (")\n"); + } + } + } + else + if ((capac > uptr->capac) || (DKUF_F_STD != DK_GET_FMT (uptr))) + uptr->capac = capac; + +#if defined (SIM_ASYNCH_IO) +sim_disk_set_async (uptr, 0); +#endif +uptr->io_flush = _sim_disk_io_flush; + +return SCPE_OK; +} + +t_stat sim_disk_detach (UNIT *uptr) +{ +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +int (*close_function)(FILE *f); +FILE *fileref = uptr->fileref; +DEVICE *dptr; +t_bool auto_format; + +if (uptr == NULL) + return SCPE_IERR; +switch (DK_GET_FMT (uptr)) { /* case on format */ + case DKUF_F_STD: /* Simh */ + close_function = fclose; + break; + case DKUF_F_VHD: /* Virtual Disk */ + close_function = sim_vhd_disk_close; + break; + case DKUF_F_RAW: /* Physical */ + close_function = sim_os_disk_close_raw; + break; + } +if (!(uptr->flags & UNIT_ATTABLE)) /* attachable? */ + return SCPE_NOATT; +if (!(uptr->flags & UNIT_ATT)) /* attached? */ + return SCPE_OK; +if ((dptr = find_dev_from_unit (uptr)) == NULL) + return SCPE_OK; +auto_format = ctx->auto_format; + +if (uptr->io_flush) + uptr->io_flush (uptr); /* flush buffered data */ + +#if defined SIM_ASYNCH_IO +sim_disk_clr_async (uptr); +#endif + +uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO | UNIT_RAW); +free (uptr->filename); +uptr->filename = NULL; +uptr->fileref = NULL; +free (uptr->disk_ctx); +uptr->disk_ctx = NULL; +uptr->io_flush = NULL; +if (auto_format) + sim_disk_set_fmt (uptr, 0, "SIMH", NULL); /* restore file format */ +if (close_function (fileref) == EOF) + return SCPE_IOERR; +return SCPE_OK; +} + +/* Factory bad block table creation routine + + This routine writes a DEC standard 044 compliant bad block table on the + last track of the specified unit. The bad block table consists of 10 + repetitions of the same table, formatted as follows: + + words 0-1 pack id number + words 2-3 cylinder/sector/surface specifications + : + words n-n+1 end of table (-1,-1) + + Inputs: + uptr = pointer to unit + sec = number of sectors per surface + Outputs: + sta = status code +*/ + +t_stat sim_disk_pdp11_bad_block (UNIT *uptr, int32 sec) +{ +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +DEVICE *dptr; +int32 i; +t_addr da; +int32 wds = ctx->sector_size/sizeof (uint16); +uint16 *buf; + +if ((sec < 2) || (wds < 16)) + return SCPE_ARG; +if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT; +if (uptr->flags & UNIT_RO) + return SCPE_RO; +if ((dptr = find_dev_from_unit (uptr)) == NULL) + return SCPE_NOATT; +if ((dptr->dwidth / dptr->aincr) <= 8) /* Must be Word oriented Capacity */ + return SCPE_IERR; +if (!get_yn ("Overwrite last track? [N]", FALSE)) + return SCPE_OK; +if ((buf = (uint16 *) malloc (wds * sizeof (uint16))) == NULL) + return SCPE_MEM; +buf[0] = buf[1] = 012345u; +buf[2] = buf[3] = 0; +for (i = 4; i < wds; i++) + buf[i] = 0177777u; +da = uptr->capac - (sec * wds); +for (i = 0; (i < sec) && (i < 10); i++, da += wds) + if (sim_disk_wrsect (uptr, (t_lba)(da/wds), (void *)buf, NULL, 1)) { + free (buf); + return SCPE_IOERR; + } +free (buf); +return SCPE_OK; +} + +void sim_disk_data_trace(UNIT *uptr, const uint8 *data, size_t lba, size_t len, const char* txt, int detail, uint32 reason) +{ +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; + +if (ctx->dptr->dctrl & reason) { + sim_debug (reason, ctx->dptr, "%s%d %s lbn: %08X len: %08X\n", ctx->dptr->name, uptr-ctx->dptr->units, txt, lba, len); + if (detail) { + size_t i, same, group, sidx, oidx; + char outbuf[80], strbuf[18]; + static char hex[] = "0123456789ABCDEF"; + + for (i=same=0; i 0) && (0 == memcmp (&data[i], &data[i-16], 16))) { + ++same; + continue; + } + if (same > 0) { + sim_debug (reason, ctx->dptr, "%04X thru %04X same as above\n", i-(16*same), i-1); + same = 0; + } + group = (((len - i) > 16) ? 16 : (len - i)); + for (sidx=oidx=0; sidx>4)&0xf]; + outbuf[oidx++] = hex[data[i+sidx]&0xf]; + if (isprint (data[i+sidx])) + strbuf[sidx] = data[i+sidx]; + else + strbuf[sidx] = '.'; + } + outbuf[oidx] = '\0'; + strbuf[sidx] = '\0'; + sim_debug (reason, ctx->dptr, "%04X%-48s %s\n", i, outbuf, strbuf); + } + if (same > 0) + sim_debug (reason, ctx->dptr, "%04X thru %04X same as above\n", i-(16*same), len-1); + } + } +} + + +/* OS Specific RAW Disk I/O support */ + +#if defined _WIN32 + +static void _set_errno_from_status (DWORD dwStatus) +{ +switch (dwStatus) { + case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: case ERROR_NO_MORE_FILES: + case ERROR_BAD_NET_NAME: case ERROR_BAD_NETPATH: + case ERROR_BAD_PATHNAME: case ERROR_FILENAME_EXCED_RANGE: + errno = ENOENT; + return; + case ERROR_INVALID_ACCESS: case ERROR_INVALID_DATA: + case ERROR_INVALID_FUNCTION: case ERROR_INVALID_PARAMETER: + case ERROR_NEGATIVE_SEEK: + errno = EINVAL; + return; + case ERROR_ARENA_TRASHED: case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_INVALID_BLOCK: case ERROR_NOT_ENOUGH_QUOTA: + errno = ENOMEM; + return; + case ERROR_TOO_MANY_OPEN_FILES: + errno = EMFILE; + return; + case ERROR_ACCESS_DENIED: case ERROR_CURRENT_DIRECTORY: + case ERROR_LOCK_VIOLATION: case ERROR_NETWORK_ACCESS_DENIED: + case ERROR_CANNOT_MAKE: case ERROR_FAIL_I24: + case ERROR_DRIVE_LOCKED: case ERROR_SEEK_ON_DEVICE: + case ERROR_NOT_LOCKED: case ERROR_LOCK_FAILED: + errno = EACCES; + return; + case ERROR_ALREADY_EXISTS: case ERROR_FILE_EXISTS: + errno = EEXIST; + return; + case ERROR_INVALID_HANDLE: case ERROR_INVALID_TARGET_HANDLE: + case ERROR_DIRECT_ACCESS_HANDLE: + errno = EBADF; + return; + case ERROR_DIR_NOT_EMPTY: + errno = ENOTEMPTY; + return; + case ERROR_BAD_ENVIRONMENT: + errno = E2BIG; + return; + case ERROR_BAD_FORMAT: + errno = ENOEXEC; + return; + case ERROR_NOT_SAME_DEVICE: + errno = EXDEV; + return; + case ERROR_BROKEN_PIPE: + errno = EPIPE; + return; + case ERROR_DISK_FULL: + errno = ENOSPC; + return; + case ERROR_WAIT_NO_CHILDREN: case ERROR_CHILD_NOT_COMPLETE: + errno = ECHILD; + return; + case ERROR_NO_PROC_SLOTS: case ERROR_MAX_THRDS_REACHED: + case ERROR_NESTING_NOT_ALLOWED: + errno = EAGAIN; + return; + } +if ((dwStatus >= ERROR_WRITE_PROTECT) && (dwStatus <= ERROR_SHARING_BUFFER_EXCEEDED)) { + errno = EACCES; + return; + } +if ((dwStatus >= ERROR_INVALID_STARTING_CODESEG) && (dwStatus <= ERROR_INFLOOP_IN_RELOC_CHAIN)) { + errno = ENOEXEC; + return; + } +errno = EINVAL; +} +#include +struct _device_type { + int32 Type; + char *desc; + } DeviceTypes[] = { + {FILE_DEVICE_8042_PORT, "8042_PORT"}, + {FILE_DEVICE_ACPI, "ACPI"}, + {FILE_DEVICE_BATTERY, "BATTERY"}, + {FILE_DEVICE_BEEP, "BEEP"}, +#ifdef FILE_DEVICE_BLUETOOTH + {FILE_DEVICE_BLUETOOTH, "BLUETOOTH"}, +#endif + {FILE_DEVICE_BUS_EXTENDER, "BUS_EXTENDER"}, + {FILE_DEVICE_CD_ROM, "CD_ROM"}, + {FILE_DEVICE_CD_ROM_FILE_SYSTEM, "CD_ROM_FILE_SYSTEM"}, + {FILE_DEVICE_CHANGER, "CHANGER"}, + {FILE_DEVICE_CONTROLLER, "CONTROLLER"}, +#ifdef FILE_DEVICE_CRYPT_PROVIDER + {FILE_DEVICE_CRYPT_PROVIDER, "CRYPT_PROVIDER"}, +#endif + {FILE_DEVICE_DATALINK, "DATALINK"}, + {FILE_DEVICE_DFS, "DFS"}, + {FILE_DEVICE_DFS_FILE_SYSTEM, "DFS_FILE_SYSTEM"}, + {FILE_DEVICE_DFS_VOLUME, "DFS_VOLUME"}, + {FILE_DEVICE_DISK, "DISK"}, + {FILE_DEVICE_DISK_FILE_SYSTEM, "DISK_FILE_SYSTEM"}, + {FILE_DEVICE_DVD, "DVD"}, + {FILE_DEVICE_FILE_SYSTEM, "FILE_SYSTEM"}, +#ifdef FILE_DEVICE_FIPS + {FILE_DEVICE_FIPS, "FIPS"}, +#endif + {FILE_DEVICE_FULLSCREEN_VIDEO, "FULLSCREEN_VIDEO"}, +#ifdef FILE_DEVICE_INFINIBAND + {FILE_DEVICE_INFINIBAND, "INFINIBAND"}, +#endif + {FILE_DEVICE_INPORT_PORT, "INPORT_PORT"}, + {FILE_DEVICE_KEYBOARD, "KEYBOARD"}, + {FILE_DEVICE_KS, "KS"}, + {FILE_DEVICE_KSEC, "KSEC"}, + {FILE_DEVICE_MAILSLOT, "MAILSLOT"}, + {FILE_DEVICE_MASS_STORAGE, "MASS_STORAGE"}, + {FILE_DEVICE_MIDI_IN, "MIDI_IN"}, + {FILE_DEVICE_MIDI_OUT, "MIDI_OUT"}, + {FILE_DEVICE_MODEM, "MODEM"}, + {FILE_DEVICE_MOUSE, "MOUSE"}, + {FILE_DEVICE_MULTI_UNC_PROVIDER, "MULTI_UNC_PROVIDER"}, + {FILE_DEVICE_NAMED_PIPE, "NAMED_PIPE"}, + {FILE_DEVICE_NETWORK, "NETWORK"}, + {FILE_DEVICE_NETWORK_BROWSER, "NETWORK_BROWSER"}, + {FILE_DEVICE_NETWORK_FILE_SYSTEM, "NETWORK_FILE_SYSTEM"}, + {FILE_DEVICE_NETWORK_REDIRECTOR, "NETWORK_REDIRECTOR"}, + {FILE_DEVICE_NULL, "NULL"}, + {FILE_DEVICE_PARALLEL_PORT, "PARALLEL_PORT"}, + {FILE_DEVICE_PHYSICAL_NETCARD, "PHYSICAL_NETCARD"}, + {FILE_DEVICE_PRINTER, "PRINTER"}, + {FILE_DEVICE_SCANNER, "SCANNER"}, + {FILE_DEVICE_SCREEN, "SCREEN"}, + {FILE_DEVICE_SERENUM, "SERENUM"}, + {FILE_DEVICE_SERIAL_MOUSE_PORT, "SERIAL_MOUSE_PORT"}, + {FILE_DEVICE_SERIAL_PORT, "SERIAL_PORT"}, + {FILE_DEVICE_SMARTCARD, "SMARTCARD"}, + {FILE_DEVICE_SMB, "SMB"}, + {FILE_DEVICE_SOUND, "SOUND"}, + {FILE_DEVICE_STREAMS, "STREAMS"}, + {FILE_DEVICE_TAPE, "TAPE"}, + {FILE_DEVICE_TAPE_FILE_SYSTEM, "TAPE_FILE_SYSTEM"}, + {FILE_DEVICE_TERMSRV, "TERMSRV"}, + {FILE_DEVICE_TRANSPORT, "TRANSPORT"}, + {FILE_DEVICE_UNKNOWN, "UNKNOWN"}, + {FILE_DEVICE_VDM, "VDM"}, + {FILE_DEVICE_VIDEO, "VIDEO"}, + {FILE_DEVICE_VIRTUAL_DISK, "VIRTUAL_DISK"}, +#ifdef FILE_DEVICE_VMBUS + {FILE_DEVICE_VMBUS, "VMBUS"}, +#endif + {FILE_DEVICE_WAVE_IN, "WAVE_IN"}, + {FILE_DEVICE_WAVE_OUT, "WAVE_OUT"}, +#ifdef FILE_DEVICE_WPD + {FILE_DEVICE_WPD, "WPD"}, +#endif + {0, NULL}}; + +static const char *_device_type_name (int DeviceType) +{ +int i; + +for (i=0; DeviceTypes[i].desc; i++) + if (DeviceTypes[i].Type == DeviceType) + return DeviceTypes[i].desc; +return "Unknown"; +} + +static t_stat sim_os_disk_implemented_raw (void) +{ +return SCPE_OK; +} + +static FILE *sim_os_disk_open_raw (const char *rawdevicename, const char *openmode) +{ +HANDLE Handle; +DWORD DesiredAccess = 0; + +if (strchr (openmode, 'r')) + DesiredAccess |= GENERIC_READ; +if (strchr (openmode, 'w') || strchr (openmode, '+')) + DesiredAccess |= GENERIC_WRITE; +Handle = CreateFileA (rawdevicename, DesiredAccess, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL); +if (Handle == INVALID_HANDLE_VALUE) { + _set_errno_from_status (GetLastError ()); + return NULL; + } +return (FILE *)Handle; +} + +static int sim_os_disk_close_raw (FILE *f) +{ +if (!CloseHandle ((HANDLE)f)) { + _set_errno_from_status (GetLastError ()); + return EOF; + } +return 0; +} + +static void sim_os_disk_flush_raw (FILE *f) +{ +FlushFileBuffers ((HANDLE)f); +} + +static t_addr sim_os_disk_size_raw (FILE *Disk) +{ +DWORD IoctlReturnSize; +LARGE_INTEGER Size; +WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize); + +if (GetFileSizeEx((HANDLE)Disk, &Size)) + return (t_addr)(Size.QuadPart); +#ifdef IOCTL_STORAGE_READ_CAPACITY +if (1) { + STORAGE_READ_CAPACITY S; + + ZeroMemory (&S, sizeof (S)); + S.Version = sizeof (STORAGE_READ_CAPACITY); + if (DeviceIoControl((HANDLE)Disk, /* handle to volume */ + IOCTL_STORAGE_READ_CAPACITY, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + (LPVOID) &S, /* output buffer */ + (DWORD) sizeof(S), /* size of output buffer */ + (LPDWORD) &IoctlReturnSize, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) /* OVERLAPPED structure */ + return (t_addr)(S.DiskLength.QuadPart); + } +#endif +#ifdef IOCTL_DISK_GET_DRIVE_GEOMETRY_EX +if (1) { + DISK_GEOMETRY_EX G; + + ZeroMemory (&G, sizeof (G)); + if (DeviceIoControl((HANDLE)Disk, /* handle to volume */ + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + (LPVOID) &G, /* output buffer */ + (DWORD) sizeof(G), /* size of output buffer */ + (LPDWORD) &IoctlReturnSize, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) /* OVERLAPPED structure */ + return (t_addr)(G.DiskSize.QuadPart); + } +#endif +#ifdef IOCTL_DISK_GET_DRIVE_GEOMETRY +if (1) { + DISK_GEOMETRY G; + + if (DeviceIoControl((HANDLE)Disk, /* handle to volume */ + IOCTL_DISK_GET_DRIVE_GEOMETRY, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + (LPVOID) &G, /* output buffer */ + (DWORD) sizeof(G), /* size of output buffer */ + (LPDWORD) &IoctlReturnSize, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) /* OVERLAPPED structure */ + return (t_addr)(G.Cylinders.QuadPart*G.TracksPerCylinder*G.SectorsPerTrack*G.BytesPerSector); + } +#endif +_set_errno_from_status (GetLastError ()); +return (t_addr)-1; +} + +static t_stat sim_os_disk_unload_raw (FILE *Disk) +{ +#ifdef IOCTL_STORAGE_EJECT_MEDIA +DWORD BytesReturned; + +if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */ + IOCTL_STORAGE_EJECT_MEDIA, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + NULL, /* lpOutBuffer */ + 0, /* nOutBufferSize */ + (LPDWORD) &BytesReturned, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) { /* OVERLAPPED structure */ + _set_errno_from_status (GetLastError ()); + return SCPE_IOERR; + } +return SCPE_OK; +#else +return SCPE_NOFNC; +#endif +} + +static t_bool sim_os_disk_isavailable_raw (FILE *Disk) +{ +#ifdef IOCTL_STORAGE_EJECT_MEDIA +DWORD BytesReturned; + +if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */ + IOCTL_STORAGE_CHECK_VERIFY, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + NULL, /* lpOutBuffer */ + 0, /* nOutBufferSize */ + (LPDWORD) &BytesReturned, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) { /* OVERLAPPED structure */ + _set_errno_from_status (GetLastError ()); + return FALSE; + } +#endif +return TRUE; +} + +static t_stat sim_os_disk_info_raw (FILE *Disk, size_t *sector_size, uint32 *removable) +{ +DWORD IoctlReturnSize; +#ifndef __GNUC__ +STORAGE_DEVICE_NUMBER Device; + +ZeroMemory (&Device, sizeof (Device)); +if (DeviceIoControl((HANDLE)Disk, /* handle to volume */ + IOCTL_STORAGE_GET_DEVICE_NUMBER, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + (LPVOID) &Device, /* output buffer */ + (DWORD) sizeof(Device), /* size of output buffer */ + (LPDWORD) &IoctlReturnSize, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) /* OVERLAPPED structure */ + printf ("Device OK - Type: %s, Number: %d\n", _device_type_name (Device.DeviceType), Device.DeviceNumber); +#endif + +if (sector_size) + *sector_size = 512; +if (removable) + *removable = 0; +#ifdef IOCTL_STORAGE_READ_CAPACITY +if (1) { + STORAGE_READ_CAPACITY S; + + ZeroMemory (&S, sizeof (S)); + S.Version = sizeof (STORAGE_READ_CAPACITY); + if (DeviceIoControl((HANDLE)Disk, /* handle to volume */ + IOCTL_STORAGE_READ_CAPACITY, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + (LPVOID) &S, /* output buffer */ + (DWORD) sizeof(S), /* size of output buffer */ + (LPDWORD) &IoctlReturnSize, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) /* OVERLAPPED structure */ + if (sector_size) + *sector_size = S.BlockLength; + } +#endif +#ifdef IOCTL_DISK_GET_DRIVE_GEOMETRY_EX +if (1) { + DISK_GEOMETRY_EX G; + + ZeroMemory (&G, sizeof (G)); + if (DeviceIoControl((HANDLE)Disk, /* handle to volume */ + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + (LPVOID) &G, /* output buffer */ + (DWORD) sizeof(G), /* size of output buffer */ + (LPDWORD) &IoctlReturnSize, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) /* OVERLAPPED structure */ + if (sector_size) + *sector_size = G.Geometry.BytesPerSector; + } +#endif +#ifdef IOCTL_DISK_GET_DRIVE_GEOMETRY +if (1) { + DISK_GEOMETRY G; + + if (DeviceIoControl((HANDLE)Disk, /* handle to volume */ + IOCTL_DISK_GET_DRIVE_GEOMETRY, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + (LPVOID) &G, /* output buffer */ + (DWORD) sizeof(G), /* size of output buffer */ + (LPDWORD) &IoctlReturnSize, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) /* OVERLAPPED structure */ + if (sector_size) + *sector_size = G.BytesPerSector; + } +#endif +#ifdef IOCTL_STORAGE_GET_HOTPLUG_INFO +if (1) { + STORAGE_HOTPLUG_INFO H; + + ZeroMemory (&H, sizeof (H)); + if (DeviceIoControl((HANDLE)Disk, /* handle to volume */ + IOCTL_STORAGE_GET_HOTPLUG_INFO, /* dwIoControlCode */ + NULL, /* lpInBuffer */ + 0, /* nInBufferSize */ + (LPVOID) &H, /* output buffer */ + (DWORD) sizeof(H), /* size of output buffer */ + (LPDWORD) &IoctlReturnSize, /* number of bytes returned */ + (LPOVERLAPPED) NULL)) /* OVERLAPPED structure */ + if (removable) + *removable = H.MediaRemovable; + } +#endif +if (removable && *removable) + printf ("Removable Device\n"); +return SCPE_OK; +} + +static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects) +{ +OVERLAPPED pos; +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +long long addr; + +sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); + +addr = ((long long)lba) * ctx->sector_size; +memset (&pos, 0, sizeof (pos)); +pos.Offset = (DWORD)addr; +pos.OffsetHigh = (DWORD)(addr >> 32); +if (ReadFile ((HANDLE)(uptr->fileref), buf, sects * ctx->sector_size, (LPDWORD)sectsread, &pos)) { + if (sectsread) + *sectsread /= ctx->sector_size; + return SCPE_OK; + } +_set_errno_from_status (GetLastError ()); +return SCPE_IOERR; +} + +static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects) +{ +OVERLAPPED pos; +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +long long addr; + +sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); + +addr = ((long long)lba) * ctx->sector_size; +memset (&pos, 0, sizeof (pos)); +pos.Offset = (DWORD)addr; +pos.OffsetHigh = (DWORD)(addr >> 32); +if (WriteFile ((HANDLE)(uptr->fileref), buf, sects * ctx->sector_size, (LPDWORD)sectswritten, &pos)) { + if (sectswritten) + *sectswritten /= ctx->sector_size; + return SCPE_OK; + } +_set_errno_from_status (GetLastError ()); +return SCPE_IOERR; +} + +#elif defined (__linux) || defined (__sun__) + +#include +#include +#include +#include + +static t_stat sim_os_disk_implemented_raw (void) +{ +return SCPE_OK; +} + +static FILE *sim_os_disk_open_raw (const char *rawdevicename, const char *openmode) +{ +int fd; +int mode = 0; + +if (strchr (openmode, 'r') && (strchr (openmode, '+') || strchr (openmode, 'w'))) + mode = O_RDWR; +else + if (strchr (openmode, 'r')) + mode = O_RDONLY; +#ifdef O_LARGEFILE +mode |= O_LARGEFILE; +#endif +return (FILE *)((long)open (rawdevicename, mode, 0)); +} + +static int sim_os_disk_close_raw (FILE *f) +{ +return close ((int)((long)f)); +} + +static void sim_os_disk_flush_raw (FILE *f) +{ +fsync ((int)((long)f)); +} + +static t_addr sim_os_disk_size_raw (FILE *f) +{ +struct stat64 statb; + +if (fstat64 ((int)((long)f), &statb)) + return (t_addr)-1; +return (t_addr)statb.st_size; +} + +static t_stat sim_os_disk_unload_raw (FILE *f) +{ +return SCPE_IOERR; +} + +static t_bool sim_os_disk_isavailable_raw (FILE *Disk) +{ +return TRUE; +} + +static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects) +{ +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +off_t addr; +ssize_t bytesread; + +sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); + +addr = ((off_t)lba) * ctx->sector_size; +bytesread = pread((int)((long)uptr->fileref), buf, sects * ctx->sector_size, addr); +if (bytesread < 0) { + if (sectsread) + *sectsread = 0; + return SCPE_IOERR; + } +if (sectsread) + *sectsread = bytesread / ctx->sector_size; +return SCPE_OK; +} + +static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects) +{ +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; +off_t addr; +ssize_t byteswritten; + +sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); + +addr = ((off_t)lba) * ctx->sector_size; +byteswritten = pwrite((int)((long)uptr->fileref), buf, sects * ctx->sector_size, addr); +if (byteswritten < 0) { + if (sectswritten) + *sectswritten = 0; + return SCPE_IOERR; + } +if (sectswritten) + *sectswritten = byteswritten / ctx->sector_size; +return SCPE_OK; +} + +static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable) +{ +if (sector_size) + *sector_size = 512; +if (removable) + *removable = 0; +return SCPE_OK; +} + +#else +/*============================================================================*/ +/* Non-implemented versions */ +/*============================================================================*/ + +static t_stat sim_os_disk_implemented_raw (void) +{ +return SCPE_NOFNC; +} + +static FILE *sim_os_disk_open_raw (const char *rawdevicename, const char *openmode) +{ +return NULL; +} + +static int sim_os_disk_close_raw (FILE *f) +{ +return EOF; +} + +static void sim_os_disk_flush_raw (FILE *f) +{ +} + +static t_addr sim_os_disk_size_raw (FILE *f) +{ +return (t_addr)-1; +} + +static t_stat sim_os_disk_unload_raw (FILE *f) +{ +return SCPE_NOFNC; +} + +static t_bool sim_os_disk_isavailable_raw (FILE *Disk) +{ +return FALSE; +} + +static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects) +{ +return SCPE_NOFNC; +} + +static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects) +{ +return SCPE_NOFNC; +} + +static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable) +{ +return SCPE_NOFNC; +} + +#endif + +/* OS Independent Disk Virtual Disk (VHD) I/O support */ + +#if (defined (VMS) && !(defined (__ALPHA) || defined (__ia64))) +#define DONT_DO_VHD_SUPPORT /* VAX/VMS compilers don't have 64 bit integers */ +#endif + +#if defined (DONT_DO_VHD_SUPPORT) + +/*============================================================================*/ +/* Non-implemented version */ +/* This is only for hody systems which don't have 64 bit integer types */ +/*============================================================================*/ + +static t_stat sim_vhd_disk_implemented (void) +{ +return SCPE_NOFNC; +} + +static FILE *sim_vhd_disk_open (const char *rawdevicename, const char *openmode) +{ +return NULL; +} + +static FILE *sim_vhd_disk_create (const char *szVHDPath, t_addr desiredsize) +{ +return NULL; +} + +static FILE *sim_vhd_disk_create_diff (const char *szVHDPath, const char *szParentVHDPath) +{ +return NULL; +} + +static int sim_vhd_disk_close (FILE *f) +{ +return -1; +} + +static void sim_vhd_disk_flush (FILE *f) +{ +} + +static t_addr sim_vhd_disk_size (FILE *f) +{ +return (t_addr)-1; +} + +static t_stat sim_vhd_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects) +{ +return SCPE_IOERR; +} + +static t_stat sim_vhd_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects) +{ +return SCPE_IOERR; +} + +static t_stat sim_vhd_disk_set_dtype (FILE *f, const char *dtype) +{ +return SCPE_NOFNC; +} + +static const char *sim_vhd_disk_get_dtype (FILE *f) +{ +return NULL; +} + +#else + +/*++ + This code follows the details specified in the "Virtual Hard Disk Image + Format Specification", Version 1.0 October 11, 2006. +--*/ + +typedef t_uint64 uint64; +typedef t_int64 int64; + +typedef struct _VHD_Footer { + /* + Cookies are used to uniquely identify the original creator of the hard disk + image. The values are case-sensitive. Microsoft uses the “conectix” string + to identify this file as a hard disk image created by Microsoft Virtual + Server, Virtual PC, and predecessor products. The cookie is stored as an + eight-character ASCII string with the “c” in the first byte, the “o” in + the second byte, and so on. + */ + char Cookie[8]; + /* + This is a bit field used to indicate specific feature support. The following + table displays the list of features. + Any fields not listed are reserved. + + Feature Value: + No features enabled 0x00000000 + Temporary 0x00000001 + Reserved 0x00000002 + + No features enabled. + The hard disk image has no special features enabled in it. + Temporary. + This bit is set if the current disk is a temporary disk. A + temporary disk designation indicates to an application that + this disk is a candidate for deletion on shutdown. + Reserved. + This bit must always be set to 1. + All other bits are also reserved and should be set to 0. + */ + uint32 Features; + /* + This field is divided into a major/minor version and matches the version of + the specification used in creating the file. The most-significant two bytes + are for the major version. The least-significant two bytes are the minor + version. This must match the file format specification. For the current + specification, this field must be initialized to 0x00010000. + The major version will be incremented only when the file format is modified + in such a way that it is no longer compatible with older versions of the + file format. + */ + uint32 FileFormatVersion; + /* + This field holds the absolute byte offset, from the beginning of the file, + to the next structure. This field is used for dynamic disks and differencing + disks, but not fixed disks. For fixed disks, this field should be set to + 0xFFFFFFFF. + */ + uint64 DataOffset; + /* + This field stores the creation time of a hard disk image. This is the number + of seconds since January 1, 2000 12:00:00 AM in UTC/GMT. + */ + uint32 TimeStamp; + /* + This field is used to document which application created the hard disk. The + field is a left-justified text field. It uses a single-byte character set. + If the hard disk is created by Microsoft Virtual PC, "vpc " is written in + this field. If the hard disk image is created by Microsoft Virtual Server, + then "vs " is written in this field. + Other applications should use their own unique identifiers. + */ + char CreatorApplication[4]; + /* + This field holds the major/minor version of the application that created + the hard disk image. Virtual Server 2004 sets this value to 0x00010000 and + Virtual PC 2004 sets this to 0x00050000. + */ + uint32 CreatorVersion; + /* + This field stores the type of host operating system this disk image is + created on. + Host OS type Value + Windows 0x5769326B (Wi2k) + Macintosh 0x4D616320 (Mac ) + */ + uint8 CreatorHostOS[4]; + /* + This field stores the size of the hard disk in bytes, from the perspective + of the virtual machine, at creation time. This field is for informational + purposes. + */ + uint64 OriginalSize; + /* + This field stores the current size of the hard disk, in bytes, from the + perspective of the virtual machine. + This value is same as the original size when the hard disk is created. + This value can change depending on whether the hard disk is expanded. + */ + uint64 CurrentSize; + /* + This field stores the cylinder, heads, and sectors per track value for the + hard disk. + Disk Geometry field Size (bytes) + Cylinder 2 + Heads 1 + Sectors per track/cylinder 1 + + When a hard disk is configured as an ATA hard disk, the CHS values (that is, + Cylinder, Heads, Sectors per track) are used by the ATA controller to + determine the size of the disk. When the user creates a hard disk of a + certain size, the size of the hard disk image in the virtual machine is + smaller than that created by the user. This is because CHS value calculated + from the hard disk size is rounded down. The pseudo-code for the algorithm + used to determine the CHS values can be found in the appendix of this + document. + */ + uint32 DiskGeometry; + /* + Disk Type field Value + None 0 + Reserved (deprecated) 1 + Fixed hard disk 2 + Dynamic hard disk 3 + Differencing hard disk 4 + Reserved (deprecated) 5 + Reserved (deprecated) 6 + */ + uint32 DiskType; + /* + This field holds a basic checksum of the hard disk footer. It is just a + one’s complement of the sum of all the bytes in the footer without the + checksum field. + If the checksum verification fails, the Virtual PC and Virtual Server + products will instead use the header. If the checksum in the header also + fails, the file should be assumed to be corrupt. The pseudo-code for the + algorithm used to determine the checksum can be found in the appendix of + this document. + */ + uint32 Checksum; + /* + Every hard disk has a unique ID stored in the hard disk. This is used to + identify the hard disk. This is a 128-bit universally unique identifier + (UUID). This field is used to associate a parent hard disk image with its + differencing hard disk image(s). + */ + uint8 UniqueID[16]; + /* + This field holds a one-byte flag that describes whether the system is in + saved state. If the hard disk is in the saved state the value is set to 1. + Operations such as compaction and expansion cannot be performed on a hard + disk in a saved state. + */ + uint8 SavedState; + /* + This field contains zeroes. It is 427 bytes in size. + */ + uint8 Reserved1[11]; + /* + This field is an extension to the VHD spec and includes a simh drive type + name as a nul terminated string. + */ + uint8 DriveType[16]; + /* + This field contains zeroes. It is 400 bytes in size. + */ + uint8 Reserved[400]; + } VHD_Footer; + +/* +For dynamic and differencing disk images, the “Data Offset” field within +the image footer points to a secondary structure that provides additional +information about the disk image. The dynamic disk header should appear on +a sector (512-byte) boundary. +*/ +typedef struct _VHD_DynamicDiskHeader { + /* + This field holds the value "cxsparse". This field identifies the header. + */ + char Cookie[8]; + /* + This field contains the absolute byte offset to the next structure in the + hard disk image. It is currently unused by existing formats and should be + set to 0xFFFFFFFF. + */ + uint64 DataOffset; + /* + This field stores the absolute byte offset of the Block Allocation Table + (BAT) in the file. + */ + uint64 TableOffset; + /* + This field stores the version of the dynamic disk header. The field is + divided into Major/Minor version. The least-significant two bytes represent + the minor version, and the most-significant two bytes represent the major + version. This must match with the file format specification. For this + specification, this field must be initialized to 0x00010000. + The major version will be incremented only when the header format is + modified in such a way that it is no longer compatible with older versions + of the product. + */ + uint32 HeaderVersion; + /* + This field holds the maximum entries present in the BAT. This should be + equal to the number of blocks in the disk (that is, the disk size divided + by the block size). + */ + uint32 MaxTableEntries; + /* + A block is a unit of expansion for dynamic and differencing hard disks. It + is stored in bytes. This size does not include the size of the block bitmap. + It is only the size of the data section of the block. The sectors per block + must always be a power of two. The default value is 0x00200000 (indicating a + block size of 2 MB). + */ + uint32 BlockSize; + /* + This field holds a basic checksum of the dynamic header. It is a one’s + complement of the sum of all the bytes in the header without the checksum + field. + If the checksum verification fails the file should be assumed to be corrupt. + */ + uint32 Checksum; + /* + This field is used for differencing hard disks. A differencing hard disk + stores a 128-bit UUID of the parent hard disk. For more information, see + “Creating Differencing Hard Disk Images” later in this paper. + */ + uint8 ParentUniqueID[16]; + /* + This field stores the modification time stamp of the parent hard disk. This + is the number of seconds since January 1, 2000 12:00:00 AM in UTC/GMT. + */ + uint32 ParentTimeStamp; + /* + This field should be set to zero. + */ + uint32 Reserved0; + /* + This field contains a Unicode string (UTF-16) of the parent hard disk + filename. + */ + char ParentUnicodeName[512]; + /* + These entries store an absolute byte offset in the file where the parent + locator for a differencing hard disk is stored. This field is used only for + differencing disks and should be set to zero for dynamic disks. + */ + struct VHD_ParentLocator { + /* + The platform code describes which platform-specific format is used for the + file locator. For Windows, a file locator is stored as a path (for example. + “c:\disksimages\ParentDisk.vhd”). On a Macintosh system, the file locator + is a binary large object (blob) that contains an “alias.” The parent locator + table is used to support moving hard disk images across platforms. + Some current platform codes include the following: + Platform Code Description + None (0x0) + Wi2r (0x57693272) [deprecated] + Wi2k (0x5769326B) [deprecated] + W2ru (0x57327275) Unicode pathname (UTF-16) on Windows relative to the differencing disk pathname. + W2ku (0x57326B75) Absolute Unicode (UTF-16) pathname on Windows. + Mac (0x4D616320) (Mac OS alias stored as a blob) + MacX(0x4D616358) A file URL with UTF-8 encoding conforming to RFC 2396. + */ + uint8 PlatformCode[4]; + /* + This field stores the number of 512-byte sectors needed to store the parent + hard disk locator. + */ + uint32 PlatformDataSpace; + /* + This field stores the actual length of the parent hard disk locator in bytes. + */ + uint32 PlatformDataLength; + /* + This field must be set to zero. + */ + uint32 Reserved; + /* + This field stores the absolute file offset in bytes where the platform + specific file locator data is stored. + */ + uint64 PlatformDataOffset; + /* + This field stores the absolute file offset in bytes where the platform + specific file locator data is stored. + */ + } ParentLocatorEntries[8]; + /* + This must be initialized to zeroes. + */ + char Reserved[256]; + } VHD_DynamicDiskHeader; + +#define VHD_BAT_FREE_ENTRY (0xFFFFFFFF) + +static char *VHD_DiskTypes[] = + { + "None", /* 0 */ + "Reserved (deprecated)", /* 1 */ + "Fixed hard disk", /* 2 */ +#define VHD_DT_Fixed 2 + "Dynamic hard disk", /* 3 */ +#define VHD_DT_Dynamic 3 + "Differencing hard disk", /* 4 */ +#define VHD_DT_Differencing 4 + "Reserved (deprecated)", /* 5 */ + "Reserved (deprecated)", /* 6 */ + }; + +static uint32 NtoHl(uint32 value); + +static uint64 NtoHll(uint64 value); + +typedef struct VHD_IOData *VHDHANDLE; + +static t_stat ReadFilePosition(FILE *File, void *buf, size_t bufsize, size_t *bytesread, uint64 position) +{ +uint32 err = sim_fseek (File, (t_addr)position, SEEK_SET); +size_t i; + +if (!err) { + i = fread (buf, 1, bufsize, File); + err = ferror (File); + if ((!err) && bytesread) + *bytesread = i; + } +return (err ? SCPE_IOERR : SCPE_OK); +} + +static t_stat WriteFilePosition(FILE *File, void *buf, size_t bufsize, size_t *byteswritten, uint64 position) +{ +uint32 err = sim_fseek (File, (t_addr)position, SEEK_SET); +size_t i; + +if (!err) { + i = fwrite (buf, 1, bufsize, File); + err = ferror (File); + if ((!err) && byteswritten) + *byteswritten = i; + } +return (err ? SCPE_IOERR : SCPE_OK); +} + +static uint32 +CalculateVhdFooterChecksum(void *data, + size_t size) +{ +uint32 sum = 0; +uint8 *c = (uint8 *)data; + +while (size--) + sum += *c++; +return ~sum; +} + +#if defined(_WIN32) || defined (__ALPHA) || defined (__ia64) || defined (VMS) +#ifndef __BYTE_ORDER__ +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#endif +#endif +#ifndef __BYTE_ORDER__ +#define __BYTE_ORDER__ UNKNOWN +#endif +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +static uint32 +NtoHl(uint32 value) +{ +uint8 *l = (uint8 *)&value; +return l[3] | (l[2]<<8) | (l[1]<<16) | (l[0]<<24); +} + +static uint64 +NtoHll(uint64 value) +{ +uint8 *l = (uint8 *)&value; +uint64 highresult = l[3] | (l[2]<<8) | (l[1]<<16) | (l[0]<<24); +uint32 lowresult = l[7] | (l[6]<<8) | (l[5]<<16) | (l[4]<<24); +return (highresult << 32) | lowresult; +} +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +static uint32 +NtoHl(uint32 value) +{ +return value; +} + +static uint64 +NtoHll(uint64 value) +{ +return value; +} +#else +static uint32 +NtoHl(uint32 value) +{ +uint8 *l = (uint8 *)&value; + +if (sim_end) + return l[3] | (l[2]<<8) | (l[1]<<16) | (l[0]<<24); +return value; +} + +static uint64 +NtoHll(uint64 value) +{ +uint8 *l = (uint8 *)&value; + +if (sim_end) { + uint64 highresult = l[3] | (l[2]<<8) | (l[1]<<16) | (l[0]<<24); + uint32 lowresult = l[7] | (l[6]<<8) | (l[5]<<16) | (l[4]<<24); + return (highresult << 32) | lowresult; + } +return value; +} +#endif + +static +int +GetVHDFooter(const char *szVHDPath, + VHD_Footer *sFooter, + VHD_DynamicDiskHeader *sDynamic, + uint32 **aBAT, + uint32 *ModifiedTimeStamp, + char *szParentVHDPath, + size_t ParentVHDPathSize) +{ +FILE *File = NULL; +uint64 position; +uint32 sum, saved_sum; +int Return = 0; +VHD_Footer sHeader; +struct stat statb; + +if (sFooter) + memset(sFooter, '\0', sizeof(*sFooter)); +if (sDynamic) + memset(sDynamic, '\0', sizeof(*sDynamic)); +if (aBAT) + *aBAT = NULL; +File = sim_fopen (szVHDPath, "rb"); +if (!File) { + Return = errno; + goto Return_Cleanup; + } +if (ModifiedTimeStamp) + if (stat (szVHDPath, &statb)) { + Return = errno; + goto Return_Cleanup; + } + else + *ModifiedTimeStamp = NtoHl ((uint32)(statb.st_mtime-946684800)); +position = sim_fsize_ex (File); +if (((int64)position) == -1) { + Return = errno; + goto Return_Cleanup; + } +position -= sizeof(*sFooter); +if (ReadFilePosition(File, + sFooter, + sizeof(*sFooter), + NULL, + position)) { + Return = errno; + goto Return_Cleanup; + } +saved_sum = NtoHl(sFooter->Checksum); +sFooter->Checksum = 0; +sum = CalculateVhdFooterChecksum(sFooter, sizeof(*sFooter)); +sFooter->Checksum = NtoHl(saved_sum); +if ((sum != saved_sum) || (memcmp("conectix", sFooter->Cookie, sizeof(sFooter->Cookie)))) { + Return = EINVAL; /* File Corrupt */ + goto Return_Cleanup; + } +if (ReadFilePosition(File, + &sHeader, + sizeof(sHeader), + NULL, + (uint64)0)) { + Return = errno; + goto Return_Cleanup; + } +if ((NtoHl(sFooter->DiskType) != VHD_DT_Dynamic) && + (NtoHl(sFooter->DiskType) != VHD_DT_Differencing) && + (NtoHl(sFooter->DiskType) != VHD_DT_Fixed)) { + Return = EINVAL; /* File Corrupt */ + goto Return_Cleanup; + } +if (((NtoHl(sFooter->DiskType) == VHD_DT_Dynamic) || + (NtoHl(sFooter->DiskType) == VHD_DT_Differencing)) && + memcmp(sFooter, &sHeader, sizeof(sHeader))) { + Return = EINVAL; /* File Corrupt */ + goto Return_Cleanup; + } +if ((sDynamic) && + ((NtoHl(sFooter->DiskType) == VHD_DT_Dynamic) || + (NtoHl(sFooter->DiskType) == VHD_DT_Differencing))) { + if (ReadFilePosition(File, + sDynamic, + sizeof (*sDynamic), + NULL, + NtoHll (sFooter->DataOffset))) { + Return = errno; + goto Return_Cleanup; + } + saved_sum = NtoHl (sDynamic->Checksum); + sDynamic->Checksum = 0; + sum = CalculateVhdFooterChecksum (sDynamic, sizeof(*sDynamic)); + sDynamic->Checksum = NtoHl (saved_sum); + if ((sum != saved_sum) || (memcmp ("cxsparse", sDynamic->Cookie, sizeof (sDynamic->Cookie)))) { + Return = errno; + goto Return_Cleanup; + } + if (aBAT) + { + *aBAT = malloc(512*((sizeof(**aBAT)*NtoHl(sDynamic->MaxTableEntries)+511)/512)); + if (ReadFilePosition(File, + *aBAT, + sizeof (**aBAT)*NtoHl(sDynamic->MaxTableEntries), + NULL, + NtoHll (sDynamic->TableOffset))) { + Return = EINVAL; /* File Corrupt */ + goto Return_Cleanup; + } + } + if (szParentVHDPath && ParentVHDPathSize) { + VHD_Footer sParentFooter; + + memset (szParentVHDPath, '\0', ParentVHDPathSize); + if (NtoHl (sFooter->DiskType) == VHD_DT_Differencing) + { + size_t i, j; + + for (j=0; j<8; ++j) + { + uint8 *Pdata; + char ParentName[256]; + char CheckPath[256]; + uint32 ParentModificationTime; + + if ('\0' == sDynamic->ParentLocatorEntries[j].PlatformCode[0]) + continue; + memset (ParentName, '\0', sizeof(ParentName)); + memset (CheckPath, '\0', sizeof(CheckPath)); + Pdata = calloc (1, NtoHl(sDynamic->ParentLocatorEntries[j].PlatformDataSpace)+1); + if (!Pdata) + continue; + if (ReadFilePosition(File, + Pdata, + NtoHl (sDynamic->ParentLocatorEntries[j].PlatformDataSpace), + NULL, + NtoHll (sDynamic->ParentLocatorEntries[j].PlatformDataOffset))) { + free (Pdata); + continue; + } + for (i=0; iParentLocatorEntries[j].PlatformDataLength); i+=2) + if ((Pdata[i] == '\0') && (Pdata[i+1] == '\0')) { + ParentName[i/2] = '\0'; + break; + } + else + ParentName[i/2] = Pdata[i] ? Pdata[i] : Pdata[i+1]; + free (Pdata); + if (0 == memcmp (sDynamic->ParentLocatorEntries[j].PlatformCode, "W2ku", 4)) + strncpy (CheckPath, ParentName, sizeof (CheckPath)-1); + else + if (0 == memcmp (sDynamic->ParentLocatorEntries[j].PlatformCode, "W2ru", 4)) { + char *c; + + if ((c = strrchr (szVHDPath, '/')) || (c = strrchr (szVHDPath, '\\'))) + memcpy (CheckPath, szVHDPath, c-szVHDPath+1); + strncpy (CheckPath+strlen(CheckPath), ParentName, sizeof (CheckPath)-(strlen (CheckPath)+1)); + } + if ((0 == GetVHDFooter(CheckPath, + &sParentFooter, + NULL, + NULL, + &ParentModificationTime, + NULL, + 0)) && + (0 == memcmp (sDynamic->ParentUniqueID, sParentFooter.UniqueID, sizeof (sParentFooter.UniqueID))) && + (sDynamic->ParentTimeStamp == ParentModificationTime)) + { + strncpy (szParentVHDPath, CheckPath, ParentVHDPathSize); + break; + } + } + if (!szParentVHDPath) + Return = EINVAL; /* File Corrupt */ + } + } + } +Return_Cleanup: +if (File) + fclose(File); +if (aBAT && (0 != Return)) { + free (*aBAT); + *aBAT = NULL; + } +return errno = Return; +} + +struct VHD_IOData { + VHD_Footer Footer; + VHD_DynamicDiskHeader Dynamic; + uint32 *BAT; + FILE *File; + char ParentVHDPath[512]; + struct VHD_IOData *Parent; + }; + +static t_stat sim_vhd_disk_implemented (void) +{ +return SCPE_OK; +} + +static t_stat sim_vhd_disk_set_dtype (FILE *f, const char *dtype) +{ +VHDHANDLE hVHD = (VHDHANDLE)f; +int Status = 0; + +memset (hVHD->Footer.DriveType, '\0', sizeof hVHD->Footer.DriveType); +memcpy (hVHD->Footer.DriveType, dtype, ((1+strlen (dtype)) < sizeof (hVHD->Footer.DriveType)) ? (1+strlen (dtype)) : sizeof (hVHD->Footer.DriveType)); +hVHD->Footer.Checksum = 0; +hVHD->Footer.Checksum = NtoHl (CalculateVhdFooterChecksum (&hVHD->Footer, sizeof(hVHD->Footer))); + +if (NtoHl (hVHD->Footer.DiskType) == VHD_DT_Fixed) { + if (WriteFilePosition(hVHD->File, + &hVHD->Footer, + sizeof(hVHD->Footer), + NULL, + NtoHll (hVHD->Footer.CurrentSize))) + Status = errno; + goto Cleanup_Return; + } +else { + uint64 position; + + position = sim_fsize_ex (hVHD->File); + if (((int64)position) == -1) { + Status = errno; + goto Cleanup_Return; + } + position -= sizeof(hVHD->Footer); + /* Update both copies on a dynamic disk */ + if (WriteFilePosition(hVHD->File, + &hVHD->Footer, + sizeof(hVHD->Footer), + NULL, + (uint64)0)) { + Status = errno; + goto Cleanup_Return; + } + if (WriteFilePosition(hVHD->File, + &hVHD->Footer, + sizeof(hVHD->Footer), + NULL, + position)) { + Status = errno; + goto Cleanup_Return; + } + } +Cleanup_Return: +if (Status) + return SCPE_IOERR; +return SCPE_OK; +} + +static const char *sim_vhd_disk_get_dtype (FILE *f) +{ +VHDHANDLE hVHD = (VHDHANDLE)f; + +return (char *)(&hVHD->Footer.DriveType[0]); +} + +static FILE *sim_vhd_disk_open (const char *szVHDPath, const char *DesiredAccess) + { + VHDHANDLE hVHD = calloc (1, sizeof(*hVHD)); + int Status; + + if (!hVHD) + return (FILE *)hVHD; + if (Status = GetVHDFooter (szVHDPath, + &hVHD->Footer, + &hVHD->Dynamic, + &hVHD->BAT, + NULL, + hVHD->ParentVHDPath, + sizeof (hVHD->ParentVHDPath))) + goto Cleanup_Return; + if (NtoHl (hVHD->Footer.DiskType) == VHD_DT_Differencing) { + hVHD->Parent = (VHDHANDLE)sim_vhd_disk_open (hVHD->ParentVHDPath, "rb"); + if (!hVHD->Parent) { + Status = errno; + goto Cleanup_Return; + } + } + if (hVHD->Footer.SavedState) { + Status = EAGAIN; /* Busy */ + goto Cleanup_Return; + } + hVHD->File = sim_fopen (szVHDPath, DesiredAccess); + if (!hVHD->File) { + Status = errno; + goto Cleanup_Return; + } +Cleanup_Return: + if (Status) { + free (hVHD->BAT); + free (hVHD); + hVHD = NULL; + } + errno = Status; + return (FILE *)hVHD; + } + +static int sim_vhd_disk_close (FILE *f) +{ +VHDHANDLE hVHD = (VHDHANDLE)f; + +if (NULL != hVHD) { + if (hVHD->Parent) + sim_vhd_disk_close ((FILE *)hVHD->Parent); + free (hVHD->BAT); + if (hVHD->File) { + fflush (hVHD->File); + fclose (hVHD->File); + } + free (hVHD); + return 0; + } +return -1; +} + +static void sim_vhd_disk_flush (FILE *f) +{ +VHDHANDLE hVHD = (VHDHANDLE)f; + +if ((NULL != hVHD) && (hVHD->File)) + fflush (hVHD->File); +} + +static t_addr sim_vhd_disk_size (FILE *f) +{ +VHDHANDLE hVHD = (VHDHANDLE)f; + +return (t_addr)(NtoHll (hVHD->Footer.CurrentSize)); +} + +#include +#include +static void +_rand_uuid_gen (void *uuidaddr) +{ +int i; +uint8 *b = (uint8 *)uuidaddr; +uint32 timenow = (uint32)time (NULL); + +memcpy (uuidaddr, &timenow, sizeof (timenow)); +srand ((unsigned)timenow); +for (i=4; i<16; i++) { + b[i] = (uint8)rand(); + } +} + +#if defined (_WIN32) +static void +uuid_gen (void *uuidaddr) +{ +static +RPC_STATUS +(RPC_ENTRY *UuidCreate_c) (void *); + +if (!UuidCreate_c) { + HINSTANCE hDll; + hDll = LoadLibrary("rpcrt4.dll"); + UuidCreate_c = (void *)GetProcAddress(hDll, "UuidCreate"); + } +if (UuidCreate_c) + UuidCreate_c(uuidaddr); +else + _rand_uuid_gen (uuidaddr); +} +#elif defined (USE_LIBUUID) +#include + +static void +uuid_gen (void *uuidaddr) +{ +uuid_generate((uuid_t)uuidaddr); +} +#else +static void +uuid_gen (void *uuidaddr) +{ +_rand_uuid_gen (uuidaddr); +} +#endif + +static VHDHANDLE +CreateVirtualDisk(const char *szVHDPath, + uint32 SizeInSectors, + uint32 BlockSize, + t_bool bFixedVHD) +{ +VHD_Footer Footer; +VHD_DynamicDiskHeader Dynamic; +uint32 *BAT = NULL; +time_t now; +uint32 i; +FILE *File; +uint32 Status = 0; +uint32 BytesPerSector = 512; +uint64 SizeInBytes = ((uint64)SizeInSectors)*BytesPerSector; +uint32 MaxTableEntries; +VHDHANDLE hVHD = NULL; + +if (SizeInBytes > ((uint64)(1024*1024*1024))*2040) { + Status = EFBIG; + goto Cleanup_Return; + } +if (File = sim_fopen (szVHDPath, "rb")) { + fclose (File); + Status = EEXIST; + goto Cleanup_Return; + } +File = sim_fopen (szVHDPath, "wb"); +if (!File) { + Status = errno; + goto Cleanup_Return; + } + +memset (&Footer, 0, sizeof(Footer)); +memcpy (Footer.Cookie, "conectix", 8); +Footer.Features = NtoHl (0x00000002);; +Footer.FileFormatVersion = NtoHl (0x00010000);; +Footer.DataOffset = NtoHll (bFixedVHD ? ((long long)-1) : (long long)(sizeof(Footer))); +time (&now); +Footer.TimeStamp = NtoHl ((uint32)(now-946684800)); +memcpy (Footer.CreatorApplication, "simh", 4); +Footer.CreatorVersion = NtoHl (0x00010000); +memcpy (Footer.CreatorHostOS, "Wi2k", 4); +Footer.OriginalSize = NtoHll (SizeInBytes); +Footer.CurrentSize = NtoHll (SizeInBytes); +uuid_gen (Footer.UniqueID); +Footer.DiskType = NtoHl (bFixedVHD ? VHD_DT_Fixed : VHD_DT_Dynamic); +Footer.DiskGeometry = NtoHl (0xFFFF10FF); +if (1) { /* CHS Calculation */ + uint32 totalSectors = (uint32)(SizeInBytes/BytesPerSector);/* Total data sectors present in the disk image */ + uint32 cylinders; /* Number of cylinders present on the disk */ + uint32 heads; /* Number of heads present on the disk */ + uint32 sectorsPerTrack; /* Sectors per track on the disk */ + uint32 cylinderTimesHeads; /* Cylinders x heads */ + + if (totalSectors > 65535 * 16 * 255) + totalSectors = 65535 * 16 * 255; + + if (totalSectors >= 65535 * 16 * 63) { + sectorsPerTrack = 255; + heads = 16; + cylinderTimesHeads = totalSectors / sectorsPerTrack; + } + else { + sectorsPerTrack = 17; + cylinderTimesHeads = totalSectors / sectorsPerTrack; + + heads = (cylinderTimesHeads + 1023) / 1024; + + if (heads < 4) + heads = 4; + if (cylinderTimesHeads >= (heads * 1024) || heads > 16) + { + sectorsPerTrack = 31; + heads = 16; + cylinderTimesHeads = totalSectors / sectorsPerTrack; + } + if (cylinderTimesHeads >= (heads * 1024)) + { + sectorsPerTrack = 63; + heads = 16; + cylinderTimesHeads = totalSectors / sectorsPerTrack; + } + } + cylinders = cylinderTimesHeads / heads; + Footer.DiskGeometry = NtoHl ((cylinders<<16)|(heads<<8)|sectorsPerTrack); + } +Footer.Checksum = NtoHl (CalculateVhdFooterChecksum(&Footer, sizeof(Footer))); + +if (bFixedVHD) { + if (WriteFilePosition(File, + &Footer, + sizeof(Footer), + NULL, + SizeInBytes)) + Status = errno; + goto Cleanup_Return; + } + +/* Dynamic Disk */ +memset (&Dynamic, 0, sizeof(Dynamic)); +memcpy (Dynamic.Cookie, "cxsparse", 8); +Dynamic.DataOffset = NtoHll (0xFFFFFFFFFFFFFFFFLL); +Dynamic.TableOffset = NtoHll ((uint64)(BytesPerSector*((sizeof(Dynamic)+sizeof(Footer)+BytesPerSector-1)/BytesPerSector))); +Dynamic.HeaderVersion = NtoHl (0x00010000); +if (0 == BlockSize) + BlockSize = 2*1024*1024; +Dynamic.BlockSize = NtoHl (BlockSize); +MaxTableEntries = (uint32)((SizeInBytes+BlockSize-1)/BlockSize); +Dynamic.MaxTableEntries = NtoHl (MaxTableEntries); +Dynamic.Checksum = NtoHl (CalculateVhdFooterChecksum(&Dynamic, sizeof(Dynamic))); +BAT = malloc (BytesPerSector*((MaxTableEntries*sizeof(*BAT)+BytesPerSector-1)/BytesPerSector)); +memset (BAT, 0, BytesPerSector*((MaxTableEntries*sizeof(*BAT)+BytesPerSector-1)/BytesPerSector)); +for (i=0; iDynamic.TableOffset)+BytesPerSector*((NtoHl (hVHD->Dynamic.MaxTableEntries)*sizeof(*hVHD->BAT)+BytesPerSector-1)/BytesPerSector); +hVHD->Dynamic.Checksum = 0; +RelativeParentVHDPath = calloc (1, BytesPerSector+1); +FullParentVHDPath = calloc (1, BytesPerSector+1); +RelativeParentVHDPathBuffer = calloc (1, BytesPerSector); +FullParentVHDPathBuffer = calloc (1, BytesPerSector); +FullVHDPath = calloc (1, BytesPerSector+1); +ExpandToFullPath (szParentVHDPath, FullParentVHDPath, BytesPerSector); +for (i=0; i < strlen (FullParentVHDPath); i++) + hVHD->Dynamic.ParentUnicodeName[i*2+1] = FullParentVHDPath[i]; +for (i=0; i < strlen (FullParentVHDPath); i++) + FullParentVHDPathBuffer[i*2] = FullParentVHDPath[i]; +ExpandToFullPath (szVHDPath, FullVHDPath, BytesPerSector); +for (i=0, RelativeMatch=UpDirectories=0; iDynamic.ParentTimeStamp = ParentTimeStamp; +memcpy (hVHD->Dynamic.ParentUniqueID, ParentFooter.UniqueID, sizeof (hVHD->Dynamic.ParentUniqueID)); +hVHD->Dynamic.ParentLocatorEntries[7].PlatformDataSpace = NtoHl (BytesPerSector); +hVHD->Dynamic.ParentLocatorEntries[7].PlatformDataOffset = NtoHll (LocatorPosition+LocatorsWritten*BytesPerSector); +++LocatorsWritten; +hVHD->Dynamic.ParentLocatorEntries[6].PlatformDataSpace = NtoHl (BytesPerSector); +hVHD->Dynamic.ParentLocatorEntries[6].PlatformDataOffset = NtoHll (LocatorPosition+LocatorsWritten*BytesPerSector); +++LocatorsWritten; +if (RelativeMatch) { + memcpy (hVHD->Dynamic.ParentLocatorEntries[5].PlatformCode, "W2ru", 4); + hVHD->Dynamic.ParentLocatorEntries[5].PlatformDataSpace = NtoHl (BytesPerSector); + hVHD->Dynamic.ParentLocatorEntries[5].PlatformDataLength = NtoHl (2*strlen(RelativeParentVHDPath)); + hVHD->Dynamic.ParentLocatorEntries[5].Reserved = 0; + hVHD->Dynamic.ParentLocatorEntries[5].PlatformDataOffset = NtoHll (LocatorPosition+LocatorsWritten*BytesPerSector); + ++LocatorsWritten; + } +memcpy (hVHD->Dynamic.ParentLocatorEntries[4].PlatformCode, "W2ku", 4); +hVHD->Dynamic.ParentLocatorEntries[4].PlatformDataSpace = NtoHl (BytesPerSector); +hVHD->Dynamic.ParentLocatorEntries[4].PlatformDataLength = NtoHl (2*strlen(FullParentVHDPath)); +hVHD->Dynamic.ParentLocatorEntries[4].Reserved = 0; +hVHD->Dynamic.ParentLocatorEntries[4].PlatformDataOffset = NtoHll (LocatorPosition+LocatorsWritten*BytesPerSector); +++LocatorsWritten; +hVHD->Dynamic.Checksum = NtoHl (CalculateVhdFooterChecksum (&hVHD->Dynamic, sizeof(hVHD->Dynamic))); +hVHD->Footer.Checksum = 0; +hVHD->Footer.DiskType = NtoHl (VHD_DT_Differencing); +memcpy (hVHD->Footer.DriveType, ParentFooter.DriveType, sizeof (hVHD->Footer.DriveType)); +hVHD->Footer.Checksum = NtoHl (CalculateVhdFooterChecksum (&hVHD->Footer, sizeof(hVHD->Footer))); + +if (WriteFilePosition (hVHD->File, + &hVHD->Footer, + sizeof (hVHD->Footer), + NULL, + 0)) { + Status = errno; + goto Cleanup_Return; + } +if (WriteFilePosition (hVHD->File, + &hVHD->Dynamic, + sizeof (hVHD->Dynamic), + NULL, + NtoHll (hVHD->Footer.DataOffset))) { + Status = errno; + goto Cleanup_Return; + } +LocatorsWritten = 0; +if (RelativeMatch) { + if (WriteFilePosition (hVHD->File, + RelativeParentVHDPath, + BytesPerSector, + NULL, + LocatorPosition+LocatorsWritten*BytesPerSector)) { + Status = errno; + goto Cleanup_Return; + } + ++LocatorsWritten; + } +if (WriteFilePosition (hVHD->File, + FullParentVHDPath, + BytesPerSector, + NULL, + LocatorPosition+LocatorsWritten*BytesPerSector)) { + Status = errno; + goto Cleanup_Return; + } +++LocatorsWritten; +if (RelativeMatch) { + if (WriteFilePosition (hVHD->File, + RelativeParentVHDPathBuffer, + BytesPerSector, + NULL, + LocatorPosition+LocatorsWritten*BytesPerSector)) { + Status = errno; + goto Cleanup_Return; + } + ++LocatorsWritten; + } +if (WriteFilePosition (hVHD->File, + FullParentVHDPathBuffer, + BytesPerSector, + NULL, + LocatorPosition+LocatorsWritten*BytesPerSector)) { + Status = errno; + goto Cleanup_Return; + } +++LocatorsWritten; +if (WriteFilePosition (hVHD->File, + &hVHD->Footer, + sizeof(hVHD->Footer), + NULL, + LocatorPosition+LocatorsWritten*BytesPerSector)) { + Status = errno; + goto Cleanup_Return; + } + +Cleanup_Return: +free (RelativeParentVHDPath); +free (FullParentVHDPath); +free (RelativeParentVHDPathBuffer); +free (FullParentVHDPathBuffer); +free (FullVHDPath); +sim_vhd_disk_close ((FILE *)hVHD); +hVHD = NULL; +if (Status) { + if (EEXIST != Status) + remove (szVHDPath); + } +else { + hVHD = (VHDHANDLE)sim_vhd_disk_open (szVHDPath, "rb+"); + if (!hVHD) + Status = errno; + } +errno = Status; +return hVHD; +} + +static FILE *sim_vhd_disk_create (const char *szVHDPath, t_addr desiredsize) +{ +return (FILE *)CreateVirtualDisk (szVHDPath, (uint32)(desiredsize/512), 0, (sim_switches & SWMASK ('X'))); +} + +static FILE *sim_vhd_disk_create_diff (const char *szVHDPath, const char *szParentVHDPath) +{ +return (FILE *)CreateDifferencingVirtualDisk (szVHDPath, szParentVHDPath); +} + +static t_stat +ReadVirtualDiskSectors(VHDHANDLE hVHD, + uint8 *buf, + t_seccnt sects, + t_seccnt *sectsread, + uint32 SectorSize, + t_lba lba) +{ +uint64 BlockOffset = ((uint64)lba)*SectorSize; +uint32 BlocksRead = 0; +uint32 SectorsInRead; +size_t BytesRead; + +if (!hVHD || (hVHD->File == NULL)) { + errno = EBADF; + return SCPE_IOERR; + } +if ((BlockOffset + sects*SectorSize) > (uint64)NtoHll (hVHD->Footer.CurrentSize)) { + errno = ERANGE; + return SCPE_IOERR; + } +if (NtoHl (hVHD->Footer.DiskType) == VHD_DT_Fixed) { + if (ReadFilePosition(hVHD->File, + buf, + sects*SectorSize, + &BytesRead, + BlockOffset)) { + if (sectsread) + *sectsread = (t_seccnt)(BytesRead/SectorSize); + return SCPE_IOERR; + } + if (sectsread) + *sectsread /= SectorSize; + return SCPE_OK; + } +/* We are now dealing with a Dynamically expanding or differencing disk */ +while (sects) { + uint32 SectorsPerBlock = NtoHl (hVHD->Dynamic.BlockSize)/SectorSize; + uint64 BlockNumber = lba/SectorsPerBlock; + uint32 BitMapBytes = (7+(NtoHl (hVHD->Dynamic.BlockSize)/SectorSize))/8; + uint32 BitMapSectors = (BitMapBytes+SectorSize-1)/SectorSize; + + SectorsInRead = 1; + if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY) { + if (!hVHD->Parent) + memset (buf, 0, SectorSize); + else { + SectorsInRead = SectorsPerBlock - lba%SectorsPerBlock; + if (SectorsInRead > sects) + SectorsInRead = sects; + if (ReadVirtualDiskSectors(hVHD->Parent, + buf, + SectorsInRead, + NULL, + SectorSize, + lba)) { + if (sectsread) + *sectsread = BlocksRead; + return FALSE; + } + } + } + else { + BlockOffset = SectorSize*((uint64)(NtoHl (hVHD->BAT[BlockNumber]) + lba%SectorsPerBlock + BitMapSectors)); + SectorsInRead = SectorsPerBlock - lba%SectorsPerBlock; + if (SectorsInRead > sects) + SectorsInRead = sects; + if (ReadFilePosition(hVHD->File, + buf, + SectorsInRead*SectorSize, + NULL, + BlockOffset)) { + if (sectsread) + *sectsread = BlocksRead; + return SCPE_IOERR; + } + } + sects -= SectorsInRead; + buf = (uint8 *)(((char *)buf) + SectorSize*SectorsInRead); + lba += SectorsInRead; + BlocksRead += SectorsInRead; + } +if (sectsread) + *sectsread = BlocksRead; +return SCPE_OK; +} + +static t_stat sim_vhd_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects) +{ +VHDHANDLE hVHD = (VHDHANDLE)uptr->fileref; +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; + +return ReadVirtualDiskSectors(hVHD, buf, sects, sectsread, ctx->sector_size, lba); +} + +static t_bool +BufferIsZeros(void *Buffer, size_t BufferSize) +{ +size_t i; +char *c = (char *)Buffer; + +for (i=0; iFile) { + errno = EBADF; + return SCPE_IOERR; + } +if ((BlockOffset + sects*SectorSize) > (uint64)NtoHll(hVHD->Footer.CurrentSize)) { + errno = ERANGE; + return SCPE_IOERR; + } +if (NtoHl(hVHD->Footer.DiskType) == VHD_DT_Fixed) { + if (WriteFilePosition(hVHD->File, + buf, + sects*SectorSize, + &BytesWritten, + BlockOffset)) { + if (sectswritten) + *sectswritten = (t_seccnt)(BytesWritten/SectorSize); + return SCPE_IOERR; + } + if (sectswritten) + *sectswritten /= SectorSize; + return SCPE_OK; + } +/* We are now dealing with a Dynamically expanding or differencing disk */ +while (sects) { + uint32 SectorsPerBlock = NtoHl(hVHD->Dynamic.BlockSize)/SectorSize; + uint64 BlockNumber = lba/SectorsPerBlock; + uint32 BitMapBytes = (7+(NtoHl(hVHD->Dynamic.BlockSize)/SectorSize))/8; + uint32 BitMapSectors = (BitMapBytes+SectorSize-1)/SectorSize; + + if (BlockNumber >= NtoHl(hVHD->Dynamic.MaxTableEntries)) { + if (sectswritten) + *sectswritten = BlocksWritten; + return SCPE_EOF; + } + SectorsInWrite = 1; + if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY) { + void *BitMap = NULL; + void *BlockData = NULL; + + if (!hVHD->Parent && BufferIsZeros(buf, SectorSize)) + goto IO_Done; + /* Need to allocate a new Data Block. */ + BlockOffset = sim_fsize_ex (hVHD->File); + if (((int64)BlockOffset) == -1) + return SCPE_IOERR; + BitMap = malloc(BitMapSectors*SectorSize); + memset(BitMap, 0xFF, BitMapBytes); + BlockOffset -= sizeof(hVHD->Footer); + hVHD->BAT[BlockNumber] = NtoHl((uint32)(BlockOffset/SectorSize)); + if (WriteFilePosition(hVHD->File, + BitMap, + BitMapSectors*SectorSize, + NULL, + BlockOffset)) { + free (BitMap); + return SCPE_IOERR; + } + free(BitMap); + BitMap = NULL; + BlockOffset += SectorSize * (SectorsPerBlock + BitMapSectors); + if (WriteFilePosition(hVHD->File, + &hVHD->Footer, + sizeof(hVHD->Footer), + NULL, + BlockOffset)) + goto Fatal_IO_Error; + if (WriteFilePosition(hVHD->File, + hVHD->BAT, + SectorSize*((sizeof(*hVHD->BAT)*NtoHl(hVHD->Dynamic.MaxTableEntries)+511)/512), + NULL, + NtoHll(hVHD->Dynamic.TableOffset))) + goto Fatal_IO_Error; + if (hVHD->Parent) + { /* Need to populate data block contents from parent VHD */ + BlockData = malloc(SectorsPerBlock*SectorSize); + if (ReadVirtualDiskSectors(hVHD->Parent, + BlockData, + SectorsPerBlock, + NULL, + SectorSize, + (lba/SectorsPerBlock)*SectorsPerBlock)) + goto Fatal_IO_Error; + if (WriteVirtualDiskSectors(hVHD, + BlockData, + SectorsPerBlock, + NULL, + SectorSize, + (lba/SectorsPerBlock)*SectorsPerBlock)) + goto Fatal_IO_Error; + free(BlockData); + } + continue; +Fatal_IO_Error: + free (BitMap); + free (BlockData); + fclose (hVHD->File); + hVHD->File = NULL; + return SCPE_IOERR; + } + else { + BlockOffset = 512*((uint64)(NtoHl(hVHD->BAT[BlockNumber]) + lba%SectorsPerBlock + BitMapSectors)); + SectorsInWrite = SectorsPerBlock - lba%SectorsPerBlock; + if (SectorsInWrite > sects) + SectorsInWrite = sects; + if (WriteFilePosition(hVHD->File, + buf, + SectorsInWrite*SectorSize, + NULL, + BlockOffset)) { + if (sectswritten) + *sectswritten = BlocksWritten; + return SCPE_IOERR; + } + } +IO_Done: + sects -= SectorsInWrite; + buf = (uint8 *)(((char *)buf) + SectorsInWrite*SectorSize); + lba += SectorsInWrite; + BlocksWritten += SectorsInWrite; + } +if (sectswritten) + *sectswritten = BlocksWritten; +return SCPE_OK; +} + +static t_stat sim_vhd_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects) +{ +VHDHANDLE hVHD = (VHDHANDLE)uptr->fileref; +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; + +return WriteVirtualDiskSectors(hVHD, buf, sects, sectswritten, ctx->sector_size, lba); +} +#endif diff --git a/sim_disk.h b/sim_disk.h new file mode 100644 index 00000000..3fa70e9d --- /dev/null +++ b/sim_disk.h @@ -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 diff --git a/sim_ether.c b/sim_ether.c index 5a1fb115..feb04995 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -637,7 +637,7 @@ t_stat eth_show (FILE* st, UNIT* uptr, int32 val, void* desc) for (i=0, min=0; i min) min = len; for (i=0; ihost_nic_phy_hw_addr)) dev->have_host_nic_phy_addr = 1; -#else +#elif !defined (__VMS) { char command[1024]; FILE *f; diff --git a/sim_fio.c b/sim_fio.c index 70b2800a..b9a91ecb 100644 --- a/sim_fio.c +++ b/sim_fio.c @@ -23,6 +23,8 @@ used in advertising or otherwise to promote the sale, use or other dealings 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) 10-Jul-06 RMS Fixed linux conditionalization (from Chaskiel Grundman) 15-May-06 RMS Added sim_fsize_name @@ -35,12 +37,17 @@ This library includes: - sim_finit - initialize package - sim_fopen - open file - sim_fread - endian independent read (formerly fxread) - sim_write - endian independent write (formerly fxwrite) - sim_fseek - extended (>32b) seek (formerly fseek_ext) - sim_fsize - get file size + sim_finit - initialize package + sim_fopen - open file + sim_fread - endian independent read (formerly fxread) + sim_write - endian independent write (formerly fxwrite) + sim_fseek - extended (>32b) seek (formerly fseek_ext) + 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_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; } -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; unsigned char by, *sptr, *dptr; -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 */ -for (j = 0, dptr = sptr = (unsigned char *) bptr; j < c; j++) { /* loop on items */ +if (sim_end || (count == 0) || (size == sizeof (char))) + return; +for (j = 0, dptr = sptr = (unsigned char *) bptr; /* loop on items */ + j < count; j++) { for (k = size - 1; k >= (((int32) size + 1) / 2); k--) { by = *sptr; /* swap end-for-end */ *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 */ } +} + +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; } +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 c, j, nelem, nbuf, lcnt, total; -int32 i, k; -unsigned char *sptr, *dptr; +size_t c, nelem, nbuf, lcnt, total; +int32 i; +unsigned char *sptr; if ((size == 0) || (count == 0)) /* check arguments */ return 0; @@ -119,11 +154,8 @@ total = 0; sptr = (unsigned char *) bptr; /* init input ptr */ for (i = nbuf; i > 0; i--) { /* loop on buffers */ c = (i == 1)? lcnt: nelem; - for (j = 0, dptr = sim_flip; j < c; j++) { /* loop on items */ - for (k = size - 1; k >= 0; k--) - *(dptr + k) = *sptr++; - dptr = dptr + size; - } + sim_buf_copy_swapped (sim_flip, sptr, size, c); + sptr = sptr + size * count; c = fwrite (sim_flip, size, c, fptr); if (c == 0) return total; @@ -132,31 +164,45 @@ for (i = nbuf; i > 0; i--) { /* loop on buffers */ return total; } +/* Forward Declaration */ + +static t_addr _sim_ftell (FILE *st); + /* 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; -uint32 sz; +t_addr sz; if ((fp = sim_fopen (fname, "rb")) == NULL) return 0; -sz = sim_fsize (fp); +sz = sim_fsize_ex (fp); fclose (fp); return sz; } +uint32 sim_fsize_name (char *fname) +{ +return (uint32)(sim_fsize_name_ex (fname)); +} + uint32 sim_fsize (FILE *fp) { -uint32 pos, sz; - -if (fp == NULL) - return 0; -pos = ftell (fp); -fseek (fp, 0, SEEK_END); -sz = ftell (fp); -fseek (fp, pos, SEEK_SET); -return sz; +return (uint32)(sim_fsize_ex (fp)); } /* OS-dependent routines */ @@ -227,6 +273,9 @@ switch (whence) { fileaddr = offset; break; + case SEEK_END: + if (_fseeki64 (st, 0, SEEK_END)) + return (-1); case SEEK_CUR: if (fgetpos (st, &filepos)) return (-1); @@ -243,6 +292,14 @@ int64_to_fpos_t (fileaddr, &filepos, 127); 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 /* Alpha UNIX - natively 64b */ @@ -255,16 +312,23 @@ int sim_fseek (FILE *st, t_addr offset, int whence) return fseek (st, offset, whence); } +static t_addr _sim_ftell (FILE *st) +{ +return (t_addr)(ftell (st)); +} + #endif /* Windows */ #if defined (_WIN32) #define _SIM_IO_FSEEK_EXT_ 1 +#include int sim_fseek (FILE *st, t_addr offset, int whence) { fpos_t fileaddr; +struct _stati64 statb; switch (whence) { @@ -272,6 +336,11 @@ switch (whence) { fileaddr = offset; break; + case SEEK_END: + if (_fstati64 (_fileno (st), &statb)) + return (-1); + fileaddr = statb.st_size + offset; + break; case SEEK_CUR: if (fgetpos (st, &fileaddr)) return (-1); @@ -286,6 +355,14 @@ switch (whence) { 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 */ /* Linux */ @@ -298,6 +375,11 @@ int sim_fseek (FILE *st, t_addr xpos, int origin) return fseeko64 (st, xpos, origin); } +static t_addr _sim_ftell (FILE *st) +{ +return (t_addr)(ftello64 (st)); +} + #endif /* end Linux with LFS */ /* Apple OS/X */ @@ -310,6 +392,11 @@ int sim_fseek (FILE *st, t_addr xpos, int 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 64b seek defs */ @@ -324,6 +411,11 @@ int sim_fseek (FILE *st, t_addr xpos, int origin) return fseek (st, (int32) xpos, origin); } +static t_addr _sim_ftell (FILE *st) +{ +return (t_addr)(ftell (st)); +} + #endif uint32 sim_taddr_64 = _SIM_IO_FSEEK_EXT_; diff --git a/sim_fio.h b/sim_fio.h index 264ea971..a6985426 100644 --- a/sim_fio.h +++ b/sim_fio.h @@ -23,6 +23,8 @@ 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. + 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 16-Aug-05 RMS Fixed C++ declaration and cast problems 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); uint32 sim_fsize (FILE *fptr); 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 diff --git a/sim_tape.c b/sim_tape.c index c3a0c9b2..d50a4887 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -26,6 +26,17 @@ Ultimately, this will be a place to hide processing of various tape formats, as well as OS-specific direct hardware access. + 05-Feb-11 MP Refactored to prepare for SIM_ASYNC_IO support + Added higher level routines: + sim_tape_wreomrw - erase remainder of tape & rewind + sim_tape_sprecsf - skip records + sim_tape_spfilef - skip files + sim_tape_sprecsr - skip records rev + sim_tape_spfiler - skip files rev + sim_tape_position - general purpose position + These routines correspond to natural tape operations + and will align better when physical tape support is + included here. 08-Jun-08 JDB Fixed signed/unsigned warning in sim_tape_set_fmt 23-Jan-07 JDB Fixed backspace over gap at BOT 22-Jan-07 RMS Fixed bug in P7B format read reclnt rev (found by Rich Cornwell) @@ -53,7 +64,13 @@ sim_tape_sprecr space tape record reverse sim_tape_wrtmk write tape mark sim_tape_wreom erase remainder of tape + sim_tape_wreomrw erase remainder of tape & rewind sim_tape_wrgap write erase gap + sim_tape_sprecsf space records forward + sim_tape_spfilef space files forward + sim_tape_sprecsr space records reverse + sim_tape_spfiler space files reverse + sim_tape_position generalized position sim_tape_rewind rewind sim_tape_reset reset unit sim_tape_bot TRUE if at beginning of tape @@ -63,10 +80,17 @@ sim_tape_show_fmt show tape format sim_tape_set_capac set tape capacity sim_tape_show_capac show tape capacity + sim_tape_set_async enable asynchronous operation + sim_tape_clr_async disable asynchronous operation */ #include "sim_defs.h" #include "sim_tape.h" +#include + +#if defined SIM_ASYNCH_IO +#include +#endif struct sim_tape_fmt { char *name; /* name */ @@ -90,14 +114,276 @@ t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat); uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map); t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map); +struct tape_context { + DEVICE *dptr; /* Device for unit (access to debug flags) */ + uint32 dbit; /* debugging bit */ +#if defined SIM_ASYNCH_IO + int asynch_io; /* Asynchronous Interrupt scheduling enabled */ + int asynch_io_latency; /* instructions to delay pending interrupt */ + pthread_mutex_t lock; + pthread_t io_thread; /* I/O Thread Id */ + pthread_mutex_t io_lock; + pthread_cond_t io_cond; + int io_top; + uint8 *buf; + uint32 *bc; + uint32 *fc; + uint32 vbc; + uint32 max; + uint32 gaplen; + uint32 bpi; + uint32 *objupdate; + TAPE_PCALLBACK callback; + t_stat io_status; +#endif + }; +#define tape_ctx up8 /* Field in Unit structure which points to the tape_context */ + +#if defined SIM_ASYNCH_IO +#define AIO_CALLSETUP \ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; \ + \ +if ((!callback) || !ctx->asynch_io) + +#define AIO_CALL(op, _buf, _bc, _fc, _max, _vbc, _gaplen, _bpi, _obj, _callback)\ + if (1) { \ + struct tape_context *ctx = \ + (struct tape_context *)uptr->tape_ctx; \ + \ + \ + sim_debug (ctx->dbit, ctx->dptr, \ + "sim_tape AIO_CALL(op=%d, unit=%d)\n", op, uptr-ctx->dptr->units);\ + \ + if (ctx->callback) \ + abort(); /* horrible mistake, stop */ \ + ctx->io_top = op; \ + ctx->buf = _buf; \ + ctx->bc = _bc; \ + ctx->fc = _fc; \ + ctx->max = _max; \ + ctx->vbc = _vbc; \ + ctx->gaplen = _gaplen; \ + ctx->bpi = _bpi; \ + ctx->objupdate = _obj; \ + ctx->callback = _callback; \ + pthread_cond_signal (&ctx->io_cond); \ + } +#define TOP_DONE 0 /* close */ +#define TOP_RDRF 1 /* sim_tape_rdrecf_a */ +#define TOP_RDRR 2 /* sim_tape_rdrecr_a */ +#define TOP_WREC 3 /* sim_tape_wrrecf_a */ +#define TOP_WTMK 4 /* sim_tape_wrtmk_a */ +#define TOP_WEOM 5 /* sim_tape_wreom_a */ +#define TOP_WEMR 6 /* sim_tape_wreomrw_a */ +#define TOP_WGAP 7 /* sim_tape_wrgap_a */ +#define TOP_SPRF 8 /* sim_tape_sprecf_a */ +#define TOP_SRSF 9 /* sim_tape_sprecsf_a */ +#define TOP_SPRR 10 /* sim_tape_sprecr_a */ +#define TOP_SRSR 11 /* sim_tape_sprecsr_a */ +#define TOP_SPFF 12 /* sim_tape_spfilef */ +#define TOP_SFRF 13 /* sim_tape_spfilebyrecf */ +#define TOP_SPFR 14 /* sim_tape_spfiler */ +#define TOP_SFRR 15 /* sim_tape_spfilebyrecr */ +#define TOP_RWND 16 /* sim_tape_rewind_a */ +#define TOP_POSN 17 /* sim_tape_position_a */ + +static void * +_tape_io(void *arg) +{ +UNIT* volatile uptr = (UNIT*)arg; +int sched_policy; +struct sched_param sched_priority; +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; + + /* Boost Priority for this I/O thread vs the CPU instruction execution + thread which in general won't be readily yielding the processor when + this thread needs to run */ + pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); + ++sched_priority.sched_priority; + pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); + + sim_debug (ctx->dbit, ctx->dptr, "_tape_io(unit=%d) starting\n", uptr-ctx->dptr->units); + + pthread_mutex_lock (&ctx->io_lock); + while (1) { + pthread_cond_wait (&ctx->io_cond, &ctx->io_lock); + if (ctx->io_top == TOP_DONE) + break; + pthread_mutex_unlock (&ctx->io_lock); + switch (ctx->io_top) { + case TOP_RDRF: + ctx->io_status = sim_tape_rdrecf (uptr, ctx->buf, ctx->bc, ctx->max); + break; + case TOP_RDRR: + ctx->io_status = sim_tape_rdrecr (uptr, ctx->buf, ctx->bc, ctx->max); + break; + case TOP_WREC: + ctx->io_status = sim_tape_wrrecf (uptr, ctx->buf, ctx->vbc); + break; + case TOP_WTMK: + ctx->io_status = sim_tape_wrtmk (uptr); + break; + case TOP_WEOM: + ctx->io_status = sim_tape_wreom (uptr); + break; + case TOP_WEMR: + ctx->io_status = sim_tape_wreomrw (uptr); + break; + case TOP_WGAP: + ctx->io_status = sim_tape_wrgap (uptr, ctx->gaplen, ctx->bpi); + break; + case TOP_SPRF: + ctx->io_status = sim_tape_sprecf (uptr, ctx->bc); + break; + case TOP_SRSF: + ctx->io_status = sim_tape_sprecsf (uptr, ctx->vbc, ctx->bc); + break; + case TOP_SPRR: + ctx->io_status = sim_tape_sprecr (uptr, ctx->bc); + break; + case TOP_SRSR: + ctx->io_status = sim_tape_sprecsr (uptr, ctx->vbc, ctx->bc); + break; + case TOP_SPFF: + ctx->io_status = sim_tape_spfilef (uptr, ctx->vbc, ctx->bc); + break; + case TOP_SFRF: + ctx->io_status = sim_tape_spfilebyrecf (uptr, ctx->vbc, ctx->bc, ctx->fc); + break; + case TOP_SPFR: + ctx->io_status = sim_tape_spfiler (uptr, ctx->vbc, ctx->bc); + break; + case TOP_SFRR: + ctx->io_status = sim_tape_spfilebyrecr (uptr, ctx->vbc, ctx->bc, ctx->fc); + break; + case TOP_RWND: + ctx->io_status = sim_tape_rewind (uptr); + break; + case TOP_POSN: + ctx->io_status = sim_tape_position (uptr, ctx->vbc, ctx->gaplen, ctx->bc, ctx->bpi, ctx->fc, ctx->objupdate); + break; + } + pthread_mutex_lock (&ctx->io_lock); + ctx->io_top = TOP_DONE; + sim_activate (uptr, ctx->asynch_io_latency); + } + pthread_mutex_unlock (&ctx->io_lock); + + sim_debug (ctx->dbit, ctx->dptr, "_tape_io(unit=%d) exiting\n", uptr-ctx->dptr->units); + + return NULL; +} + +/* This routine is called in the context of the main simulator thread before + processing events for any unit. It is only called when an asynchronous + thread has called sim_activate() to activate a unit. The job of this + routine is to put the unit in proper condition to digest what may have + occurred in the asynchrcondition thread. + + Since tape processing only handles a single I/O at a time to a + particular tape device, we have the opportunity to possibly detect + improper attempts to issue multiple concurrent I/O requests. */ +static void _tape_completion_dispatch (UNIT *uptr) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; +TAPE_PCALLBACK callback = ctx->callback; + +sim_debug (ctx->dbit, ctx->dptr, "_tape_completion_dispatch(unit=%d, top=%d, callback=%p)\n", uptr-ctx->dptr->units, ctx->io_top, ctx->callback); + +if (ctx->io_top != TOP_DONE) + abort(); /* horribly wrong, stop */ + +if (ctx->callback && ctx->io_top == TOP_DONE) { + ctx->callback = NULL; + callback (uptr, ctx->io_status); + } +} +#else +#define AIO_CALLSETUP +#define AIO_CALL(op, _buf, _fc, _bc, _max, _vbc, _gaplen, _bpi, _obj, _callback) \ + if (_callback) \ + (_callback) (uptr, r); +#endif + + +/* Enable asynchronous operation */ + +t_stat sim_tape_set_async (UNIT *uptr, int latency) +{ +#if !defined(SIM_ASYNCH_IO) +extern FILE *sim_log; /* log file */ +char *msg = "Tape: can't operate asynchronously\r\n"; +printf ("%s", msg); +if (sim_log) fprintf (sim_log, "%s", msg); +return SCPE_NOFNC; +#else +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; +pthread_attr_t attr; + +ctx->asynch_io = 1; +ctx->asynch_io_latency = latency; +pthread_mutex_init (&ctx->io_lock, NULL); +pthread_cond_init (&ctx->io_cond, NULL); +pthread_attr_init(&attr); +pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); +pthread_create (&ctx->io_thread, &attr, _tape_io, (void *)uptr); +pthread_attr_destroy(&attr); +uptr->a_check_completion = _tape_completion_dispatch; +#endif +return SCPE_OK; +} + +/* Disable asynchronous operation */ + +t_stat sim_tape_clr_async (UNIT *uptr) +{ +#if !defined(SIM_ASYNCH_IO) +return SCPE_NOFNC; +#else +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; + +/* make sure device exists */ +if (!ctx) return SCPE_UNATT; + +if (ctx->asynch_io) { + pthread_mutex_lock (&ctx->io_lock); + ctx->asynch_io = 0; + pthread_cond_signal (&ctx->io_cond); + pthread_mutex_unlock (&ctx->io_lock); + pthread_join (ctx->io_thread, NULL); + pthread_mutex_destroy (&ctx->io_lock); + pthread_cond_destroy (&ctx->io_cond); + } +return SCPE_OK; +#endif +} + +static void _sim_tape_io_flush (UNIT *uptr) +{ +#if defined (SIM_ASYNCH_IO) +sim_tape_clr_async (uptr); +sim_tape_set_async (uptr, 0); +#endif +fflush (uptr->fileref); +} + /* Attach tape unit */ t_stat sim_tape_attach (UNIT *uptr, char *cptr) { +return sim_tape_attach_ex (uptr, cptr, 0); +} + +t_stat sim_tape_attach_ex (UNIT *uptr, char *cptr, uint32 dbit) +{ +struct tape_context *ctx; uint32 objc; +DEVICE *dptr; char gbuf[CBUFSIZE]; t_stat r; +if ((dptr = find_dev_from_unit (uptr)) == NULL) + return SCPE_NOATT; if (sim_switches & SWMASK ('F')) { /* format spec? */ cptr = get_glyph (cptr, gbuf, 0); /* get spec */ if (*cptr == 0) /* must be more */ @@ -129,7 +415,17 @@ switch (MT_GET_FMT (uptr)) { /* case on format */ break; } +uptr->tape_ctx = ctx = (struct tape_context *)calloc(1, sizeof(struct tape_context)); +ctx->dptr = dptr; /* save DEVICE pointer */ +ctx->dbit = dbit; /* save debug bit */ + sim_tape_rewind (uptr); + +#if defined (SIM_ASYNCH_IO) +sim_tape_set_async (uptr, 0); +#endif +uptr->io_flush = _sim_tape_io_flush; + return SCPE_OK; } @@ -140,6 +436,10 @@ t_stat sim_tape_detach (UNIT *uptr) uint32 f = MT_GET_FMT (uptr); t_stat r; +#if defined (SIM_ASYNCH_IO) +sim_tape_clr_async (uptr); +#endif + r = detach_unit (uptr); /* detach unit */ if (r != SCPE_OK) return r; @@ -157,9 +457,52 @@ switch (f) { /* case on format */ } sim_tape_rewind (uptr); +free (uptr->tape_ctx); +uptr->tape_ctx = NULL; +uptr->io_flush = NULL; return SCPE_OK; } +void sim_tape_data_trace(UNIT *uptr, const uint8 *data, size_t len, const char* txt, int detail, uint32 reason) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; + +if (ctx->dptr->dctrl & reason) { + sim_debug (reason, ctx->dptr, "%s%d %s len: %08X\n", ctx->dptr->name, uptr-ctx->dptr->units, txt, len); + if (detail) { + size_t i, same, group, sidx, oidx; + char outbuf[80], strbuf[18]; + static char hex[] = "0123456789ABCDEF"; + + for (i=same=0; i 0) && (0 == memcmp (&data[i], &data[i-16], 16))) { + ++same; + continue; + } + if (same > 0) { + sim_debug (reason, ctx->dptr, "%04X thru %04X same as above\n", i-(16*same), i-1); + same = 0; + } + group = (((len - i) > 16) ? 16 : (len - i)); + for (sidx=oidx=0; sidx>4)&0xf]; + outbuf[oidx++] = hex[data[i+sidx]&0xf]; + if (isprint (data[i+sidx])) + strbuf[sidx] = data[i+sidx]; + else + strbuf[sidx] = '.'; + } + outbuf[oidx] = '\0'; + strbuf[sidx] = '\0'; + sim_debug (reason, ctx->dptr, "%04X%-48s %s\n", i, outbuf, strbuf); + } + if (same > 0) + sim_debug (reason, ctx->dptr, "%04X thru %04X same as above\n", i-(16*same), len-1); + } + } +} + /* Read record length forward (internal routine) Inputs: @@ -398,11 +741,14 @@ return MTSE_OK; t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max) { +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; uint32 f = MT_GET_FMT (uptr); t_mtrlnt i, tbc, rbc; t_addr opos; t_stat st; +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rdrecf(unit=%d, buf=%p, max=%d)\n", uptr-ctx->dptr->units, buf, max); + opos = uptr->pos; /* old position */ if (st = sim_tape_rdlntf (uptr, &tbc)) /* read rec lnt */ return st; @@ -425,6 +771,16 @@ if (f == MTUF_F_P7B) /* p7b? strip SOR */ return (MTR_F (tbc)? MTSE_RECE: MTSE_OK); } +t_stat sim_tape_rdrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback) +{ +t_stat r = SCPE_OK; +AIO_CALLSETUP + r = sim_tape_rdrecf (uptr, buf, bc, max); +AIO_CALL(TOP_RDRF, buf, bc, NULL, max, 0, 0, 0, NULL, callback); +return r; +} + + /* Read record reverse Inputs: @@ -449,10 +805,13 @@ return (MTR_F (tbc)? MTSE_RECE: MTSE_OK); t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max) { +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; uint32 f = MT_GET_FMT (uptr); t_mtrlnt i, rbc, tbc; t_stat st; +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rdrecr(unit=%d, buf=%p, max=%d)\n", uptr-ctx->dptr->units, buf, max); + if (st = sim_tape_rdlntr (uptr, &tbc)) /* read rec lnt */ return st; *bc = rbc = MTR_L (tbc); /* strip error flag */ @@ -468,6 +827,15 @@ if (f == MTUF_F_P7B) /* p7b? strip SOR */ return (MTR_F (tbc)? MTSE_RECE: MTSE_OK); } +t_stat sim_tape_rdrecr_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback) +{ +t_stat r = SCPE_OK; +AIO_CALLSETUP + r = sim_tape_rdrecr (uptr, buf, bc, max); +AIO_CALL(TOP_RDRR, buf, bc, NULL, max, 0, 0, 0, NULL, callback); +return r; +} + /* Write record forward Inputs: @@ -487,9 +855,12 @@ return (MTR_F (tbc)? MTSE_RECE: MTSE_OK); t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc) { +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; uint32 f = MT_GET_FMT (uptr); t_mtrlnt sbc; +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrrecf(unit=%d, buf=%p, bc=%d)\n", uptr-ctx->dptr->units, buf, bc); + MT_CLR_PNU (uptr); sbc = MTR_L (bc); if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ @@ -529,6 +900,15 @@ switch (f) { /* case on format */ return MTSE_OK; } +t_stat sim_tape_wrrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt bc, TAPE_PCALLBACK callback) +{ +t_stat r = SCPE_OK; +AIO_CALLSETUP + r = sim_tape_wrrecf (uptr, buf, bc); +AIO_CALL(TOP_WREC, buf, 0, NULL, 0, bc, 0, 0, NULL, callback); +return r; +} + /* Write metadata forward (internal routine) */ t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat) @@ -552,6 +932,9 @@ return MTSE_OK; t_stat sim_tape_wrtmk (UNIT *uptr) { +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; + +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrtmk(unit=%d)\n", uptr-ctx->dptr->units); if (MT_GET_FMT (uptr) == MTUF_F_P7B) { /* P7B? */ uint8 buf = P7B_EOF; /* eof mark */ return sim_tape_wrrecf (uptr, &buf, 1); /* write char */ @@ -559,15 +942,61 @@ if (MT_GET_FMT (uptr) == MTUF_F_P7B) { /* P7B? */ return sim_tape_wrdata (uptr, MTR_TMK); } +t_stat sim_tape_wrtmk_a (UNIT *uptr, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_wrtmk (uptr); +AIO_CALL(TOP_WTMK, NULL, NULL, NULL, 0, 0, 0, 0, NULL, callback); +return r; +} + /* Write end of medium */ t_stat sim_tape_wreom (UNIT *uptr) { +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; + +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wreom(unit=%d)\n", uptr-ctx->dptr->units); if (MT_GET_FMT (uptr) == MTUF_F_P7B) /* cant do P7B */ return MTSE_FMT; return sim_tape_wrdata (uptr, MTR_EOM); } +t_stat sim_tape_wreom_a (UNIT *uptr, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_wreom (uptr); +AIO_CALL(TOP_WEOM, NULL, NULL, NULL, 0, 0, 0, 0, NULL, callback); +return r; +} + +/* Write end of medium-rewind */ + +t_stat sim_tape_wreomrw (UNIT *uptr) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; +t_stat r; + +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wreomrw(unit=%d)\n", uptr-ctx->dptr->units); +if (MT_GET_FMT (uptr) == MTUF_F_P7B) /* cant do P7B */ + return MTSE_FMT; +r = sim_tape_wrdata (uptr, MTR_EOM); +if (r == MTSE_OK) + r = sim_tape_rewind (uptr); +return r; +} + +t_stat sim_tape_wreomrw_a (UNIT *uptr, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_wreomrw (uptr); +AIO_CALL(TOP_WEMR, NULL, NULL, NULL, 0, 0, 0, 0, NULL, callback); +return r; +} + /* Write erase gap Inputs: @@ -659,6 +1088,7 @@ return sim_tape_wrdata (uptr, MTR_EOM); t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen, uint32 bpi) { +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; t_stat st; t_mtrlnt meta, sbc, new_len, rec_size; t_addr gap_pos = uptr->pos; @@ -669,6 +1099,8 @@ int32 gap_needed = (gaplen * bpi) / 10; /* gap remainder still n const uint32 meta_size = sizeof (t_mtrlnt); /* bytes per metadatum */ const uint32 min_rec_size = 2 + sizeof (t_mtrlnt) * 2; /* smallest data record size */ +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrgap(unit=%d, gaplen=%p, bpi=%d)\n", uptr-ctx->dptr->units, gaplen, bpi); + MT_CLR_PNU (uptr); if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ @@ -794,23 +1226,126 @@ while (--marker_count > 0); return MTSE_OK; } -/* Space record forward */ +t_stat sim_tape_wrgap_a (UNIT *uptr, uint32 gaplen, uint32 bpi, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_wrgap (uptr, gaplen, bpi); +AIO_CALL(TOP_RDRR, NULL, NULL, NULL, 0, 0, gaplen, bpi, NULL, callback); +return r; +} + +/* Space record forward + + Inputs: + uptr = pointer to tape unit + bc = pointer to size of record skipped + Outputs: + status = operation status + + exit condition position + + unit unattached unchanged + read error unchanged, PNU set + end of file/medium unchanged, PNU set + tape mark updated + data record updated + data record error updated +*/ t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc) { +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; t_stat st; +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecf(unit=%d)\n", uptr-ctx->dptr->units); + st = sim_tape_rdlntf (uptr, bc); /* get record length */ *bc = MTR_L (*bc); return st; } -/* Space record reverse */ +t_stat sim_tape_sprecf_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_sprecf (uptr, bc); +AIO_CALL(TOP_SPRF, NULL, bc, NULL, 0, 0, 0, 0, NULL, callback); +return r; +} + +/* Space records forward + + Inputs: + uptr = pointer to tape unit + count = count of records to skip + skipped = pointer to number of records actually skipped + Outputs: + status = operation status + + exit condition position + + unit unattached unchanged + read error unchanged, PNU set + end of file/medium unchanged, PNU set + tape mark updated + data record updated + data record error updated +*/ + +t_stat sim_tape_sprecsf (UNIT *uptr, uint32 count, uint32 *skipped) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; +t_stat st; +t_mtrlnt tbc; + +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecsf(unit=%d, count=%d)\n", uptr-ctx->dptr->units, count); + +*skipped = 0; +while (*skipped < count) { /* loopo */ + st = sim_tape_sprecf (uptr, &tbc); /* spc rec */ + if (st != MTSE_OK) + return st; + *skipped = *skipped + 1; /* # recs skipped */ + } +return MTSE_OK; +} + +t_stat sim_tape_sprecsf_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_sprecsf (uptr, count, skipped); +AIO_CALL(TOP_SRSF, NULL, skipped, NULL, 0, count, 0, 0, NULL, callback); +return r; +} + +/* Space record reverse + + Inputs: + uptr = pointer to tape unit + bc = pointer to size of records skipped + Outputs: + status = operation status + + exit condition position + + unit unattached unchanged + beginning of tape unchanged + read error unchanged + end of file unchanged + end of medium updated + tape mark updated + data record updated +*/ t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc) { +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; t_stat st; +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecr(unit=%d)\n", uptr-ctx->dptr->units); + if (MT_TST_PNU (uptr)) { MT_CLR_PNU (uptr); *bc = 0; @@ -821,15 +1356,331 @@ st = sim_tape_rdlntr (uptr, bc); /* get record length */ return st; } +t_stat sim_tape_sprecr_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_sprecr (uptr, bc); +AIO_CALL(TOP_SPRR, NULL, bc, NULL, 0, 0, 0, 0, NULL, callback); +return r; +} + +/* Space records reverse + + Inputs: + uptr = pointer to tape unit + count = count of records to skip + skipped = pointer to number of records actually skipped + Outputs: + status = operation status + + exit condition position + + unit unattached unchanged + beginning of tape unchanged + read error unchanged + end of file unchanged + end of medium updated + tape mark updated + data record updated +*/ + +t_stat sim_tape_sprecsr (UNIT *uptr, uint32 count, uint32 *skipped) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; +t_stat st; +t_mtrlnt tbc; + +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecsr(unit=%d, count=%d)\n", uptr-ctx->dptr->units, count); + +*skipped = 0; +while (*skipped < count) { /* loopo */ + st = sim_tape_sprecr (uptr, &tbc); /* spc rec rev */ + if (st != MTSE_OK) + return st; + *skipped = *skipped + 1; /* # recs skipped */ + } +return MTSE_OK; +} + +t_stat sim_tape_sprecsr_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_sprecsr (uptr, count, skipped); +AIO_CALL(TOP_SRSR, NULL, skipped, NULL, 0, count, 0, 0, NULL, callback); +return r; +} + +/* Space files forward by record + + Inputs: + uptr = pointer to tape unit + count = count of files to skip + skipped = pointer to number of files actually skipped + recsskipped = pointer to number of records skipped + Outputs: + status = operation status + + exit condition position + + unit unattached unchanged + read error unchanged, PNU set + end of file/medium unchanged, PNU set + tape mark updated + data record updated + data record error updated +*/ + +t_stat sim_tape_spfilebyrecf (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; +t_stat st; +uint32 filerecsskipped; + +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilebyrecf(unit=%d, count=%d)\n", uptr-ctx->dptr->units, count); + +*skipped = 0; +*recsskipped = 0; +while (*skipped < count) { /* loopo */ + while (1) { + st = sim_tape_sprecsf (uptr, 0x1ffffff, &filerecsskipped);/* spc recs */ + *recsskipped += filerecsskipped; + if (st != MTSE_OK) + break; + } + if (st == MTSE_TMK) + *skipped = *skipped + 1; /* # files skipped */ + else + return st; + } +return MTSE_OK; +} + +t_stat sim_tape_spfilebyrecf_a (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_spfilebyrecf (uptr, count, skipped, recsskipped); +AIO_CALL(TOP_SPFF, NULL, skipped, recsskipped, 0, count, 0, 0, NULL, callback); +return r; +} + +/* Space files forward + + Inputs: + uptr = pointer to tape unit + count = count of files to skip + skipped = pointer to number of files actually skipped + Outputs: + status = operation status + + exit condition position + + unit unattached unchanged + read error unchanged, PNU set + end of file/medium unchanged, PNU set + tape mark updated + data record updated + data record error updated +*/ + +t_stat sim_tape_spfilef (UNIT *uptr, uint32 count, uint32 *skipped) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; +uint32 totalrecsskipped; + +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilef(unit=%d, count=%d)\n", uptr-ctx->dptr->units, count); + +return sim_tape_spfilebyrecf (uptr, count, skipped, &totalrecsskipped); +} + +t_stat sim_tape_spfilef_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_spfilef (uptr, count, skipped); +AIO_CALL(TOP_SPFF, NULL, skipped, NULL, 0, count, 0, 0, NULL, callback); +return r; +} + +/* Space files reverse by record + + Inputs: + uptr = pointer to tape unit + count = count of files to skip + skipped = pointer to number of files actually skipped + recsskipped = pointer to number of records skipped + Outputs: + status = operation status + + exit condition position + + unit unattached unchanged + beginning of tape unchanged + read error unchanged + end of file unchanged + end of medium updated + tape mark updated + data record updated +*/ + +t_stat sim_tape_spfilebyrecr (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; +t_stat st; +uint32 filerecsskipped; + +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilebyrecr(unit=%d, count=%d)\n", uptr-ctx->dptr->units, count); + +*skipped = 0; +*recsskipped = 0; +while (*skipped < count) { /* loopo */ + while (1) { + st = sim_tape_sprecsr (uptr, 0x1ffffff, &filerecsskipped);/* spc recs rev */ + *recsskipped += filerecsskipped; + if (st != MTSE_OK) + break; + } + if (st == MTSE_TMK) + *skipped = *skipped + 1; /* # files skipped */ + else + return st; + } +return MTSE_OK; +} + +t_stat sim_tape_spfilebyrecr_a (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_spfilebyrecr (uptr, count, skipped, recsskipped); +AIO_CALL(TOP_SPFR, NULL, skipped, recsskipped, 0, count, 0, 0, NULL, callback); +return r; +} + +/* Space files reverse + + Inputs: + uptr = pointer to tape unit + count = count of files to skip + skipped = pointer to number of files actually skipped + Outputs: + status = operation status + + exit condition position + + unit unattached unchanged + beginning of tape unchanged + read error unchanged + end of file unchanged + end of medium updated + tape mark updated + data record updated +*/ + +t_stat sim_tape_spfiler (UNIT *uptr, uint32 count, uint32 *skipped) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; +uint32 totalrecsskipped; + +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfiler(unit=%d, count=%d)\n", uptr-ctx->dptr->units, count); + +return sim_tape_spfilebyrecr (uptr, count, skipped, &totalrecsskipped); +} + +t_stat sim_tape_spfiler_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_spfiler (uptr, count, skipped); +AIO_CALL(TOP_SPFR, NULL, skipped, NULL, 0, count, 0, 0, NULL, callback); +return r; +} + /* Rewind tape */ t_stat sim_tape_rewind (UNIT *uptr) { +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; + +if (uptr->flags & UNIT_ATT) + sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rewind(unit=%d)\n", uptr-ctx->dptr->units); uptr->pos = 0; MT_CLR_PNU (uptr); return MTSE_OK; } +t_stat sim_tape_rewind_a (UNIT *uptr, TAPE_PCALLBACK callback) +{ +t_stat r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_rewind (uptr); +AIO_CALL(TOP_RWND, NULL, NULL, NULL, 0, 0, 0, 0, NULL, callback); +return r; +} + +/* Position Tape */ + +t_stat sim_tape_position (UNIT *uptr, uint8 flags, uint32 recs, uint32 *recsskipped, uint32 files, uint32 *filesskipped, uint32 *objectsskipped) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; +t_stat r = MTSE_OK; + +sim_debug (ctx->dbit, ctx->dptr, "sim_tape_position(unit=%d, flags=0x%X, recs=%d, files=%d)\n", uptr-ctx->dptr->units, flags, recs, files); + +*recsskipped = *filesskipped = *objectsskipped = 0; +if (flags & MTPOS_M_REW) + r = sim_tape_rewind (uptr); +if (r != MTSE_OK) + return r; +if (flags & MTPOS_M_OBJ) { + uint32 objs = recs; + uint32 skipped; + uint32 objsremaining = objs; + + while (*objectsskipped < objs) { /* loopo */ + if (flags & MTPOS_M_REV) /* reverse? */ + r = sim_tape_sprecsr (uptr, objsremaining, &skipped); + else + r = sim_tape_sprecsf (uptr, objsremaining, &skipped); + objsremaining = objsremaining - (skipped + ((r == MTSE_TMK) ? 1 : 0)); + if ((r == MTSE_TMK) || (r == MTSE_OK)) + *objectsskipped = *objectsskipped + skipped + ((r == MTSE_TMK) ? 1 : 0); + else + return r; + } + r = MTSE_OK; + } +else { + uint32 fileskiprecs; + + if (flags & MTPOS_M_REV) /* reverse? */ + r = sim_tape_spfilebyrecr (uptr, files, filesskipped, &fileskiprecs); + else + r = sim_tape_spfilebyrecf (uptr, files, filesskipped, &fileskiprecs); + if (r != MTSE_OK) + return r; + if (flags & MTPOS_M_REV) /* reverse? */ + r = sim_tape_sprecsr (uptr, recs, recsskipped); + else + r = sim_tape_sprecsf (uptr, recs, recsskipped); + if (r == MTSE_TMK) + *filesskipped = *filesskipped + 1; + *objectsskipped = fileskiprecs + *filesskipped + *recsskipped; + } +return r; +} + +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 r = MTSE_OK; +AIO_CALLSETUP + r = sim_tape_position (uptr, flags, recs, recsskipped, files, filesskipped, objectsskipped); +AIO_CALL(TOP_POSN, NULL, recsskipped, filesskipped, 0, flags, recs, files, objectsskipped, callback); +return r; +} + /* Reset tape */ t_stat sim_tape_reset (UNIT *uptr) diff --git a/sim_tape.h b/sim_tape.h index 22eb4aac..f851ff6e 100644 --- a/sim_tape.h +++ b/sim_tape.h @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings 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 14-Feb-06 RMS Added variable tape capacity 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_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 */ #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_WRP 9 /* write protected */ +typedef void (*TAPE_PCALLBACK)(UNIT *unit, t_stat status); + /* 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_detach (UNIT *uptr); 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_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_a (UNIT *uptr, uint8 *buf, t_mtrlnt bc, TAPE_PCALLBACK callback); 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_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_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_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_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_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_bool sim_tape_bot (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_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_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 diff --git a/sim_timer.c b/sim_timer.c index 783661e1..7d482f99 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 05-Jan-11 MP Added Asynch I/O support 29-Dec-10 MP Fixed clock resolution determination for Unix platforms 22-Sep-08 RMS Added "stability threshold" for idle routine 27-May-08 RMS Fixed bug in Linux idle routines (from Walter Mueller) @@ -52,6 +53,7 @@ #include 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_stable = SIM_IDLE_STDFLT; @@ -77,6 +79,11 @@ UNIT sim_throt_unit = { UDATA (&sim_throt_svc, 0, 0) }; #if defined (__VAX) #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 #include @@ -139,10 +146,30 @@ sys$waitfr (2); 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) +/* Win32 routines */ + #include const t_bool rtc_avail = TRUE; @@ -193,10 +220,26 @@ Sleep (msec); 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__) +/* OS/2 routines, from Bruce Ray */ + const t_bool rtc_avail = FALSE; uint32 sim_os_msec () @@ -267,6 +310,22 @@ treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI; 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 /* UNIX routines */ @@ -312,6 +371,24 @@ if (tim > SIM_IDLE_MAX) tim = 0; return tim; } +#if !defined(_POSIX_SOURCE) && defined(SIM_ASYNCH_IO) +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 1 +typedef int clockid_t; +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 /* CLOCK_REALTIME */ +#endif /* !defined(_POSIX_SOURCE) && defined(SIM_ASYNCH_IO) */ uint32 sim_os_ms_sleep (unsigned int milliseconds) { @@ -326,6 +403,31 @@ return sim_os_msec () - stime; #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 */ static int32 rtc_ticks[SIM_NTIMERS] = { 0 }; /* ticks */ @@ -407,6 +509,7 @@ if (rtc_based[tmr] <= 0) /* never negative or zer rtc_based[tmr] = 1; if (rtc_currd[tmr] <= 0) /* never negative or zero! */ rtc_currd[tmr] = 1; +AIO_SET_INTERRUPT_LATENCY(rtc_currd[tmr]*ticksper); /* set interrrupt latency */ return rtc_currd[tmr]; } @@ -446,7 +549,8 @@ return (sim_idle_rate_ms != 0); 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; if ((sim_clock_queue == NULL) || /* clock queue empty? */ @@ -456,7 +560,8 @@ if ((sim_clock_queue == NULL) || /* clock queue empty? */ sim_interval = sim_interval - 1; 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 (sin_cyc) sim_interval = sim_interval - 1; @@ -469,11 +574,11 @@ if (w_idle == 0) { /* none? */ sim_interval = sim_interval - 1; 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; if (sim_interval > act_cyc) sim_interval = sim_interval - act_cyc; -else sim_interval = 1; +else sim_interval = 0; return TRUE; } diff --git a/swtp/swtp_cpu.c b/swtp/swtp_cpu.c index 09cdaa83..e01f1d7e 100644 --- a/swtp/swtp_cpu.c +++ b/swtp/swtp_cpu.c @@ -161,7 +161,7 @@ address is here, 'nulldev' means no device is available */ struct idev { - int32 (*routine)(); + int32 (*routine)(int32, int32); }; struct idev dev_table[32] = { @@ -405,7 +405,7 @@ int32 sim_instr (void) } */ IR = OP = mem_get_byte(PC); /* fetch instruction */ - PC = ++PC & ADDRMASK; /* increment PC */ + PC = (PC + 1) & ADDRMASK; /* increment PC */ sim_interval--; /* The Big Instruction Decode Switch */ @@ -421,11 +421,11 @@ int32 sim_instr (void) A = get_psw(); break; case 0x08: /* INX */ - IX = ++IX & ADDRMASK; + IX = (IX + 1) & ADDRMASK; condevalZ(IX); break; case 0x09: /* DEX */ - IX = --IX & ADDRMASK; + IX = (IX + 1) & ADDRMASK; condevalZ(IX); break; case 0x0A: /* CLV */ @@ -558,60 +558,60 @@ int32 sim_instr (void) IX = (SP + 1) & ADDRMASK; break; case 0x31: /* INS */ - SP = ++SP & ADDRMASK; + SP = (SP + 1) & ADDRMASK; break; case 0x32: /* PUL A */ - SP = ++SP & ADDRMASK; + SP = (SP + 1) & ADDRMASK; A = mem_get_byte(SP); break; case 0x33: /* PUL B */ - SP = ++SP & ADDRMASK; + SP = (SP + 1) & ADDRMASK; B = mem_get_byte(SP); break; case 0x34: /* DES */ - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; break; case 0x35: /* TXS */ SP = (IX - 1) & ADDRMASK; break; case 0x36: /* PSH A */ mem_put_byte(SP, A); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; break; case 0x37: /* PSH B */ mem_put_byte(SP, B); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; break; case 0x39: /* RTS */ - SP = ++SP & ADDRMASK; + SP = (SP + 1) & ADDRMASK; PC = mem_get_word(SP) & ADDRMASK; - SP = ++SP & ADDRMASK; + SP = (SP + 1) & ADDRMASK; break; case 0x3B: /* RTI */ - SP = ++SP & ADDRMASK; + SP = (SP + 1) & ADDRMASK; set_psw(mem_get_byte(SP)); - SP = ++SP & ADDRMASK; + SP = (SP + 1) & ADDRMASK; B = mem_get_byte(SP); - SP = ++SP & ADDRMASK; + SP = (SP + 1) & ADDRMASK; A = mem_get_byte(SP); - SP = ++SP & ADDRMASK; + SP = (SP + 1) & ADDRMASK; IX = mem_get_word(SP); - SP = (SP += 2) & ADDRMASK; + SP = (SP + 2) & ADDRMASK; PC = mem_get_word(SP) & ADDRMASK; - SP = ++SP & ADDRMASK; + SP = (SP + 1) & ADDRMASK; break; case 0x3E: /* WAI */ - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; mem_put_word(SP, PC); - SP = (SP -= 2) & ADDRMASK; + SP = (SP - 2) & ADDRMASK; mem_put_word(SP, IX); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; mem_put_byte(SP, A); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; mem_put_byte(SP, B); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; mem_put_byte(SP, get_psw()); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; if (I) { reason = STOP_HALT; continue; @@ -621,17 +621,17 @@ int32 sim_instr (void) } break; case 0x3F: /* SWI */ - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; mem_put_word(SP, PC); - SP = (SP -= 2) & ADDRMASK; + SP = (SP - 2) & ADDRMASK; mem_put_word(SP, IX); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; mem_put_byte(SP, A); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; mem_put_byte(SP, B); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; mem_put_byte(SP, get_psw()); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; I = 0x10000; PC = mem_get_word(0xFFFB) & ADDRMASK; break; @@ -720,7 +720,7 @@ int32 sim_instr (void) V = 0; if (A == 0x80) V = 0x10000; - A = --A & 0xFF; + A = (A - 1) & 0xFF; condevalN(A); condevalZ(A); break; @@ -728,7 +728,7 @@ int32 sim_instr (void) V = 0; if (A == 0x7F) V = 0x10000; - A = ++A & 0xFF; + A = (A + 1) & 0xFF; condevalN(A); condevalZ(A); break; @@ -829,7 +829,7 @@ int32 sim_instr (void) V = 0; if (B == 0x80) V = 0x10000; - B = --B & 0xFF; + B = (B - 1) & 0xFF; condevalN(B); condevalZ(B); break; @@ -837,7 +837,7 @@ int32 sim_instr (void) V = 0; if (B == 0x7F) V = 0x10000; - B = ++B & 0xFF; + B = (B + 1) & 0xFF; condevalN(B); condevalZ(B); break; @@ -957,7 +957,7 @@ int32 sim_instr (void) V = 0; if (lo == 0x80) V = 0x10000; - lo = --lo & 0xFF; + lo = (lo - 1) & 0xFF; mem_put_byte(DAR, lo); condevalN(lo); condevalZ(lo); @@ -968,7 +968,7 @@ int32 sim_instr (void) V = 0; if (lo == 0x7F) V = 0x10000; - lo = ++lo & 0xFF; + lo = (lo + 1) & 0xFF; mem_put_byte(DAR, lo); condevalN(lo); condevalZ(lo); @@ -1094,7 +1094,7 @@ int32 sim_instr (void) V = 0; if (lo == 0x80) V = 0x10000; - lo = --lo & 0xFF; + lo = (lo - 1) & 0xFF; mem_put_byte(DAR, lo); condevalN(lo); condevalZ(lo); @@ -1105,7 +1105,7 @@ int32 sim_instr (void) V = 0; if (lo == 0x7F) V = 0x10000; - lo = ++lo & 0xFF; + lo = (lo + 1) & 0xFF; mem_put_byte(DAR, lo); condevalN(lo); condevalZ(lo); @@ -1215,9 +1215,9 @@ int32 sim_instr (void) break; case 0x8D: /* BSR rel */ lo = get_rel_addr(); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; mem_put_word(SP, PC); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; PC = PC + lo; PC &= ADDRMASK; break; @@ -1429,9 +1429,9 @@ int32 sim_instr (void) break; case 0xAD: /* JSR ind */ DAR = get_indir_addr(); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; mem_put_word(SP, PC); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; PC = DAR; break; case 0xAE: /* LDS ind */ @@ -1542,9 +1542,9 @@ int32 sim_instr (void) break; case 0xBD: /* JSR ext */ DAR = get_ext_addr(); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; mem_put_word(SP, PC); - SP = --SP & ADDRMASK; + SP = (SP - 1) & ADDRMASK; PC = DAR; break; case 0xBE: /* LDS ext */ @@ -2010,7 +2010,7 @@ int32 get_dir_addr() int32 temp; temp = mem_get_byte(PC); - PC = ++PC & ADDRMASK; + PC = (PC + 1) & ADDRMASK; return temp & 0xFF; } diff --git a/swtp/swtp_defs.h b/swtp/swtp_defs.h index 9e946c18..cf9041ad 100644 --- a/swtp/swtp_defs.h +++ b/swtp/swtp_defs.h @@ -27,7 +27,7 @@ Copyright (c) 2005, 2007, William Beech */ -#include "../sim_defs.h" // simulator defs +#include "sim_defs.h" // simulator defs /* Memory */ diff --git a/swtp/swtp_dsk.c b/swtp/swtp_dsk.c index 3a636279..b41943ef 100644 --- a/swtp/swtp_dsk.c +++ b/swtp/swtp_dsk.c @@ -408,7 +408,7 @@ int32 fdccmd(int32 io, int32 data) #endif break; default: - printf("Unknown FDC command %02H\n\r", data); + printf("Unknown FDC command %02X\n\r", data); } } else { /* read status from fdc */ val = cur_flg[cur_dsk]; /* set return value */ diff --git a/swtp/swtp_sio.c b/swtp/swtp_sio.c index 859074c4..1f6f8a77 100644 --- a/swtp/swtp_sio.c +++ b/swtp/swtp_sio.c @@ -114,7 +114,7 @@ int32 ptp_flag = 0, ptr_flag = 0; /* console input service routine */ -int32 sio_svc (UNIT *uptr) +t_stat sio_svc (UNIT *uptr) { int32 temp; @@ -132,21 +132,21 @@ int32 sio_svc (UNIT *uptr) /* paper tape reader input service routine */ -int32 ptr_svc (UNIT *uptr) +t_stat ptr_svc (UNIT *uptr) { return SCPE_OK; } /* paper tape punch output service routine */ -int32 ptp_svc (UNIT *uptr) +t_stat ptp_svc (UNIT *uptr) { return SCPE_OK; } /* Reset console */ -int32 sio_reset (DEVICE *dptr) +t_stat sio_reset (DEVICE *dptr) { sio_unit.buf = 0; // Data buffer sio_unit.u3 = 0x02; // Status buffer @@ -156,7 +156,7 @@ int32 sio_reset (DEVICE *dptr) /* Reset paper tape reader */ -int32 ptr_reset (DEVICE *dptr) +t_stat ptr_reset (DEVICE *dptr) { ptr_unit.buf = 0; ptr_unit.u3 = 0x02; @@ -166,7 +166,7 @@ int32 ptr_reset (DEVICE *dptr) /* Reset paper tape punch */ -int32 ptp_reset (DEVICE *dptr) +t_stat ptp_reset (DEVICE *dptr) { ptp_unit.buf = 0; ptp_unit.u3 = 0x02;