Merge branch 'master' into Extra-VAXen
Conflicts: makefile
This commit is contained in:
commit
3e10dfbd95
25 changed files with 2029 additions and 1269 deletions
|
@ -5,6 +5,9 @@ Theory of operation.
|
|||
Features.
|
||||
- Optional Use. Build with or without SIM_ASYNCH_IO defined and
|
||||
simulators will still build and perform correctly when run.
|
||||
Additionmally, a simulator built with SIM_ASYNCH_IO defined can
|
||||
dynamically disable and reenable asynchronous operation with
|
||||
the scp commands SET NOASYNCH and SET ASYNCH respectively.
|
||||
- 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
|
||||
|
|
|
@ -43,9 +43,9 @@ bridge, or route TAP devices for you.
|
|||
Integrated Universal TUN/TAP support can be used for host<->simulator network
|
||||
traffic (on the platforms where it is available) by using the SIMH command:
|
||||
"attach xq tap:tapN" (i.e. attach xq tap:tap0). Platforms that this has been
|
||||
tested on include: Linux, FreeBSD, OpenBSD, NetBSD. Each of these platforms
|
||||
has some way to create a tap pseudo device and then bridge it with a physical
|
||||
network interface.
|
||||
tested on include: Linux, FreeBSD, OpenBSD, NetBSD and OSX. Each of these
|
||||
platforms has some way to create a tap pseudo device (and possibly then to
|
||||
bridge it with a physical network interface).
|
||||
|
||||
The following steps were performed to get a working SIMH vax simulator
|
||||
sharing a physical NIC and allowing Host<->SIMH vax communications:
|
||||
|
@ -117,6 +117,53 @@ NetBSD (NetBSD 5.0.2)
|
|||
|
||||
# Run simulator and "attach xq tap:tap0"
|
||||
|
||||
OSX (Snow Leopard)
|
||||
OSX Does NOT have native support for tun/tap interfaces. It also does not have native
|
||||
support for bridging.
|
||||
|
||||
Mattias Nissler has created tun/tap functionality available at http://tuntaposx,sourceforge.net/
|
||||
|
||||
We'll punt on bridging for the sake of this example and move on to use a basic tap
|
||||
based internal network so a host and guest can communicate directly.
|
||||
|
||||
Download the install package from:
|
||||
http://sourceforge.net/projects/tuntaposx/files/tuntap/20090913/tuntap_20090913.tar.gz
|
||||
|
||||
Expand the tarball to a directory.
|
||||
Invoke the package installer tuntap_20090913.pkg
|
||||
Click through the various prompts accepting things and eventually installing the package.
|
||||
|
||||
# Build and Run simulator and:
|
||||
sim> attach xq tap:tap0
|
||||
sim> ! ifconfig tap0 192.168.6.1 netmask 255.255.255.0
|
||||
|
||||
Simulated system uses IP address 192.168.6.2 and host uses 192.167.6.1
|
||||
and things work.
|
||||
You must run as root for this to work.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
An alternative to direct pcap and tun/tap networking on *nix environments is
|
||||
VDE (Virtual Distributed Ethernet).
|
||||
|
||||
Note 1: Using vde based networking is likely more flexible, but it isn't
|
||||
nearly as efficient. Host OS overhead will always be higher when
|
||||
vde networking is used as compared to native pcap and/or tun/tap
|
||||
networking.
|
||||
Note 2: Root access will likely be needed to configure or start the vde
|
||||
environment prior to starting a simulator which may use it.
|
||||
Note 3: Simulators running using VDE networking can run without root
|
||||
privilege.
|
||||
|
||||
Linux (Ubuntu 10.04):
|
||||
apt-get install libvdeplug-dev
|
||||
apt-get install vde2
|
||||
|
||||
vde_switch -s /tmp/switch1 -tap tap0 -m 666
|
||||
ifconfig tap0 192.168.6.1 netmask 255.255.255.0 up
|
||||
|
||||
# Build and Run simulator and:
|
||||
sim> attach xq vde:/tmp/switch1 #simulator uses IP address 192.168.6.2
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Windows notes:
|
||||
|
@ -134,6 +181,11 @@ Windows notes:
|
|||
|
||||
|
||||
Building on Windows:
|
||||
Building with MinGW can use the provided makefile following the instructions
|
||||
below. Alternatively, you can use the free Visual C++ Express 2008 or 2010
|
||||
interactive development environments. Read the file
|
||||
".\Visual Studio Projects\0ReadMe_Projects.txt" for details.
|
||||
|
||||
1. Install WinPCAP 4.x runtime and the WinPCAP Developer's kit.
|
||||
|
||||
2. Put the required .h files (bittypes,devioctl,ip6_misc,pcap,pcap-stdinc
|
||||
|
@ -159,8 +211,11 @@ Linux, {Free|Net|Open}BSD, OS/X, and Un*x notes:
|
|||
----- WARNING ----- WARNING ----- WARNING ----- WARNING ----- WARNING -----
|
||||
|
||||
Sim_Ether has been reworked to be more universal; because of this, you will
|
||||
need to get a version of libpcap that is 0.9 or greater. This can be
|
||||
downloaded from www.tcpdump.org - see the comments at the top of Sim_ether.c
|
||||
need to get a version of libpcap that is 0.9 or greater. All current Linux
|
||||
distributions provide a libpcap-dev package which has the needed version
|
||||
of libpcap and the required components to build applications using it.
|
||||
If you are running an older Linux OS, you can download and build the required
|
||||
library from www.tcpdump.org - see the comments at the top of Sim_ether.c
|
||||
for details.
|
||||
|
||||
----- WARNING ----- WARNING ----- WARNING ----- WARNING ----- WARNING -----
|
||||
|
@ -187,11 +242,13 @@ for details.
|
|||
will be welcomed.
|
||||
|
||||
2. If you want to use TAP devices, and any surrounding system network/bridge
|
||||
setup must be done before running SIMH.
|
||||
setup must be done before running SIMH. However, once that is done
|
||||
(possibly at system boot time), using the TAP devices can be done without
|
||||
root privileges.
|
||||
|
||||
Building on Linux, {Free|Net|Open}BSD, OS/X, Un*x:
|
||||
|
||||
1. Get/make/install the libpcap package for your operating system. Sources:
|
||||
1. Get/make/install the libpcap-dev package for your operating system. Sources:
|
||||
All : http://www.tcpdump.org/
|
||||
Older versions of libpcap can be found, for various systems, at:
|
||||
Linux : search for your variant on http://rpmfind.net
|
||||
|
@ -214,7 +271,7 @@ Building on Linux, {Free|Net|Open}BSD, OS/X, Un*x:
|
|||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
OpenVMS Alpha notes:
|
||||
OpenVMS Alpha and OpenVMS Integrety (IA64) notes:
|
||||
1. Ethernet support will only work on Alpha VMS 7.3-1 or later, which is
|
||||
when required VCI promiscuous mode support was added. Hobbyists can
|
||||
get the required version of VMS from the OpenVMS Alpha Hobbyist Kit 3.0.
|
||||
|
@ -247,10 +304,10 @@ OpenVMS Alpha notes:
|
|||
adapter prior trying to connect with SIMH, or the host may crash.
|
||||
The execlet is not written to create an I/O structure for the device.
|
||||
|
||||
Building on OpenVMS Alpha:
|
||||
Building on OpenVMS Alpha and OpenVMS Integrety (IA64):
|
||||
The current descrip.mms file will build simulators capable of using
|
||||
Ethernet support with them automatically. These currently are: VAX,
|
||||
PDP11, and PDP10. The descrip.mms driven builds will also build the
|
||||
VAX780, and PDP11. The descrip.mms driven builds will also build the
|
||||
pcap library and build and install the VCI execlet.
|
||||
|
||||
1. Fetch the VMS-PCAP zip file from:
|
||||
|
@ -321,6 +378,17 @@ Dave
|
|||
Change Log
|
||||
===============================================================================
|
||||
|
||||
30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking
|
||||
29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX
|
||||
17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and
|
||||
vector assignments
|
||||
12-Aug-11 MP Cleaned up payload length determination
|
||||
Fixed race condition detecting reflections when threaded
|
||||
reading and writing is enabled
|
||||
07-Jul-11 MB VMS Pcap (from Mike Burke)
|
||||
- Fixed Alpha issues
|
||||
- Added OpenVMS Integrety support
|
||||
20-Apr-11 MP Fixed save/restore behavior
|
||||
12-Jan-11 DTH Added SHOW XU FILTERS modifier
|
||||
11-Jan-11 DTH Corrected DEUNA/DELUA SELFTEST command, enabling use by
|
||||
VMS 3.7, VMS 4.7, and Ultrix 1.1
|
||||
|
|
|
@ -469,7 +469,7 @@ den = GET_DEN (tutc); /* get density */
|
|||
uptr = tu_dev.units + drv; /* get unit */
|
||||
if (DEBUG_PRS (tu_dev)) {
|
||||
fprintf (sim_deb, ">>TU%d STRT: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=",
|
||||
drv, tu_fname[fnc], tufc, tufs, tuer, uptr->pos);
|
||||
drv, tu_fname[fnc], tufc, tufs, tuer);
|
||||
fprint_val (sim_deb, uptr->pos, 10, T_ADDR_W, PV_LEFT);
|
||||
fprintf (sim_deb, "\n");
|
||||
}
|
||||
|
|
|
@ -2584,6 +2584,7 @@ t_stat xq_attach(UNIT* uptr, char* cptr)
|
|||
if (xq->var->poll == 0) {
|
||||
status = eth_set_async(xq->var->etherface, xq->var->coalesce_latency_ticks);
|
||||
if (status != SCPE_OK) {
|
||||
eth_close(xq->var->etherface);
|
||||
free(tptr);
|
||||
free(xq->var->etherface);
|
||||
xq->var->etherface = NULL;
|
||||
|
|
|
@ -87,7 +87,7 @@ extern int32 int_req[IPL_HLVL];
|
|||
|
||||
#define XQ_QUE_MAX 500 /* read queue size in packets */
|
||||
#define XQ_FILTER_MAX 14 /* number of filters allowed */
|
||||
#if defined SIM_ASYNCH_IO
|
||||
#if defined(SIM_ASYNCH_IO) && defined(USE_READER_THREAD)
|
||||
#define XQ_SERVICE_INTERVAL 0 /* polling interval - No Polling with Asynch I/O */
|
||||
#else
|
||||
#define XQ_SERVICE_INTERVAL 100 /* polling interval - X per second */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* pdp8_fpp.c: PDP-8 floating point processor (FPP8A)
|
||||
|
||||
Copyright (c) 2007-2011, Robert M Supnik
|
||||
Copyright (c) 2007-2010, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* pdp8_sys.c: PDP-8 simulator interface
|
||||
|
||||
Copyright (c) 1993-2011, Robert M Supnik
|
||||
Copyright (c) 1993-2009, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -24,7 +24,7 @@
|
|||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
24-Mar-09 RMS Added link to FPP
|
||||
24-Jun-08 RMS Fixed bug in new rim loader (Don North)
|
||||
24-Jun-08 RMS Fixed bug in new rim loader (found by Don North)
|
||||
24-May-08 RMS Fixed signed/unsigned declaration inconsistency
|
||||
03-Sep-07 RMS Added FPP8 support
|
||||
Rewrote rim and binary loaders
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
td TD8E/TU56 DECtape
|
||||
|
||||
23-Mar-11 RMS Fixed SDLC to clear AC (from Dave Gesswein)
|
||||
23-Jun-06 RMS Fixed switch conflict in ATTACH
|
||||
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
||||
09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR
|
||||
|
@ -302,6 +303,7 @@ switch (pulse) {
|
|||
if (td_newsa (td_cmd)) /* new command */
|
||||
return AC | (IORETURN (td_stopoffr, STOP_DTOFF) << IOT_V_REASON);
|
||||
}
|
||||
AC = 0;
|
||||
break;
|
||||
|
||||
case 05: /* SDLD */
|
||||
|
|
|
@ -30,11 +30,34 @@
|
|||
todr TODR clock
|
||||
tmr interval timer
|
||||
|
||||
28-Sep-11 MP Generalized setting TODR for all OSes.
|
||||
Unbound the TODR value from the 100hz clock tick
|
||||
interrupt. TODR now behaves like the original
|
||||
battery backed-up clock and runs with the wall
|
||||
clock, not the simulated instruction clock.
|
||||
Two operational modes are available:
|
||||
- Default VMS mode, which is similar to the previous
|
||||
behavior in that without initializing the TODR it
|
||||
would default to the value VMS would set it to if
|
||||
VMS knew the correct time. This would be correct
|
||||
almost all the time unless a VMS disk hadn't been
|
||||
booted from for more than a year. This mode
|
||||
produces strange time results for non VMS OSes on
|
||||
each system boot.
|
||||
- OS Agnostic mode. This mode behaves precisely like
|
||||
the VAX780 TODR and works correctly for all OSes.
|
||||
This mode is enabled by attaching the TODR to a
|
||||
battery backup state file for the TOY clock
|
||||
(i.e. sim> attach TODR TOY_CLOCK). When operating
|
||||
in OS Agnostic mode, the TODR will initially start
|
||||
counting from 0 and be adjusted differently when an
|
||||
OS specifically writes to the TODR. VMS will prompt
|
||||
to set the time on each boot unless the SYSGEN
|
||||
parameter TIMEPROMPTWAIT is set to 0.
|
||||
29-Mar-2011 MB First Version
|
||||
*/
|
||||
|
||||
#include "vax_defs.h"
|
||||
#include <time.h>
|
||||
|
||||
/* Terminal definitions */
|
||||
|
||||
|
@ -159,6 +182,11 @@ int32 clk_tps = 100; /* ticks/second */
|
|||
int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */
|
||||
int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
|
||||
int32 todr_reg = 0; /* TODR register */
|
||||
struct todr_battery_info {
|
||||
uint32 toy_gmtbase; /* GMT base of set value */
|
||||
uint32 toy_gmtbasemsec; /* The milliseconds of the set value */
|
||||
};
|
||||
typedef struct todr_battery_info TOY;
|
||||
|
||||
int32 td_swait = 100; /* seek, per block */
|
||||
int32 td_cwait = 150; /* command time */
|
||||
|
@ -187,6 +215,8 @@ t_stat tmr_svc (UNIT *uptr);
|
|||
t_stat tti_reset (DEVICE *dptr);
|
||||
t_stat tto_reset (DEVICE *dptr);
|
||||
t_stat clk_reset (DEVICE *dptr);
|
||||
t_stat clk_attach (UNIT *uptr, char *cptr);
|
||||
t_stat clk_detach (UNIT *uptr);
|
||||
t_stat tmr_reset (DEVICE *dptr);
|
||||
t_stat td_svc (UNIT *uptr);
|
||||
t_stat td_reset (DEVICE *dptr);
|
||||
|
@ -269,7 +299,7 @@ DEVICE tto_dev = {
|
|||
|
||||
/* TODR and TMR data structures */
|
||||
|
||||
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY }; /* 100Hz */
|
||||
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE+UNIT_FIX, sizeof(TOY)), CLK_DELAY };/* 100Hz */
|
||||
|
||||
REG clk_reg[] = {
|
||||
{ DRDATA (TODR, todr_reg, 32), PV_LEFT },
|
||||
|
@ -280,9 +310,9 @@ REG clk_reg[] = {
|
|||
|
||||
DEVICE clk_dev = {
|
||||
"TODR", &clk_unit, clk_reg, NULL,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
1, 0, 8, 1, 0, 0,
|
||||
NULL, NULL, &clk_reset,
|
||||
NULL, NULL, NULL,
|
||||
NULL, &clk_attach, &clk_detach,
|
||||
NULL, 0
|
||||
};
|
||||
|
||||
|
@ -763,7 +793,6 @@ 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 */
|
||||
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 */
|
||||
return SCPE_OK;
|
||||
|
@ -836,9 +865,44 @@ t_stat clk_reset (DEVICE *dptr)
|
|||
tmr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init 100Hz timer */
|
||||
sim_activate_abs (&clk_unit, tmr_poll); /* activate 100Hz unit */
|
||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||
if (clk_unit.filebuf == NULL) { /* make sure the TODR is initialized */
|
||||
clk_unit.filebuf = calloc(sizeof(TOY), 1);
|
||||
if (clk_unit.filebuf == NULL)
|
||||
return SCPE_MEM;
|
||||
todr_resync ();
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* CLK attach */
|
||||
|
||||
t_stat clk_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
uptr->flags = uptr->flags | (UNIT_ATTABLE | UNIT_BUFABLE);
|
||||
memset (uptr->filebuf, 0, (size_t)uptr->capac);
|
||||
r = attach_unit (uptr, cptr);
|
||||
if (r != SCPE_OK)
|
||||
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
|
||||
else
|
||||
uptr->hwmark = (uint32) uptr->capac;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* CLK detach */
|
||||
|
||||
t_stat clk_detach (UNIT *uptr)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
r = detach_unit (uptr);
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* Interval timer reset */
|
||||
|
||||
t_stat tmr_reset (DEVICE *dptr)
|
||||
|
@ -857,32 +921,58 @@ return SCPE_OK;
|
|||
|
||||
int32 todr_rd (void)
|
||||
{
|
||||
return todr_reg;
|
||||
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||
struct timespec base, now, val;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &now); /* get curr time */
|
||||
base.tv_sec = toy->toy_gmtbase;
|
||||
base.tv_nsec = toy->toy_gmtbasemsec * 1000000;
|
||||
sim_timespec_diff (&val, &now, &base);
|
||||
return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */
|
||||
}
|
||||
|
||||
void todr_wr (int32 data)
|
||||
{
|
||||
todr_reg = data;
|
||||
return;
|
||||
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||
struct timespec now, val, base;
|
||||
|
||||
/* Save the GMT time when set value was 0 to record the base for future
|
||||
read operations in "battery backed-up" state */
|
||||
|
||||
if (-1 == clock_gettime(CLOCK_REALTIME, &now)) /* get curr time */
|
||||
return; /* error? */
|
||||
val.tv_sec = ((uint32)data) / 100;
|
||||
val.tv_nsec = (((uint32)data) % 100) * 10000000;
|
||||
sim_timespec_diff (&base, &now, &val); /* base = now - data */
|
||||
toy->toy_gmtbase = base.tv_sec;
|
||||
toy->toy_gmtbasemsec = base.tv_nsec/1000000;
|
||||
}
|
||||
|
||||
t_stat todr_resync (void)
|
||||
{
|
||||
uint32 base;
|
||||
time_t curr;
|
||||
struct tm *ctm;
|
||||
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||
|
||||
curr = time (NULL); /* get curr time */
|
||||
if (curr == (time_t) -1) /* error? */
|
||||
if (clk_unit.flags & UNIT_ATT) { /* Attached means behave like real VAX780 */
|
||||
if (!toy->toy_gmtbase) /* Never set? */
|
||||
todr_wr (0); /* Start ticking from 0 */
|
||||
}
|
||||
else { /* Not-Attached means */
|
||||
uint32 base; /* behave like simh VMS default */
|
||||
time_t curr;
|
||||
struct tm *ctm;
|
||||
|
||||
curr = time (NULL); /* get curr time */
|
||||
if (curr == (time_t) -1) /* error? */
|
||||
return SCPE_NOFNC;
|
||||
ctm = localtime (&curr); /* decompose */
|
||||
if (ctm == NULL) /* error? */
|
||||
ctm = localtime (&curr); /* decompose */
|
||||
if (ctm == NULL) /* error? */
|
||||
return SCPE_NOFNC;
|
||||
base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */
|
||||
base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */
|
||||
ctm->tm_hour) * 60) +
|
||||
ctm->tm_min) * 60) +
|
||||
ctm->tm_sec;
|
||||
todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */
|
||||
todr_wr ((base * 100) + 0x10000000); /* use VMS form */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,30 @@
|
|||
todr TODR clock
|
||||
tmr interval timer
|
||||
|
||||
28-Sep-11 MP Generalized setting TODR for all OSes.
|
||||
Unbound the TODR value from the 100hz clock tick
|
||||
interrupt. TODR now behaves like the original
|
||||
battery backed-up clock and runs with the wall
|
||||
clock, not the simulated instruction clock.
|
||||
Two operational modes are available:
|
||||
- Default VMS mode, which is similar to the previous
|
||||
behavior in that without initializing the TODR it
|
||||
would default to the value VMS would set it to if
|
||||
VMS knew the correct time. This would be correct
|
||||
almost all the time unless a VMS disk hadn't been
|
||||
booted from for more than a year. This mode
|
||||
produces strange time results for non VMS OSes on
|
||||
each system boot.
|
||||
- OS Agnostic mode. This mode behaves precisely like
|
||||
the VAX780 TODR and works correctly for all OSes.
|
||||
This mode is enabled by attaching the TODR to a
|
||||
battery backup state file for the TOY clock
|
||||
(i.e. sim> attach TODR TOY_CLOCK). When operating
|
||||
in OS Agnostic mode, the TODR will initially start
|
||||
counting from 0 and be adjusted differently when an
|
||||
OS specifically writes to the TODR. VMS will prompt
|
||||
to set the time on each boot unless the SYSGEN
|
||||
parameter TIMEPROMPTWAIT is set to 0.
|
||||
21-Mar-11 RMS Added reboot capability
|
||||
17-Aug-08 RMS Resync TODR on any clock reset
|
||||
18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock
|
||||
|
@ -56,7 +80,7 @@
|
|||
*/
|
||||
|
||||
#include "vax_defs.h"
|
||||
#include <time.h>
|
||||
|
||||
|
||||
/* Terminal definitions */
|
||||
|
||||
|
@ -171,6 +195,11 @@ int32 clk_tps = 100; /* ticks/second */
|
|||
int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */
|
||||
int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
|
||||
int32 todr_reg = 0; /* TODR register */
|
||||
struct todr_battery_info {
|
||||
uint32 toy_gmtbase; /* GMT base of set value */
|
||||
uint32 toy_gmtbasemsec; /* The milliseconds of the set value */
|
||||
};
|
||||
typedef struct todr_battery_info TOY;
|
||||
|
||||
int32 fl_fnc = 0; /* function */
|
||||
int32 fl_esr = 0; /* error status */
|
||||
|
@ -197,6 +226,8 @@ t_stat tmr_svc (UNIT *uptr);
|
|||
t_stat tti_reset (DEVICE *dptr);
|
||||
t_stat tto_reset (DEVICE *dptr);
|
||||
t_stat clk_reset (DEVICE *dptr);
|
||||
t_stat clk_attach (UNIT *uptr, char *cptr);
|
||||
t_stat clk_detach (UNIT *uptr);
|
||||
t_stat tmr_reset (DEVICE *dptr);
|
||||
t_stat fl_svc (UNIT *uptr);
|
||||
t_stat fl_reset (DEVICE *dptr);
|
||||
|
@ -281,7 +312,7 @@ DEVICE tto_dev = {
|
|||
|
||||
/* TODR and TMR data structures */
|
||||
|
||||
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY }; /* 100Hz */
|
||||
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE+UNIT_FIX, sizeof(TOY)), CLK_DELAY };/* 100Hz */
|
||||
|
||||
REG clk_reg[] = {
|
||||
{ DRDATA (TODR, todr_reg, 32), PV_LEFT },
|
||||
|
@ -296,9 +327,9 @@ REG clk_reg[] = {
|
|||
|
||||
DEVICE clk_dev = {
|
||||
"TODR", &clk_unit, clk_reg, NULL,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
1, 0, 8, 1, 0, 0,
|
||||
NULL, NULL, &clk_reset,
|
||||
NULL, NULL, NULL,
|
||||
NULL, &clk_attach, &clk_detach,
|
||||
NULL, 0
|
||||
};
|
||||
|
||||
|
@ -578,7 +609,6 @@ 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 */
|
||||
return SCPE_OK;
|
||||
|
@ -651,9 +681,44 @@ t_stat clk_reset (DEVICE *dptr)
|
|||
tmr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init 100Hz timer */
|
||||
sim_activate_abs (&clk_unit, tmr_poll); /* activate 100Hz unit */
|
||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||
if (clk_unit.filebuf == NULL) { /* make sure the TODR is initialized */
|
||||
clk_unit.filebuf = calloc(sizeof(TOY), 1);
|
||||
if (clk_unit.filebuf == NULL)
|
||||
return SCPE_MEM;
|
||||
todr_resync ();
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* CLK attach */
|
||||
|
||||
t_stat clk_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
uptr->flags = uptr->flags | (UNIT_ATTABLE | UNIT_BUFABLE);
|
||||
memset (uptr->filebuf, 0, (size_t)uptr->capac);
|
||||
r = attach_unit (uptr, cptr);
|
||||
if (r != SCPE_OK)
|
||||
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
|
||||
else
|
||||
uptr->hwmark = (uint32) uptr->capac;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* CLK detach */
|
||||
|
||||
t_stat clk_detach (UNIT *uptr)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
r = detach_unit (uptr);
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* Interval timer reset */
|
||||
|
||||
t_stat tmr_reset (DEVICE *dptr)
|
||||
|
@ -672,32 +737,59 @@ return SCPE_OK;
|
|||
|
||||
int32 todr_rd (void)
|
||||
{
|
||||
return todr_reg;
|
||||
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||
struct timespec base, now, val;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &now); /* get curr time */
|
||||
base.tv_sec = toy->toy_gmtbase;
|
||||
base.tv_nsec = toy->toy_gmtbasemsec * 1000000;
|
||||
sim_timespec_diff (&val, &now, &base);
|
||||
return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */
|
||||
}
|
||||
|
||||
|
||||
void todr_wr (int32 data)
|
||||
{
|
||||
todr_reg = data;
|
||||
return;
|
||||
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||
struct timespec now, val, base;
|
||||
|
||||
/* Save the GMT time when set value was 0 to record the base for future
|
||||
read operations in "battery backed-up" state */
|
||||
|
||||
if (-1 == clock_gettime(CLOCK_REALTIME, &now)) /* get curr time */
|
||||
return; /* error? */
|
||||
val.tv_sec = ((uint32)data) / 100;
|
||||
val.tv_nsec = (((uint32)data) % 100) * 10000000;
|
||||
sim_timespec_diff (&base, &now, &val); /* base = now - data */
|
||||
toy->toy_gmtbase = base.tv_sec;
|
||||
toy->toy_gmtbasemsec = base.tv_nsec/1000000;
|
||||
}
|
||||
|
||||
t_stat todr_resync (void)
|
||||
{
|
||||
uint32 base;
|
||||
time_t curr;
|
||||
struct tm *ctm;
|
||||
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||
|
||||
curr = time (NULL); /* get curr time */
|
||||
if (curr == (time_t) -1) /* error? */
|
||||
if (clk_unit.flags & UNIT_ATT) { /* Attached means behave like real VAX780 */
|
||||
if (!toy->toy_gmtbase) /* Never set? */
|
||||
todr_wr (0); /* Start ticking from 0 */
|
||||
}
|
||||
else { /* Not-Attached means */
|
||||
uint32 base; /* behave like simh VMS default */
|
||||
time_t curr;
|
||||
struct tm *ctm;
|
||||
|
||||
curr = time (NULL); /* get curr time */
|
||||
if (curr == (time_t) -1) /* error? */
|
||||
return SCPE_NOFNC;
|
||||
ctm = localtime (&curr); /* decompose */
|
||||
if (ctm == NULL) /* error? */
|
||||
ctm = localtime (&curr); /* decompose */
|
||||
if (ctm == NULL) /* error? */
|
||||
return SCPE_NOFNC;
|
||||
base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */
|
||||
base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */
|
||||
ctm->tm_hour) * 60) +
|
||||
ctm->tm_min) * 60) +
|
||||
ctm->tm_sec;
|
||||
todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */
|
||||
todr_wr ((base * 100) + 0x10000000); /* use VMS form */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
|
170
VAX/vax_stddev.c
170
VAX/vax_stddev.c
|
@ -27,6 +27,31 @@
|
|||
tto terminal output
|
||||
clk 100Hz and TODR clock
|
||||
|
||||
28-Sep-11 MP Generalized setting TODR for all OSes.
|
||||
Unbound the TODR value from the 100hz clock tick
|
||||
interrupt. TODR now behaves like the original
|
||||
battery backed-up clock and runs with the wall
|
||||
clock, not the simulated instruction clock
|
||||
(except when running ROM diagnostics).
|
||||
Two operational modes are available:
|
||||
- Default VMS mode, which is similar to the previous
|
||||
behavior in that without initializing the TODR it
|
||||
would default to the value VMS would set it to if
|
||||
VMS knew the correct time. This would be correct
|
||||
almost all the time unless a VMS disk hadn't been
|
||||
booted from for more than a year. This mode
|
||||
produces strange time results for non VMS OSes on
|
||||
each system boot.
|
||||
- OS Agnostic mode. This mode behaves precisely like
|
||||
the VAX780 TODR and works correctly for all OSes.
|
||||
This mode is enabled by attaching the TODR to a
|
||||
battery backup state file for the TOY clock
|
||||
(i.e. sim> attach TODR TOY_CLOCK). When operating
|
||||
in OS Agnostic mode, the TODR will initially start
|
||||
counting from 0 and be adjusted differently when an
|
||||
OS specifically writes to the TODR. VMS will prompt
|
||||
to set the time on each boot unless the SYSGEN
|
||||
parameter TIMEPROMPTWAIT is set to 0.
|
||||
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
|
||||
|
@ -70,6 +95,11 @@ int32 clk_csr = 0; /* control/status */
|
|||
int32 clk_tps = 100; /* ticks/second */
|
||||
int32 todr_reg = 0; /* TODR register */
|
||||
int32 todr_blow = 1; /* TODR battery low */
|
||||
struct todr_battery_info {
|
||||
uint32 toy_gmtbase; /* GMT base of set value */
|
||||
uint32 toy_gmtbasemsec; /* The milliseconds of the set value */
|
||||
};
|
||||
typedef struct todr_battery_info TOY;
|
||||
int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */
|
||||
int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
|
||||
|
||||
|
@ -79,9 +109,12 @@ t_stat clk_svc (UNIT *uptr);
|
|||
t_stat tti_reset (DEVICE *dptr);
|
||||
t_stat tto_reset (DEVICE *dptr);
|
||||
t_stat clk_reset (DEVICE *dptr);
|
||||
t_stat clk_attach (UNIT *uptr, char *cptr);
|
||||
t_stat clk_detach (UNIT *uptr);
|
||||
t_stat todr_resync (void);
|
||||
|
||||
extern int32 sysd_hlt_enb (void);
|
||||
extern int32 fault_PC;
|
||||
|
||||
/* TTI data structures
|
||||
|
||||
|
@ -168,7 +201,7 @@ DEVICE tto_dev = {
|
|||
|
||||
DIB clk_dib = { 0, 0, NULL, NULL, 1, IVCL (CLK), SCB_INTTIM, { NULL } };
|
||||
|
||||
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY };
|
||||
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE+UNIT_FIX, sizeof(TOY)), CLK_DELAY };/* 100Hz */
|
||||
|
||||
REG clk_reg[] = {
|
||||
{ HRDATA (CSR, clk_csr, 16) },
|
||||
|
@ -180,6 +213,7 @@ REG clk_reg[] = {
|
|||
{ 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 (ASYNCH, sim_asynch_enabled, 1), PV_LEFT },
|
||||
{ DRDATA (LATENCY, sim_asynch_latency, 32), PV_LEFT },
|
||||
{ DRDATA (INST_LATENCY, sim_asynch_inst_latency, 32), PV_LEFT },
|
||||
#endif
|
||||
|
@ -193,16 +227,15 @@ MTAB clk_mod[] = {
|
|||
|
||||
DEVICE clk_dev = {
|
||||
"CLK", &clk_unit, clk_reg, clk_mod,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
1, 0, 8, 1, 0, 0,
|
||||
NULL, NULL, &clk_reset,
|
||||
NULL, NULL, NULL,
|
||||
NULL, &clk_attach, &clk_detach,
|
||||
&clk_dib, 0
|
||||
};
|
||||
|
||||
/* Clock and terminal MxPR routines
|
||||
|
||||
iccs_rd/wr interval timer
|
||||
todr_rd/wr time of year clock
|
||||
rxcs_rd/wr input control/status
|
||||
rxdb_rd input buffer
|
||||
txcs_rd/wr output control/status
|
||||
|
@ -214,11 +247,6 @@ int32 iccs_rd (void)
|
|||
return (clk_csr & CLKCSR_IMP);
|
||||
}
|
||||
|
||||
int32 todr_rd (void)
|
||||
{
|
||||
return todr_reg;
|
||||
}
|
||||
|
||||
int32 rxcs_rd (void)
|
||||
{
|
||||
return (tti_csr & TTICSR_IMP);
|
||||
|
@ -247,14 +275,6 @@ clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW);
|
|||
return;
|
||||
}
|
||||
|
||||
void todr_wr (int32 data)
|
||||
{
|
||||
todr_reg = data;
|
||||
if (data)
|
||||
todr_blow = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
void rxcs_wr (int32 data)
|
||||
{
|
||||
if ((data & CSR_IE) == 0)
|
||||
|
@ -357,7 +377,8 @@ return SCPE_OK;
|
|||
|
||||
clk_svc process event (clock tick)
|
||||
clk_reset process reset
|
||||
todr_powerup powerup for TODR (get date from system)
|
||||
todr_rd/wr time of year clock
|
||||
todr_resync powerup for TODR (get date from system)
|
||||
*/
|
||||
|
||||
t_stat clk_svc (UNIT *uptr)
|
||||
|
@ -370,8 +391,8 @@ t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
|
|||
sim_activate (&clk_unit, t); /* reactivate unit */
|
||||
tmr_poll = t; /* set tmr poll */
|
||||
tmxr_poll = t * TMXR_MULT; /* set mux poll */
|
||||
if (!todr_blow) /* incr TODR */
|
||||
todr_reg = todr_reg + 1;
|
||||
if (!todr_blow && todr_reg) /* if running? */
|
||||
todr_reg = todr_reg + 1; /* incr TODR */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
@ -385,26 +406,80 @@ t = sim_is_active (&clk_unit);
|
|||
return (t? t - 1: wait);
|
||||
}
|
||||
|
||||
int32 todr_rd (void)
|
||||
{
|
||||
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||
struct timespec base, now, val;
|
||||
|
||||
if ((fault_PC&0xFFFE0000) == 0x20040000) /* running from ROM? */
|
||||
return todr_reg; /* return counted value for ROM diags */
|
||||
|
||||
if (0 == todr_reg) /* clock running? */
|
||||
return todr_reg;
|
||||
|
||||
/* Maximum number of seconds which can be represented as 10ms ticks
|
||||
in the 32bit TODR. This is the 33bit value 0x100000000/100 to get seconds */
|
||||
#define TOY_MAX_SECS (0x40000000/25)
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &now); /* get curr time */
|
||||
base.tv_sec = toy->toy_gmtbase;
|
||||
base.tv_nsec = toy->toy_gmtbasemsec * 1000000;
|
||||
sim_timespec_diff (&val, &now, &base);
|
||||
|
||||
if (val.tv_sec >= TOY_MAX_SECS) /* todr overflowed? */
|
||||
return todr_reg = 0; /* stop counting */
|
||||
|
||||
return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */
|
||||
}
|
||||
|
||||
|
||||
void todr_wr (int32 data)
|
||||
{
|
||||
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||
struct timespec now, val, base;
|
||||
|
||||
/* Save the GMT time when set value was 0 to record the base for future
|
||||
read operations in "battery backed-up" state */
|
||||
|
||||
if (-1 == clock_gettime(CLOCK_REALTIME, &now)) /* get curr time */
|
||||
return; /* error? */
|
||||
val.tv_sec = ((uint32)data) / 100;
|
||||
val.tv_nsec = (((uint32)data) % 100) * 10000000;
|
||||
sim_timespec_diff (&base, &now, &val); /* base = now - data */
|
||||
toy->toy_gmtbase = base.tv_sec;
|
||||
toy->toy_gmtbasemsec = base.tv_nsec/1000000;
|
||||
todr_reg = data;
|
||||
if (data)
|
||||
todr_blow = 0;
|
||||
}
|
||||
|
||||
/* TODR resync routine */
|
||||
|
||||
t_stat todr_resync (void)
|
||||
{
|
||||
uint32 base;
|
||||
time_t curr;
|
||||
struct tm *ctm;
|
||||
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||
|
||||
curr = time (NULL); /* get curr time */
|
||||
if (curr == (time_t) -1) /* error? */
|
||||
if (clk_unit.flags & UNIT_ATT) { /* Attached means behave like real VAX780 */
|
||||
if (!toy->toy_gmtbase) /* Never set? */
|
||||
todr_wr (0); /* Start ticking from 0 */
|
||||
}
|
||||
else { /* Not-Attached means */
|
||||
uint32 base; /* behave like simh VMS default */
|
||||
time_t curr;
|
||||
struct tm *ctm;
|
||||
|
||||
curr = time (NULL); /* get curr time */
|
||||
if (curr == (time_t) -1) /* error? */
|
||||
return SCPE_NOFNC;
|
||||
ctm = localtime (&curr); /* decompose */
|
||||
if (ctm == NULL) /* error? */
|
||||
ctm = localtime (&curr); /* decompose */
|
||||
if (ctm == NULL) /* error? */
|
||||
return SCPE_NOFNC;
|
||||
base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */
|
||||
base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */
|
||||
ctm->tm_hour) * 60) +
|
||||
ctm->tm_min) * 60) +
|
||||
ctm->tm_sec;
|
||||
todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */
|
||||
todr_blow = 0;
|
||||
todr_wr ((base * 100) + 0x10000000); /* use VMS form */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
@ -414,13 +489,46 @@ t_stat clk_reset (DEVICE *dptr)
|
|||
{
|
||||
int32 t;
|
||||
|
||||
todr_resync (); /* resync clock */
|
||||
clk_csr = 0;
|
||||
CLR_INT (CLK);
|
||||
t = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init timer */
|
||||
sim_activate_abs (&clk_unit, t); /* activate unit */
|
||||
tmr_poll = t; /* set tmr poll */
|
||||
tmxr_poll = t * TMXR_MULT; /* set mux poll */
|
||||
if (clk_unit.filebuf == NULL) { /* make sure the TODR is initialized */
|
||||
clk_unit.filebuf = calloc(sizeof(TOY), 1);
|
||||
if (clk_unit.filebuf == NULL)
|
||||
return SCPE_MEM;
|
||||
todr_resync ();
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* CLK attach */
|
||||
|
||||
t_stat clk_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
uptr->flags = uptr->flags | (UNIT_ATTABLE | UNIT_BUFABLE);
|
||||
memset (uptr->filebuf, 0, (size_t)uptr->capac);
|
||||
r = attach_unit (uptr, cptr);
|
||||
if (r != SCPE_OK)
|
||||
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
|
||||
else
|
||||
uptr->hwmark = (uint32) uptr->capac;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* CLK detach */
|
||||
|
||||
t_stat clk_detach (UNIT *uptr)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
r = detach_unit (uptr);
|
||||
if ((uptr->flags & UNIT_ATT) == 0)
|
||||
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@
|
|||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
AdditionalIncludeDirectories="./;../;../VAX/;../pdp11/;../../winpcap/Wpdpack/Include;"../../pthreads/Pre-built.2/include""
|
||||
PreprocessorDefinitions="USE_INT64;USE_ADDR64;VM_VAX;VAX_730;USE_SHARED;_CRT_SECURE_NO_WARNINGS;USE_READER_THREAD"
|
||||
PreprocessorDefinitions="USE_INT64;USE_ADDR64;VM_VAX;VAX_730;USE_SHARED;_CRT_SECURE_NO_WARNINGS;USE_READER_THREAD;SIM_ASYNCH_IO"
|
||||
StringPooling="true"
|
||||
RuntimeLibrary="0"
|
||||
EnableFunctionLevelLinking="true"
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
Description="Build Dependent ROM include File(s)"
|
||||
CommandLine="pushd ..
$(TargetDir)BuildROMs
popd"
|
||||
CommandLine="pushd ..
$(TargetDir)BuildROMs
popd
"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
|
@ -112,7 +112,7 @@
|
|||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
Description="Build Dependent ROM include File(s)"
|
||||
CommandLine="pushd ..
$(TargetDir)BuildROMs
popd"
|
||||
CommandLine="pushd ..
$(TargetDir)BuildROMs
popd
"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
|
@ -134,7 +134,7 @@
|
|||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
AdditionalIncludeDirectories="./;../;../VAX/;../pdp11/;../../winpcap/Wpdpack/Include;"../../pthreads/Pre-built.2/include""
|
||||
PreprocessorDefinitions="USE_INT64;USE_ADDR64;VM_VAX;VAX_780;USE_SHARED;_CRT_SECURE_NO_WARNINGS;USE_READER_THREAD"
|
||||
PreprocessorDefinitions="USE_INT64;USE_ADDR64;VM_VAX;VAX_780;USE_SHARED;_CRT_SECURE_NO_WARNINGS;USE_READER_THREAD;SIM_ASYNCH_IO"
|
||||
StringPooling="true"
|
||||
RuntimeLibrary="0"
|
||||
EnableFunctionLevelLinking="true"
|
||||
|
|
|
@ -57,8 +57,8 @@
|
|||
#
|
||||
# MMK/MACRO=(NOASYNCH=1)
|
||||
#
|
||||
# On AXP the AXP PCAP components are built and used to provide network
|
||||
# support for the VAX and PDP11 simulators.
|
||||
# On AXP and IA64 the VMS PCAP components are built and used to provide
|
||||
# network support for the VAX and PDP11 simulators.
|
||||
#
|
||||
# The AXP PCAP components can only be built using a version of the
|
||||
# DEC/Compaq/HP Compiler version V6.5-001 or later. To build using an
|
||||
|
|
32
makefile
32
makefile
|
@ -13,6 +13,7 @@
|
|||
#
|
||||
ifeq ($(WIN32),)
|
||||
#*nix Environments (&& cygwin)
|
||||
GCC = gcc
|
||||
ifeq (SunOS,$(shell uname))
|
||||
TEST = /bin/test
|
||||
else
|
||||
|
@ -23,16 +24,20 @@ ifeq ($(WIN32),)
|
|||
else
|
||||
ifeq (Linux,$(shell uname))
|
||||
LIBEXT = so
|
||||
else
|
||||
ifeq (SunOS,$(shell uname))
|
||||
LIBEXT = so
|
||||
else
|
||||
LIBEXT = a
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
OS_CCDEFS = -D_GNU_SOURCE
|
||||
ifeq (libm,$(shell if $(TEST) -e /usr/lib/libm.$(LIBEXT); then echo libm; fi))
|
||||
ifeq (libm,$(shell if $(TEST) -e /usr/lib/libm.$(LIBEXT) -o -e /usr/lib64/libm.$(LIBEXT); then echo libm; fi))
|
||||
OS_LDFLAGS += -lm
|
||||
endif
|
||||
ifeq (SunOS,$(shell uname))
|
||||
OS_CCDEFS += -I/opt/sfw/include
|
||||
OS_CCDEFS += -I/opt/sfw/include -DSIM_ASYNCH_IO -DUSE_READER_THREAD
|
||||
OS_LDFLAGS += -lsocket -lnsl -lrt -lm -lpthread -L/opt/sfw/lib -R/opt/sfw/lib
|
||||
endif
|
||||
ifeq (cygwin,$(findstring cygwin,$(OSTYPE)))
|
||||
|
@ -46,29 +51,41 @@ ifeq ($(WIN32),)
|
|||
OS_LDFLAGS += -lpthread
|
||||
endif
|
||||
ifeq (readline,$(shell if $(TEST) -e /usr/lib/libreadline.$(LIBEXT) -o -e /usr/lib64/libreadline.$(LIBEXT) -o -e /opt/sfw/lib/libreadline.a; then echo readline; fi))
|
||||
ifeq (readline_h,$(shell if $(TEST) -e /usr/include/readline/readline.h -o -e /usr/include/readline.h; then echo readline_h; fi))
|
||||
ifeq (readline_h,$(shell if $(TEST) -e /usr/include/readline/readline.h -o -e /usr/include/readline.h -o -e /opt/sfw/include/readline/readline.h; then echo readline_h; fi))
|
||||
# Use Locally installed and available readline support
|
||||
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
|
||||
ifeq (curses,$(shell if $(TEST) -e /usr/lib/libcurses.$(LIBEXT); then echo curses; fi))
|
||||
OS_CCDEFS += -DHAVE_READLINE
|
||||
OS_LDFLAGS += -lreadline -lcurses
|
||||
else
|
||||
ifeq (solaris_readline,$(shell if $(TEST) ! -e /opt/sfw/lib/libreadline.a; then echo solaris_readline; fi))
|
||||
OS_CCDEFS += -DHAVE_READLINE
|
||||
OS_LDFLAGS += -lreadline
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
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
|
||||
NETWORK_LDFLAGS = -lpcap
|
||||
endif
|
||||
ifeq (vde,$(shell if $(TEST) -e /usr/include/libvdeplug.h -a \( -e /usr/lib/libvdeplug.$(LIBEXT) -o -e /usr/lib64/libvdeplug.$(LIBEXT) \); then echo vde; fi))
|
||||
# Provide support for vde networking
|
||||
NETWORK_CCDEFS += -DUSE_VDE_NETWORK
|
||||
NETWORK_LDFLAGS += -lvdeplug
|
||||
endif
|
||||
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
|
||||
NETWORK_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 -o -e /Library/Extensions/tap.kext; then echo bsdtuntap; fi))
|
||||
# Provide support for Tap networking
|
||||
NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP
|
||||
NETWORK_CCDEFS += -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP
|
||||
endif
|
||||
ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi))
|
||||
MKDIRBIN = if $(TEST) ! -e BIN; then mkdir BIN; fi
|
||||
|
@ -79,6 +96,7 @@ ifeq ($(WIN32),)
|
|||
endif
|
||||
else
|
||||
#Win32 Environments (via MinGW32)
|
||||
GCC = gcc
|
||||
GCC_Path := $(dir $(shell where gcc.exe))
|
||||
ifeq ($(NOASYNCH),)
|
||||
ifeq (pthreads,$(shell if exist ..\pthreads\Pre-built.2\include\pthread.h echo pthreads))
|
||||
|
@ -119,7 +137,7 @@ else
|
|||
endif
|
||||
|
||||
|
||||
CC = gcc -std=c99 -U__STRICT_ANSI__ -g -I . $(NETWORK_CCDEFS) $(NETWORK_TAP_CCDEFS) $(OS_CCDEFS) $(ROMS_OPT)
|
||||
CC = $(GCC) -std=c99 -U__STRICT_ANSI__ -g -I . $(NETWORK_CCDEFS) $(OS_CCDEFS) $(ROMS_OPT)
|
||||
LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS)
|
||||
|
||||
#
|
||||
|
|
107
scp.c
107
scp.c
|
@ -23,6 +23,17 @@
|
|||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
25-Sep-11 MP Added the ability for a simulator built with
|
||||
SIM_ASYNCH_IO to change whether I/O is actually done
|
||||
asynchronously by the new scp command SET ASYNCH and
|
||||
SET NOASYNCH
|
||||
22-Sep-11 MP Added signal catching of SIGHUP and SIGTERM to cause
|
||||
simulator STOP. This allows an externally signalled
|
||||
event (i.e. system shutdown, or logoff) to signal a
|
||||
running simulator of these events and to allow
|
||||
reasonable actions to be taken. This will facilitate
|
||||
running a simulator as a 'service' on *nix platforms,
|
||||
given a sufficiently flexible simulator .ini file.
|
||||
20-Apr-11 MP Added expansion of %STATUS% and %TSTATUS% in do command
|
||||
arguments. STATUS is the numeric value of the last
|
||||
command error status and TSTATUS is the text message
|
||||
|
@ -271,6 +282,7 @@ 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;
|
||||
t_bool sim_asynch_enabled = TRUE;
|
||||
int32 sim_asynch_check;
|
||||
int32 sim_asynch_latency = 4000; /* 4 usec interrupt latency */
|
||||
int32 sim_asynch_inst_latency = 20; /* assume 5 mip simulator */
|
||||
|
@ -387,6 +399,7 @@ t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr,
|
|||
t_stat step_svc (UNIT *ptr);
|
||||
void sub_args (char *instr, char *tmpbuf, int32 maxstr, char *do_arg[]);
|
||||
t_stat set_on (int32 flag, char *cptr);
|
||||
t_stat set_asynch (int32 flag, char *cptr);
|
||||
|
||||
|
||||
/* Global data */
|
||||
|
@ -603,8 +616,11 @@ static CTAB cmd_table[] = {
|
|||
"set console NODEBUG disable console debugging\n"
|
||||
"set break <list> set breakpoints\n"
|
||||
"set nobreak <list> clear breakpoints\n"
|
||||
"set throttle x{M|K|%%} set simulation rate\n"
|
||||
"set throttle {x{M|K|%}}|{x/t}\n"
|
||||
" set simulation rate\n"
|
||||
"set nothrottle set simulation rate to maximum\n"
|
||||
"set asynch enable asynchronous I/O\n"
|
||||
"set noasynch disable asynchronous I/O\n"
|
||||
"set <dev> OCT|DEC|HEX set device display radix\n"
|
||||
"set <dev> ENABLED enable device\n"
|
||||
"set <dev> DISABLED disable device\n"
|
||||
|
@ -628,6 +644,7 @@ static CTAB cmd_table[] = {
|
|||
"sh{ow} q{ueue} show event queue\n"
|
||||
"sh{ow} ti{me} show simulated time\n"
|
||||
"sh{ow} th{rottle} show simulation rate\n"
|
||||
"sh{ow} a{synch} show asynchronouse I/O state\n"
|
||||
"sh{ow} ve{rsion} show simulator version\n"
|
||||
"sh{ow} <dev> RADIX show device display radix\n"
|
||||
"sh{ow} <dev> DEBUG show device debug flags\n"
|
||||
|
@ -1006,13 +1023,6 @@ do {
|
|||
(cmdp->action != &on_cmd) &&
|
||||
(cmdp->action != &echo_cmd)))
|
||||
sim_last_cmd_stat = stat; /* save command error status */
|
||||
staying = (stat != SCPE_EXIT) && /* decide if staying */
|
||||
(stat != SCPE_AFAIL) &&
|
||||
(!errabort || (stat < SCPE_BASE) || (stat == SCPE_STEP));
|
||||
if ((stat == SCPE_AFAIL) && /* handle special case AFAIL */
|
||||
sim_on_check[sim_do_depth] && /* and use trap action if defined */
|
||||
sim_on_actions[sim_do_depth][stat]) /* otherwise exit */
|
||||
staying = TRUE;
|
||||
if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) && /* error from cmd? */
|
||||
(stat != SCPE_STEP)) {
|
||||
if (!echo && !sim_quiet && /* report if not echoing */
|
||||
|
@ -1023,8 +1033,23 @@ do {
|
|||
}
|
||||
stat = stat & ~SCPE_DOFAILED; /* remove possible flag */
|
||||
}
|
||||
switch (stat) {
|
||||
case SCPE_OK:
|
||||
case SCPE_STEP:
|
||||
break;
|
||||
case SCPE_AFAIL:
|
||||
staying = (sim_on_check[sim_do_depth] && /* if trap action defined */
|
||||
sim_on_actions[sim_do_depth][stat]); /* use it, otherwise exit */
|
||||
break;
|
||||
case SCPE_EXIT:
|
||||
staying = FALSE;
|
||||
break;
|
||||
default:
|
||||
staying = sim_on_check[sim_do_depth];
|
||||
break;
|
||||
}
|
||||
if ((staying || !interactive) && /* report error if staying */
|
||||
(stat >= SCPE_BASE)) { /* or in cmdline file */
|
||||
(stat >= SCPE_BASE) && !isdo) { /* or in cmdline file */
|
||||
printf ("%s\n", sim_error_text (stat));
|
||||
if (sim_log)
|
||||
fprintf (sim_log, "%s\n", sim_error_text (stat));
|
||||
|
@ -1033,7 +1058,7 @@ do {
|
|||
(sim_on_check[sim_do_depth]) &&
|
||||
(stat != SCPE_OK) &&
|
||||
(stat != SCPE_STEP))
|
||||
if (sim_on_actions[sim_do_depth][stat])
|
||||
if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat])
|
||||
sim_brk_act[sim_do_depth] = sim_on_actions[sim_do_depth][stat];
|
||||
else
|
||||
sim_brk_act[sim_do_depth] = sim_on_actions[sim_do_depth][0];
|
||||
|
@ -1281,6 +1306,61 @@ if ((sim_do_depth != 0) &&
|
|||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Set asynch/noasynch routine */
|
||||
|
||||
t_stat sim_set_asynch (int32 flag, char *cptr)
|
||||
{
|
||||
if (cptr && (*cptr != 0)) /* now eol? */
|
||||
return SCPE_2MARG;
|
||||
#ifdef SIM_ASYNCH_IO
|
||||
if (flag == sim_asynch_enabled) /* already set correctly? */
|
||||
return SCPE_OK;
|
||||
sim_asynch_enabled = flag;
|
||||
if (1) {
|
||||
uint32 i, j;
|
||||
DEVICE *dptr;
|
||||
UNIT *uptr;
|
||||
|
||||
/* Call unit flush routines to report asynch status change to device layer */
|
||||
for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* flush attached files */
|
||||
for (j = 0; j < dptr->numunits; j++) { /* if not buffered in mem */
|
||||
uptr = dptr->units + j;
|
||||
if ((uptr->flags & UNIT_ATT) && /* attached, */
|
||||
!(uptr->flags & UNIT_BUF) && /* not buffered, */
|
||||
(uptr->fileref)) /* real file, */
|
||||
if (uptr->io_flush) /* unit specific flush routine */
|
||||
uptr->io_flush (uptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sim_quiet)
|
||||
printf ("Asynchronous I/O %sabled\n", sim_asynch_enabled ? "en" : "dis");
|
||||
if (sim_log)
|
||||
fprintf (sim_log, "Asynchronous I/O %sabled\n", sim_asynch_enabled ? "en" : "dis");
|
||||
return SCPE_OK;
|
||||
#else
|
||||
if (!sim_quiet)
|
||||
printf ("Asynchronous I/O is not available in this simulator\n");
|
||||
if (sim_log)
|
||||
fprintf (sim_log, "Asynchronous I/O is not available in this simulator\n");
|
||||
return SCPE_NOFNC;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Show asynch routine */
|
||||
|
||||
t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)
|
||||
{
|
||||
if (cptr && (*cptr != 0))
|
||||
return SCPE_2MARG;
|
||||
#ifdef SIM_ASYNCH_IO
|
||||
fprintf (st, "Asynchronous I/O is %sabled\n", (sim_asynch_enabled) ? "en" : "dis");
|
||||
#else
|
||||
fprintf (st, "Asynchronous I/O is not available in this simulator\n");
|
||||
#endif
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Set command */
|
||||
|
||||
t_stat set_cmd (int32 flag, char *cptr)
|
||||
|
@ -1305,6 +1385,8 @@ static CTAB set_glob_tab[] = {
|
|||
{ "NODEBUG", &sim_set_deboff, 0 }, /* deprecated */
|
||||
{ "THROTTLE", &sim_set_throt, 1 },
|
||||
{ "NOTHROTTLE", &sim_set_throt, 0 },
|
||||
{ "ASYNCH", &sim_set_asynch, 1 },
|
||||
{ "NOASYNCH", &sim_set_asynch, 0 },
|
||||
{ "ON", &set_on, 1 },
|
||||
{ "NOON", &set_on, 0 },
|
||||
{ NULL, NULL, 0 }
|
||||
|
@ -1570,6 +1652,7 @@ static SHTAB show_glob_tab[] = {
|
|||
{ "TELNET", &sim_show_telnet, 0 }, /* deprecated */
|
||||
{ "DEBUG", &sim_show_debug, 0 }, /* deprecated */
|
||||
{ "THROTTLE", &sim_show_throt, 0 },
|
||||
{ "ASYNCH", &sim_show_asynch, 0 },
|
||||
{ "ON", &show_on, 0 },
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
@ -2878,7 +2961,9 @@ for (j=0, r = SCPE_OK; j<attcnt; j++) {
|
|||
if (r == SCPE_OK) {
|
||||
dptr = find_dev_from_unit (attunits[j]);
|
||||
sim_switches = attswitches[j];
|
||||
r = scp_attach_unit (dptr, attunits[j], attnames[j]); /* reattach unit */
|
||||
r = scp_attach_unit (dptr, attunits[j], attnames[j]);/* reattach unit */
|
||||
if (r != SCPE_OK)
|
||||
printf ("Error Attaching %s to %s\n", sim_dname (dptr), attnames[j]);
|
||||
}
|
||||
free (attnames[j]);
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ fprintf (iFile, "#define ROM_%s_H 0\n", rom_array_name);
|
|||
fprintf (iFile, "/*\n");
|
||||
fprintf (iFile, " %s produced at %s", include_filename, ctime(&now));
|
||||
fprintf (iFile, " from %s which was last modified at %s", rom_filename, ctime(&statb.st_mtime));
|
||||
fprintf (iFile, " file size: %d (0x%X)\n", statb.st_size, statb.st_size);
|
||||
fprintf (iFile, " file size: %d (0x%X)\n", (int)statb.st_size, (int)statb.st_size);
|
||||
fprintf (iFile, "*/\n");
|
||||
fprintf (iFile, "unsigned char %s[] = {", rom_array_name);
|
||||
for (bytes_written=0;bytes_written<statb.st_size; ++bytes_written) {
|
||||
|
|
|
@ -424,7 +424,8 @@ while (*cptr != 0) { /* do all mods */
|
|||
*cvptr++ = 0;
|
||||
get_glyph (gbuf, gbuf, 0); /* modifier to UC */
|
||||
if (isdigit (*gbuf)) {
|
||||
if (sim_con_tmxr.master) return SCPE_ALATT; /* already open? */
|
||||
if (sim_con_tmxr.master) /* already open? */
|
||||
sim_set_notelnet (0, NULL); /* close first */
|
||||
return tmxr_open_master (&sim_con_tmxr, gbuf); /* open master socket */
|
||||
}
|
||||
else
|
||||
|
@ -633,8 +634,12 @@ if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) { /* connected or buffered
|
|||
tmxr_poll_rx (&sim_con_tmxr); /* poll (check disconn) */
|
||||
if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) { /* still connected? */
|
||||
if (!sim_con_ldsc.conn) {
|
||||
printf ("Running with Buffered Console\n"); /* print transition */
|
||||
printf ("Running with Buffered Console\r\n"); /* print transition */
|
||||
fflush (stdout);
|
||||
if (sim_log) { /* log file? */
|
||||
fprintf (sim_log, "Running with Buffered Console\n");
|
||||
fflush (sim_log);
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
@ -643,8 +648,12 @@ for (i = 0; i < sec; i++) { /* loop */
|
|||
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) { /* poll connect */
|
||||
sim_con_ldsc.rcve = 1; /* rcv enabled */
|
||||
if (i) { /* if delayed */
|
||||
printf ("Running\n"); /* print transition */
|
||||
printf ("Running\r\n"); /* print transition */
|
||||
fflush (stdout);
|
||||
if (sim_log) { /* log file? */
|
||||
fprintf (sim_log, "Running\n");
|
||||
fflush (sim_log);
|
||||
}
|
||||
}
|
||||
return SCPE_OK; /* ready to proceed */
|
||||
}
|
||||
|
@ -652,8 +661,12 @@ for (i = 0; i < sec; i++) { /* loop */
|
|||
if ((c == SCPE_STOP) || stop_cpu)
|
||||
return SCPE_STOP;
|
||||
if ((i % 10) == 0) { /* Status every 10 sec */
|
||||
printf ("Waiting for console Telnet connection\n");
|
||||
printf ("Waiting for console Telnet connection\r\n");
|
||||
fflush (stdout);
|
||||
if (sim_log) { /* log file? */
|
||||
fprintf (sim_log, "Waiting for console Telnet connection\n");
|
||||
fflush (sim_log);
|
||||
}
|
||||
}
|
||||
sim_os_sleep (1); /* wait 1 second */
|
||||
}
|
||||
|
|
|
@ -565,6 +565,7 @@ 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 t_bool sim_asynch_enabled;
|
||||
extern int32 sim_asynch_check;
|
||||
extern int32 sim_asynch_latency;
|
||||
extern int32 sim_asynch_inst_latency;
|
||||
|
|
39
sim_disk.c
39
sim_disk.c
|
@ -408,15 +408,17 @@ return SCPE_NOFNC;
|
|||
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
|
||||
pthread_attr_t attr;
|
||||
|
||||
ctx->asynch_io = 1;
|
||||
ctx->asynch_io = sim_asynch_enabled;
|
||||
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;
|
||||
if (ctx->asynch_io) {
|
||||
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;
|
||||
}
|
||||
|
@ -723,7 +725,8 @@ uint32 f = DK_GET_FMT (uptr);
|
|||
|
||||
#if defined (SIM_ASYNCH_IO)
|
||||
sim_disk_clr_async (uptr);
|
||||
sim_disk_set_async (uptr, 0);
|
||||
if (sim_asynch_enabled)
|
||||
sim_disk_set_async (uptr, 0);
|
||||
#endif
|
||||
switch (f) { /* case on format */
|
||||
case DKUF_F_STD: /* Simh */
|
||||
|
@ -1332,7 +1335,7 @@ 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);
|
||||
Handle = CreateFileA (rawdevicename, DesiredAccess, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS|FILE_FLAG_WRITE_THROUGH, NULL);
|
||||
if (Handle == INVALID_HANDLE_VALUE) {
|
||||
_set_errno_from_status (GetLastError ());
|
||||
return NULL;
|
||||
|
@ -1418,8 +1421,11 @@ static t_stat sim_os_disk_unload_raw (FILE *Disk)
|
|||
{
|
||||
#ifdef IOCTL_STORAGE_EJECT_MEDIA
|
||||
DWORD BytesReturned;
|
||||
uint32 Removable = FALSE;
|
||||
|
||||
if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */
|
||||
sim_os_disk_info_raw (Disk, NULL, &Removable);
|
||||
if (Removable) {
|
||||
if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */
|
||||
IOCTL_STORAGE_EJECT_MEDIA, /* dwIoControlCode */
|
||||
NULL, /* lpInBuffer */
|
||||
0, /* nInBufferSize */
|
||||
|
@ -1430,6 +1436,7 @@ if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */
|
|||
_set_errno_from_status (GetLastError ());
|
||||
return SCPE_IOERR;
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
#else
|
||||
return SCPE_NOFNC;
|
||||
|
@ -1440,8 +1447,11 @@ static t_bool sim_os_disk_isavailable_raw (FILE *Disk)
|
|||
{
|
||||
#ifdef IOCTL_STORAGE_EJECT_MEDIA
|
||||
DWORD BytesReturned;
|
||||
uint32 Removable = FALSE;
|
||||
|
||||
if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */
|
||||
sim_os_disk_info_raw (Disk, NULL, &Removable);
|
||||
if (Removable) {
|
||||
if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */
|
||||
IOCTL_STORAGE_CHECK_VERIFY, /* dwIoControlCode */
|
||||
NULL, /* lpInBuffer */
|
||||
0, /* nInBufferSize */
|
||||
|
@ -1452,6 +1462,7 @@ if (!DeviceIoControl((HANDLE)Disk, /* handle to disk */
|
|||
_set_errno_from_status (GetLastError ());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -2646,6 +2657,7 @@ if (SizeInBytes > ((uint64)(1024*1024*1024))*2040) {
|
|||
}
|
||||
if (File = sim_fopen (szVHDPath, "rb")) {
|
||||
fclose (File);
|
||||
File = NULL;
|
||||
Status = EEXIST;
|
||||
goto Cleanup_Return;
|
||||
}
|
||||
|
@ -2773,7 +2785,8 @@ if (WriteFilePosition(File,
|
|||
|
||||
Cleanup_Return:
|
||||
free (BAT);
|
||||
fclose (File);
|
||||
if (File)
|
||||
fclose (File);
|
||||
if (Status) {
|
||||
if (Status != EEXIST)
|
||||
remove (szVHDPath);
|
||||
|
|
1048
sim_ether.c
1048
sim_ether.c
File diff suppressed because it is too large
Load diff
14
sim_ether.h
14
sim_ether.h
|
@ -28,6 +28,7 @@
|
|||
|
||||
Modification history:
|
||||
|
||||
30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking
|
||||
18-Apr-11 MP Fixed race condition with self loopback packets in
|
||||
multithreaded environments
|
||||
09-Dec-10 MP Added support to determine if network address conflicts exist
|
||||
|
@ -89,13 +90,13 @@
|
|||
#if defined (USE_READER_THREAD)
|
||||
#if defined (USE_SETNONBLOCK)
|
||||
#undef USE_SETNONBLOCK
|
||||
#endif
|
||||
#endif /* USE_SETNONBLOCK */
|
||||
#undef PCAP_READ_TIMEOUT
|
||||
#define PCAP_READ_TIMEOUT 15
|
||||
#if !defined (xBSD) && !defined(_WIN32) && !defined(VMS)
|
||||
#define MUST_DO_SELECT
|
||||
#endif
|
||||
#if (!defined (xBSD) && !defined(_WIN32) && !defined(VMS)) || defined (USE_TAP_NETWORK) || defined (USE_VDE_NETWORK)
|
||||
#define MUST_DO_SELECT 1
|
||||
#endif
|
||||
#endif /* USE_READER_THREAD */
|
||||
|
||||
/*
|
||||
USE_BPF is defined to let this code leverage the libpcap/OS kernel provided
|
||||
|
@ -175,7 +176,10 @@ struct eth_device {
|
|||
char* name; /* name of ethernet device */
|
||||
void* handle; /* handle of implementation-specific device */
|
||||
int fd_handle; /* fd to kernel device (where needed) */
|
||||
int pcap_mode; /* Flag indicating if pcap API are being used to move packets */
|
||||
int eth_api; /* Designator for which API is being used to move packets */
|
||||
#define ETH_API_PCAP 0 /* Pcap API in use */
|
||||
#define ETH_API_TAP 1 /* tun/tap API in use */
|
||||
#define ETH_API_VDE 2 /* VDE API in use */
|
||||
ETH_PCALLBACK read_callback; /* read callback function */
|
||||
ETH_PCALLBACK write_callback; /* write callback function */
|
||||
ETH_PACK* read_packet; /* read packet */
|
||||
|
|
19
sim_tape.c
19
sim_tape.c
|
@ -320,14 +320,16 @@ return SCPE_NOFNC;
|
|||
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
|
||||
pthread_attr_t attr;
|
||||
|
||||
ctx->asynch_io = 1;
|
||||
ctx->asynch_io = sim_asynch_enabled;
|
||||
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);
|
||||
if (ctx->asynch_io) {
|
||||
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;
|
||||
|
@ -362,7 +364,8 @@ static void _sim_tape_io_flush (UNIT *uptr)
|
|||
{
|
||||
#if defined (SIM_ASYNCH_IO)
|
||||
sim_tape_clr_async (uptr);
|
||||
sim_tape_set_async (uptr, 0);
|
||||
if (sim_asynch_enabled)
|
||||
sim_tape_set_async (uptr, 0);
|
||||
#endif
|
||||
fflush (uptr->fileref);
|
||||
}
|
||||
|
|
109
sim_timer.c
109
sim_timer.c
|
@ -23,6 +23,28 @@
|
|||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
21-Oct-11 MP Fixed throttling in several ways:
|
||||
- Sleep for the observed clock tick size while throttling
|
||||
- Recompute the throttling wait once every 10 seconds
|
||||
to account for varying instruction mixes during
|
||||
different phases of a simulator execution or to
|
||||
accommodate the presence of other load on the host
|
||||
system.
|
||||
- Each of the pre-existing throttling modes (Kcps,
|
||||
Mcps, and %) all compute the appropriate throttling
|
||||
interval dynamically. These dynamic computations
|
||||
assume that 100% of the host CPU is dedicated to
|
||||
the current simulator during this computation.
|
||||
This assumption may not always be true and under
|
||||
certain conditions may never provide a way to
|
||||
correctly determine the appropriate throttling
|
||||
wait. An additional throttling mode has been added
|
||||
which allows the simulator operator to explicitly
|
||||
state the desired throttling wait parameters.
|
||||
These are specified by:
|
||||
SET THROT insts/delay
|
||||
where 'insts' is the number of instructions to
|
||||
execute before sleeping for 'delay' milliseconds.
|
||||
22-Apr-11 MP Fixed Asynch I/O support to reasonably account cycles
|
||||
when an idle wait is terminated by an external event
|
||||
05-Jan-11 MP Added Asynch I/O support
|
||||
|
@ -67,6 +89,7 @@ static uint32 sim_throt_ms_stop = 0;
|
|||
static uint32 sim_throt_type = 0;
|
||||
static uint32 sim_throt_val = 0;
|
||||
static uint32 sim_throt_state = 0;
|
||||
static uint32 sim_throt_sleep_time = 0;
|
||||
static int32 sim_throt_wait = 0;
|
||||
extern int32 sim_interval, sim_switches;
|
||||
extern FILE *sim_log;
|
||||
|
@ -152,8 +175,7 @@ return sim_os_msec () - stime;
|
|||
}
|
||||
|
||||
#if defined(SIM_ASYNCH_IO)
|
||||
#ifndef CLOCK_REALTIME
|
||||
#define CLOCK_REALTIME 1
|
||||
#ifdef NEED_CLOCK_GETTIME
|
||||
int clock_gettime(int clk_id, struct timespec *tp)
|
||||
{
|
||||
uint32 secs, ns, tod[2], unixbase[2] = {0xd53e8000, 0x019db1de};
|
||||
|
@ -225,12 +247,13 @@ Sleep (msec);
|
|||
return sim_os_msec () - stime;
|
||||
}
|
||||
|
||||
#if !defined(CLOCK_REALTIME) && defined (SIM_ASYNCH_IO)
|
||||
#define CLOCK_REALTIME 1
|
||||
#if defined(NEED_CLOCK_GETTIME)
|
||||
int clock_gettime(int clk_id, struct timespec *tp)
|
||||
{
|
||||
t_uint64 now, unixbase;
|
||||
|
||||
if (clk_id != CLOCK_REALTIME)
|
||||
return -1;
|
||||
unixbase = 116444736;
|
||||
unixbase *= 1000000000;
|
||||
GetSystemTimeAsFileTime((FILETIME*)&now);
|
||||
|
@ -315,8 +338,7 @@ 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
|
||||
#if defined(NEED_CLOCK_GETTIME)
|
||||
int clock_gettime(int clk_id, struct timespec *tp)
|
||||
{
|
||||
struct timeval cur;
|
||||
|
@ -377,8 +399,7 @@ if (tim > SIM_IDLE_MAX)
|
|||
return tim;
|
||||
}
|
||||
#if !defined(_POSIX_SOURCE) && defined(SIM_ASYNCH_IO)
|
||||
#ifndef CLOCK_REALTIME
|
||||
#define CLOCK_REALTIME 1
|
||||
#ifdef NEED_CLOCK_GETTIME
|
||||
typedef int clockid_t;
|
||||
int clock_gettime(clockid_t clk_id, struct timespec *tp)
|
||||
{
|
||||
|
@ -408,6 +429,21 @@ return sim_os_msec () - stime;
|
|||
|
||||
#endif
|
||||
|
||||
/* diff = min - sub */
|
||||
void
|
||||
sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub)
|
||||
{
|
||||
/* move the minuend value to the difference and operate there. */
|
||||
*diff = *min;
|
||||
/* Borrow as needed for the nsec value */
|
||||
if (sub->tv_nsec > min->tv_nsec) {
|
||||
--diff->tv_sec;
|
||||
diff->tv_nsec += 1000000000;
|
||||
}
|
||||
diff->tv_nsec -= sub->tv_nsec;
|
||||
diff->tv_sec -= sub->tv_sec;
|
||||
}
|
||||
|
||||
#if defined(SIM_ASYNCH_IO)
|
||||
uint32 sim_idle_ms_sleep (unsigned int msec)
|
||||
{
|
||||
|
@ -628,8 +664,11 @@ return SCPE_OK;
|
|||
|
||||
t_stat sim_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
if (sim_idle_enab)
|
||||
fprintf (st, "idle enabled, stability wait = %ds, minimum sleep resolution = %dms", sim_idle_stable, sim_idle_rate_ms);
|
||||
if (sim_idle_enab) {
|
||||
fprintf (st, "idle enabled");
|
||||
if (sim_switches & SWMASK ('D'))
|
||||
fprintf (st, ", stability wait = %ds, minimum sleep resolution = %dms", sim_idle_stable, sim_idle_rate_ms);
|
||||
}
|
||||
else fputs ("idle disabled", st);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
@ -639,7 +678,7 @@ return SCPE_OK;
|
|||
t_stat sim_set_throt (int32 arg, char *cptr)
|
||||
{
|
||||
char *tptr, c;
|
||||
t_value val;
|
||||
t_value val, val2;
|
||||
|
||||
if (arg == 0) {
|
||||
if ((cptr != 0) && (*cptr != 0))
|
||||
|
@ -653,8 +692,11 @@ else {
|
|||
val = strtotv (cptr, &tptr, 10);
|
||||
if (cptr == tptr)
|
||||
return SCPE_ARG;
|
||||
sim_throt_sleep_time = sim_idle_rate_ms;
|
||||
c = toupper (*tptr++);
|
||||
if (*tptr != 0)
|
||||
if (c == '/')
|
||||
val2 = strtotv (tptr, &tptr, 10);
|
||||
if ((*tptr != 0) || (val == 0))
|
||||
return SCPE_ARG;
|
||||
if (c == 'M')
|
||||
sim_throt_type = SIM_THROT_MCYC;
|
||||
|
@ -662,6 +704,9 @@ else {
|
|||
sim_throt_type = SIM_THROT_KCYC;
|
||||
else if ((c == '%') && (val > 0) && (val < 100))
|
||||
sim_throt_type = SIM_THROT_PCT;
|
||||
else if ((c == '/') && (val2 != 0)) {
|
||||
sim_throt_type = SIM_THROT_SPC;
|
||||
}
|
||||
else return SCPE_ARG;
|
||||
if (sim_idle_enab) {
|
||||
printf ("Idling disabled\n");
|
||||
|
@ -670,6 +715,14 @@ else {
|
|||
sim_clr_idle (NULL, 0, NULL, NULL);
|
||||
}
|
||||
sim_throt_val = (uint32) val;
|
||||
if (sim_throt_type == SIM_THROT_SPC) {
|
||||
if (val2 >= sim_idle_rate_ms)
|
||||
sim_throt_sleep_time = (uint32) val2;
|
||||
else {
|
||||
sim_throt_sleep_time = (uint32) (val2 * sim_idle_rate_ms);
|
||||
sim_throt_val = (uint32) (val * sim_idle_rate_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
@ -693,13 +746,17 @@ else {
|
|||
fprintf (st, "Throttle = %d%%\n", sim_throt_val);
|
||||
break;
|
||||
|
||||
case SIM_THROT_SPC:
|
||||
fprintf (st, "Throttle = %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_val);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (st, "Throttling disabled\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (sim_switches & SWMASK ('D')) {
|
||||
fprintf (st, "Wait rate = %d ms\n", sim_idle_rate_ms);
|
||||
fprintf (st, "minimum sleep resolution = %d ms\n", sim_idle_rate_ms);
|
||||
if (sim_throt_type != 0)
|
||||
fprintf (st, "Throttle interval = %d cycles\n", sim_throt_wait);
|
||||
}
|
||||
|
@ -712,7 +769,6 @@ void sim_throt_sched (void)
|
|||
sim_throt_state = 0;
|
||||
if (sim_throt_type)
|
||||
sim_activate (&sim_throt_unit, SIM_THROT_WINIT);
|
||||
return;
|
||||
}
|
||||
|
||||
void sim_throt_cancel (void)
|
||||
|
@ -722,7 +778,8 @@ sim_cancel (&sim_throt_unit);
|
|||
|
||||
/* Throttle service
|
||||
|
||||
Throttle service has three distinct states
|
||||
Throttle service has three distinct states used while dynamically
|
||||
determining a throttling interval:
|
||||
|
||||
0 take initial measurement
|
||||
1 take final measurement, calculate wait values
|
||||
|
@ -734,12 +791,16 @@ t_stat sim_throt_svc (UNIT *uptr)
|
|||
uint32 delta_ms;
|
||||
double a_cps, d_cps;
|
||||
|
||||
if (sim_throt_type == SIM_THROT_SPC) { /* Non dynamic? */
|
||||
sim_throt_state = 2; /* force state */
|
||||
sim_throt_wait = sim_throt_val;
|
||||
}
|
||||
switch (sim_throt_state) {
|
||||
|
||||
case 0: /* take initial reading */
|
||||
sim_throt_ms_start = sim_os_msec ();
|
||||
sim_throt_wait = SIM_THROT_WST;
|
||||
sim_throt_state++; /* next state */
|
||||
sim_throt_state = 1; /* next state */
|
||||
break; /* reschedule */
|
||||
|
||||
case 1: /* take final reading */
|
||||
|
@ -761,24 +822,32 @@ switch (sim_throt_state) {
|
|||
d_cps = (double) sim_throt_val * 1000.0;
|
||||
else d_cps = (a_cps * ((double) sim_throt_val)) / 100.0;
|
||||
if (d_cps >= a_cps) {
|
||||
sim_throt_state = 0;
|
||||
sim_throt_sched (); /* start over */
|
||||
return SCPE_OK;
|
||||
}
|
||||
sim_throt_wait = (int32) /* time between waits */
|
||||
((a_cps * d_cps * ((double) sim_idle_rate_ms)) /
|
||||
(1000.0 * (a_cps - d_cps)));
|
||||
if (sim_throt_wait < SIM_THROT_WMIN) { /* not long enough? */
|
||||
sim_throt_state = 0;
|
||||
sim_throt_sched (); /* start over */
|
||||
return SCPE_OK;
|
||||
}
|
||||
sim_throt_state++;
|
||||
sim_throt_ms_start = sim_throt_ms_stop;
|
||||
sim_throt_state = 2;
|
||||
// fprintf (stderr, "Throttle values a_cps = %f, d_cps = %f, wait = %d\n",
|
||||
// a_cps, d_cps, sim_throt_wait);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* throttling */
|
||||
sim_os_ms_sleep (1);
|
||||
sim_os_ms_sleep (sim_throt_sleep_time);
|
||||
delta_ms = sim_os_msec () - sim_throt_ms_start;
|
||||
if ((sim_throt_type != SIM_THROT_SPC) && /* when dynamic throttling */
|
||||
(delta_ms >= 10000)) { /* recompute every 10 sec */
|
||||
sim_throt_ms_start = sim_os_msec ();
|
||||
sim_throt_wait = SIM_THROT_WST;
|
||||
sim_throt_state = 1; /* next state */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
28
sim_timer.h
28
sim_timer.h
|
@ -31,6 +31,26 @@
|
|||
#ifndef _SIM_TIMER_H_
|
||||
#define _SIM_TIMER_H_ 0
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#if defined (__APPLE__)
|
||||
#define HAVE_STRUCT_TIMESPEC 1 /* OSX defined the structure but doesn't tell us */
|
||||
#endif
|
||||
|
||||
#ifndef CLOCK_REALTIME
|
||||
#define CLOCK_REALTIME 1
|
||||
#define NEED_CLOCK_GETTIME 1
|
||||
#ifndef HAVE_STRUCT_TIMESPEC
|
||||
#define HAVE_STRUCT_TIMESPEC 1
|
||||
struct timespec {
|
||||
long tv_sec;
|
||||
long tv_nsec;
|
||||
};
|
||||
#endif /* HAVE_STRUCT_TIMESPEC */
|
||||
int clock_gettime(int clock_id, struct timespec *tp);
|
||||
#endif
|
||||
|
||||
|
||||
#define SIM_NTIMERS 8 /* # timers */
|
||||
#define SIM_TMAX 500 /* max timer makeup */
|
||||
|
||||
|
@ -46,11 +66,13 @@
|
|||
#define SIM_THROT_WMIN 100 /* min wait */
|
||||
#define SIM_THROT_MSMIN 10 /* min for measurement */
|
||||
#define SIM_THROT_NONE 0 /* throttle parameters */
|
||||
#define SIM_THROT_MCYC 1
|
||||
#define SIM_THROT_KCYC 2
|
||||
#define SIM_THROT_PCT 3
|
||||
#define SIM_THROT_MCYC 1 /* MegaCycles Per Sec */
|
||||
#define SIM_THROT_KCYC 2 /* KiloCycles Per Sec */
|
||||
#define SIM_THROT_PCT 3 /* Max Percent of host CPU */
|
||||
#define SIM_THROT_SPC 4 /* Specific periodic Delay */
|
||||
|
||||
t_bool sim_timer_init (void);
|
||||
void sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub);
|
||||
int32 sim_rtcn_init (int32 time, int32 tmr);
|
||||
void sim_rtcn_init_all (void);
|
||||
int32 sim_rtcn_calb (int32 ticksper, int32 tmr);
|
||||
|
|
Loading…
Add table
Reference in a new issue