1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-01-11 23:52:48 +00:00

SCP: Updated to current version.

This commit is contained in:
Richard Cornwell 2018-02-15 18:07:19 -05:00
parent 328ddcc23c
commit 8f26b58deb
31 changed files with 11846 additions and 530 deletions

166
display/README Normal file
View File

@ -0,0 +1,166 @@
$Id: README,v 1.15 2004/02/09 07:20:18 phil Exp $
XY Display Simulation
Simulates XY plotting displays used on DEC PDP systems.
Copyright (c) 2003-2004, Philip L. Budne and Douglas A. Gwyn
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
THE AUTHORS 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 the authors shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from the authors.
Phil Budne <phil@ultimate.com>
Douglas A Gwyn <gwyn@arl.army.mil>
February 5, 2004
Designed for use with Bob Supnik's SIMH, but the code should be easily
portable, and usable standalone (see vttest.c for an example).
Display code is provided for X11 (Unix/VMS) and Win32.
We're not GUI programmers, so the code is PRIMITIVE!!
Started from VC8E simulator by Douglas W. Jones
(distribution 5, of Feb 4, 1997);
This PDP8 Emulator was written by Douglas W. Jones at the
University of Iowa. It is distributed as freeware, of
uncertain function and uncertain utility.
Original phosphor decay constants for Type 30 display from XMame 0.72.1
VT11 support GREATLY enhanced (and VT48 support added) and
other general improvements from Douglas A Gwyn.
In the interest of fair play we have supplied two makefiles (neither
of which is named Makefile nor makefile), one which works under all
flavors of "make" (after necessary editing, in the traditional manner),
and one which functions only under the GNU version of make (sometimes
installed as "gmake", but the default "make" on many systems). We have
not added a third flavor which uses BSD make enhancements, because our
deeply held roots (over 40 combined years of Unix experience by the
authors) demand that things should work on all platforms. Both the
Linux and Windows worlds violate this simple credo (everything works so
long as you use OUR preferred software), and many current users may not
even realize that editing Makefiles used to be de rigeur. Since the
GNU environment is widely available and "gmake" has features that
support automatic configuration for multiple platforms, we have
supplied thr GNU-specific variant with the expectation that many users
will find it more convenient. You can copy or link whichever flavor of
makefile suits your taste to whichever spelling of "makefile" suits
your fancy, or invoke "make" with the -f flag specifying the desired
makefile.
To compile test programs:
========================
On Unix:
# edit smakefile to match your environment
make -f smakefile
or
gmake -f gmakefile
On Win32 (using Cygwin);
make -f gmakefile WIN32=1
On Win32 (using MINGW):
# edit smakefile to match your environment
make -f smakefile
or
mingw32-make -f gmakefile WIN32=1
or
execute build-mingw.bat in a DOS command window
creates:
munch: standalone simulation of PDP-1 munching squares;
examines console "test switches" (see next section)
vt11: sequences through VT11/VS60 simulator test displays;
shows how the diplay-processor simulator can be used
from applications other than PDP-11 simulators
Console switches:
================
Upto 18 simulated console switches, toggled by hitting keys:
123 456 789 qwe rty uio
space bar clears all switches.
Spacewar Switches:
=================
Key presses for simulated Spacewar control box switches;
action player
1 2
rotate clockwise a k
rotate counter clockwise s l
fire engines d ;
launch torpedo f '
hyperspace (both at once) as kl
Light pen:
=========
The light pen is active when any mouse button is held down.
Mouse button 1 acts as a "tip switch" for models so equipped (VS60).
The light pen may be dragged while active.
Too many compile time parameters:
================================
Read the comments in display.c for more explanations!!
DISPLAY_TYPE default display type, one of:
DIS_VR14, DIS_VR17, DIS_VR20, DIS_VR48, DIS_TYPE30, DIS_TYPE340
selects screen characteristics (phosphor, dimensions).
Only affects programs which do not make an expicit
display_init() call.
PIX_SCALE one of RES_FULL, RES_HALF, RES_QUARTER, RES_EIGHTH
selects default display scaling factor.
PEN_RADIUS default radius of light pen in (scaled) pixels
MAXELAPSED Upper limit in real microseconds between polls/delays
MINELAPSED Lower limit in real microseconds between polls/delays
MINDELAY Lower limit in real microseconds for attempted delay
MAXDELAY Upper limit in real microseconds for attempted delay
GAINSHIFT delay_check increment/decrement gain factor
In display system support (x11.c, win32.c);
PIX_SIZE selects displayed pixel size (default 1)
makes screen larger, useful when display scaled to small size
Programming interface:
=====================
see display.h
Source repository:
=================
Up-to-date Sources are available by anonymous CVS.
See http://www.ultimate.com/phil/xy/

12
display/build_mingw.bat Normal file
View File

@ -0,0 +1,12 @@
@echo off
rem $Id: build_mingw.bat,v 1.1 2004/01/25 17:48:03 phil Exp $
rem Compile all test programs using MINGW make and gcc environment
rem
rem If needed, define the path for the MINGW bin directory.
rem (this should already be set if MINGW was installed correctly)
rem
gcc -v 1>NUL 2>NUL
if ERRORLEVEL 1 path C:\MinGW\bin;D:\MinGW\bin;E:\MinGW\bin;%path%
gcc -v 1>NUL 2>NUL
if ERRORLEVEL 1 echo "MinGW Environment Unavailable"
mingw32-make WIN32=1 -f gmakefile %1 %2 %3 %4

333
display/carbon.c Normal file
View File

@ -0,0 +1,333 @@
/*
* $Id: carbon.c,v 1.2 2005/08/06 21:09:03 phil Exp $
* Mac OS X Carbon support for XY display simulator
* John Dundas <dundas@caltech.edu>
* December 2004
*
* This is a simplistic driver under Mac OS Carbon for the XY display
* simulator.
*
* A more interesting driver would use OpenGL directly.
*/
#include <Carbon/Carbon.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ws.h"
#include "display.h"
#include <sys/types.h>
#include <sys/time.h>
#define ARRAYLEN(a) (sizeof (a) / sizeof (a[0]))
#ifndef PIX_SIZE
#define PIX_SIZE 1
#endif
/*
* light pen location
* see ws.h for full description
*/
int ws_lp_x = -1;
int ws_lp_y = -1;
static RGBColor blckColor = { 0x0000, 0x0000, 0x0000 };
static RGBColor whteColor = { 0xFFFF, 0xFFFF, 0xFFFF };
static WindowRef mainWind;
static RgnHandle rgn;
static MouseTrackingRef mouseRef;
static int xpixels, ypixels;
static int buttons = 0; /* tracks state of all buttons */
static EventTargetRef EventDispatchTarget;
void MyEventWait ( EventTimeout timeout ) /* double */
{
EventRef theEvent;
if (ReceiveNextEvent (0, NULL, timeout, true, &theEvent) == noErr) {
SendEventToEventTarget (theEvent, EventDispatchTarget);
ReleaseEvent (theEvent);
}
}
static pascal OSStatus doMouseEvent ( EventHandlerCallRef handlerRef,
EventRef event,
void *userData )
{
OSStatus err = eventNotHandledErr;
Point start;
GrafPtr prevPort;
/* make sure the display is the current grafport */
if (!QDSwapPort (GetWindowPort (mainWind), &prevPort))
prevPort = NULL;
switch (GetEventKind (event)) {
case kEventMouseEntered:
if (ActiveNonFloatingWindow () != mainWind)
break;
SetThemeCursor (kThemeCrossCursor);
break;
case kEventMouseExited:
if (ActiveNonFloatingWindow () != mainWind)
break;
SetThemeCursor (kThemeArrowCursor);
break;
case kEventMouseDown:
GetEventParameter (event, kEventParamMouseLocation,
typeQDPoint, NULL, sizeof (typeQDPoint), NULL, &start);
GlobalToLocal (&start);
ws_lp_x = start.h;
ws_lp_y = ypixels - start.v;
display_lp_sw = 1;
break;
case kEventMouseUp:
display_lp_sw = 0;
ws_lp_x = ws_lp_y = -1;
break;
default:
break;
}
if (prevPort)
SetPort (prevPort);
return (err);
}
static pascal OSStatus updateWindow ( EventHandlerCallRef handlerRef,
EventRef event,
void *userData )
{
OSStatus err = eventNotHandledErr;
switch (GetEventKind (event)) {
case kEventWindowActivated:
/* update menus */
break;
case kEventWindowClose: /* Override window close */
err = noErr;
break;
case kEventWindowDrawContent:
display_repaint ();
err = noErr;
default:
break;
}
return (err);
}
static pascal OSStatus doKbdEvent ( EventHandlerCallRef handlerRef,
EventRef event,
void *userData )
{
UInt32 c, m;
char key;
GetEventParameter (event, kEventParamKeyCode,
typeUInt32, NULL, sizeof (typeUInt32), NULL, &c);
GetEventParameter (event, kEventParamKeyMacCharCodes,
typeChar, NULL, sizeof (typeChar), NULL, &key);
GetEventParameter (event, kEventParamKeyModifiers,
typeUInt32, NULL, sizeof (typeUInt32), NULL, &m);
/* Keys with meta-modifiers are not allowed at this time. */
#define KEY_MODIFIERS (cmdKey | optionKey | kEventKeyModifierFnMask)
if (m & KEY_MODIFIERS)
return (eventNotHandledErr);
switch (GetEventKind (event)) {
case kEventRawKeyRepeat:
case kEventRawKeyDown:
display_keydown (key);
break;
case kEventRawKeyUp:
display_keyup (key);
break;
default:
break;
}
return (noErr);
}
int ws_init ( const char *crtname, /* crt type name */
int xp, /* screen size in pixels */
int yp,
int colors, /* colors to support (not used) */
void *dptr)
{
WindowAttributes windowAttrs;
Rect r;
CFStringRef str;
static MouseTrackingRegionID mouseID = { 'AAPL', 0 };
static const EventTypeSpec moEvent[] = {
{ kEventClassMouse, kEventMouseEntered },
{ kEventClassMouse, kEventMouseExited },
{ kEventClassMouse, kEventMouseDown },
{ kEventClassMouse, kEventMouseUp },
};
static const EventTypeSpec wuEvent[] = {
{ kEventClassWindow, kEventWindowDrawContent },
{ kEventClassWindow, kEventWindowClose },
{ kEventClassWindow, kEventWindowActivated},
};
static const EventTypeSpec kdEvent[] = {
{ kEventClassKeyboard, kEventRawKeyDown },
{ kEventClassKeyboard, kEventRawKeyRepeat },
{ kEventClassKeyboard, kEventRawKeyUp},
};
xpixels = xp; /* save screen size */
ypixels = yp;
r.top = 100; r.left = 100; r.bottom = r.top + yp; r.right = r.left + xp;
/* should check this r against GetQDGlobalsScreenBits (&screen); */
windowAttrs = kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute;
if (CreateNewWindow (kDocumentWindowClass, windowAttrs, &r, &mainWind) != noErr)
return (0);
if (str = CFStringCreateWithCString (kCFAllocatorDefault, crtname,
kCFStringEncodingASCII)) {
SetWindowTitleWithCFString (mainWind, str);
CFRelease (str);
}
SetPortWindowPort (mainWind);
/*
* Setup to handle events
*/
EventDispatchTarget = GetEventDispatcherTarget ();
InstallEventHandler (GetWindowEventTarget (mainWind),
NewEventHandlerUPP (doMouseEvent), ARRAYLEN(moEvent),
(EventTypeSpec *) &moEvent, NULL, NULL);
InstallEventHandler (GetWindowEventTarget (mainWind),
NewEventHandlerUPP (updateWindow), ARRAYLEN(wuEvent),
(EventTypeSpec *) &wuEvent, NULL, NULL);
InstallEventHandler (GetWindowEventTarget (mainWind),
NewEventHandlerUPP (doKbdEvent), ARRAYLEN(kdEvent),
(EventTypeSpec *) &kdEvent, NULL, NULL);
/* create region to track cursor shape */
r.top = 0; r.left = 0; r.bottom = yp; r.right = xp;
rgn = NewRgn ();
RectRgn (rgn, &r);
CloseRgn (rgn);
CreateMouseTrackingRegion (mainWind, rgn, NULL,
kMouseTrackingOptionsLocalClip, mouseID, NULL, NULL, &mouseRef);
ShowWindow (mainWind);
RGBForeColor (&blckColor);
PaintRect (&r);
RGBBackColor (&blckColor);
return (1);
}
void ws_shutdown (void)
{
}
void *ws_color_black (void)
{
return (&blckColor);
}
void *ws_color_white (void)
{
return (&whteColor);
}
void *ws_color_rgb ( int r,
int g,
int b )
{
RGBColor *color;
if ((color = malloc (sizeof (RGBColor))) != NULL) {
color->red = r;
color->green = g;
color->blue = b;
}
return (color);
}
/* put a point on the screen */
void ws_display_point ( int x,
int y,
void *color )
{
#if PIX_SIZE != 1
Rect r;
#endif
if (x > xpixels || y > ypixels)
return;
y = ypixels - y /* - 1 */;
#if PIX_SIZE == 1
SetCPixel (x, y, (color == NULL) ? &blckColor : color);
#else
r.top = y * PIX_SIZE;
r.left = x * PIX_SIZE;
r.bottom = (y + 1) * PIX_SIZE;
r.right = (x + 1) * PIX_SIZE;
RGBForeColor ((color == NULL) ? &blckColor : color);
PaintRect (&r);
#endif
}
void ws_sync (void)
{
;
}
/*
* elapsed wall clock time since last call
* +INF on first call
*/
struct elapsed_state {
struct timeval tvs[2];
int new;
};
static unsigned long
elapsed(struct elapsed_state *ep)
{
unsigned long val;
gettimeofday(&ep->tvs[ep->new], NULL);
if (ep->tvs[!ep->new].tv_sec == 0)
val = ~0L;
else
val = ((ep->tvs[ep->new].tv_sec - ep->tvs[!ep->new].tv_sec) * 1000000 +
(ep->tvs[ep->new].tv_usec - ep->tvs[!ep->new].tv_usec));
ep->new = !ep->new;
return val;
}
/* called periodically */
int ws_poll ( int *valp,
int maxusec )
{
static struct elapsed_state es; /* static to avoid clearing! */
elapsed(&es); /* start clock */
do {
unsigned long e;
MyEventWait (maxusec * kEventDurationMicrosecond);
e = elapsed(&es);
maxusec -= e;
} while (maxusec > 10000); /* 10ms */
return (1);
}
void ws_beep (void)
{
SysBeep (3);
}
/* public version, used by delay code */
unsigned long os_elapsed (void)
{
static struct elapsed_state es;
return (elapsed (&es));
}

1068
display/display.c Normal file

File diff suppressed because it is too large Load Diff

144
display/display.h Normal file
View File

@ -0,0 +1,144 @@
/*
* $Id: display.h,v 1.13 2004/01/24 08:34:33 phil Exp $
* interface to O/S independent layer of XY display simulator
* Phil Budne <phil@ultimate.com>
* September 2003
*
* Changes from Douglas A. Gwyn, Jan 12, 2004
*/
/*
* Copyright (c) 2003-2004, Philip L. Budne
*
* 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
* THE AUTHORS 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 the authors shall
* not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization
* from the authors.
*/
/*
* known display types
*/
enum display_type {
DIS_VR14 = 14,
DIS_VR17 = 17,
DIS_VR20 = 20,
DIS_TYPE30 = 30,
DIS_TX0 = 33,
DIS_VR48 = 48,
DIS_TYPE340 = 340
};
/*
* display scale factors
*/
#define RES_FULL 1
#define RES_HALF 2
#define RES_QUARTER 4
#define RES_EIGHTH 8
/*
* must be called before first call to display_age()
* (but called implicitly by display_point())
*/
extern int display_init(enum display_type, int scale, void *dptr);
/* return size of virtual display */
extern int display_xpoints(void);
extern int display_ypoints(void);
/* virtual points between display and menu sections */
#define VR48_GUTTER 8 /* just a guess */
/* conversion factor from virtual points and displayed pixels */
extern int display_scale(void);
/*
* simulate passage of time; first argument is simulated microseconds elapsed,
* second argument is flag to slow down simulated speed
* see comments in display.c for why you should call it often!!
* Under X11 polls for window events!!
*/
extern int display_age(int,int);
/*
* display intensity levels.
* always at least 8 (for VT11/VS60) -- may be mapped internally
*/
#define DISPLAY_INT_MAX 7
#define DISPLAY_INT_MIN 0 /* lowest "on" level */
/*
* plot a point; argumen ts are x, y, intensity, color (0/1)
* returns true if light pen active (mouse button down)
* at (or very near) this location.
*
* Display initialized on first call.
*/
extern int display_point(int,int,int,int);
/*
* force window system to output bits to screen;
* call after adding points, or aging the screen
* collect any window system input (mouse or keyboard)
*/
extern void display_sync(void);
/*
* currently a noop
*/
extern void display_reset(void);
/*
* ring the bell
*/
extern void display_beep(void);
/*
* Set light-pen radius; maximum radius in display coordinates
* from a "lit" location that the light pen will see.
*/
extern void display_lp_radius(int);
/*
* set by simulated spacewar switch box switches
* 18 bits (only high 4 and low 4 used)
*/
extern unsigned long spacewar_switches;
/*
* light pen "tip switch" activated (for VS60 emulation etc.)
* should only be set from "driver" (window system layer)
*/
extern unsigned char display_lp_sw;
/*
* deactivates light pen
* (SIMH DR11-C simulation when initialized sets this and
* then reports mouse coordinates as Talos digitizer data)
*/
extern unsigned char display_tablet;
/*
* users of this library are expected to provide these calls.
* simulator will set 18 simulated switches.
*/
extern unsigned long cpu_get_switches(void); /* get current switch state */
extern void cpu_set_switches(unsigned long); /* set switches */

86
display/gmakefile Normal file
View File

@ -0,0 +1,86 @@
# $Id: gmakefile,v 1.24 2005/11/05 02:06:14 phil Exp $
# (GNU) Makefile for test programs under Unix/X11 and Win32
#
# Unix:
# edit Unix defs to fit your compiler/library environment, then
# gmake -f gmakefile
# or if GNU make is the default:
# make -f gmakefile
#
# OS X (Carbon)
# make -f gmakefile OSX=1
#
# Win32 (Cygwin)
# make -f gmakefile WIN32=1
#
# Win32 (MINGW):
# mingw32-make -f gmakefile WIN32=1
DISP_DEFS=-DTEST_DIS=DIS_VR48 -DTEST_RES=RES_HALF # -DDEBUG_VT11
ifeq ($(WIN32),)
ifeq ($(OSX),)
#Unix environments
X11BASE=/usr/X11R6
X11LIBDIR=$(X11BASE)/lib
X11INCDIR=$(X11BASE)/include
LIBS=-L$(X11LIBDIR) -lXt -lX11 -lm
OSFLAGS=-I$(X11INCDIR)
DRIVER=x11.o
EXT=
else
DRIVER=carbon.o
LIBS=-framework Carbon
endif
else
#Win32 environments
LIBS=-lgdi32
OSFLAGS=
DRIVER=win32.o
EXT=.exe
endif
#PROF=-g # -pg
OPT=-O2
CFLAGS=$(OPT) $(PROF) $(OSFLAGS) $(DISP_DEFS)
CC=gcc -Wunused
LDFLAGS=$(PROF)
ALL= munch$(EXT) vt11$(EXT)
ALL: $(ALL)
# munching squares; see README file for
# how to use console switches
MUNCH=$(DRIVER) xy.o test.o
munch$(EXT): $(MUNCH)
$(CC) $(LDFLAGS) -o munch$(EXT) $(MUNCH) $(LIBS)
VT11=$(DRIVER) vt11.o vttest.o xy.o
vt11$(EXT): $(VT11)
$(CC) $(LDFLAGS) -o vt11$(EXT) $(VT11) $(LIBS)
xy.o: xy.h ws.h
vt11.o: xy.h vt11.h
x11.o: ws.h xy.h
carbon.o: ws.h
win32.o: ws.h
test.o: xy.h vt11.h
vttest.o: xy.h vt11.h vtmacs.h
clean:
ifeq ($(WIN32),)
rm -f *.o *~ .#*
else
if exist *.o del /q *.o
if exist *~ del /q *~
if exist .#* del /q .#*
endif
clobber: clean
ifeq ($(WIN32),)
rm -f $(ALL)
else
if exist *.exe del /q *.exe
endif

422
display/sim_ws.c Normal file
View File

@ -0,0 +1,422 @@
/*
* simh sim_video support for XY display simulator
* Mark Pizzolato <mark@infocomm.com>
* January 2016
* Based on win32.c module by Phil Budne
*/
/*
* Copyright (c) 2016, 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
* THE AUTHORS 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 the authors shall
* not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization
* from the authors.
*/
/*
* BUGS:
* Does not allow you to close display window;
* would need to tear down both system, and system independent data.
*
*/
#include "sim_video.h"
#include <stdio.h>
#include <stdlib.h>
#include "ws.h"
#include "display.h"
#ifndef PIX_SIZE
#define PIX_SIZE 1
#endif
/*
* light pen location
* see ws.h for full description
*/
int ws_lp_x = -1;
int ws_lp_y = -1;
static int xpixels, ypixels;
static int pix_size = PIX_SIZE;
static const char *window_name;
static uint32 *colors = NULL;
static uint32 ncolors = 0, size_colors = 0;
static uint32 *surface = NULL;
typedef struct cursor {
Uint8 *data;
Uint8 *mask;
int width;
int height;
int hot_x;
int hot_y;
} CURSOR;
static CURSOR *arrow_cursor;
static CURSOR *cross_cursor;
static int
map_key(int k)
{
switch (k) {
case SIM_KEY_0: return '0';
case SIM_KEY_1: return '1';
case SIM_KEY_2: return '2';
case SIM_KEY_3: return '3';
case SIM_KEY_4: return '4';
case SIM_KEY_5: return '5';
case SIM_KEY_6: return '6';
case SIM_KEY_7: return '7';
case SIM_KEY_8: return '8';
case SIM_KEY_9: return '9';
case SIM_KEY_A: return 'a';
case SIM_KEY_B: return 'b';
case SIM_KEY_C: return 'c';
case SIM_KEY_D: return 'd';
case SIM_KEY_E: return 'e';
case SIM_KEY_F: return 'f';
case SIM_KEY_G: return 'g';
case SIM_KEY_H: return 'h';
case SIM_KEY_I: return 'i';
case SIM_KEY_J: return 'j';
case SIM_KEY_K: return 'k';
case SIM_KEY_L: return 'l';
case SIM_KEY_M: return 'm';
case SIM_KEY_N: return 'n';
case SIM_KEY_O: return 'o';
case SIM_KEY_P: return 'p';
case SIM_KEY_Q: return 'q';
case SIM_KEY_R: return 'r';
case SIM_KEY_S: return 's';
case SIM_KEY_T: return 't';
case SIM_KEY_U: return 'u';
case SIM_KEY_V: return 'v';
case SIM_KEY_W: return 'w';
case SIM_KEY_X: return 'x';
case SIM_KEY_Y: return 'y';
case SIM_KEY_Z: return 'z';
case SIM_KEY_BACKQUOTE: return '`';
case SIM_KEY_MINUS: return '-';
case SIM_KEY_EQUALS: return '=';
case SIM_KEY_LEFT_BRACKET: return '[';
case SIM_KEY_RIGHT_BRACKET: return ']';
case SIM_KEY_SEMICOLON: return ';';
case SIM_KEY_SINGLE_QUOTE: return '\'';
case SIM_KEY_BACKSLASH: return '\\';
case SIM_KEY_LEFT_BACKSLASH: return '\\';
case SIM_KEY_COMMA: return ',';
case SIM_KEY_PERIOD: return '.';
case SIM_KEY_SLASH: return '/';
case SIM_KEY_BACKSPACE: return '\b';
case SIM_KEY_TAB: return '\t';
case SIM_KEY_ENTER: return '\r';
case SIM_KEY_SPACE: return ' ';
}
return k;
}
int
ws_poll(int *valp, int maxus)
{
SIM_MOUSE_EVENT mev;
SIM_KEY_EVENT kev;
if (maxus > 1000)
sim_os_ms_sleep (maxus/1000);
if (SCPE_OK == vid_poll_mouse (&mev)) {
unsigned char old_lp_sw = display_lp_sw;
if ((display_lp_sw = mev.b1_state)) {
ws_lp_x = mev.x_pos;
ws_lp_y = (ypixels - 1) - mev.y_pos; /* range 0 - (ypixels-1) */
/* convert to display coordinates */
ws_lp_x /= pix_size;
ws_lp_y /= pix_size;
if (!old_lp_sw && !display_tablet)
vid_set_cursor (1, cross_cursor->width, cross_cursor->height, cross_cursor->data, cross_cursor->mask, cross_cursor->hot_x, cross_cursor->hot_y);
}
else {
ws_lp_x = ws_lp_y = -1;
if (old_lp_sw && !display_tablet)
vid_set_cursor (1, arrow_cursor->width, arrow_cursor->height, arrow_cursor->data, arrow_cursor->mask, arrow_cursor->hot_x, arrow_cursor->hot_y);
}
vid_set_cursor_position (mev.x_pos, mev.y_pos);
}
if (SCPE_OK == vid_poll_kb (&kev)) {
switch (kev.state) {
case SIM_KEYPRESS_DOWN:
case SIM_KEYPRESS_REPEAT:
display_keydown(map_key(kev.key));
break;
case SIM_KEYPRESS_UP:
display_keyup(map_key(kev.key));
break;
}
}
return 1;
}
/* XPM */
static const char *arrow[] = {
/* width height num_colors chars_per_pixel */
" 16 16 3 1",
/* colors */
"X c #000000", /* black */
". c #ffffff", /* white */
" c None",
/* pixels */
"X ",
"XX ",
"X.X ",
"X..X ",
"X...X ",
"X....X ",
"X.....X ",
"X......X ",
"X.......X ",
"X........X ",
"X.....XXXXX ",
"X..X..X ",
"X.X X..X ",
"XX X..X ",
"X X..X ",
" XX ",
};
/* XPM */
static const char *cross[] = {
/* width height num_colors chars_per_pixel hot_x hot_y*/
" 16 16 3 1 7 7",
/* colors */
"X c #000000", /* black */
". c #ffffff", /* white */
" c None",
/* pixels */
" XXXX ",
" X..X ",
" X..X ",
" X..X ",
" X..X ",
" X..X ",
"XXXXXXX..XXXXXXX",
"X..............X",
"X..............X",
"XXXXXXX..XXXXXXX",
" X..X ",
" X..X ",
" X..X ",
" X..X ",
" X..X ",
" XXXX ",
"7,7"
};
static CURSOR *ws_create_cursor(const char *image[])
{
int byte, bit, row, col;
Uint8 *data = NULL;
Uint8 *mask = NULL;
char black, white, transparent;
CURSOR *result = NULL;
int width, height, colors, cpp;
int hot_x = 0, hot_y = 0;
if (4 > sscanf(image[0], "%d %d %d %d %d %d",
&width, &height, &colors, &cpp, &hot_x, &hot_y))
return result;
if ((cpp != 1) || (0 != width%8) || (colors != 3))
return result;
black = image[1][0];
white = image[2][0];
transparent = image[3][0];
data = (Uint8 *)calloc (1, (width / 8) * height);
mask = (Uint8 *)calloc (1, (width / 8) * height);
if (!data || !mask) {
free (data);
free (mask);
return result;
}
bit = 7;
byte = 0;
for (row=0; row<height; ++row) {
for (col=0; col<width; ++col) {
if (image[colors+1+row][col] == black) {
data[byte] |= (1 << bit);
mask[byte] |= (1 << bit);
}
else
if (image[colors+1+row][col] == white) {
mask[byte] |= (1 << bit);
}
else
if (image[colors+1+row][col] != transparent) {
free (data);
free (mask);
return result;
}
--bit;
if (bit < 0) {
++byte;
bit = 7;
}
}
}
result = (CURSOR *)calloc (1, sizeof(*result));
if (result) {
result->data = data;
result->mask = mask;
result->width = width;
result->height = height;
result->hot_x = hot_x;
result->hot_y = hot_y;
}
else {
free (data);
free (mask);
}
return result;
}
static void ws_free_cursor (CURSOR *cursor)
{
if (!cursor)
return;
free (cursor->data);
free (cursor->mask);
free (cursor);
}
/* called from display layer on first display op */
int
ws_init(const char *name, int xp, int yp, int colors, void *dptr)
{
int i;
int ret;
arrow_cursor = ws_create_cursor (arrow);
cross_cursor = ws_create_cursor (cross);
xpixels = xp;
ypixels = yp;
window_name = name;
surface = (uint32 *)realloc (surface, xpixels*ypixels*sizeof(*surface));
for (i=0; i<xpixels*ypixels; i++)
surface[i] = vid_mono_palette[0];
ret = (0 == vid_open ((DEVICE *)dptr, name, xp*pix_size, yp*pix_size, 0));
if (ret)
vid_set_cursor (1, arrow_cursor->width, arrow_cursor->height, arrow_cursor->data, arrow_cursor->mask, arrow_cursor->hot_x, arrow_cursor->hot_y);
return ret;
}
void
ws_shutdown(void)
{
ws_free_cursor(arrow_cursor);
ws_free_cursor(cross_cursor);
vid_close();
}
void *
ws_color_rgb(int r, int g, int b)
{
uint32 color, i;
color = sim_end ? (0xFF000000 | ((r & 0xFF00) << 8) | (g & 0xFF00) | ((b & 0xFF00) >> 8)) : (0x000000FF | (r & 0xFF00) | ((g & 0xFF00) << 8) | ((b & 0xFF00) << 16));
for (i=0; i<ncolors; i++) {
if (colors[i] == color)
return &colors[i];
}
if (ncolors == size_colors) {
colors = (uint32 *)realloc (colors, (ncolors + 1000) * sizeof (*colors));
size_colors += 1000;
if (size_colors == 1000) {
colors[0] = vid_mono_palette[0];
colors[1] = vid_mono_palette[1];
ncolors = 2;
}
}
colors[ncolors] = color;
++ncolors;
return (void *)&colors[ncolors-1];
}
void *
ws_color_black(void)
{
return (void *)&vid_mono_palette[0];
}
void *
ws_color_white(void)
{
return (void *)&vid_mono_palette[1];
}
void
ws_display_point(int x, int y, void *color)
{
uint32 *brush = (uint32 *)color;
if (x > xpixels || y > ypixels)
return;
y = ypixels - 1 - y; /* invert y, top left origin */
if (brush == NULL)
brush = (uint32 *)ws_color_black ();
if (pix_size > 1) {
int i, j;
for (i=0; i<pix_size; i++)
for (j=0; j<pix_size; j++)
surface[(y + i)*xpixels + x + j] = *brush;
}
else
surface[y*xpixels + x] = *brush;
}
void
ws_sync(void) {
vid_draw (0, 0, xpixels, ypixels, surface);
vid_refresh ();
}
void
ws_beep(void) {
vid_beep ();
}
unsigned long
os_elapsed(void)
{
static int tnew;
unsigned long ret;
static uint32 t[2];
t[tnew] = sim_os_msec();
if (t[!tnew] == 0)
ret = ~0L; /* +INF */
else
ret = (t[tnew] - t[!tnew]) * 1000;/* usecs */
tnew = !tnew; /* Ecclesiastes III */
return ret;
}

91
display/smakefile Normal file
View File

@ -0,0 +1,91 @@
# $Id: smakefile,v 1.6 2005/11/05 02:06:14 phil Exp $
# Makefile for test programs (standard Unix "make" version)
# Unix:
# comment out OS X, Windows defs, uncomment Unix defs,
# edit Unix defs to fit your compiler/library environment, then
# make -f smakefile
#
# OS X (Carbon)
# comment out Unix, Windows defs, uncomment OS X defs
# make -f smakefile
#
# Win32 (Cygwin)
# comment out Unix defs, uncomment Windows defs, then
# make -f smakefile
#
# Win32 (MINGW)
# comment out Unix defs, uncomment Windows defs, then
# mingw32-make
DISP_DEFS=-DTEST_DIS=DIS_VR48 -DTEST_RES=RES_HALF # -DDEBUG_VT11
#Unix environments
CC=cc
#CC=gcc -Wunused
#X11BASE=/usr/X11R6
#X11LIBDIR=$(X11BASE)/lib
#X11INCDIR=$(X11BASE)/include
LIBS=-lXt -lX11 -lm # -L$(X11LIBDIR)
OSFLAGS=-I$(X11INCDIR)
DRIVER=x11.o
EXT=
PROF=-g # -pg
OPT=-O # -O2
CFLAGS=$(OPT) $(PROF) $(OSFLAGS) $(DISP_DEFS)
LDFLAGS=$(PROF)
##OS X
#CC=cc -Wunused
#LIBS=-framework Carbon
#OSFLAGS=
#DRIVER=carbon.o
#EXT=
#PROF=-g # -pg
#OPT=-O # -O2
#CFLAGS=$(OPT) $(PROF) $(OSFLAGS) $(DISP_DEFS)
#LDFLAGS=$(PROF)
##Win32 environments
#LIBS=-lgdi32
#OSFLAGS=
#DRIVER=win32.o
#EXT=.exe
#PROF=-g # -pg
#OPT=-O2
#CFLAGS=$(OPT) $(PROF) $(OSFLAGS) $(DISP_DEFS)
#CC=gcc -Wunused
LDFLAGS=$(PROF)
ALL= munch$(EXT) vt11$(EXT)
ALL: $(ALL)
# munching squares; see README file for
# how to use console switches
MUNCH=$(DRIVER) xy.o test.o
munch$(EXT): $(MUNCH)
$(CC) $(LDFLAGS) -o munch$(EXT) $(MUNCH) $(LIBS)
VT11=$(DRIVER) vt11.o vttest.o xy.o
vt11$(EXT): $(VT11)
$(CC) $(LDFLAGS) -o vt11$(EXT) $(VT11) $(LIBS)
xy.o: xy.h ws.h
vt11.o: xy.h vt11.h
x11.o: ws.h xy.h
carbon.o: ws.h
win32.o: ws.h
test.o: xy.h vt11.h
vttest.o: xy.h vt11.h vtmacs.h
clean:
rm -f *.o *~ .#* # Unix
# if exist *.o del /q *.o # Win32
# if exist *~ del /q *~ # Win32
# if exist .#* del /q .#* # Win32
clobber: clean
rm -f $(ALL) # Unix
# if exist *.exe del /q *.exe # Win32

192
display/test.c Normal file
View File

@ -0,0 +1,192 @@
/*
* $Id: test.c,v 1.22 2004/01/25 17:20:50 phil Exp - revised by DAG $
* XY Display simulator test program (PDP-1 Munching Squares)
* Phil Budne <phil@ultimate.com>
* September 2003
*
* Updates from Douglas A. Gwyn, 12 Jan. 2004
*
* With thanks to Daniel Smith for his web page:
* http://world.std.com/~dpbsmith/munch.html
*/
/*
* Copyright (c) 2003-2004, Philip L. Budne
*
* 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
* THE AUTHORS 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 the authors shall
* not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization
* from the authors.
*/
#ifndef TEST_DIS
#define TEST_DIS DIS_TYPE30
#endif
#ifndef TEST_RES
#define TEST_RES RES_HALF
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef EXIT_FAILURE
/* SunOS4 <stdlib.h> doesn't define this */
#define EXIT_FAILURE 1
#endif
#include "display.h"
static unsigned long test_switches = 0;
/* called from display code: */
unsigned long
cpu_get_switches(void) {
return test_switches;
}
/* called from display code: */
void
cpu_set_switches(bits)
unsigned long bits;
{
printf("switches: %06lo\n", bits);
test_switches = bits;
}
void
munch(void) {
static long us = 0;
static long io = 0, v = 0;
long ac;
int x, y;
ac = test_switches;
ac += v; /* add v */
if (ac & ~0777777) {
ac++;
ac &= 0777777;
}
v = ac; /* dac v */
ac <<= 9; /* rcl 9s */
io <<= 9;
io |= ac>>18;
ac &= 0777777;
ac |= io>>18;
io &= 0777777;
ac ^= v; /* xor v */
/* convert +/-512 one's complement to 0..1022, origin in lower left */
y = (io >> 8) & 01777; /* hi 10 */
if (y & 01000)
y ^= 01000;
else
y += 511;
x = (ac >> 8) & 01777; /* hi 10 */
if (x & 01000) /* negative */
x ^= 01000;
else
x += 511;
if (display_point(x, y, DISPLAY_INT_MAX, 0))
printf("light pen hit at (%d,%d)\n", x, y);
/*#define US 100000 /* 100ms (10/sec) */
/*#define US 50000 /* 50ms (20/sec) */
/*#define US 20000 /* 20ms (50/sec) */
/*#define US 10000 /* 10ms (100/sec) */
#define US 0
us += 50; /* 10 5us PDP-1 memory cycles */
if (us >= US) {
display_age(us, 1);
us = 0;
}
display_sync(); /* XXX push down */
}
#ifdef T2
/* display all window system level intensities;
* must be compiled with -DINTENSITIES=<n> -DT2
*/
void
t2(void) {
int x, y;
display_init(TEST_DIS, TEST_RES, NULL);
for (x = INTENSITIES-1; x >= 0; x--) {
for (y = 0; y < 20; y++) {
ws_display_point(x*4, y, x, 0);
ws_display_point(x*4+1, y, x, 0);
ws_display_point(x*4+2, y, x, 0);
ws_display_point(x*4+3, y, x, 0);
}
display_sync();
}
fflush(stdout);
for (;;)
/* wait */ ;
}
#endif
#ifdef T3
/* display all "user" level intensities;
* must be compiled with -DINTENSITIES=<n> -DT3
*
* skip every other virtual point on both axes
* default scaling maps adjacent pixels and
* causes re-intensification!
*/
void
t3(void) {
int x, y;
display_init(TEST_DIS, TEST_RES, NULL);
for (x = DISPLAY_INT_MAX; x >= 0; x--) {
for (y = 0; y < 20; y++) {
display_point(x*2, y*2, x, 0);
}
display_sync();
}
fflush(stdout);
for (;;)
/* wait */ ;
}
#endif
int
main(void) {
if (!display_init(TEST_DIS, TEST_RES, NULL))
exit(EXIT_FAILURE);
cpu_set_switches(04000UL); /* classic starting value */
for (;;) {
#ifdef T2
t2();
#endif
#ifdef T3
t3();
#endif
munch();
}
/*NOTREACHED*/
}

706
display/type340.c Normal file
View File

@ -0,0 +1,706 @@
/*
* $Id: type340.c,v 1.6 2005/01/14 18:58:00 phil Exp $
* Simulator Independent DEC Type 340 Graphic Display Processor Simulation
* Phil Budne <phil@ultimate.com>
* September 20, 2003
* from vt11.c
*
* Information from DECUS 7-13
* http://www.spies.com/~aek/pdf/dec/pdp7/7-13_340displayProgMan.pdf
*/
/*
* Copyright (c) 2003-2004, Philip L. Budne
*
* 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
* THE AUTHORS 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 name of the author shall
* not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization
* from the authors.
*/
#include "display.h" /* XY plot interface */
/*
* The Type 340 was used on the PDP-{4,6,7,9,10}
* and used 18-bit words, with bits numbered 0 thru 17
* (most significant to least)
*/
#define BITMASK(N) (1<<(17-(N)))
/* mask for a field */
#define FIELDMASK(START,END) ((1<<((END)-(START)+1))-1)
/* extract a field */
#define GETFIELD(W,START,END) (((W)>>(17-(END)))&FIELDMASK(START,END))
/* extract a 1-bit field */
#define TESTBIT(W,B) (((W) & BITMASK(B)) != 0)
#ifdef DEBUG_TY340
#define DEBUGF(X) printf X
#else
#define DEBUGF(X)
#endif
typedef long ty340word;
static ty340word DAC; /* Display Address Counter */
static unsigned char shift; /* 1 bit */
static enum mode mode; /* 3 bits */
static int scale; /* 2 bits */
enum mode { PARAM=0, POINT, SLAVE, CHAR, VECTOR, VCONT, INCR, SUBR };
enum jump_type { DJP=2, DJS=3, DDS=1 };
static ty340word ASR; /* Address Save Register */
static unsigned char save_ff; /* "save" flip-flop */
static unsigned char intensity; /* 3 bits */
static unsigned char lp_ena; /* 1 bit */
/* kept signed for raster violation checking */
static short xpos, ypos; /* 10 bits, signed */
static unsigned char sequence; /* 2 bits */
/* XXX make defines public for 340_cycle return */
#define STOPPED 01
#define LPHIT 02
#define VEDGE 04
#define HEDGE 010
static unsigned char status = STOPPED;
/*
* callbacks into PDP-6/10 simulator
*/
extern ty340word ty340_fetch(ty340word);
extern void ty340_store(ty340word, ty340word);
extern void ty340_stop_int(void);
extern void ty340_lp_int(void);
void
ty340_set_dac(ty340word addr)
{
DAC = addr;
mode = 0;
DEBUGF(("set DAC %06\r\n", DAC));
status = 0; /* XXX just clear stopped? */
/* XXX clear other stuff? save_ff? */
}
void
ty340_reset(void)
{
/* XXX call display layer? destroy window? */
xpos = ypos = 0;
status = STOPPED;
}
static int
point(int x, int y, int seq)
{
int i;
/* XXX apply scale? */
i = DISPLAY_INT_MAX-7+intensity;
if (i <= 0)
i = 1;
if (x < 0 || x > 1023) {
status |= VEDGE;
return 0;
}
if (y < 0 || y > 1023) {
status |= HEDGE;
return 0;
}
if (display_point(x, y, i, 0)) {
if (lp_ena) {
/* XXX save location? */
status |= LPHIT;
sequence = seq;
}
}
}
/*
* two-step algorithm, developed by Xiaolin Wu
* from http://graphics.lcs.mit.edu/~mcmillan/comp136/Lecture6/Lines.html
*/
/*
* The two-step algorithm takes the interesting approach of treating
* line drawing as a automaton, or finite state machine. If one looks
* at the possible configurations for the next two pixels of a line,
* it is easy to see that only a finite set of possibilities exist.
* The two-step algorithm shown here also exploits the symmetry of
* line-drawing by simultaneously drawn from both ends towards the
* midpoint.
*/
static void
lineTwoStep(int x0, int y0, int x1, int y1)
{
int dy = y1 - y0;
int dx = x1 - x0;
int stepx, stepy;
if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
lpoint(x0,y0);
if (dx == 0 && dy == 0) /* following algorithm won't work */
return; /* just the one dot */
lpoint(x1, y1);
if (dx > dy) {
int length = (dx - 1) >> 2;
int extras = (dx - 1) & 3;
int incr2 = (dy << 2) - (dx << 1);
if (incr2 < 0) {
int c = dy << 1;
int incr1 = c << 1;
int d = incr1 - dx;
int i;
for (i = 0; i < length; i++) {
x0 += stepx;
x1 -= stepx;
if (d < 0) { /* Pattern: */
lpoint(x0, y0);
lpoint(x0 += stepx, y0); /* x o o */
lpoint(x1, y1);
lpoint(x1 -= stepx, y1);
d += incr1;
}
else {
if (d < c) { /* Pattern: */
lpoint(x0, y0); /* o */
lpoint(x0 += stepx, y0 += stepy); /* x o */
lpoint(x1, y1);
lpoint(x1 -= stepx, y1 -= stepy);
} else {
lpoint(x0, y0 += stepy); /* Pattern: */
lpoint(x0 += stepx, y0); /* o o */
lpoint(x1, y1 -= stepy); /* x */
lpoint(x1 -= stepx, y1);
}
d += incr2;
}
}
if (extras > 0) {
if (d < 0) {
lpoint(x0 += stepx, y0);
if (extras > 1) lpoint(x0 += stepx, y0);
if (extras > 2) lpoint(x1 -= stepx, y1);
} else
if (d < c) {
lpoint(x0 += stepx, y0);
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
if (extras > 2) lpoint(x1 -= stepx, y1);
} else {
lpoint(x0 += stepx, y0 += stepy);
if (extras > 1) lpoint(x0 += stepx, y0);
if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
}
}
} else {
int c = (dy - dx) << 1;
int incr1 = c << 1;
int d = incr1 + dx;
int i;
for (i = 0; i < length; i++) {
x0 += stepx;
x1 -= stepx;
if (d > 0) {
lpoint(x0, y0 += stepy); /* Pattern: */
lpoint(x0 += stepx, y0 += stepy); /* o */
lpoint(x1, y1 -= stepy); /* o */
lpoint(x1 -= stepx, y1 -= stepy); /* x */
d += incr1;
} else {
if (d < c) {
lpoint(x0, y0); /* Pattern: */
lpoint(x0 += stepx, y0 += stepy); /* o */
lpoint(x1, y1); /* x o */
lpoint(x1 -= stepx, y1 -= stepy);
} else {
lpoint(x0, y0 += stepy); /* Pattern: */
lpoint(x0 += stepx, y0); /* o o */
lpoint(x1, y1 -= stepy); /* x */
lpoint(x1 -= stepx, y1);
}
d += incr2;
}
}
if (extras > 0) {
if (d > 0) {
lpoint(x0 += stepx, y0 += stepy);
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
} else if (d < c) {
lpoint(x0 += stepx, y0);
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
if (extras > 2) lpoint(x1 -= stepx, y1);
} else {
lpoint(x0 += stepx, y0 += stepy);
if (extras > 1) lpoint(x0 += stepx, y0);
if (extras > 2) {
if (d > c)
lpoint(x1 -= stepx, y1 -= stepy);
else
lpoint(x1 -= stepx, y1);
}
}
}
}
} else {
int length = (dy - 1) >> 2;
int extras = (dy - 1) & 3;
int incr2 = (dx << 2) - (dy << 1);
if (incr2 < 0) {
int c = dx << 1;
int incr1 = c << 1;
int d = incr1 - dy;
int i;
for (i = 0; i < length; i++) {
y0 += stepy;
y1 -= stepy;
if (d < 0) {
lpoint(x0, y0);
lpoint(x0, y0 += stepy);
lpoint(x1, y1);
lpoint(x1, y1 -= stepy);
d += incr1;
} else {
if (d < c) {
lpoint(x0, y0);
lpoint(x0 += stepx, y0 += stepy);
lpoint(x1, y1);
lpoint(x1 -= stepx, y1 -= stepy);
} else {
lpoint(x0 += stepx, y0);
lpoint(x0, y0 += stepy);
lpoint(x1 -= stepx, y1);
lpoint(x1, y1 -= stepy);
}
d += incr2;
}
}
if (extras > 0) {
if (d < 0) {
lpoint(x0, y0 += stepy);
if (extras > 1) lpoint(x0, y0 += stepy);
if (extras > 2) lpoint(x1, y1 -= stepy);
} else
if (d < c) {
lpoint(x0, y0 += stepy);
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
if (extras > 2) lpoint(x1, y1 -= stepy);
} else {
lpoint(x0 += stepx, y0 += stepy);
if (extras > 1) lpoint(x0, y0 += stepy);
if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
}
}
} else {
int c = (dx - dy) << 1;
int incr1 = c << 1;
int d = incr1 + dy;
int i;
for (i = 0; i < length; i++) {
y0 += stepy;
y1 -= stepy;
if (d > 0) {
lpoint(x0 += stepx, y0);
lpoint(x0 += stepx, y0 += stepy);
lpoint(x1 -= stepy, y1);
lpoint(x1 -= stepx, y1 -= stepy);
d += incr1;
} else {
if (d < c) {
lpoint(x0, y0);
lpoint(x0 += stepx, y0 += stepy);
lpoint(x1, y1);
lpoint(x1 -= stepx, y1 -= stepy);
} else {
lpoint(x0 += stepx, y0);
lpoint(x0, y0 += stepy);
lpoint(x1 -= stepx, y1);
lpoint(x1, y1 -= stepy);
}
d += incr2;
}
}
if (extras > 0) {
if (d > 0) {
lpoint(x0 += stepx, y0 += stepy);
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
if (extras > 2) lpoint(x1 -= stepx, y1 -= stepy);
} else if (d < c) {
lpoint(x0, y0 += stepy);
if (extras > 1) lpoint(x0 += stepx, y0 += stepy);
if (extras > 2) lpoint(x1, y1 -= stepy);
} else {
lpoint(x0 += stepx, y0 += stepy);
if (extras > 1) lpoint(x0, y0 += stepy);
if (extras > 2) {
if (d > c)
lpoint(x1 -= stepx, y1 -= stepy);
else
lpoint(x1, y1 -= stepy);
}
}
}
}
}
} /* lineTwoStep */
static int
vector(int i, int sx, int dx, int sy, int dy)
{
int x0, y0, x1, y1;
x0 = xpos;
y0 = ypos;
if (sx) {
x1 = x0 - dx;
if (x1 < 0) /* XXX TEMP? */
x1 = 0;
}
else {
x1 = x0 + dx;
if (x1 > 1023) /* XXX TEMP? */
x1 = 1023;
}
if (sy) {
y1 = y0 - dy;
if (y1 < 0) /* XXX TEMP? */
y1 = 0;
}
else {
y1 = y0 + dy; /* XXX TEMP? */
if (y1 > 1023)
y1 = 1023;
}
DEBUGF(("vector i%d (%d,%d) to (%d,%d)\r\n", i, x0, y0, x1, y1));
if (i)
lineTwoStep(x0, y0, x1, y1);
xpos = x1;
ypos = y1;
return 0;
}
/* return true on raster violation */
int
ipoint(int i, int n, unsigned char byte)
{
if (byte & 010) { /* left/right */
if (byte & 04) {
if (xpos == 0) {
status |= VEDGE;
return 1;
}
xpos--;
}
else {
if (xpos == 1023) {
status |= VEDGE;
return 1;
}
xpos++;
}
}
if (byte & 02) { /* up/down */
if (byte & 04) {
if (ypos == 0) {
status |= HEDGE;
return 1;
}
ypos--;
}
else {
if (ypos == 1023) {
status |= HEDGE;
return 1;
}
ypos++;
}
}
if (i)
point(xpos, ypos, n);
return 0;
}
/*
* 342 character generator - first 64 characters (from manual)
*/
static const unsigned char chars[64][5] = {
{ 0070, 0124, 0154, 0124, 0070 }, /* 00 */
{ 0174, 0240, 0240, 0240, 0174 }, /* 01 A */
{ 0376, 0222, 0222, 0222, 0154 }, /* 02 B */
{ 0174, 0202, 0202, 0202, 0104 }, /* 03 C */
{ 0376, 0202, 0202, 0202, 0174 }, /* 04 D */
{ 0376, 0222, 0222, 0222, 0222 }, /* 05 E */
{ 0376, 0220, 0220, 0220, 0220 }, /* 06 F */
{ 0174, 0202, 0222, 0222, 0134 }, /* 07 G */
{ 0376, 0020, 0020, 0020, 0376 }, /* 10 H */
{ 0000, 0202, 0376, 0202, 0000 }, /* 11 I */
{ 0004, 0002, 0002, 0002, 0374 }, /* 12 J */
{ 0376, 0020, 0050, 0104, 0202 }, /* 13 K */
{ 0376, 0002, 0002, 0002, 0002 }, /* 14 K */
{ 0374, 0100, 0040, 0100, 0374 }, /* 15 M */
{ 0376, 0100, 0040, 0020, 0376 }, /* 16 N */
{ 0174, 0202, 0202, 0202, 0174 }, /* 17 O */
{ 0376, 0220, 0220, 0220, 0140 }, /* 20 P */
{ 0174, 0202, 0212, 0206, 0176 }, /* 21 Q */
{ 0376, 0220, 0230, 0224, 0142 }, /* 22 R */
{ 0144, 0222, 0222, 0222, 0114 }, /* 23 S */
{ 0200, 0200, 0376, 0200, 0200 }, /* 24 T */
{ 0374, 0002, 0002, 0002, 0374 }, /* 25 U */
{ 0370, 0004, 0002, 0004, 0370 }, /* 26 V */
{ 0376, 0004, 0010, 0004, 0376 }, /* 27 W */
{ 0202, 0104, 0070, 0104, 0202 }, /* 30 X */
{ 0200, 0100, 0076, 0100, 0200 }, /* 31 Y */
{ 0226, 0232, 0222, 0262, 0322 }, /* 32 Z */
{ 0000, 0000, 0000, 0000, 0000 }, /* 33 LF */
{ 0000, 0000, 0000, 0000, 0000 }, /* 34 CR */
{ 0000, 0000, 0000, 0000, 0000 }, /* 35 HORIZ */
{ 0000, 0000, 0000, 0000, 0000 }, /* 36 VERT */
{ 0000, 0000, 0000, 0000, 0000 }, /* 37 ESC */
{ 0000, 0000, 0000, 0000, 0000 }, /* 40 space */
{ 0000, 0000, 0372, 0000, 0000 }, /* 41 ! */
{ 0000, 0340, 0000, 0340, 0000 }, /* 42 " */
{ 0050, 0376, 0050, 0376, 0050 }, /* 43 # */
{ 0144, 0222, 0376, 0222, 0114 }, /* 44 $ */
{ 0306, 0310, 0220, 0246, 0306 }, /* 45 % */
{ 0154, 0222, 0156, 0004, 0012 }, /* 46 & */
{ 0000, 0000, 0300, 0340, 0000 }, /* 47 ' */
{ 0070, 0104, 0202, 0000, 0000 }, /* 50 ( */
{ 0000, 0000, 0202, 0104, 0070 }, /* 51 ) */
{ 0124, 0070, 0174, 0070, 0124 }, /* 52 * */
{ 0020, 0020, 0174, 0020, 0020 }, /* 53 + */
{ 0000, 0014, 0016, 0000, 0000 }, /* 54 , */
{ 0020, 0020, 0020, 0020, 0020 }, /* 55 - */
{ 0000, 0006, 0006, 0000, 0000 }, /* 56 . */
{ 0004, 0010, 0020, 0040, 0100 }, /* 57 / */
{ 0174, 0212, 0222, 0242, 0174 }, /* 60 0 */
{ 0000, 0102, 0376, 0002, 0000 }, /* 61 1 */
{ 0116, 0222, 0222, 0222, 0142 }, /* 62 2 */
{ 0104, 0202, 0222, 0222, 0154 }, /* 63 3 */
{ 0020, 0060, 0120, 0376, 0020 }, /* 64 4 */
{ 0344, 0222, 0222, 0222, 0214 }, /* 65 5 */
{ 0174, 0222, 0222, 0222, 0114 }, /* 66 6 */
{ 0306, 0210, 0220, 0240, 0300 }, /* 67 7 */
{ 0154, 0222, 0222, 0222, 0154 }, /* 70 8 */
{ 0144, 0222, 0222, 0222, 0174 }, /* 71 9 */
{ 0000, 0066, 0066, 0000, 0000 }, /* 72 : */
{ 0000, 0154, 0156, 0000, 0000 }, /* 73 ; */
{ 0020, 0050, 0104, 0202, 0000 }, /* 74 < */
{ 0050, 0050, 0050, 0050, 0050 }, /* 75 = */
{ 0000, 0202, 0104, 0050, 0020 }, /* 76 > */
{ 0100, 0200, 0236, 0220, 0140 } /* 77 ? */
};
/*
* type 342 Character/Symbol generator for type 340 display
* return true if ESCaped
*/
static int
character(int n, char c)
{
int x, y;
switch (c) {
case 033: /* LF */
if (ypos < 12) {
status |= HEDGE;
ypos = 0;
}
else
ypos -= 12; /* XXX scale? */
return 0;
case 034: /* CR */
xpos = 0;
return 0;
case 035: /* shift in */
shift = 1;
return 0;
case 036: /* shift out */
shift = 0;
return 0;
case 037: /* escape */
sequence = n;
return 1;
}
/* XXX plot character from character set selected by "shift"
* (offset index by 64?)
*/
for (x = 0; x < 5; x++) {
for (y = 0; y < 7; y++) {
if (chars[c][x] & (1<<y)) {
/* XXX check for raster violation? */
point(xpos+x, ypos+y, n); /* XXX scale? */
}
}
}
xpos += 7; /* XXX scale? */
if (xpos > 1023) {
xpos = 1023;
status |= VEDGE;
}
return 0;
}
int
ty340_cycle(int us, int slowdown)
{
ty340word inst, addr;
int i, escape, stopped;
if (status & STOPPED)
return 0; /* XXX age display? */
inst = ty340_fetch(DAC);
DEBUGF(("%06o: %06o\r\n", DAC, inst));
DAC++;
escape = 0;
switch (mode) {
case PARAM:
mode = GETFIELD(inst, 2, 4);
if (TESTBIT(inst, 5)) { /* load l.p. enable */
lp_ena = TESTBIT(inst,6);
DEBUGF(("lp_ena %d\r\n", lp_ena));
}
if (TESTBIT(inst, 7)) {
status |= STOPPED;
if (TESTBIT(inst, 8))
ty340_stop_int(); /* set stop_int_end? */
}
if (TESTBIT(inst, 11))
scale = GETFIELD(inst, 12, 13);
if (TESTBIT(inst, 14))
intensity = GETFIELD(inst, 15, 17);
break;
case POINT:
mode = GETFIELD(inst, 2, 4);
if (TESTBIT(inst, 5)) /* load l.p. enable */
lp_ena = TESTBIT(inst,6);
if (TESTBIT(inst, 1))
ypos = GETFIELD(inst, 8, 17);
else
xpos = GETFIELD(inst, 8, 17);
if (TESTBIT(inst, 7))
point(xpos, ypos, 0);
break;
case SLAVE:
mode = GETFIELD(inst, 2, 4);
break;
case CHAR:
escape = (character(0, GETFIELD(inst, 0, 5)) ||
character(1, GETFIELD(inst, 6, 11)) ||
character(2, GETFIELD(inst, 12, 17)));
break;
case VECTOR:
escape = TESTBIT(inst, 0);
if (vector(TESTBIT(inst, 1),
TESTBIT(inst, 2), GETFIELD(inst, 3, 9),
TESTBIT(inst, 10), GETFIELD(inst, 11, 17))) {
/* XXX interrupt? */
}
break;
case VCONT:
escape = TESTBIT(inst, 0);
if (vector(TESTBIT(inst, 1),
TESTBIT(inst, 2), GETFIELD(inst, 3, 9),
TESTBIT(inst, 10), GETFIELD(inst, 11, 17))) {
/* XXX set escape? */
mode = PARAM; /* raster violation */
}
break;
case INCR:
escape = TESTBIT(inst, 0); /* escape bit */
i = TESTBIT(inst, 1);
if (ipoint(i, 0, GETFIELD(inst, 2, 5)) ||
ipoint(i, 1, GETFIELD(inst, 6, 9)) ||
ipoint(i, 2, GETFIELD(inst, 10, 13)) ||
ipoint(i, 3, GETFIELD(inst, 14, 17)))
/* XXX set escape? */
mode = PARAM; /* raster violation */
break;
case SUBR:
/* type 347 Display Subroutine Option? */
mode = GETFIELD(inst, 2, 4);
/* XXX take high bits of current DAC? */
addr = GETFIELD(inst, 5, 17);
switch (GETFIELD(inst, 0, 1)) {
case DJS: /* display jump and save */
ASR = DAC;
save_ff = 1; /* set "save" flip-flop */
/* FALL */
case DJP: /* display jump */
DAC = addr;
break;
case DDS: /* display deposit save register */
ty340_deposit(addr, (DJP<<16) | ASR);
save_ff = 0; /* ?? */
break;
default:
/* XXX ??? */
break;
}
break;
}
if (escape) {
mode = PARAM;
if (save_ff) {
/* return from subroutine */
DAC = ASR;
save_ff = 0;
}
}
return status;
} /* ty340_cycle */

3824
display/vt11.c Normal file

File diff suppressed because it is too large Load Diff

144
display/vt11.h Normal file
View File

@ -0,0 +1,144 @@
/*
* $Id: vt11.h,v 1.8 2005/01/14 18:58:02 phil Exp $
* interface to VT11 simulator
* Phil Budne <phil@ultimate.com>
* September 16, 2003
* Substantially revised by Douglas A. Gwyn, 14 Jan. 2004
*
* prerequisite: display.h
*/
/*
* Copyright (c) 2003-2004, Philip L. Budne and Douglas A. Gwyn
*
* 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
* THE AUTHORS 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 the authors shall
* not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization
* from the authors.
*/
#if defined(__cplusplus)
extern "C" {
#endif
#ifndef SIM_DEFS_H_
typedef unsigned short uint16;
typedef int int32;
typedef unsigned int uint32;
#endif /* SIM_DEFS_H_ */
/*
* VT11 jumpers control character spacing; VS60 always uses VT11 normal.
* The VT11_CSP_{W,H} #defines establish the initial default character
* spacing; to change the VT11 simulation from these default values,
* set vt11_csp_{w,h} before calling any function named vt11_*.
*/
extern unsigned char vt11_csp_w; /* horizontal character spacing */
#ifdef VT11_NARROW_OPT /* W3 or W6 installed */
#define VT11_CSP_W 12
#else /* VT11 normal; W4 or W5 installed */
#define VT11_CSP_W 14
#endif
extern unsigned char vt11_csp_h; /* vertical character spacing */
#ifdef VT11_TALL_OPT /* W3 or W4 installed */
#define VT11_CSP_H 26
#else /* VT11 normal; W5 or W6 installed */
#define VT11_CSP_H 24
#endif
/*
* The DISPLAY_TYPE #define establishes the initial default display
* type; to change from the default display type, set vt11_display
* before calling any function named vt11_* (other than vt11_reset()).
*/
#ifndef DISPLAY_TYPE
#define DISPLAY_TYPE DIS_VR17 /* default display type */
#endif
extern enum display_type vt11_display; /* DIS_VR{14,17,48} */
/*
* The PIX_SCALE #define establishes the initial default display scale
* factor; to change from the default scale factor, set vt11_scale
* before calling any function named vt11_* (other than vt11_reset()).
*/
#ifndef PIX_SCALE
#define PIX_SCALE RES_HALF /* default display scale factor */
#endif
extern int vt11_scale; /* RES_{FULL,HALF,QUARTER,EIGHTH} */
/*
* When vt11_init (READONLY) is nonzero, it indicates that it is too late
* to change display parameters (type, scale, character spacing, etc.).
*/
extern unsigned char vt11_init; /* set after display_init() called */
/* vt11.c simulates either a VT11 or a VT48(VS60), according to display type: */
#define VS60 (vt11_display == DIS_VR48)
#define VT11 (!VS60)
/* The display file is an array of 16-bit words. */
typedef uint16 vt11word;
extern int32 vt11_get_dpc(void); /* read Display PC */
extern int32 vt11_get_mpr(void); /* read mode parameter register */
extern int32 vt11_get_xpr(void); /* read graphplot incr/X pos register */
extern int32 vt11_get_ypr(void); /* read char code/Y pos register */
extern int32 vt11_get_rr(void); /* read relocate register */
extern int32 vt11_get_spr(void); /* read status parameter register */
extern int32 vt11_get_xor(void); /* read X offset register */
extern int32 vt11_get_yor(void); /* read Y offset register */
extern int32 vt11_get_anr(void); /* read associative name register */
extern int32 vt11_get_scr(void); /* read slave console/color register */
extern int32 vt11_get_nr(void); /* read name register */
extern int32 vt11_get_sdr(void); /* read stack data register */
extern int32 vt11_get_str(void); /* read char string term register */
extern int32 vt11_get_sar(void); /* read stack address/maint register */
extern int32 vt11_get_zpr(void); /* read Z position register */
extern int32 vt11_get_zor(void); /* read Z offset register */
extern void vt11_set_dpc(uint16); /* write Display PC */
extern void vt11_set_mpr(uint16); /* write mode parameter register */
extern void vt11_set_xpr(uint16); /* write graphplot inc/X pos register */
extern void vt11_set_ypr(uint16); /* write char code/Y pos register */
extern void vt11_set_rr(uint16); /* write relocate register */
extern void vt11_set_spr(uint16); /* write status parameter register */
extern void vt11_set_xor(uint16); /* write X offset register */
extern void vt11_set_yor(uint16); /* write Y offset register */
extern void vt11_set_anr(uint16); /* write associative name register */
extern void vt11_set_scr(uint16); /* write slave console/color register */
extern void vt11_set_nr(uint16); /* write name register */
extern void vt11_set_sdr(uint16); /* write stack data register */
extern void vt11_set_str(uint16); /* write char string term register */
extern void vt11_set_sar(uint16); /* write stack address/maint register */
extern void vt11_set_zpr(uint16); /* write Z position register */
extern void vt11_set_zor(uint16); /* write Z offset register */
extern void vt11_reset(void *, int); /* reset the display processor */
extern int vt11_cycle(int, int); /* perform a display processor cycle */
/*
* callbacks from VT11/VS60 simulator (to SIMH PDP-11 VT driver, for example)
*/
extern int vt_fetch(uint32, vt11word *); /* get a display-file word */
extern void vt_stop_intr(void); /* post a display-stop interrupt */
extern void vt_lpen_intr(void); /* post a surface-related interrupt */
extern void vt_char_intr(void); /* post a bad-char./timeout interrupt */
extern void vt_name_intr(void); /* post a name-match interrupt */
#if defined(__cplusplus)
}
#endif

297
display/vtmacs.h Normal file
View File

@ -0,0 +1,297 @@
/*
* $Id: vtmacs.h,v 1.3 2004/01/24 20:54:54 phil Exp - revised by DAG $
* macros for coding a VT11/VS60 display file (instructions and data)
* for standalone use of vt11.c (not embedded in PDP-11 simulator)
* Douglas A. Gwyn <gwyn@arl.army.mil>
* September 03, 2004
*
* XXX -- assumes ASCII host character set
*/
/* helper macros (not for use outside this header): */
#define SGN_(x) ((x) < 0)
#define MAG_(x) ((x) >= 0 ? (x) : -(x)) /* -0 not expressible directly in C */
#if 0 /* manual seems to say this; wrong! */
#define JDL_(x) ((SGN_(raddr) << 8) | MAG_(raddr))
#else /* sign extend, 9-bit twos complement */
#define JDL_(x) ((x) >= 0 ? (x) : ((~(unsigned)-(x))+1) & 0777)
#endif
/* control instructions: */
/* load status register A: */
#define LSRA(stop,stop_intr,lp_hit_chg,ital,refresh,menu) \
0170000 | stop | stop_intr | lp_hit_chg | ital | refresh | menu
/* display stop: */
#define ST_SAME 00000 /* don't stop display */
#define ST_STOP 02000 /* stop display */
/* stop interrupt: */
#define SI_SAME 00000 /* no change */
#define SI_INHIBIT 01000 /* inhibit interrupt on stop */
#define SI_GENERATE 01400 /* generate interrupt on stop */
/* light pen hit intensify (bright-down on VS60): */
#define LI_SAME 0000 /* no change */
#define LI_INTENSIFY 0200 /* enable intensify on hit (VT11) */
#define LI_BRIGHTDOWN 0200 /* enable bright down on hit (VS60) */
#define LI_NOINTENSIFY 0300 /* inhibit intensify on hit (VT11) */
#define LI_NOBRIGHTDOWN 0300 /* inhibit bright down on hit (VS60) */
/* italic font: */
#define IT_SAME 000 /* no change */
#define IT_NORMAL 040 /* normal font */
#define IT_ITALIC 060 /* italic font */
/* refresh rate: */
#define RF_UNSYNC 000 /* unsynchronized */
#define RF_SAME 000 /* (happens to work like that) */
#define RF_LINE 004 /* sync with line (VT11) */
#define RF_30 004 /* 30 frames/sec (VS60) */
#define RF_40 010 /* 40 frames/sec (VS60) */
#define RF_EXT 014 /* external sync (VS60) */
/* menu/main area (VS60): */
#define MN_SAME 0 /* no change */
#define MN_MAIN 2 /* major screen area */
#define MN_MENU 3 /* menu area */
/* load status register B: */
#define LSRB(color,set_step,step) \
0174000 | color | set_step | (step)
/* color select (VS60): */
#define CL_SAME 00000 /* no change */
#define CL_GREEN 01000 /* green */
#define CL_YELLOW 01200 /* yellow */
#define CL_ORANGE 01400 /* orange */
#define CL_RED 01600 /* red */
/* graphplot increment register change enable: */
#define SS_SAME 0000 /* no change (step value ignored) */
#define SS_CHANGE 0100 /* write step value into register */
/* load status register BB (VS60): */
#define LSRBB(z_data,edge_intr,depth_cue,char_esc) \
0176000 | z_data | edge_intr | depth_cue | char_esc
/* file Z data: */
#define ZD_SAME 000 /* no change */
#define ZD_NO 010 /* d.file does not contain Z coords. */
#define ZD_YES 014 /* d.file contains Z coordinates */
/* edge interrupts enable: */
#define ED_SAME 000 /* no change */
#define ED_DIS 040 /* disable intr. on edge transition */
#define ED_ENA 060 /* enable intr. on edge transition */
/* depth cue processing: */
#define DQ_SAME 0000 /* no change */
#define DQ_OFF 0200 /* disable depth cueing (Z intensity) */
#define DQ_ON 0300 /* enable depth cueing (Z intensity) */
/* escape on terminating character: */
#define ES_SAME 0 /* no change */
#define ES_NO 2 /* disable POPR on terminating char. */
#define ES_YES 3 /* enable POPR on terminating char. */
/* load status register C (VS60): */
#define LSRC(rotate,cs_change,cscale,vs_change,vscale) \
0154000 | rotate | cs_change | ((cscale)<<5) | \
vs_change | (vscale)
/* character rotation: */
#define RO_SAME 00000 /* no change */
#define RO_HORIZONTAL 01000 /* no text rotation */
#define RO_VERTICAL 01400 /* rotate text 90 degrees CCW */
/* character scale change enable: */
#define CS_SAME 0000 /* no change (cscale value ignored) */
#define CS_CHANGE 0200 /* set character scale */
/* vector scale change enable: */
#define VS_SAME 000 /* no change (vscale value ignored) */
#define VS_CHANGE 020 /* set vector scale */
/* load scope selection register (VS60): */
#define LSSR(console,disp,lp_intr,sw_intr) \
0164000 | console | disp | lp_intr | sw_intr
/* console to which this instruction applies: */
#define CN_0 0000 /* console # 0 */
#define CN_1 0400 /* console # 1 */
/* display enable: */
#define DS_SAME 0000 /* no change */
#define DS_DIS 0200 /* disable display (blank CRT) */
#define DS_ENA 0300 /* enable display (use CRT) */
/* light-pen hit interrupt enable: */
#define LH_SAME 0000 /* no change */
#define LH_DIS 0040 /* light-pen hit interrupt disabled */
#define LH_ENA 0060 /* light-pen hit interrupt enabled */
/* tip-switch transition interrupt enable: */
#define SW_SAME 0000 /* no change */
#define SW_DIS 0010 /* tip-switch interrupt disabled */
#define SW_ENA 0014 /* tip-switch hit interrupt enabled */
/* load name register (VS60): */
#define LNR(name) \
0150000 | (name)
/* set graphic mode: */
#define SGM(mode,intens,lp_intr,blink,line_type) \
0100000 | mode | intens | lp_intr | blink | line_type
/* graphic mode: */
#define GM_CHAR 000000 /* character */
#define GM_SVECT 004000 /* short vector */
#define GM_LVECT 010000 /* long vector */
#define GM_APOINT 014000 /* absolute point, or offset */
#define GM_GRAPHX 020000 /* graphplot X, or basic long vector */
#define GM_GRAPHY 024000 /* graphplot Y, or basic long vector */
#define GM_RPOINT 030000 /* relative point */
#define GM_BSVECT 034000 /* basic short vector */
#define GM_ARC 040000 /* circle/arc */
#define GM_AVECT 044000 /* absolute vector */
/* intensity: */
#define IN_SAME 00000 /* no change */
#define IN_0 02000 /* intensity level 0 (dimmest) */
#define IN_1 02200 /* intensity level 1 */
#define IN_2 02400 /* intensity level 2 */
#define IN_3 02600 /* intensity level 3 */
#define IN_4 03000 /* intensity level 4 */
#define IN_5 03200 /* intensity level 5 */
#define IN_6 03400 /* intensity level 6 */
#define IN_7 03600 /* intensity level 7 (brightest) */
/* light pen interrupt: */
#define LP_SAME 0000 /* no change */
#define LP_DIS 0100 /* light-pen hit interrupt disabled */
#define LP_ENA 0140 /* light-pen hit interrupt enabled */
/* blink: */
#define BL_SAME 000 /* no change */
#define BL_OFF 020 /* blink off */
#define BL_ON 030 /* blink on */
/* line type: */
#define LT_SAME 00 /* no change */
#define LT_SOLID 04 /* solid */
#define LT_LDASH 05 /* long dash */
#define LT_SDASH 06 /* short dash */
#define LT_DDASH 07 /* dot dash */
/* display jump absolute: */
#define DJMP_ABS(addr) \
0160000, \
(addr) & ~1
/* display jump relative (VS60) [raddr in words]: */
#define DJMP_REL(raddr) \
0161000 | JDL_(raddr)
/* display jump to subroutine absolute (VS60): */
#define DJSR_ABS(addr) \
0162000, \
(addr) & ~1
/* display jump to subroutine relative (VS60) [raddr in words]: */
#define DJSR_REL(raddr) \
0163000 | JDL_(raddr)
/* display no-op: */
#define DNOP \
0164000
/* display pop, no restore (VS60): */
#define DPOP_NR \
0165000
/* display pop, restore (VS60): */
#define DPOP_R \
0165000
/* display stop: */
#define DSTOP LSRA(ST_STOP,SI_SAME,LI_SAME,IT_SAME,RF_UNSYNC,MN_SAME)
/* graphic data: */
/* intensify enable (common to all modes exept CHAR and OFFSET): */
#define I_OFF 000000 /* beam off */
#define I_ON 040000 /* beam on */
/* Note: when VS60 "file Z data" is enabled,
use the *3() macros instead of the corresponding normal ones. */
/* character data: */
#define CHAR(c1,c2) \
((c2) << 8) | (c1) /* 7-bit ASCII assumed */
/* short vector data: */
#define SVECT(i,dx,dy) \
i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy)
#define SVECT3(i,dx,dy,dz) \
i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy), \
(SGN_(dz) << 13) | (MAG_(dz) << 2)
/* long vector data: */
#define LVECT(i,dx,dy) \
i | (SGN_(dx) << 13) | MAG_(dx), \
(SGN_(dy) << 13) | MAG_(dy)
#define LVECT3(i,dx,dy,dz) \
i | (SGN_(dx) << 13) | MAG_(dx), \
(SGN_(dy) << 13) | MAG_(dy), \
(SGN_(dz) << 13) | (MAG_(dz) << 2)
/* rotation data (VS60, probably unimplemented): */
#define ROTATE(i,a,b) \
i | (SGN_(a) << 13) | 010000 | MAG_(a), \
(SGN_(b) << 13) | MAG_(b)
#define ROTATE3(i,a,b,c) \
i | (SGN_(a) << 13) | 010000 | MAG_(a), \
(SGN_(b) << 13) | MAG_(b), \
(SGN_(c) << 13) | (MAG_(c) << 2)
/* absolute point data: */
#define APOINT(i,x,y) \
i | (SGN_(x) << 13) | MAG_(x), \
(SGN_(y) << 13) | MAG_(y)
#define APOINT3(i,x,y,z) \
i | (SGN_(x) << 13) | MAG_(x), \
(SGN_(y) << 13) | MAG_(y), \
(SGN_(z) << 13) | (MAG_(z) << 2)
/* offset data (VS60): */
#define OFFSET(x,y) \
(SGN_(x) << 13) | 010000 | MAG_(x), \
(SGN_(y) << 13) | 010000 | MAG_(y)
#define OFFSET3(x,y,z) \
(SGN_(x) << 13) | 010000 | MAG_(x), \
(SGN_(y) << 13) | 010000 | MAG_(y), \
(SGN_(z) << 13) | 010000 | (MAG_(z) << 2)
/* graphplot X data: */
#define GRAPHX(i,x) \
i | (x)
/* graphplot Y data: */
#define GRAPHY(i,y) \
i | (y)
/* basic long vector data (VS60): */
#define BLVECT(i,dir,len) \
i | ((dir) << 11) | 02000 | (len)
/* relative point data: */
#define RPOINT(i,dx,dy) \
i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy)
#define RPOINT3(i,dx,dy,dz) \
i | (SGN_(dx) << 13) | (MAG_(dx) << 7) | (SGN_(dy) << 6) | MAG_(dy), \
(SGN_(dz) << 13) | (MAG_(dz) << 2)
/* basic short vector data (VS60): */
#define BSVECT(i,dir1,len1,dir2,len2) \
i | ((dir2) << 11) | ((len2) << 7) | ((dir1) << 4) | (len1)
/* circle/arc data (VS60, option): */
#define ARC(i,dcx,dcy,dex,dey) \
i | (SGN_(dcx) << 13) | MAG_(dcx), \
(SGN_(dcy) << 13) | MAG_(dcy), \
(SGN_(dex) << 13) | MAG_(dex), \
(SGN_(dey) << 13) | MAG_(dey)
#define ARC3(i,dcx,dcy,cz,dex,dey,ez) \
i | (SGN_(dcx) << 13) | MAG_(dcx), \
(SGN_(dcy) << 13) | MAG_(dcy), \
(SGN_(cz) << 13) | (MAG_(cz) << 2), \
(SGN_(dex) << 13) | MAG_(dex), \
(SGN_(dey) << 13) | MAG_(dey), \
(SGN_(ez) << 13) | (MAG_(ez) << 2)
/* absolute vector data (VS60): */
#define AVECT(i,x,y) \
i | (SGN_(x) << 13) | MAG_(x), \
(SGN_(y) << 13) | MAG_(y)
#define AVECT3(i,x,y,z) \
i | (SGN_(x) << 13) | MAG_(x), \
(SGN_(y) << 13) | MAG_(y), \
(SGN_(z) << 13) | (MAG_(z) << 2)

1465
display/vttest.c Normal file

File diff suppressed because it is too large Load Diff

422
display/win32.c Normal file
View File

@ -0,0 +1,422 @@
/*
* $Id: win32.c,v 1.39 2005/01/14 18:58:03 phil Exp $
* Win32 support for XY display simulator
* Phil Budne <phil@ultimate.com>
* September 2003
* Revised by Douglas A. Gwyn, 05 Feb. 2004
*/
/*
* Copyright (c) 2003-2004, Philip L. Budne
*
* 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
* THE AUTHORS 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 the authors shall
* not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization
* from the authors.
*/
/* use a thread to handle windows messages; */
#define THREADS
/*
* BUGS:
* Does not allow you to close display window;
* would need to tear down both system, and system independent data.
*
* now tries to handle PAINT message, as yet untested!!
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "ws.h"
#include "display.h"
#ifndef PIX_SIZE
#define PIX_SIZE 1
#endif
#define APP_CLASS "XYAppClass"
#define APP_MENU "XYAppMenu" /* ?? */
/*
* light pen location
* see ws.h for full description
*/
int ws_lp_x = -1;
int ws_lp_y = -1;
static HWND static_wh;
static HINSTANCE static_inst;
static int xpixels, ypixels;
static const char *window_name;
static HBRUSH white_brush;
static HBRUSH black_brush;
#ifdef SWITCH_CURSORS
static HCURSOR cross, arrow;
#endif
static __inline int
map_key(int k)
{
switch (k) {
case 186: return ';'; /* VK_OEM_1? */
case 222: return '\''; /* VK_OEM_7? */
}
return k;
}
static void
keydown(int k)
{
display_keydown(map_key(k));
}
static void
keyup(int k)
{
display_keyup(map_key(k));
}
/*
* here on any button click, or if mouse dragged while a button down
*/
static void
mousepos(DWORD lp)
{
int x, y;
x = LOWORD(lp);
y = HIWORD(lp);
/* convert to display coordinates */
#if PIX_SIZE > 1
x /= PIX_SIZE;
y /= PIX_SIZE;
#endif
y = ypixels - 1 - y;
/* if window has been stretched, can get out of range bits!! */
if (x >= 0 && x < xpixels && y >= 0 && y < ypixels) {
/* checked by display_add_point() */
ws_lp_x = x;
ws_lp_y = y;
}
}
/* thoingggg!! "message for you sir!!!" */
static LRESULT CALLBACK
patsy(HWND wh, UINT msg, WPARAM wp, LPARAM lp) /* "WndProc" */
{
/* printf("msg %d\n", msg); */
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_MOUSEMOVE:
if (wp & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) {
#ifdef SWITCH_CURSORS
if (ws_lp_x == -1 && !display_tablet)
SetCursor(cross);
#endif
mousepos(lp);
}
#ifdef SWITCH_CURSORS
else if (ws_lp_x != -1 && !display_tablet)
SetCursor(arrow);
#endif
break; /* return?? */
case WM_LBUTTONDOWN:
display_lp_sw = 1;
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
#ifdef SWITCH_CURSORS
if (!display_tablet)
SetCursor(cross);
#endif
mousepos(lp);
break; /* return?? */
case WM_LBUTTONUP:
display_lp_sw = 0;
case WM_MBUTTONUP:
case WM_RBUTTONUP:
#ifdef SWITCH_CURSORS
if (!display_tablet)
SetCursor(arrow);
#endif
ws_lp_x = ws_lp_y = -1;
break; /* return?? */
case WM_KEYDOWN:
keydown(wp);
break;
case WM_KEYUP:
keyup(wp);
break;
case WM_PAINT:
display_repaint();
break; /* return?? */
}
return DefWindowProc(wh, msg, wp, lp);
}
int
ws_poll(int *valp, int maxus)
{
#ifdef THREADS
/* msgthread handles window events; just delay simulator */
if (maxus > 0)
Sleep((maxus+999)/1000);
#else
MSG msg;
DWORD start;
int maxms = (maxus + 999) / 1000;
for (start = GetTickCount(); GetTickCount() - start < maxms; Sleep(1)) {
/* empty message queue without blocking */
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#endif
return 1;
}
/* called from non-threaded main program */
int
ws_loop(void (*func)(void *), void *arg)
{
int val;
while (ws_poll(&val, 0))
(*func)(arg);
return val;
}
/* worker for display init */
static void
ws_init2(void) {
WNDCLASS wc;
int h, w;
#ifdef SWITCH_CURSORS
if (!display_tablet) {
arrow = LoadCursor(NULL, IDC_ARROW);
cross = LoadCursor(NULL, IDC_CROSS);
}
#endif
black_brush = GetStockObject(BLACK_BRUSH);
white_brush = GetStockObject(WHITE_BRUSH);
wc.lpszClassName = APP_CLASS;
wc.lpfnWndProc = patsy;
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
/* also CS_NOCLOSE? CS_SAVEBITS? */
wc.hInstance = static_inst = GetModuleHandleA(0);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
#ifdef SWITCH_CURSORS
wc.hCursor = NULL;
#else
wc.hCursor = display_tablet ? NULL : LoadCursor(NULL, IDC_CROSS);
#endif
wc.hbrBackground = black_brush;
wc.lpszMenuName = APP_MENU;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
/* WNDCLASSEX/RegisterClassEx include hIconSm (small icon) */
RegisterClass(&wc);
/*
* WS_OVERLAPPEDWINDOW=>
* WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME,
* WS_MINIMIZEBOX, WS_MAXIMIZEBOX
*
* WS_CHILD (no menu bar), WS_POPUP (mutually exclusive)
*/
/* empirical crocks to get entire screen; */
w = (xpixels*PIX_SIZE)+6;
h = (ypixels*PIX_SIZE)+32;
/* XXX -- above values work with XP; Phil had +10,+30 */
static_wh = CreateWindow(APP_CLASS, /* registered class name */
window_name, /* window name */
WS_OVERLAPPED, /* style */
CW_USEDEFAULT, CW_USEDEFAULT, /* X,Y */
w, h,
NULL, /* HWND hWndParent */
NULL, /* HMENU hMenu */
static_inst, /* application instance */
NULL); /* lpParam */
ShowWindow(static_wh, SW_SHOW);
UpdateWindow(static_wh);
}
#ifdef THREADS
static volatile int init_done;
static DWORD msgthread_id;
static DWORD WINAPI
msgthread(LPVOID arg)
{
MSG msg;
ws_init2();
/* XXX use a mutex? */
init_done = 1;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
static void
ws_thread_init(void)
{
HANDLE th = CreateThread(NULL, /* sec. attr. */
0, /* stack size */
msgthread,
NULL, /* param */
0, /* flags */
&msgthread_id);
CloseHandle(th);
/* XXX use a mutex; don't wait forever!! */
while (!init_done)
Sleep(200);
}
#endif /* THREADS */
/* called from display layer on first display op */
int
ws_init(const char *name, int xp, int yp, int colors, void *dptr)
{
xpixels = xp;
ypixels = yp;
window_name = name;
#ifdef THREADS
ws_thread_init();
#else
ws_init2();
#endif
return 1; /* XXX return errors!! */
}
void ws_shutdown (void)
{
}
void *
ws_color_rgb(int r, int g, int b)
{
/* XXX check for failure??? try GetNearestColor??? */
return CreateSolidBrush(RGB(r/256, g/256, b/256));
}
void *
ws_color_black(void)
{
return black_brush;
}
void *
ws_color_white(void)
{
return white_brush;
}
void
ws_display_point(int x, int y, void *color)
{
HDC dc;
RECT r;
HBRUSH brush = color;
if (x > xpixels || y > ypixels)
return;
y = ypixels - 1 - y; /* invert y, top left origin */
/* top left corner */
r.left = x*PIX_SIZE;
r.top = y*PIX_SIZE;
/* bottom right corner, non-inclusive */
r.right = (x+1)*PIX_SIZE;
r.bottom = (y+1)*PIX_SIZE;
if (brush == NULL)
brush = black_brush;
dc = GetDC(static_wh);
FillRect(dc, &r, brush);
ReleaseDC(static_wh, dc);
}
void
ws_sync(void) {
/* noop */
}
void
ws_beep(void) {
#if 0
/* play SystemDefault sound; does not work over terminal service */
MessageBeep(MB_OK);
#else
/* works over terminal service? Plays default sound/beep on Win9x/ME */
Beep(440, 500); /* Hz, ms. */
#endif
}
unsigned long
os_elapsed(void)
{
static int new;
unsigned long ret;
static DWORD t[2];
/*
* only returns milliseconds, but Sleep()
* only takes milliseconds.
*
* wraps after 49.7 days of uptime.
* DWORD is an unsigned long, so this should be OK
*/
t[new] = GetTickCount();
if (t[!new] == 0)
ret = ~0L; /* +INF */
else
ret = (t[new] - t[!new]) * 1000;
new = !new; /* Ecclesiastes III */
return ret;
}

65
display/ws.h Normal file
View File

@ -0,0 +1,65 @@
/*
* $Id: ws.h,v 1.17 2004/02/03 21:23:51 phil Exp $
* Interfaces to window-system specific code for XY display simulation
*/
/*
* Copyright (c) 2003-2004, Philip L. Budne
*
* 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
* THE AUTHORS 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 the authors shall
* not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization
* from the authors.
*/
/* unless you're writing a new driver, you shouldn't be looking here! */
extern int ws_init(const char *, int, int, int, void *);
void ws_shutdown(void);
extern void *ws_color_rgb(int, int, int);
extern void *ws_color_black(void);
extern void *ws_color_white(void);
extern void ws_display_point(int, int, void *);
extern void ws_sync(void);
extern int ws_poll(int *, int);
extern void ws_beep(void);
/* entries into display.c from below: */
extern void display_keyup(int);
extern void display_keydown(int);
extern void display_repaint(void);
/*
* Globals set by O/S display level to SCALED location in display
* coordinate system in order to save an upcall on every mouse
* movement.
*
* *NOT* for consumption by clients of display.c; although display
* clients can now get the scaling factor, real displays only give you
* a light pen "hit" when the beam passes under the light pen.
*/
extern int ws_lp_x, ws_lp_y;
/*
* O/S services in theory independent of window system,
* but in (current) practice not!
*/
extern unsigned long os_elapsed(void);

494
display/x11.c Normal file
View File

@ -0,0 +1,494 @@
/*
* $Id: x11.c,v 1.32 2005/01/14 18:58:03 phil Exp $
* X11 support for XY display simulator
* Phil Budne <phil@ultimate.com>
* September 2003
*
* Changes from Douglas A. Gwyn, Jan 8, 2004
*
* started from PDP-8/E simulator (vc8e.c & kc8e.c);
* This PDP8 Emulator was written by Douglas W. Jones at the
* University of Iowa. It is distributed as freeware, of
* uncertain function and uncertain utility.
*/
/*
* Copyright (c) 2003-2004, Philip L. Budne
*
* 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
* THE AUTHORS 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 the authors shall
* not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization
* from the authors.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ws.h"
#include "display.h"
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Core.h>
#include <X11/Shell.h>
#include <X11/cursorfont.h>
#include <sys/types.h>
#include <sys/time.h>
#ifndef PIX_SIZE
#define PIX_SIZE 1
#endif
/*
* light pen location
* see ws.h for full description
*/
int ws_lp_x = -1;
int ws_lp_y = -1;
static XtAppContext app_context; /* the topmost context for everything */
static Display* dpy; /* its display */
static int scr; /* its screen */
static Colormap cmap; /* its colormap */
static Widget crtshell; /* the X window shell */
static Widget crt; /* the X window in which output will plot */
static int xpixels, ypixels;
#ifdef FULL_SCREEN
/* occupy entire screen for vintage computer fan Sellam Ismail */
static int xoffset, yoffset;
#endif
static GC whiteGC; /* gc with white foreground */
static GC blackGC; /* gc with black foreground */
static int buttons = 0; /* tracks state of all buttons */
static int os_pollfd(int, int); /* forward */
/* here on any mouse button down, AND movement when any button down */
static void
handle_button_press(w, d, e, b)
Widget w;
XtPointer d;
XEvent *e;
Boolean *b;
{
int x, y;
x = e->xbutton.x;
y = e->xbutton.y;
#ifdef FULL_SCREEN
/* untested! */
x -= xoffset;
y -= yoffset;
#endif
#if PIX_SIZE > 1
x *= PIX_SIZE;
y *= PIX_SIZE;
#endif
if (!display_tablet)
/* crosshair cursor to indicate tip of active pen */
XDefineCursor(dpy, XtWindow(crt),
(Cursor) XCreateFontCursor(dpy, XC_crosshair));
y = ypixels - y - 1;
/*printf("lightpen at %d,%d\n", x, y); fflush(stdout);*/
ws_lp_x = x;
ws_lp_y = y;
if (e->type == ButtonPress) {
buttons |= e->xbutton.button;
if (e->xbutton.button == 1) {
display_lp_sw = 1;
/*printf("tip switch activated\n"); fflush(stdout);*/
}
}
if (b)
*b = TRUE;
}
static void
handle_button_release(w, d, e, b)
Widget w;
XtPointer d;
XEvent *e;
Boolean *b;
{
if ((buttons &= ~e->xbutton.button) == 0) { /* all buttons released */
if (!display_tablet)
/* pencil cursor (close to a pen!) to indicate inactive pen posn */
XDefineCursor(dpy, XtWindow(crt),
(Cursor) XCreateFontCursor(dpy, XC_pencil));
/* XXX change cursor back?? */
ws_lp_x = ws_lp_y = -1;
}
if (e->xbutton.button == 1) {
display_lp_sw = 0;
/*printf("tip switch deactivated\n"); fflush(stdout);*/
}
if (b)
*b = TRUE;
}
static void
handle_key_press(w, d, e, b)
Widget w;
XtPointer d;
XEvent *e;
Boolean *b;
{
int shift = (ShiftMask & e->xkey.state) != 0;
KeySym key = XKeycodeToKeysym( dpy, e->xkey.keycode, shift );
/*printf("key %d down\n", key); fflush(stdout);*/
if ((key & 0xff00) == 0)
display_keydown(key);
if (b)
*b = TRUE;
}
static void
handle_key_release(w, d, e, b)
Widget w;
XtPointer d;
XEvent *e;
Boolean *b;
{
int shift = (ShiftMask & e->xkey.state) != 0;
KeySym key = XKeycodeToKeysym( dpy, e->xkey.keycode, shift );
/*printf("key %d up\n", key); fflush(stdout);*/
if ((key & 0xff00) == 0)
display_keyup(key);
if (b)
*b = TRUE;
}
static void
handle_exposure(w, d, e, b)
Widget w;
XtPointer d;
XEvent *e;
Boolean *b;
{
display_repaint();
if (b)
*b = TRUE;
}
int
ws_init(const char *crtname, /* crt type name */
int xp, int yp, /* screen size in pixels */
int colors, /* colors to support (not used) */
void *dptr)
{
Arg arg[25];
XGCValues gcvalues;
unsigned int n;
int argc;
char *argv[1];
int height, width;
xpixels = xp; /* save screen size */
ypixels = yp;
XtToolkitInitialize();
app_context = XtCreateApplicationContext();
argc = 0;
argv[0] = NULL;
dpy = XtOpenDisplay( app_context, NULL, NULL, crtname, NULL, 0,
&argc, argv);
scr = DefaultScreen(dpy);
crtshell = XtAppCreateShell( crtname, /* app name */
crtname, /* app class */
applicationShellWidgetClass, /* wclass */
dpy, /* display */
NULL, /* arglist */
0); /* nargs */
cmap = DefaultColormap(dpy, scr);
/*
* Create a drawing area
*/
n = 0;
#ifdef FULL_SCREEN
/* center raster in full-screen black window */
width = DisplayWidth(dpy,scr);
height = DisplayHeight(dpy,scr);
xoffset = (width - xpixels*PIX_SIZE)/2;
yoffset = (height - ypixels*PIX_SIZE)/2;
#else
width = xpixels*PIX_SIZE;
height = ypixels*PIX_SIZE;
#endif
XtSetArg(arg[n], XtNwidth, width); n++;
XtSetArg(arg[n], XtNheight, height); n++;
XtSetArg(arg[n], XtNbackground, BlackPixel( dpy, scr )); n++;
crt = XtCreateWidget( crtname, widgetClass, crtshell, arg, n);
XtManageChild(crt);
XtPopup(crtshell, XtGrabNonexclusive);
XtSetKeyboardFocus(crtshell, crt); /* experimental? */
/*
* Create black and white Graphics Contexts
*/
gcvalues.foreground = BlackPixel( dpy, scr );
gcvalues.background = BlackPixel( dpy, scr );
blackGC = XCreateGC(dpy, XtWindow(crt),
GCForeground | GCBackground, &gcvalues);
gcvalues.foreground = WhitePixel( dpy, scr );
whiteGC = XCreateGC(dpy, XtWindow(crt),
GCForeground | GCBackground, &gcvalues);
if (!display_tablet) {
/* pencil cursor */
XDefineCursor(dpy, XtWindow(crt),
(Cursor) XCreateFontCursor(dpy, XC_pencil));
}
/*
* Setup to handle events
*/
XtAddEventHandler(crt, ButtonPressMask|ButtonMotionMask, FALSE,
handle_button_press, NULL);
XtAddEventHandler(crt, ButtonReleaseMask, FALSE,
handle_button_release, NULL);
XtAddEventHandler(crt, KeyPressMask, FALSE,
handle_key_press, NULL);
XtAddEventHandler(crt, KeyReleaseMask, FALSE,
handle_key_release, NULL);
XtAddEventHandler(crt, ExposureMask, FALSE,
handle_exposure, NULL);
return 1;
} /* ws_init */
void ws_shutdown (void)
{
}
void *
ws_color_black(void)
{
return blackGC;
}
void *
ws_color_white(void)
{
return whiteGC;
}
void *
ws_color_rgb(int r, int g, int b)
{
XColor color;
color.red = r;
color.green = g;
color.blue = b;
/* ignores flags */
if (XAllocColor(dpy, cmap, &color)) {
XGCValues gcvalues;
memset(&gcvalues, 0, sizeof(gcvalues));
gcvalues.foreground = gcvalues.background = color.pixel;
return XCreateGC(dpy, XtWindow(crt),
GCForeground | GCBackground,
&gcvalues);
}
/* allocation failed */
return NULL;
}
/* put a point on the screen */
void
ws_display_point(int x, int y, void *color)
{
GC gc = (GC) color;
if (x > xpixels || y > ypixels)
return;
y = ypixels - y - 1; /* X11 coordinate system */
#ifdef FULL_SCREEN
x += xoffset;
y += yoffset;
#endif
if (gc == NULL)
gc = blackGC; /* default to off */
#if PIX_SIZE == 1
XDrawPoint(dpy, XtWindow(crt), gc, x, y);
#else
XFillRectangle(dpy, XtWindow(crt), gc,
x*PIX_SIZE, y*PIX_SIZE, PIX_SIZE, PIX_SIZE);
#endif
}
void
ws_sync(void)
{
XFlush(dpy);
}
/*
* elapsed wall clock time since last call
* +INF on first call
*/
struct elapsed_state {
struct timeval tvs[2];
int new;
};
static unsigned long
elapsed(struct elapsed_state *ep)
{
unsigned long val;
gettimeofday(&ep->tvs[ep->new], NULL);
if (ep->tvs[!ep->new].tv_sec == 0)
val = ~0L;
else
val = ((ep->tvs[ep->new].tv_sec - ep->tvs[!ep->new].tv_sec) * 1000000 +
(ep->tvs[ep->new].tv_usec - ep->tvs[!ep->new].tv_usec));
ep->new = !ep->new;
return val;
}
/* called periodically */
int
ws_poll(int *valp, int maxusec)
{
static struct elapsed_state es; /* static to avoid clearing! */
#ifdef WS_POLL_DEBUG
printf("ws_poll %d\n", maxusec);
fflush(stdout);
#endif
elapsed(&es); /* start clock */
do {
unsigned long e;
/* tried checking return, but lost on TCP connections? */
os_pollfd(ConnectionNumber(dpy), maxusec);
while (XtAppPending(app_context)) {
XEvent event;
/* XXX check for connection loss; set *valp? return 0 */
XtAppNextEvent(app_context, &event );
XtDispatchEvent( &event );
}
e = elapsed(&es);
#ifdef WS_POLL_DEBUG
printf(" maxusec %d e %d\r\n", maxusec, e);
fflush(stdout);
#endif
maxusec -= e;
} while (maxusec > 10000); /* 10ms */
return 1;
}
/* utility: can be called from main program
* which is willing to cede control
*/
int
ws_loop(void (*func)(void *), void *arg)
{
int val;
/* XXX use XtAppAddWorkProc & XtAppMainLoop? */
while (ws_poll(&val,0))
(*func)(arg);
return val;
}
void
ws_beep(void)
{
XBell(dpy, 0); /* ring at base volume */
XFlush(dpy);
}
/****************
* could move these to unix.c, if VMS versions needed
* (or just (GASP!) ifdef)
*/
/* public version, used by delay code */
unsigned long
os_elapsed(void)
{
static struct elapsed_state es;
return elapsed(&es);
}
/*
* select/DisplayNumber works on VMS 7.0+?
* could move to "unix.c"
* (I have some nasty VMS code that's supposed to to the job
* for older systems)
*/
/*
* sleep for maxus microseconds, returning TRUE sooner if fd is readable
* used by X11 driver
*/
static int
os_pollfd(int fd, int maxus)
{
/* use trusty old select (most portable) */
fd_set rfds;
struct timeval tv;
if (maxus >= 1000000) { /* not bloody likely, avoid divide */
tv.tv_sec = maxus / 1000000;
tv.tv_usec = maxus % 1000000;
}
else {
tv.tv_sec = 0;
tv.tv_usec = maxus;
}
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
return select(fd+1, &rfds, NULL, NULL, &tv) > 0;
}

1036
display/xy.c Normal file

File diff suppressed because it is too large Load Diff

486
scp.c
View File

@ -541,7 +541,7 @@ UNIT *sim_dfunit = NULL;
DEVICE **sim_internal_devices = NULL;
uint32 sim_internal_device_count = 0;
int32 sim_opt_out = 0;
int32 sim_is_running = 0;
volatile t_bool sim_is_running = FALSE;
t_bool sim_processing_event = FALSE;
uint32 sim_brk_summ = 0;
uint32 sim_brk_types = 0;
@ -564,7 +564,8 @@ size_t *sim_sub_instr_off = NULL;
static double sim_time;
static uint32 sim_rtime;
static int32 noqueue_time;
volatile int32 stop_cpu = 0;
volatile t_bool stop_cpu = FALSE;
static unsigned int sim_stop_sleep_ms = 250;
static char **sim_argv;
t_value *sim_eval = NULL;
static t_value sim_last_val;
@ -585,7 +586,8 @@ static int32 sim_do_depth = 0;
static t_bool sim_cmd_echoed = FALSE; /* Command was emitted already prior to message output */
static int32 sim_on_check[MAX_DO_NEST_LVL+1];
static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+2];
#define ON_SIGINT_ACTION (SCPE_MAX_ERR+1)
static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
static const char *sim_do_label[MAX_DO_NEST_LVL+1];
@ -1082,66 +1084,66 @@ static const char simh_help[] =
/***************** 80 character line width template *************************/
#define HLP_SET_CONSOLE "*Commands SET CONSOLE"
"3Console\n"
"+set console arg{,arg...} set console options\n"
"+set console WRU=value specify console drop to simh character\n"
"+set console BRK=value specify console Break character\n"
"+set console DEL=value specify console delete character\n"
"+set console PCHAR=bitmask bit mask of printable characters in\n"
"+SET CONSOLE arg{,arg...} set console options\n"
"+SET CONSOLE WRU=value specify console drop to simh character\n"
"+SET CONSOLE BRK=value specify console Break character\n"
"+SET CONSOLE DEL=value specify console delete character\n"
"+SET CONSOLE PCHAR=bitmask bit mask of printable characters in\n"
"++++++++ range [31,0]\n"
"+set console SPEED=speed{*factor}\n"
"+SET CONSOLE SPEED=speed{*factor}\n"
"++++++++ specify console input data rate\n"
"+set console TELNET=port specify console telnet port\n"
"+set console TELNET=LOG=log_file\n"
"+SET CONSOLE TELNET=port specify console telnet port\n"
"+SET CONSOLE TELNET=LOG=log_file\n"
"++++++++ specify console telnet logging to the\n"
"++++++++ specified destination {LOG,STDOUT,STDERR,\n"
"++++++++ DEBUG or filename)\n"
"+set console TELNET=NOLOG disables console telnet logging\n"
"+set console TELNET=BUFFERED[=bufsize]\n"
"+SET CONSOLE TELNET=NOLOG disables console telnet logging\n"
"+SET CONSOLE TELNET=BUFFERED[=bufsize]\n"
"++++++++ specify console telnet buffering\n"
"+set console TELNET=NOBUFFERED\n"
"+SET CONSOLE TELNET=NOBUFFERED\n"
"++++++++ disables console telnet buffering\n"
"+set console TELNET=UNBUFFERED\n"
"+SET CONSOLE TELNET=UNBUFFERED\n"
"++++++++ disables console telnet buffering\n"
"+set console NOTELNET disable console telnet\n"
"+set console SERIAL=serialport[;config]\n"
"+SET CONSOLE NOTELNET disable console telnet\n"
"+SET CONSOLE SERIAL=serialport[;config]\n"
"++++++++ specify console serial port and optionally\n"
"++++++++ the port config (i.e. ;9600-8n1)\n"
"+set console NOSERIAL disable console serial session\n"
"+set console SPEED=nn{*fac} specifies the maximum console port input rate\n"
"+SET CONSOLE NOSERIAL disable console serial session\n"
"+SET CONSOLE SPEED=nn{*fac} specifies the maximum console port input rate\n"
/***************** 80 character line width template *************************/
#define HLP_SET_REMOTE "*Commands SET REMOTE"
"3Remote\n"
"+set remote TELNET=port specify remote console telnet port\n"
"+set remote NOTELNET disables remote console\n"
"+set remote BUFFERSIZE=bufsize\n"
"+SET REMOTE TELNET=port specify remote console telnet port\n"
"+SET REMOTE NOTELNET disables remote console\n"
"+SET REMOTE BUFFERSIZE=bufsize\n"
"++++++++ specify remote console command output buffer\n"
"++++++++ size\n"
"+set remote CONNECTIONS=n specify number of concurrent remote\n"
"+SET REMOTE CONNECTIONS=n specify number of concurrent remote\n"
"++++++++ console sessions\n"
"+set remote TIMEOUT=n specify number of seconds without input\n"
"+SET REMOTE TIMEOUT=n specify number of seconds without input\n"
"++++++++ before automatic continue\n"
"+set remote MASTER enable master mode remote console\n"
"+set remote NOMASTER disable remote master mode console\n"
"+SET REMOTE MASTER enable master mode remote console\n"
"+SET REMOTE NOMASTER disable remote master mode console\n"
#define HLP_SET_DEFAULT "*Commands SET Working_Directory"
"3Working Directory\n"
"+set default <dir> set the current directory\n"
"+cd <dir> set the current directory\n"
"+SET DEFAULT <dir> set the current directory\n"
"+CD <dir> set the current directory\n"
#define HLP_SET_LOG "*Commands SET Log"
"3Log\n"
" Interactions with the simulator session (at the \"sim>\" prompt\n"
" can be recorded to a log file\n\n"
"+set log log_file specify the log destination\n"
"+SET LOG log_file specify the log destination\n"
"++++++++ (STDOUT,DEBUG or filename)\n"
"+set nolog disables any currently active logging\n"
"+SET NOLOG disables any currently active logging\n"
"4Switches\n"
" By default, log output is written at the end of the specified log file.\n"
" A new log file can created if the -N switch is used on the command line.\n"
#define HLP_SET_DEBUG "*Commands SET Debug"
/***************** 80 character line width template *************************/
"3Debug\n"
"+set debug debug_file specify the debug destination\n"
"+SET DEBUG debug_file specify the debug destination\n"
"++++++++ (STDOUT,STDERR,LOG or filename)\n"
"+set nodebug disables any currently active debug output\n"
"+SET NODEBUG disables any currently active debug output\n"
"4Switches\n"
" Debug message output contains a timestamp which indicates the number of\n"
" simulated instructions which have been executed prior to the debug event.\n\n"
@ -1171,90 +1173,111 @@ static const char simh_help[] =
" EBCDIC characters.\n"
#define HLP_SET_BREAK "*Commands SET Breakpoints"
"3Breakpoints\n"
"+set break <list> set breakpoints\n"
"+set nobreak <list> clear breakpoints\n"
"+SET BREAK <list> set breakpoints\n"
"+SET NOBREAK <list> clear breakpoints\n"
/***************** 80 character line width template *************************/
#define HLP_SET_THROTTLE "*Commands SET Throttle"
"3Throttle\n"
"+set throttle {x{M|K|%%}}|{x/t}\n"
"++++++++ set simulation rate\n"
"+set nothrottle set simulation rate to maximum\n"
" Simulator instruction execution rate can be controlled by specifying\n"
" one of the following throttle commands:\n\n"
"+SET THROTTLE xM execute x million instructions per second\n"
"+SET THROTTLE xK execute x thousand instructions per second\n"
"+SET THROTTLE x%% occupy x percent of the host capacity\n"
"++++++++executing instructions\n"
"+SET THROTTLE x/t sleep for t milliseconds after executing x\n"
"++++++++instructions\n\n"
"+SET NOTHROTTLE set simulation rate to maximum\n\n"
" Throttling is only available on host systems that implement a precision\n"
" real-time delay function.\n\n"
" xM, xK and x%% modes require the simulator to execute sufficient\n"
" instructions to actually calibrate the desired execution rate relative\n"
" to wall clock time. Very short running programs may complete before\n"
" calibration completes and therefore before the simulated execution rate\n"
" can match the desired rate.\n\n"
" The SET NOTHROTTLE command turns off throttling. The SHOW THROTTLE\n"
" command shows the current settings for throttling and the calibration\n"
" results\n\n"
" Some simulators implement a different form of host CPU resource management\n"
" called idling. Idling suspends simulated execution whenever the program\n"
" running in the simulator is doing nothing, and runs the simulator at full\n"
" speed when there is work to do. Throttling and idling are mutually\n"
" exclusive.\n"
#define HLP_SET_CLOCKS "*Commands SET Clocks"
"3Clock\n"
#if defined (SIM_ASYNCH_CLOCKS)
"+set clock asynch enable asynchronous clocks\n"
"+set clock noasynch disable asynchronous clocks\n"
"+SET CLOCK asynch enable asynchronous clocks\n"
"+SET CLOCK noasynch disable asynchronous clocks\n"
#endif
"+set clock nocatchup disable catchup clock ticks\n"
"+set clock catchup enable catchup clock ticks\n"
"+set clock calib=n%% specify idle calibration skip %%\n"
"+set clock stop=n stop execution after n instructions\n\n"
" The set clock stop command allows execution to have a bound when\n"
"+SET CLOCK nocatchup disable catchup clock ticks\n"
"+SET CLOCK catchup enable catchup clock ticks\n"
"+SET CLOCK calib=n%% specify idle calibration skip %%\n"
"+SET CLOCK stop=n stop execution after n instructions\n\n"
" The SET CLOCK STOP command allows execution to have a bound when\n"
" execution starts with a BOOT, NEXT or CONTINUE command.\n"
#define HLP_SET_ASYNCH "*Commands SET Asynch"
"3Asynch\n"
"+set asynch enable asynchronous I/O\n"
"+set noasynch disable asynchronous I/O\n"
"+SET ASYNCH enable asynchronous I/O\n"
"+SET NOASYNCH disable asynchronous I/O\n"
#define HLP_SET_ENVIRON "*Commands SET Environment"
"3Environment\n"
"4Explicitily Changing A Variable\n"
"+set environment name=val set environment variable\n"
"+set environment name clear environment variable\n"
"+SET ENVIRONMENT name=val set environment variable\n"
"+SET ENVIRONMENT name clear environment variable\n"
"4Gathering Input From A User\n"
" Input from a user can be obtained by:\n\n"
"+set environment -p \"Prompt String\" name=default\n\n"
" The -p switch indicates that the user should be prompted\n"
"+set environment -P \"Prompt String\" name=default\n\n"
" The -P switch indicates that the user should be prompted\n"
" with the indicated prompt string and the input provided\n"
" will be saved in the environment variable 'name'. If no\n"
" input is provided, the value specified as 'default' will be\n"
" used.\n"
#define HLP_SET_ON "*Commands SET Command_Status_Trap_Dispatching"
"3Command Status Trap Dispatching\n"
"+set on enables error checking after command\n"
"+SET ON enables error checking after command\n"
"++++++++ execution\n"
"+set noon disables error checking after command\n"
"+SET NOON disables error checking after command\n"
"++++++++ execution\n"
"+set on inherit enables inheritance of ON state and\n"
"+SET ON INHERIT enables inheritance of ON state and\n"
"++++++++ actions into do command files\n"
"+set on noinherit disables inheritance of ON state and\n"
"+SET ON NOINHERIT disables inheritance of ON state and\n"
"++++++++ actions into do command files\n"
#define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
#define HLP_SET_VERIFY "*Commands SET Command_Execution_Display"
"3Command Execution Display\n"
"+set verify re-enables display of command file\n"
"+SET VERIFY re-enables display of command file\n"
"++++++++ processed commands\n"
"+set verbose re-enables display of command file\n"
"+SET VERBOSE re-enables display of command file\n"
"++++++++ processed commands\n"
"+set noverify disables display of command file processed\n"
"+SET NOVERIFY disables display of command file processed\n"
"++++++++ commands\n"
"+set noverbose disables display of command file processed\n"
"+SET NOVERBOSE disables display of command file processed\n"
"++++++++ commands\n"
#define HLP_SET_MESSAGE "*Commands SET Command_Error_Status_Display"
"3Command Error Status Display\n"
"+set message re-enables display of command file error\n"
"+SET MESSAGE re-enables display of command file error\n"
"++++++++ messages\n"
"+set nomessage disables display of command file error\n"
"+SET NOMESSAGE disables display of command file error\n"
"++++++++ messages\n"
#define HLP_SET_QUIET "*Commands SET Command_Output_Display"
"3Command Output Display\n"
"+set quiet disables suppression of some output and\n"
"+SET QUIET disables suppression of some output and\n"
"++++++++ messages\n"
"+set noquiet re-enables suppression of some output and\n"
"+SET NOQUIET re-enables suppression of some output and\n"
"++++++++ messages\n"
#define HLP_SET_PROMPT "*Commands SET Command_Prompt"
"3Command Prompt\n"
"+set prompt \"string\" sets an alternate simulator prompt string\n"
"+SET PROMPT \"string\" sets an alternate simulator prompt string\n"
"3Device and Unit\n"
"+set <dev> OCT|DEC|HEX|BIN set device display radix\n"
"+set <dev> ENABLED enable device\n"
"+set <dev> DISABLED disable device\n"
"+set <dev> DEBUG{=arg} set device debug flags\n"
"+set <dev> NODEBUG={arg} clear device debug flags\n"
"+set <dev> arg{,arg...} set device parameters (see show modifiers)\n"
"+set <unit> ENABLED enable unit\n"
"+set <unit> DISABLED disable unit\n"
"+set <unit> arg{,arg...} set unit parameters (see show modifiers)\n"
"+help <dev> set displays the device specific set commands\n"
"+SET <dev> OCT|DEC|HEX|BIN set device display radix\n"
"+SET <dev> ENABLED enable device\n"
"+SET <dev> DISABLED disable device\n"
"+SET <dev> DEBUG{=arg} set device debug flags\n"
"+SET <dev> NODEBUG={arg} clear device debug flags\n"
"+SET <dev> arg{,arg...} set device parameters (see show modifiers)\n"
"+SET <unit> ENABLED enable unit\n"
"+SET <unit> DISABLED disable unit\n"
"+SET <unit> arg{,arg...} set unit parameters (see show modifiers)\n"
"+HELP <dev> SET displays the device specific set commands\n"
"++++++++ available\n"
/***************** 80 character line width template *************************/
#define HLP_SHOW "*Commands SHOW"
@ -1557,6 +1580,10 @@ static const char simh_help[] =
" Assertion failed\n"
"5 INVREM\n"
" Invalid remote console command\n"
"5 NOTATT\n"
" Not attached \n"
"5 AMBREG\n"
" Ambiguous register\n"
#define HLP_SHIFT "*Commands Executing_Command_Files SHIFT"
"3SHIFT\n"
"++shift shift the command file's positional parameters\n"
@ -1564,10 +1591,59 @@ static const char simh_help[] =
"3CALL\n"
"++call transfer control to a labeled subroutine\n"
" a command file.\n"
#define HLP_ON "*Commands Executing_Command_Files ON"
"3ON\n"
"++on <condition> <action> perform action(s) after condition\n"
"++on <condition> clear action for specific condition\n"
/***************** 80 character line width template *************************/
#define HLP_ON "*Commands Executing_Command_Files Error_Trapping"
"3Error Trapping\n"
" Error traps can be taken when any command returns a non success status.\n"
" Actions to be performed for particular status returns are specified with\n"
" the ON command.\n"
"4Enabling Error Traps\n"
" Error trapping is enabled with:\n\n"
"++set on enable error traps\n"
"4Disabling Error Traps\n"
" Error trapping is disabled with:\n\n"
"++set noon disable error traps\n"
"4ON\n"
" To set the action(s) to take when a specific error status is returned by\n"
" a command in the currently running do command file:\n\n"
"++on <statusvalue> commandtoprocess{; additionalcommandtoprocess}\n\n"
" To clear the action(s) taken take when a specific error status is returned:\n\n"
"++on <statusvalue>\n\n"
" To set the default action(s) to take when any otherwise unspecified error\n"
" status is returned by a command in the currently running do command file:\n\n"
"++on error commandtoprocess{; additionalcommandtoprocess}\n\n"
" To clear the default action(s) taken when any otherwise unspecified error\n"
" status is returned:\n\n"
"++on error\n"
"5Parameters\n"
" Error traps can be taken for any command which returns a status other\n"
" than SCPE_STEP, SCPE_OK, and SCPE_EXIT.\n\n"
" ON Traps can specify any of these status values:\n\n"
"++NXM, UNATT, IOERR, CSUM, FMT, NOATT, OPENERR, MEM, ARG,\n"
"++STEP, UNK, RO, INCOMP, STOP, TTIERR, TTOERR, EOF, REL,\n"
"++NOPARAM, ALATT, TIMER, SIGERR, TTYERR, SUB, NOFNC, UDIS,\n"
"++NORO, INVSW, MISVAL, 2FARG, 2MARG, NXDEV, NXUN, NXREG,\n"
"++NXPAR, NEST, IERR, MTRLNT, LOST, TTMO, STALL, AFAIL,\n"
"++NOTATT, AMBREG\n\n"
" These values can be indicated by name or by their internal\n"
" numeric value (not recommended).\n"
/***************** 80 character line width template *************************/
"3CONTROL-C Trapping\n"
" A special ON trap is available to describe action(s) to be taken\n"
" when CONTROL_C (aka SIGINT) occurs during the execution of\n"
" simh commands and/or command procedures.\n\n"
"++on CONTROL_C <action> perform action(s) after CTRL+C\n"
"++on CONTROL_C restore default CTRL+C action\n\n"
" The default ON CONTROL_C handler will exit nested DO command\n"
" procedures and return to the sim> prompt.\n\n"
" Note 1: When a simulator is executing instructions entering CTRL+C\n"
"+will cause the CNTL+C character to be delivered to the simulator as\n"
"+input. The simulator instruction execution can be stopped by entering\n"
"+the WRU character (usually CTRL+E). Once instruction execution has\n"
"+stopped, CTRL+C can be entered and potentially acted on by the\n"
"+ON CONTROL_C trap handler.\n"
" Note 2: The ON CONTROL_C trapping is not affected by the SET ON and\n"
"+SET NOON commands.\n"
#define HLP_PROCEED "*Commands Executing_Command_Files PROCEED"
#define HLP_IGNORE "*Commands Executing_Command_Files PROCEED"
/***************** 80 character line width template *************************/
@ -1576,49 +1652,21 @@ static const char simh_help[] =
" placeholders for an ON action condition which should be explicitly ignored\n"
"++proceed continue command file execution without doing anything\n"
"++ignore continue command file execution without doing anything\n"
#if 0
SET ON Enables error trapping for currently defined
traps (by ON commands)
SET NOON Disables error trapping for currently
defined traps (by ON commands)
ON <statusvalue> commandtoprocess{; additionalcommandtoprocess}
Sets the action(s) to take when the specific
error status is returned by a command in the
currently running do command file. Multiple
actions can be specified with each delimited
by a semicolon character (just like
breakpoint action commands).
ON ERROR commandtoprocess{; additionalcommandtoprocess}
Sets the default action(s) to take when any
otherwise unspecified error status is returned
by a command in the currently running do
command file. Multiple actions can be
specified with each delimited by a semicolon
character (just like breakpoint action
commands).
ON <statusvalue>
ON ERROR Clears the default actions to take when any
otherwise unspecified error status is
returned by a command in the currently
running do command file.
Error traps can be taken for any command which returns a status other than SCPE_STEP, SCPE_OK, and SCPE_EXIT.
ON Traps can specify any status value from the following list: NXM, UNATT, IOERR, CSUM, FMT, NOATT, OPENERR, MEM, ARG, STEP, UNK, RO, INCOMP, STOP, TTIERR, TTOERR, EOF, REL, NOPARAM, ALATT, TIMER, SIGERR, TTYERR, SUB, NOFNC, UDIS, NORO, INVSW, MISVAL, 2FARG, 2MARG, NXDEV, NXUN, NXREG, NXPAR, NEST, IERR, MTRLNT, LOST, TTMO, STALL, AFAIL. These values can be indicated by name or by their internal numeric value (not recommended).
Interactions with ASSERT command and "DO -e":
DO -e is equivalent to SET ON, which by itself it equivalent to "SET ON; ON ERROR RETURN".
ASSERT failure have several different actions:
If error trapping is not enabled then AFAIL causes exit from the current do command file.
If error trapping is enabled and an explicit "ON AFAIL" action is defined, then the specified action is performed.
If error trapping is enabled and no "ON AFAIL" action is defined, then an AFAIL causes exit from the current do command file.
#endif
"3DO Command Processing Interactions With ASSERT\n"
" The command:\n\n"
"++DO -e commandfile\n\n"
" is equivalent to starting the invoked command file with:\n\n"
"++SET ON\n\n"
" which by itself it equivalent to:\n\n"
"++SET ON\n"
"++ON ERROR RETURN\n\n"
" ASSERT failures have several different actions:\n\n"
"+* If error trapping is not enabled then AFAIL causes exit from the\n"
"++current do command file.\n"
"+* If error trapping is enabled and an explicit \"ON AFAIL\" action\n"
"++is defined, then the specified action is performed.\n"
"+* If error trapping is enabled and no \"ON AFAIL\" action is defined,\n"
"++then an AFAIL causes exit from the current do command file.\n"
#define HLP_ECHO "*Commands Executing_Command_Files Displaying_Arbitrary_Text ECHO_Command"
/***************** 80 character line width template *************************/
"3Displaying Arbitrary Text\n"
@ -1851,7 +1899,7 @@ ASSERT failure have several different actions:
" 'm' for minutes, 'h' for hours or 'd' for days. NUMBER may be an\n"
" arbitrary floating point number. Given two or more arguments, pause\n"
" for the amount of time specified by the sum of their values.\n"
" NOTE: A SLEEP command is interruptable with SIGINT (^C).\n\n"
" NOTE: A SLEEP command is interruptable with SIGINT (CTRL+C).\n\n"
/***************** 80 character line width template *************************/
#define HLP_ASSERT "*Commands Executing_Command_Files Testing_Simulator_State"
#define HLP_IF "*Commands Executing_Command_Files Testing_Simulator_State"
@ -1940,6 +1988,7 @@ ASSERT failure have several different actions:
" The -i switch, if present, causes comparisons to be case insensitive.\n"
" <string1> and <string2> are quoted string values which may have\n"
" environment variables substituted as desired.\n"
" Either quoted string may alternatively be an environment variable name.\n"
" <compare-op> may be one of:\n\n"
"++== - equal\n"
"++EQU - equal\n"
@ -2237,12 +2286,12 @@ if (sim_vm_init != NULL) /* call once only */
(*sim_vm_init)();
sim_finit (); /* init fio package */
setenv ("SIM_NAME", sim_name, 1); /* Publish simulator name */
stop_cpu = 0;
stop_cpu = FALSE;
sim_interval = 0;
sim_time = sim_rtime = 0;
noqueue_time = 0;
sim_clock_queue = QUEUE_LIST_END;
sim_is_running = 0;
sim_is_running = FALSE;
sim_log = NULL;
if (sim_emax <= 0)
sim_emax = 1;
@ -2267,6 +2316,7 @@ if ((stat = sim_brk_init ()) != SCPE_OK) {
sim_error_text (stat));
return 0;
}
signal (SIGINT, int_handler);
if (!sim_quiet) {
printf ("\n");
show_version (stdout, NULL, NULL, 0, NULL);
@ -2355,16 +2405,32 @@ CTAB *cmdp;
stat = SCPE_BARE_STATUS(stat); /* remove possible flag */
while (stat != SCPE_EXIT) { /* in case exit */
if (stop_cpu) { /* SIGINT happened? */
stop_cpu = FALSE;
if (!sim_ttisatty()) {
stat = SCPE_EXIT;
break;
}
if (sim_on_actions[sim_do_depth][ON_SIGINT_ACTION])
sim_brk_setact (sim_on_actions[sim_do_depth][ON_SIGINT_ACTION]);
}
if ((cptr = sim_brk_getact (cbuf, sizeof(cbuf)))) /* pending action? */
printf ("%s%s\n", sim_prompt, cptr); /* echo */
else if (sim_vm_read != NULL) { /* sim routine? */
printf ("%s", sim_prompt); /* prompt */
cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
else {
if (sim_vm_read != NULL) { /* sim routine? */
printf ("%s", sim_prompt); /* prompt */
cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin);
}
else
cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);/* read with prmopt*/
}
else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);/* read with prmopt*/
if (cptr == NULL) { /* EOF? */
if (sim_ttisatty()) continue; /* ignore tty EOF */
else break; /* otherwise exit */
if (cptr == NULL) { /* EOF? or SIGINT? */
if (sim_ttisatty()) {
printf ("\n");
continue; /* ignore tty EOF */
}
else
break; /* otherwise exit */
}
if (*cptr == 0) /* ignore blank */
continue;
@ -2680,7 +2746,9 @@ if ((dptr->modifiers) && (dptr->units) && (dptr->numunits != 1)) {
if (mptr->mstring) {
fprint_header (st, &found, header);
sprintf (buf, "set %s%s %s%s", sim_dname (dptr), (dptr->numunits > 1) ? "n" : "0", mptr->mstring, (strchr(mptr->mstring, '=')) ? "" : (MODMASK(mptr,MTAB_VALR) ? "=val" : (MODMASK(mptr,MTAB_VALO) ? "{=val}": "")));
fprintf (st, "%-30s\t%s\n", buf, (strchr(mptr->mstring, '=')) ? "" : (mptr->help ? mptr->help : ""));
fprintf (st, "%-30s\t%s\n", buf, (strchr (mptr->mstring, '=')) ? ((strlen (buf) > 30) ? "" : mptr->help) : (mptr->help ? mptr->help : ""));
if ((strchr (mptr->mstring, '=')) && (strlen (buf) > 30))
fprintf (st, "%-30s\t%s\n", "", mptr->help);
}
}
}
@ -3146,7 +3214,7 @@ if (flag >= 0) { /* Only bump nesting fro
++sim_do_depth;
if (sim_on_inherit) { /* inherit ON condition actions? */
sim_on_check[sim_do_depth] = sim_on_check[sim_do_depth-1]; /* inherit On mode */
for (i=0; i<SCPE_MAX_ERR; i++) { /* replicate any on commands */
for (i=0; i<=SCPE_MAX_ERR; i++) { /* replicate appropriate on commands */
if (sim_on_actions[sim_do_depth-1][i]) {
sim_on_actions[sim_do_depth][i] = (char *)malloc(1+strlen(sim_on_actions[sim_do_depth-1][i]));
if (NULL == sim_on_actions[sim_do_depth][i]) {
@ -3185,6 +3253,14 @@ if (errabort) /* -e flag? */
set_on (1, NULL); /* equivalent to ON ERROR RETURN */
do {
if (stop_cpu) { /* SIGINT? */
if (sim_on_actions[sim_do_depth][ON_SIGINT_ACTION]) {
stop_cpu = FALSE;
sim_brk_setact (sim_on_actions[sim_do_depth][ON_SIGINT_ACTION]);/* Use specified action */
}
else
break; /* Exit this command procedure */
}
sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf)); /* get bkpt action */
if (!sim_do_ocptr[sim_do_depth]) { /* no pending action? */
sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);/* get cmd line */
@ -3221,7 +3297,8 @@ do {
else
stat = cmdp->action (cmdp->arg, cptr); /* exec other cmd */
}
else stat = SCPE_UNK; /* bad cmd given */
else
stat = SCPE_UNK; /* bad cmd given */
echo = sim_do_echo; /* Allow for SET VERIFY */
stat_nomessage = stat & SCPE_NOMESSAGE; /* extract possible message supression flag */
stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */
@ -3231,7 +3308,8 @@ do {
(cmdp->action != &goto_cmd) &&
(cmdp->action != &on_cmd) &&
(cmdp->action != &echo_cmd) &&
(cmdp->action != &echof_cmd)))
(cmdp->action != &echof_cmd) &&
(cmdp->action != &sleep_cmd)))
sim_last_cmd_stat = stat; /* save command error status */
switch (stat) {
case SCPE_AFAIL:
@ -3286,7 +3364,7 @@ if (flag >= 0) {
sim_quiet = saved_sim_quiet; /* restore quiet mode we entered with */
}
if ((flag >= 0) || (!sim_on_inherit)) {
for (i=0; i<SCPE_MAX_ERR; i++) { /* release any on commands */
for (i=0; i<=SCPE_MAX_ERR; i++) { /* release any on commands */
free (sim_on_actions[sim_do_depth][i]);
sim_on_actions[sim_do_depth][i] = NULL;
}
@ -3676,8 +3754,8 @@ return 1;
<logical-op> and <conditional-op> are the same as that
allowed for examine and deposit search specifications.
Syntax: ASSERT {-i} {NOT} "<string1>" <compare-op> "<string2>"
Syntax: IF {-i} {NOT} "<string1>" <compare-op> "<string2>" commandtoprocess{; additionalcommandtoprocess}...
Syntax: ASSERT {-i} {NOT} "<string1>"|EnvVarName1 <compare-op> "<string2>"|EnvVarName2
Syntax: IF {-i} {NOT} "<string1>"|EnvVarName1 <compare-op> "<string2>"|EnvVarName2 commandtoprocess{; additionalcommandtoprocess}...
If -i is specified, the comparisons are done in a case insensitive manner.
If NOT is specified, the resulting expression value is inverted.
@ -3697,6 +3775,28 @@ return 1;
>= - greater than or equal
GEQ - greater than or equal
*/
static CONST char *_get_string (CONST char *iptr, char *optr, char mchar)
{
const char *ap;
CONST char *tptr, *gptr;
REG *rptr;
tptr = (CONST char *)get_glyph_gen (iptr, optr, mchar, (sim_switches & SWMASK ('I')), TRUE, '\\');
if (*optr != '"') {
ap = getenv (optr);
if (!ap)
return tptr;
/* for legacy ASSERT/IF behavior give precidence to REGister names over Environment Variables */
get_glyph (optr, optr, 0);
rptr = find_reg (optr, &gptr, sim_dfdev);
if (rptr)
return tptr;
snprintf (optr, CBUFSIZE - 1, "\"%s\"", ap);
get_glyph_gen (optr, optr, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
}
return tptr;
}
t_stat assert_cmd (int32 flag, CONST char *cptr)
{
char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
@ -3725,7 +3825,8 @@ if (!strcmp (gbuf, "EXIST")) { /* File Exist Test? */
Exist = TRUE; /* remember that, and */
cptr = (CONST char *)tptr;
}
if (Exist || (*cptr == '"')) { /* quoted string comparison? */
tptr = _get_string (cptr, gbuf, '='); /* get first string */
if (Exist || (*gbuf == '"')) { /* quoted string comparison? */
char op[CBUFSIZE];
static struct {
const char *op;
@ -3743,16 +3844,14 @@ if (Exist || (*cptr == '"')) { /* quoted string compari
{"<=", 0, -1, FALSE},
{"LEQ", 0, -1, FALSE},
{">", 1, 1, FALSE},
{"GTR", 1, 1, FALSE},
{"GTR", 1, 1, FALSE},
{">=", 0, 1, FALSE},
{"GEQ", 0, 1, FALSE},
{NULL}};
tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\');
/* get first string */
if (!*tptr)
return SCPE_2FARG;
cptr += strlen (gbuf);
cptr = tptr;
while (sim_isspace (*cptr)) /* skip spaces */
++cptr;
if (!Exist) {
@ -3763,17 +3862,16 @@ if (Exist || (*cptr == '"')) { /* quoted string compari
if (!optr->op)
return sim_messagef (SCPE_ARG, "Invalid operator: %s\n", op);
cptr += strlen (op);
while (sim_isspace (*cptr)) /* skip spaces */
while (sim_isspace (*cptr)) /* skip spaces */
++cptr;
cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
/* get second string */
if (*cptr) { /* more? */
if (flag) /* ASSERT has no more args */
cptr = _get_string (cptr, gbuf2, 0); /* get second string */
if (*cptr) { /* more? */
if (flag) /* ASSERT has no more args */
return SCPE_2MARG;
}
else {
if (!flag)
return SCPE_2FARG; /* IF needs actions! */
if (!flag)
return SCPE_2FARG; /* IF needs actions! */
}
result = sim_cmp_string (gbuf, gbuf2);
result = ((result == optr->aval) || (result == optr->bval));
@ -3808,7 +3906,7 @@ else {
addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr);
else
addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix);
if (gbuf == gptr) /* error? */
if (gbuf == gptr) /* not register? */
return SCPE_NXREG;
}
if (*gptr != 0) /* more? must be search */
@ -4079,8 +4177,6 @@ t_stat sleep_cmd (int32 flag, CONST char *cptr)
char *tptr;
double wait;
stop_cpu = 0;
signal (SIGINT, int_handler);
while (*cptr) {
wait = strtod (cptr, &tptr);
switch (*tptr) {
@ -4108,7 +4204,6 @@ while (*cptr) {
wait *= (24.0*60.0*60.0);
break;
default:
signal (SIGINT, SIG_DFL); /* cancel WRU */
return sim_messagef (SCPE_ARG, "Invalid Sleep unit '%c'\n", *cptr);
}
wait *= 1000.0; /* Convert to Milliseconds */
@ -4118,8 +4213,7 @@ while (*cptr) {
if ((wait > 0.0) && (!stop_cpu))
sim_os_ms_sleep ((unsigned)wait);
}
signal (SIGINT, SIG_DFL); /* cancel WRU */
stop_cpu = 0;
stop_cpu = FALSE; /* Clear in case sleep was interrupted */
return SCPE_OK;
}
@ -4220,9 +4314,17 @@ cptr = get_glyph (cptr, gbuf, 0);
if ('\0' == gbuf[0]) return SCPE_ARG; /* unspecified condition */
if (0 == strcmp("ERROR", gbuf))
cond = 0;
else
if (SCPE_OK != sim_string_to_stat (gbuf, &cond))
return SCPE_ARG;
else {
if (SCPE_OK != sim_string_to_stat (gbuf, &cond)) {
if ((MATCH_CMD (gbuf, "CONTROL_C") == 0) ||
(MATCH_CMD (gbuf, "SIGINT") == 0))
cond = ON_SIGINT_ACTION; /* Special case */
else
return sim_messagef (SCPE_ARG, "Invalid argument: %s\n", gbuf);
}
}
if (cond == SCPE_OK)
return sim_messagef (SCPE_ARG, "Invalid argument: %s\n", gbuf);
if ((NULL == cptr) || ('\0' == *cptr)) { /* Empty Action */
free(sim_on_actions[sim_do_depth][cond]); /* Clear existing condition */
sim_on_actions[sim_do_depth][cond] = NULL; }
@ -4909,17 +5011,15 @@ const char *scale, *width;
if (sim_switches & SWMASK ('B'))
kval = 1024;
mval = kval * kval;
if (dptr->flags & DEV_SECTORS) {
kval = kval / 512;
mval = mval / 512;
}
if (dptr->flags & DEV_SECTORS)
psize = psize * 512;
if ((dptr->dwidth / dptr->aincr) > 8)
width = "W";
else
width = "B";
if (uptr->capac < (kval * 10))
if (psize < (kval * 10))
scale = "";
else if (uptr->capac < (mval * 10)) {
else if (psize < (mval * 10)) {
scale = "K";
psize = psize / kval;
}
@ -5313,12 +5413,16 @@ for (lvl=sim_do_depth; lvl >= 0; --lvl) {
fprintf(st, " is %s\n", (sim_on_check[lvl]) ? "enabled" : "disabled");
for (i=1; i<SCPE_BASE; ++i) {
if (sim_on_actions[lvl][i])
fprintf(st, " on %5d %s\n", i, sim_on_actions[lvl][i]); }
fprintf(st, " on %6d %s\n", i, sim_on_actions[lvl][i]); }
for (i=SCPE_BASE; i<=SCPE_MAX_ERR; ++i) {
if (sim_on_actions[lvl][i])
fprintf(st, " on %-5s %s\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
fprintf(st, " on %-6s %s\n", scp_errors[i-SCPE_BASE].code, sim_on_actions[lvl][i]); }
if (sim_on_actions[lvl][0])
fprintf(st, " on ERROR %s\n", sim_on_actions[lvl][0]);
fprintf(st, " on ERROR %s\n", sim_on_actions[lvl][0]);
if (sim_on_actions[lvl][ON_SIGINT_ACTION]) {
fprintf(st, "CONTROL+C/SIGINT Handling:\n");
fprintf(st, " on CONTROL_C %s\n", sim_on_actions[lvl][ON_SIGINT_ACTION]);
}
fprintf(st, "\n");
}
if (sim_on_inherit)
@ -7130,35 +7234,26 @@ for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* reposition all */
return sim_messagef (SCPE_IERR, "Can't seek to %u in %s for %s\n", (unsigned)uptr->pos, uptr->filename, sim_uname (uptr));
}
}
stop_cpu = 0;
sim_is_running = 1; /* flag running */
if ((r = sim_ttrun ()) != SCPE_OK) { /* set console mode */
sim_is_running = 0; /* flag idle */
if ((r = sim_ttrun ()) != SCPE_OK) { /* set console mode */
sim_ttcmd ();
return sim_messagef (SCPE_TTYERR, "sim_ttrun() returned: %s\n", sim_error_text (r));
}
if ((r = sim_check_console (30)) != SCPE_OK) { /* check console, error? */
sim_is_running = 0; /* flag idle */
sim_ttcmd ();
sim_messagef (r, "sim_check_console () returned: %s\n", sim_error_text (r));
}
if (signal (SIGINT, int_handler) == SIG_ERR) { /* set WRU */
sim_is_running = 0; /* flag idle */
sim_ttcmd ();
return sim_messagef (SCPE_SIGERR, "Can't establish SIGINT");
}
#ifdef SIGHUP
if (signal (SIGHUP, int_handler) == SIG_ERR) { /* set WRU */
sim_is_running = 0; /* flag idle */
sim_ttcmd ();
return sim_messagef (SCPE_SIGERR, "Can't establish SIGHUP");
}
#endif
if (signal (SIGTERM, int_handler) == SIG_ERR) { /* set WRU */
sim_is_running = 0; /* flag idle */
sim_ttcmd ();
return sim_messagef (SCPE_SIGERR, "Can't establish SIGTERM");
}
stop_cpu = FALSE;
sim_is_running = TRUE; /* flag running */
if (sim_step) /* set step timer */
sim_activate (&sim_step_unit, sim_step);
fflush(stdout); /* flush stdout */
@ -7207,15 +7302,18 @@ do {
}
else
sim_step = 1;
if (sim_step) /* set step timer */
if (sim_step) /* set step timer */
sim_activate (&sim_step_unit, sim_step);
} while (1);
sim_is_running = 0; /* flag idle */
if ((SCPE_BARE_STATUS(r) == SCPE_STOP) && /* WRU exit from sim_instr() */
(sim_on_actions[sim_do_depth][SCPE_STOP] == NULL) &&/* without a handler for a STOP condition */
(sim_on_actions[sim_do_depth][0] == NULL))
sim_os_ms_sleep (sim_stop_sleep_ms); /* wait a bit for SIGINT */
sim_is_running = FALSE; /* flag idle */
sim_stop_timer_services (); /* disable wall clock timing */
sim_ttcmd (); /* restore console */
sim_brk_clrall (BRK_TYP_DYN_STEPOVER); /* cancel any step/over subroutine breakpoints */
signal (SIGINT, SIG_DFL); /* cancel WRU */
#ifdef SIGHUP
signal (SIGHUP, SIG_DFL); /* cancel WRU */
#endif
@ -7377,7 +7475,7 @@ return sim_cancel (&sim_step_unit);
void int_handler (int sig)
{
stop_cpu = 1;
stop_cpu = TRUE;
return;
}
@ -9775,8 +9873,10 @@ t_stat sim_process_event (void)
UNIT *uptr;
t_stat reason;
if (stop_cpu) /* stop CPU? */
if (stop_cpu) { /* stop CPU? */
stop_cpu = 0;
return SCPE_STOP;
}
AIO_UPDATE_QUEUE;
UPDATE_SIM_TIME; /* update sim time */
@ -9818,8 +9918,10 @@ if (sim_clock_queue == QUEUE_LIST_END) { /* queue empty? */
else
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Processing Queue Complete New Interval = %d(%s)\n", sim_interval, sim_uname(sim_clock_queue));
if ((reason == SCPE_OK) && stop_cpu)
if ((reason == SCPE_OK) && stop_cpu) {
stop_cpu = FALSE;
reason = SCPE_STOP;
}
sim_processing_event = FALSE;
return reason;
}
@ -11231,6 +11333,10 @@ return SCPE_OK;
t_stat sim_show_send_input (FILE *st, const SEND *snd)
{
const char *dev_name = tmxr_send_line_name (snd);
uint32 delay = get_default_env_parameter (dev_name, "SIM_SEND_DELAY", SEND_DEFAULT_DELAY);
uint32 after = get_default_env_parameter (dev_name, "SIM_SEND_AFTER", delay);
fprintf (st, "%s\n", tmxr_send_line_name (snd));
if (snd->extoff < snd->insoff) {
fprintf (st, " %d bytes of pending input Data:\n ", snd->insoff-snd->extoff);
@ -11250,6 +11356,10 @@ if ((snd->delay > (sim_timer_inst_per_sec()/1000000.0)) && ((sim_timer_inst_per_
fprintf (st, " Minimum of %d instructions (%d microseconds) between characters\n", (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0)));
else
fprintf (st, " Minimum of %d instructions between characters\n", (int)snd->delay);
if (after)
fprintf (st, " Default delay before first character input is %u instructions\n", after);
if (delay)
fprintf (st, " Default delay between character input is %u instructions\n", after);
if (snd->dptr && (snd->dbit & snd->dptr->dctrl))
fprintf (st, " Send Debugging via: SET %s DEBUG%s%s\n", sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "", snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : "");
return SCPE_OK;
@ -11303,20 +11413,20 @@ int32 cond;
cptr = get_glyph (cptr, gbuf, 0);
if (0 == memcmp("SCPE_", gbuf, 5))
memmove (gbuf, gbuf+5, 1 + strlen (gbuf+5));/* skip leading SCPE_ */
for (cond=0; cond < (SCPE_MAX_ERR-SCPE_BASE); cond++)
for (cond=0; cond <= (SCPE_MAX_ERR-SCPE_BASE); cond++)
if (0 == strcmp(scp_errors[cond].code, gbuf)) {
cond += SCPE_BASE;
break;
}
if (0 == strcmp(gbuf, "OK"))
cond = SCPE_OK;
if (cond == (SCPE_MAX_ERR-SCPE_BASE)) { /* not found? */
if (cond == (1+SCPE_MAX_ERR-SCPE_BASE)) { /* not found? */
if (0 == (cond = strtol(gbuf, NULL, 0))) /* try explicit number */
return SCPE_ARG;
}
*stat = cond;
if (cond > SCPE_MAX_ERR)
return SCPE_ARG;
*stat = cond;
return SCPE_OK;
}

4
scp.h
View File

@ -347,12 +347,12 @@ extern struct timespec sim_deb_basetime; /* debug base time for r
extern DEVICE **sim_internal_devices;
extern uint32 sim_internal_device_count;
extern UNIT *sim_clock_queue;
extern int32 sim_is_running;
extern volatile t_bool sim_is_running;
extern t_bool sim_processing_event; /* Called from sim_process_event */
extern char *sim_prompt; /* prompt string */
extern const char *sim_savename; /* Simulator Name used in Save/Restore files */
extern t_value *sim_eval;
extern volatile int32 stop_cpu;
extern volatile t_bool stop_cpu;
extern uint32 sim_brk_types; /* breakpoint info */
extern uint32 sim_brk_dflt;
extern uint32 sim_brk_summ;

View File

@ -798,6 +798,8 @@ static CTAB allowed_single_remote_cmds[] = {
{ "ECHO", &echo_cmd, 0 },
{ "ECHOF", &echof_cmd, 0 },
{ "SHOW", &show_cmd, 0 },
{ "DEBUG", &debug_cmd, 1 },
{ "NODEBUG", &debug_cmd, 0 },
{ "HELP", &x_help_cmd, 0 },
{ NULL, NULL }
};
@ -1395,15 +1397,17 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
continue;
}
else {
sim_is_running = 0;
sim_is_running = FALSE;
sim_rem_collect_all_registers ();
sim_stop_timer_services ();
for (j=0; j < sim_rem_con_tmxr.lines; j++) {
TMLN *lpj = &sim_rem_con_tmxr.ldsc[j];
if ((i == j) || (!lpj->conn))
continue;
tmxr_linemsgf (lpj, "\nRemote Master Console(%s) Entering Commands\n", lp->ipad);
tmxr_send_buffered_data (lpj); /* flush any buffered data */
if (rem->act == NULL) {
for (j=0; j < sim_rem_con_tmxr.lines; j++) {
TMLN *lpj = &sim_rem_con_tmxr.ldsc[j];
if ((i == j) || (!lpj->conn))
continue;
tmxr_linemsgf (lpj, "\nRemote Master Console(%s) Entering Commands\n", lp->ipad);
tmxr_send_buffered_data (lpj); /* flush any buffered data */
}
}
}
}
@ -1418,7 +1422,7 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
if (rem->single_mode) {
if (c == sim_int_char) { /* ^E (the interrupt character) must start continue mode console interaction */
rem->single_mode = FALSE; /* enter multi command mode */
sim_is_running = 0;
sim_is_running = FALSE;
sim_rem_collect_all_registers ();
sim_stop_timer_services ();
stat = SCPE_STOP;
@ -1783,7 +1787,7 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
tmxr_linemsg (lpj, "Simulator Running...");
tmxr_send_buffered_data (lpj);
}
sim_is_running = 1;
sim_is_running = TRUE;
sim_start_timer_services ();
}
if (cmdp && (cmdp->action == &x_continue_cmd))
@ -2764,7 +2768,7 @@ if (!sim_rem_master_mode) {
else
c = SCPE_OK;
if (c == SCPE_STOP) { /* ^E */
stop_cpu = 1; /* Force a stop (which is picked up by sim_process_event */
stop_cpu = TRUE; /* Force a stop (which is picked up by sim_process_event */
return SCPE_OK;
}
if ((sim_con_tmxr.master == 0) && /* not Telnet? */
@ -2954,7 +2958,6 @@ extern pthread_mutex_t sim_tmxr_poll_lock;
extern pthread_cond_t sim_tmxr_poll_cond;
extern int32 sim_tmxr_poll_count;
extern t_bool sim_tmxr_poll_running;
extern int32 sim_is_running;
pthread_t sim_console_poll_thread; /* Keyboard Polling Thread Id */
t_bool sim_console_poll_running = FALSE;
@ -3282,7 +3285,6 @@ return SCPE_OK;
#include <fcntl.h>
#include <io.h>
#include <windows.h>
#define RAW_MODE 0
static HANDLE std_input;
static HANDLE std_output;

View File

@ -127,6 +127,8 @@ extern int sim_vax_snprintf(char *buf, size_t buf_size, const char *fmt, ...);
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#include <winerror.h>
#undef PACKED /* avoid macro name collision */
#undef ERROR /* avoid macro name collision */
#undef MEM_MAPPED /* avoid macro name collision */
@ -403,10 +405,10 @@ typedef uint32 t_addr;
#define SCPE_AMBREG (SCPE_BASE + 46) /* ambiguous register */
#define SCPE_REMOTE (SCPE_BASE + 47) /* remote console command */
#define SCPE_MAX_ERR (SCPE_BASE + 48) /* Maximum SCPE Error Value */
#define SCPE_KFLAG 0x1000 /* tti data flag */
#define SCPE_BREAK 0x2000 /* tti break flag */
#define SCPE_NOMESSAGE 0x10000000 /* message display supression flag */
#define SCPE_MAX_ERR (SCPE_BASE + 47) /* Maximum SCPE Error Value */
#define SCPE_KFLAG 0x10000000 /* tti data flag */
#define SCPE_BREAK 0x20000000 /* tti break flag */
#define SCPE_NOMESSAGE 0x40000000 /* message display supression flag */
#define SCPE_BARE_STATUS(stat) ((stat) & ~(SCPE_NOMESSAGE|SCPE_KFLAG|SCPE_BREAK))
/* Print value format codes */

View File

@ -80,9 +80,6 @@ Internal routines:
#include <ctype.h>
#include <sys/stat.h>
#ifdef _WIN32
#include <windows.h>
#endif
#if defined SIM_ASYNCH_IO
#include <pthread.h>
#endif
@ -1732,12 +1729,13 @@ if (capac && (capac != (t_offset)-1)) {
}
}
else {
if ((filesystem_capac != (t_offset)-1) &&
(filesystem_capac > capac))
capac = filesystem_capac;
if ((capac != (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))) ||
(DKUF_F_STD != DK_GET_FMT (uptr)))
uptr->capac = (t_addr)(capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
if ((filesystem_capac != (t_offset)-1) && /* Known file system data size AND */
(filesystem_capac > capac)) /* Data size greater than container size? */
capac = filesystem_capac; /* Use file system data size */
if (((filesystem_capac != (t_offset)-1) && /* Known file system data size AND */
(capac > (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)))) || /* Data > current size */
(DKUF_F_STD != DK_GET_FMT (uptr))) /* OR ! autosizeable disk */
uptr->capac = (t_addr)(capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))); /* update current size */
}
}

View File

@ -827,7 +827,7 @@ t_stat ethq_init(ETH_QUE* que, int max)
que->item = (struct eth_item *) calloc(max, sizeof(struct eth_item));
if (!que->item) {
/* failed to allocate memory */
sim_printf("EthQ: failed to allocate dynamic queue[%d]\r\n", max);
sim_printf("EthQ: failed to allocate dynamic queue[%d]\n", max);
return SCPE_MEM;
};
que->max = max;
@ -1115,7 +1115,7 @@ static void load_function(const char* function, _func* func_ptr) {
*func_ptr = (_func)((size_t)dlsym(hLib, function));
#endif
if (*func_ptr == 0) {
sim_printf ("Eth: Failed to find function '%s' in %s\r\n", function, lib_name);
sim_printf ("Eth: Failed to find function '%s' in %s\n", function, lib_name);
lib_loaded = 3;
}
}
@ -1157,11 +1157,11 @@ int load_pcap(void) {
#endif
if (hLib == 0) {
/* failed to load DLL */
sim_printf ("Eth: Failed to load %s\r\n", lib_name);
sim_printf ("Eth: Failed to load %s\n", lib_name);
#ifdef _WIN32
sim_printf ("Eth: You must install Npcap or WinPcap 4.x to use networking\r\n");
sim_printf ("Eth: You must install Npcap or WinPcap 4.x to use networking\n");
#else
sim_printf ("Eth: You must install libpcap to use networking\r\n");
sim_printf ("Eth: You must install libpcap to use networking\n");
#endif
lib_loaded = 2;
break;
@ -1939,7 +1939,7 @@ return NULL;
t_stat eth_set_async (ETH_DEV *dev, int latency)
{
#if !defined(USE_READER_THREAD) || !defined(SIM_ASYNCH_IO)
char *msg = "Eth: can't operate asynchronously, must poll\r\n";
char *msg = "Eth: can't operate asynchronously, must poll\n";
sim_printf ("%s", msg);
return SCPE_NOFNC;
#else
@ -2003,10 +2003,8 @@ if (0 == strncmp("tap:", savname, 4)) {
while (isspace(*devname))
++devname;
#if defined(HAVE_TAP_NETWORK)
if (!strcmp(savname, "tap:tapN")) {
sim_printf ("Eth: Must specify actual tap device name (i.e. tap:tap0)\r\n");
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
if (!strcmp(savname, "tap:tapN"))
return sim_messagef (SCPE_OPENERR, "Eth: Must specify actual tap device name (i.e. tap:tap0)\n");
#endif
#if (defined(__linux) || defined(__linux__)) && defined(HAVE_TAP_NETWORK)
if ((tun = open("/dev/net/tun", O_RDWR)) >= 0) {
@ -2084,17 +2082,29 @@ if (0 == strncmp("tap:", savname, 4)) {
else { /* !tap: */
if (0 == strncmp("vde:", savname, 4)) {
#if defined(HAVE_VDE_NETWORK)
char vdeswitch_s[CBUFSIZE]; /* VDE switch name */
char vdeport_s[CBUFSIZE]; /* VDE switch port (optional), numeric */
struct vde_open_args voa;
const char *devname = savname + 4;
memset(&voa, 0, sizeof(voa));
if (!strcmp(savname, "vde:vdedevice")) {
sim_printf ("Eth: Must specify actual vde device name (i.e. vde:/tmp/switch)\r\n");
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
if (!strcmp(savname, "vde:vdedevice"))
return sim_messagef (SCPE_OPENERR, "Eth: Must specify actual vde device name (i.e. vde:/tmp/switch)\n");
while (isspace(*devname))
++devname;
if (!(*handle = (void*) vde_open((char *)devname, (char *)"simh", &voa)))
++devname;
devname = get_glyph_nc (devname, vdeswitch_s, ':'); /* Extract switch name */
devname = get_glyph_nc (devname, vdeport_s, 0); /* Extract optional port number */
if (vdeport_s[0]) { /* port provided? */
t_stat r;
voa.port = (int)get_uint (vdeport_s, 10, 255, &r);
if (r != SCPE_OK)
return sim_messagef (SCPE_OPENERR, "Eth: Invalid vde port number: %s in %s\n", vdeport_s, savname);
}
if (!(*handle = (void*) vde_open((char *)vdeswitch_s, (char *)"simh", &voa)))
strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
else {
*eth_api = ETH_API_VDE;
@ -2110,7 +2120,7 @@ else { /* !tap: */
const char *devname = savname + 4;
while (isspace(*devname))
++devname;
++devname;
if (!(*handle = (void*) sim_slirp_open(devname, opaque, &_slirp_callback, dptr, dbit)))
strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
else {
@ -2127,13 +2137,11 @@ else { /* !tap: */
char hostport[2*CBUFSIZE];
const char *devname = savname + 4;
if (!strcmp(savname, "udp:sourceport:remotehost:remoteport")) {
sim_printf ("Eth: Must specify actual udp host and ports(i.e. udp:1224:somehost.com:2234)\r\n");
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
if (!strcmp(savname, "udp:sourceport:remotehost:remoteport"))
return sim_messagef (SCPE_OPENERR, "Eth: Must specify actual udp host and ports(i.e. udp:1224:somehost.com:2234)\n");
while (isspace(*devname))
++devname;
++devname;
if (SCPE_OK != sim_parse_addr_ex (devname, host, sizeof(host), "localhost", port, sizeof(port), localport, sizeof(localport), NULL))
return SCPE_OPENERR;
@ -2141,23 +2149,19 @@ else { /* !tap: */
strcpy (localport, port);
sprintf (hostport, "%s:%s", host, port);
if ((SCPE_OK == sim_parse_addr (hostport, NULL, 0, NULL, NULL, 0, NULL, "localhost")) &&
(0 == strcmp (localport, port))) {
sim_printf ("Eth: Must specify different udp localhost ports\r\n");
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
(0 == strcmp (localport, port)))
return sim_messagef (SCPE_OPENERR, "Eth: Must specify different udp localhost ports\n");
*fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, SIM_SOCK_OPT_DATAGRAM);
if (INVALID_SOCKET == *fd_handle)
return SCPE_OPENERR;
return SCPE_OPENERR;
*eth_api = ETH_API_UDP;
*handle = (void *)1; /* Flag used to indicated open */
}
else { /* not udp:, so attempt to open the parameter as if it were an explicit device name */
#if defined(HAVE_PCAP_NETWORK)
*handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
if (!*handle) { /* can't open device */
sim_printf ("Eth: pcap_open_live error - %s\r\n", errbuf);
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
if (!*handle) /* can't open device */
return sim_messagef (SCPE_OPENERR, "Eth: pcap_open_live error - %s\n", errbuf);
*eth_api = ETH_API_PCAP;
#if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__)
/* Tell the kernel that the header is fully-formed when it gets it.
@ -2174,7 +2178,7 @@ else { /* !tap: */
#ifdef USE_SETNONBLOCK
/* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
if (pcap_setnonblock (*handle, 1, errbuf) == -1) {
sim_printf ("Eth: Failed to set non-blocking: %s\r\n", errbuf);
sim_printf ("Eth: Failed to set non-blocking: %s\n", errbuf);
}
#endif
#if defined (__APPLE__)
@ -2210,15 +2214,15 @@ if (bpf_filter && (*eth_api == ETH_API_PCAP)) {
/* compile filter string */
if ((status = pcap_compile((pcap_t*)(*handle), &bpf, bpf_filter, 1, bpf_netmask)) < 0) {
sprintf(errbuf, "%s", pcap_geterr((pcap_t*)(*handle)));
sim_printf("Eth: pcap_compile error: %s\r\n", errbuf);
sim_printf("Eth: pcap_compile error: %s\n", errbuf);
/* show erroneous BPF string */
sim_printf ("Eth: BPF string is: |%s|\r\n", bpf_filter);
sim_printf ("Eth: BPF string is: |%s|\n", bpf_filter);
}
else {
/* apply compiled filter string */
if ((status = pcap_setfilter((pcap_t*)(*handle), &bpf)) < 0) {
sprintf(errbuf, "%s", pcap_geterr((pcap_t*)(*handle)));
sim_printf("Eth: pcap_setfilter error: %s\r\n", errbuf);
sim_printf("Eth: pcap_setfilter error: %s\n", errbuf);
}
else {
#ifdef USE_SETNONBLOCK
@ -2279,16 +2283,14 @@ strncpy (namebuf, savname, sizeof(namebuf)-1);
savname = namebuf;
r = _eth_open_port(namebuf, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, NULL, (void *)dev, dptr, dbit);
if (errbuf[0]) {
sim_printf ("Eth: open error - %s\r\n", errbuf);
return SCPE_OPENERR | SCPE_NOMESSAGE;
}
if (errbuf[0])
return sim_messagef (SCPE_OPENERR, "Eth: open error - %s\n", errbuf);
if (r != SCPE_OK)
return r;
if (!strcmp (desc, "No description available"))
strcpy (desc, "");
sim_printf ("Eth: opened OS device %s%s%s\r\n", savname, desc[0] ? " - " : "", desc);
sim_printf ("Eth: opened OS device %s%s%s\n", savname, desc[0] ? " - " : "", desc);
/* get the NIC's hardware MAC address */
eth_get_nic_hw_addr(dev, savname);
@ -2399,7 +2401,7 @@ ethq_destroy (&dev->read_queue); /* release FIFO queue */
#endif
_eth_close_port (dev->eth_api, pcap, pcap_fd);
sim_printf ("Eth: closed %s\r\n", dev->name);
sim_printf ("Eth: closed %s\n", dev->name);
/* clean up the mess */
free(dev->name);
@ -2419,8 +2421,8 @@ fprintf (st, " eth0 en0 (No description av
#if defined(HAVE_TAP_NETWORK)
fprintf (st, " eth1 tap:tapN (Integrated Tun/Tap support)\n");
#endif
#if defined(HAVE_SLIRP_NETWORK)
fprintf (st, " eth2 vde:device (Integrated VDE support)\n");
#if defined(HAVE_VDE_NETWORK)
fprintf (st, " eth2 vde:device{:switch-port-number} (Integrated VDE support)\n");
#endif
#if defined(HAVE_SLIRP_NETWORK)
fprintf (st, " eth3 nat:{optional-nat-parameters} (Integrated NAT (SLiRP) support)\n");
@ -2541,11 +2543,11 @@ status = _eth_write (dev, &send, NULL);
if (status != SCPE_OK) {
const char *msg;
msg = (dev->eth_api == ETH_API_PCAP) ?
"Eth: Error Transmitting packet: %s\r\n"
"You may need to run as root, or install a libpcap version\r\n"
"which is at least 0.9 from your OS vendor or www.tcpdump.org\r\n" :
"Eth: Error Transmitting packet: %s\r\n"
"You may need to run as root.\r\n";
"Eth: Error Transmitting packet: %s\n"
"You may need to run as root, or install a libpcap version\n"
"which is at least 0.9 from your OS vendor or www.tcpdump.org\n" :
"Eth: Error Transmitting packet: %s\n"
"You may need to run as root.\n";
sim_printf(msg, strerror(errno));
return status;
}
@ -3767,15 +3769,15 @@ if (dev->eth_api == ETH_API_PCAP) {
/* compile filter string */
if ((status = pcap_compile((pcap_t*)dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) {
sprintf(errbuf, "%s", pcap_geterr((pcap_t*)dev->handle));
sim_printf("Eth: pcap_compile error: %s\r\n", errbuf);
sim_printf("Eth: pcap_compile error: %s\n", errbuf);
/* show erroneous BPF string */
sim_printf ("Eth: BPF string is: |%s|\r\n", buf);
sim_printf ("Eth: BPF string is: |%s|\n", buf);
}
else {
/* apply compiled filter string */
if ((status = pcap_setfilter((pcap_t*)dev->handle, &bpf)) < 0) {
sprintf(errbuf, "%s", pcap_geterr((pcap_t*)dev->handle));
sim_printf("Eth: pcap_setfilter error: %s\r\n", errbuf);
sim_printf("Eth: pcap_setfilter error: %s\n", errbuf);
}
else {
/* Save BPF filter string */
@ -3896,7 +3898,7 @@ if (used < max) {
#endif
#ifdef HAVE_VDE_NETWORK
if (used < max) {
sprintf(list[used].name, "%s", "vde:device");
sprintf(list[used].name, "%s", "vde:device{:switch-port-number}");
sprintf(list[used].desc, "%s", "Integrated VDE support");
list[used].eth_api = ETH_API_VDE;
++used;
@ -3933,7 +3935,7 @@ memset(list, 0, max*sizeof(*list));
errbuf[0] = '\0';
/* retrieve the device list */
if (pcap_findalldevs(&alldevs, errbuf) == -1) {
sim_printf ("Eth: error in pcap_findalldevs: %s\r\n", errbuf);
sim_printf ("Eth: error in pcap_findalldevs: %s\n", errbuf);
}
else {
/* copy device list into the passed structure */
@ -3956,7 +3958,7 @@ i = eth_host_devices(i, max, list);
/* If no devices were found and an error message was left in the buffer, display it */
if ((i == 0) && (errbuf[0])) {
sim_printf ("Eth: pcap_findalldevs warning: %s\r\n", errbuf);
sim_printf ("Eth: pcap_findalldevs warning: %s\n", errbuf);
}
/* return device count */

View File

@ -63,6 +63,7 @@ extern "C" {
#if defined(_WIN32)
#include <process.h>
#include <windows.h>
#include <winerror.h>
#define sleep(n) Sleep(n*1000)
#define msleep(n) Sleep(n)
#define strtoull _strtoui64
@ -153,9 +154,9 @@ struct PANEL {
pthread_mutex_t io_send_lock;
pthread_mutex_t io_command_lock;
int command_count;
int io_reg_query_pending;
int io_waiting;
char *io_response;
char *halt_reason;
size_t io_response_data;
size_t io_response_size;
const char *completion_string;
@ -177,6 +178,7 @@ struct PANEL {
FILE *Debug;
#if defined(_WIN32)
HANDLE hProcess;
DWORD dwProcessId;
#else
pid_t pidProcess;
#endif
@ -221,7 +223,7 @@ static const char *register_collect_mid3 = " percent ";
static const char *register_get_postfix = "sampleout";
static const char *register_get_start = "# REGISTERS-START";
static const char *register_get_end = "# REGISTERS-DONE";
static const char *register_repeat_start = "# REGISTERS-REPEAT-START\r";
static const char *register_repeat_start = "# REGISTERS-REPEAT-START";
static const char *register_repeat_end = "# REGISTERS-REPEAT-DONE";
static const char *register_dev_echo = "# REGISTERS-FOR-DEVICE:";
static const char *register_ind_echo = "# REGISTER-INDIRECT:";
@ -408,9 +410,9 @@ pthread_mutex_lock (&p->io_lock);
while (p->sock != INVALID_SOCKET) {
pthread_mutex_unlock (&p->io_lock);
msleep (1000);
pthread_mutex_lock (&p->io_lock);
if (0 == (sleeps++)%flush_interval)
sim_panel_flush_debug (p);
pthread_mutex_lock (&p->io_lock);
}
pthread_mutex_unlock (&p->io_lock);
pthread_mutex_lock (&p->io_lock);
@ -484,7 +486,7 @@ size_t i, j, buf_data, buf_needed = 0, reg_count = 0, bit_reg_count = 0;
const char *dev;
pthread_mutex_lock (&panel->io_lock);
buf_needed = 3 +
buf_needed = 3 + 7 + /* EXECUTE */
strlen (register_get_start) + /* # REGISTERS-START */
strlen (register_get_prefix); /* SHOW TIME */
for (i=0; i<panel->reg_count; i++) {
@ -492,7 +494,7 @@ for (i=0; i<panel->reg_count; i++) {
++bit_reg_count;
else {
++reg_count;
buf_needed += 9 + strlen (panel->regs[i].name) + (panel->regs[i].device_name ? strlen (panel->regs[i].device_name) : 0);
buf_needed += 10 + strlen (panel->regs[i].name) + (panel->regs[i].device_name ? strlen (panel->regs[i].device_name) : 0);
if (panel->regs[i].element_count > 0)
buf_needed += 4 + 6 /* 6 digit register array index */;
if (panel->regs[i].indirect)
@ -514,7 +516,7 @@ if (buf_needed > *buf_size) {
}
buf_data = 0;
if (reg_count) {
sprintf (*buf + buf_data, "%s\r%s\r", register_get_start, register_get_prefix);
sprintf (*buf + buf_data, "EXECUTE %s;%s;", register_get_start, register_get_prefix);
buf_data += strlen (*buf + buf_data);
}
dev = "";
@ -536,7 +538,7 @@ for (i=j=0; i<panel->reg_count; i++) {
strcpy (tbuf, *buf);
free (*buf);
*buf = tbuf;
sprintf (*buf + buf_data, "%s%s%s\r", (i == 0)? "" : "\r", register_dev_echo, reg_dev);
sprintf (*buf + buf_data, "%s%s%s;", (i == 0)? "" : ";", register_dev_echo, reg_dev);
buf_data += strlen (*buf + buf_data);
dev = reg_dev;
j = 0;
@ -544,21 +546,21 @@ for (i=j=0; i<panel->reg_count; i++) {
}
if (panel->regs[i].element_count == 0) {
if (j == 0)
sprintf (*buf + buf_data, "E -H %s %s", dev, panel->regs[i].name);
sprintf (*buf + buf_data, "E -16 %s %s", dev, panel->regs[i].name);
else
sprintf (*buf + buf_data, ",%s", panel->regs[i].name);
}
else {
if (j == 0)
sprintf (*buf + buf_data, "E -H %s %s[0:%d]", dev, panel->regs[i].name, (int)(panel->regs[i].element_count-1));
sprintf (*buf + buf_data, "E -16 %s %s[0:%d]", dev, panel->regs[i].name, (int)(panel->regs[i].element_count-1));
else
sprintf (*buf + buf_data, ",%s[0:%d]", panel->regs[i].name, (int)(panel->regs[i].element_count-1));
}
++j;
buf_data += strlen (*buf + buf_data);
}
if (buf_data && ((*buf)[buf_data-1] != '\r')) {
strcpy (*buf + buf_data, "\r");
if (buf_data && ((*buf)[buf_data-1] != ';')) {
strcpy (*buf + buf_data, ";");
buf_data += strlen (*buf + buf_data);
}
for (i=j=0; i<panel->reg_count; i++) {
@ -566,13 +568,13 @@ for (i=j=0; i<panel->reg_count; i++) {
if ((!panel->regs[i].indirect) || (panel->regs[i].bits))
continue;
sprintf (*buf + buf_data, "%s%s\rE -H %s %s,$\r", register_ind_echo, panel->regs[i].name, reg_dev, panel->regs[i].name);
sprintf (*buf + buf_data, "%s%s;E -16 %s %s,$;", register_ind_echo, panel->regs[i].name, reg_dev, panel->regs[i].name);
buf_data += strlen (*buf + buf_data);
}
if (bit_reg_count) {
strcpy (*buf + buf_data, register_get_postfix);
buf_data += strlen (*buf + buf_data);
strcpy (*buf + buf_data, "\r");
strcpy (*buf + buf_data, ";");
buf_data += strlen (*buf + buf_data);
}
strcpy (*buf + buf_data, register_get_end);
@ -855,6 +857,7 @@ if (!simulator_panel) {
if (CreateProcessA(NULL, cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &StartupInfo, &ProcessInfo)) {
CloseHandle (ProcessInfo.hThread);
p->hProcess = ProcessInfo.hProcess;
p->dwProcessId = ProcessInfo.dwProcessId;
}
else { /* Creation Problem */
sim_panel_set_error (NULL, "CreateProcess Error: %d", GetLastError());
@ -1074,6 +1077,8 @@ if (panel) {
pthread_cond_destroy (&panel->io_done);
#if defined(_WIN32)
if (panel->hProcess) {
GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, panel->dwProcessId);
msleep (200);
TerminateProcess (panel->hProcess, 0);
WaitForSingleObject (panel->hProcess, INFINITE);
CloseHandle (panel->hProcess);
@ -1106,6 +1111,7 @@ if (panel) {
free (panel->regs);
free (panel->reg_query);
free (panel->io_response);
free (panel->halt_reason);
free (panel->simulator_version);
if ((panel->Debug) && (!panel->parent))
fclose (panel->Debug);
@ -1353,12 +1359,9 @@ if (panel->reg_query_size != _panel_send (panel, panel->reg_query, panel->reg_qu
pthread_mutex_unlock (&panel->io_command_lock);
return -1;
}
while (panel->io_reg_query_pending != 0) {
pthread_mutex_unlock (&panel->io_lock);
msleep (100);
pthread_mutex_lock (&panel->io_lock);
}
++panel->io_reg_query_pending;
if (panel->io_response_data)
_panel_debug (panel, DBG_RCV, "Receive Data Discarded: ", panel->io_response, panel->io_response_data);
panel->io_response_data = 0;
panel->io_waiting = 1;
while (panel->io_waiting)
pthread_cond_wait (&panel->io_done, &panel->io_lock);
@ -1372,7 +1375,7 @@ return 0;
int
sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time)
{
return _panel_get_registers (panel, 0, simulation_time);
return _panel_get_registers (panel, (panel->State == Halt), simulation_time);
}
int
@ -1472,6 +1475,15 @@ if (panel->State == Run) {
return 0;
}
const char *
sim_panel_halt_text (PANEL *panel)
{
if (!panel || !panel->halt_reason)
return "";
return panel->halt_reason;
}
int
sim_panel_exec_boot (PANEL *panel, const char *device)
{
@ -1538,7 +1550,7 @@ if ((simtime = strstr (response, "Time:"))) {
}
free (response);
panel->simulation_time_base += panel->simulation_time;
if (_panel_sendf_completion (panel, NULL, "Simulator Running...", "RUN -Q\r", 5)) {
if (_panel_sendf_completion (panel, NULL, "Simulator Running...", "RUN\r", 5)) {
_panel_debug (panel, DBG_THR, "Unable to start simulator: %s", NULL, 0, sim_panel_get_error());
return -1;
}
@ -1768,6 +1780,41 @@ free (response);
return 0;
}
int
sim_panel_device_debug_mode (PANEL *panel,
const char *device,
int set_unset,
const char *mode_bits)
{
char *response = NULL;
int cmd_stat;
if (!panel || (panel->State == Error)) {
sim_panel_set_error (NULL, "Invalid Panel");
return -1;
}
if ((device != NULL) &&
((_panel_sendf (panel, &cmd_stat, &response, "SHOW %s", device) ||
(cmd_stat)))) {
sim_panel_set_error (NULL, "Can't %s Debug Mode: '%s' on Device '%s': %s",
set_unset ? "Enable" : "Disable", mode_bits ? mode_bits : "", device, response);
free (response);
return -1;
}
free (response);
response = NULL;
if (_panel_sendf (panel, &cmd_stat, &response, "%sDEBUG %s %s",
set_unset ? "" : "NO", device ? device : "", mode_bits ? mode_bits : "") ||
(cmd_stat)) {
sim_panel_set_error (NULL, "Can't %s Debug Mode: '%s' on Device '%s': %s",
set_unset ? "Enable" : "Disable", mode_bits ? mode_bits : "", device, response);
free (response);
return -1;
}
free (response);
return 0;
}
/**
sim_panel_gen_deposit
@ -2069,7 +2116,7 @@ struct sched_param sched_priority;
char buf[4096];
int buf_data = 0;
int processing_register_output = 0;
int io_wait_done;
int io_wait_done = 0;
/*
Boost Priority for this response processing thread to quickly digest
@ -2119,18 +2166,20 @@ while ((p->sock != INVALID_SOCKET) &&
int new_data;
char *s, *e, *eol;
pthread_mutex_unlock (&p->io_lock);
new_data = sim_read_sock (p->sock, &buf[buf_data], sizeof(buf)-(buf_data+1));
pthread_mutex_lock (&p->io_lock);
if (new_data <= 0) {
sim_panel_set_error (NULL, "%s", sim_get_err_sock("Unexpected socket read"));
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
p->State = Error;
break;
if (NULL == strchr (buf, '\n')) {
pthread_mutex_unlock (&p->io_lock);
new_data = sim_read_sock (p->sock, &buf[buf_data], sizeof(buf)-(buf_data+1));
pthread_mutex_lock (&p->io_lock);
if (new_data <= 0) {
sim_panel_set_error (NULL, "%s", sim_get_err_sock("Unexpected socket read"));
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
p->State = Error;
break;
}
_panel_debug (p, DBG_RCV, "Received %d bytes: ", &buf[buf_data], new_data, new_data);
buf_data += new_data;
buf[buf_data] = '\0';
}
_panel_debug (p, DBG_RCV, "Received %d bytes: ", &buf[buf_data], new_data, new_data);
buf_data += new_data;
buf[buf_data] = '\0';
s = buf;
while ((eol = strchr (s, '\n'))) {
/* Line to process */
@ -2258,72 +2307,72 @@ while ((p->sock != INVALID_SOCKET) &&
/* Unexpected Register Data Found (or other output containing a : character) */
}
}
if (!strcmp (s + strlen (sim_prompt), register_repeat_end)) {
_panel_debug (p, DBG_RCV, "*Repeat Block Complete", NULL, 0);
if ((strlen (s) > strlen (sim_prompt)) && (!strcmp (s + strlen (sim_prompt), register_repeat_end))) {
_panel_debug (p, DBG_RCV, "*Repeat Block Complete (Accumulated Data = %d)", NULL, 0, (int)p->io_response_data);
if (p->callback) {
pthread_mutex_unlock (&p->io_lock);
p->callback (p, p->simulation_time_base + p->simulation_time, p->callback_context);
pthread_mutex_lock (&p->io_lock);
}
processing_register_output = 0;
p->io_response_data = 0;
p->io_response[p->io_response_data] = '\0';
goto Start_Next_Line;
}
if ((!strcmp (s + strlen (sim_prompt), register_repeat_start)) ||
(!strcmp (s + strlen (sim_prompt), register_get_start))) {
if ((strlen (s) > strlen (sim_prompt)) &&
((!strcmp (s + strlen (sim_prompt), register_repeat_start)) ||
(!strcmp (s + strlen (sim_prompt), register_get_start)))) {
_panel_debug (p, DBG_RCV, "*Repeat/Register Block Starting", NULL, 0);
processing_register_output = 1;
goto Start_Next_Line;
}
if (!strcmp (s + strlen (sim_prompt), register_get_end)) {
if ((strlen (s) > strlen (sim_prompt)) &&
(!strcmp (s + strlen (sim_prompt), register_get_end))) {
_panel_debug (p, DBG_RCV, "*Register Block Complete", NULL, 0);
--p->io_reg_query_pending;
p->io_waiting = 0;
processing_register_output = 0;
pthread_cond_signal (&p->io_done);
goto Start_Next_Line;
}
if (!strcmp (s + strlen (sim_prompt), command_done_echo)) {
if ((strlen (s) > strlen (sim_prompt)) && (!strcmp (s + strlen (sim_prompt), command_done_echo))) {
_panel_debug (p, DBG_RCV, "*Received Command Complete", NULL, 0);
p->io_waiting = 0;
pthread_cond_signal (&p->io_done);
goto Start_Next_Line;
}
/* Non Register Data Found (echo of EXAMINE or other commands and/or command output) */
if (p->io_waiting) {
char *t;
if (p->io_response_data + strlen (s) + 3 > p->io_response_size) {
char *t = (char *)_panel_malloc (p->io_response_data + strlen (s) + 3);
if (p->io_response_data + strlen (s) + 3 > p->io_response_size) {
t = (char *)_panel_malloc (p->io_response_data + strlen (s) + 3);
if (t == NULL) {
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
p->State = Error;
break;
}
memcpy (t, p->io_response, p->io_response_data);
free (p->io_response);
p->io_response = t;
p->io_response_size = p->io_response_data + strlen (s) + 3;
}
_panel_debug (p, DBG_RCV, "Receive Data Accumulated: '%s'", NULL, 0, s);
strcpy (p->io_response + p->io_response_data, s);
p->io_response_data += strlen(s);
strcpy (p->io_response + p->io_response_data, "\r\n");
p->io_response_data += 2;
if ((!p->parent) &&
(p->completion_string) &&
(!memcmp (s, p->completion_string, strlen (p->completion_string)))) {
_panel_debug (p, DBG_RCV, "Match with potentially coalesced additional data: '%s'", NULL, 0, p->completion_string);
if (t == NULL) {
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
p->State = Error;
break;
}
memcpy (t, p->io_response, p->io_response_data);
free (p->io_response);
p->io_response = t;
p->io_response_size = p->io_response_data + strlen (s) + 3;
}
_panel_debug (p, DBG_RCV, "Receive Data Accumulated: '%s'", NULL, 0, s);
strcpy (p->io_response + p->io_response_data, s);
p->io_response_data += strlen(s);
strcpy (p->io_response + p->io_response_data, "\r\n");
p->io_response_data += 2;
if ((!p->parent) &&
(p->completion_string) &&
(!memcmp (s, p->completion_string, strlen (p->completion_string)))) {
_panel_debug (p, DBG_RCV, "Match with potentially coalesced additional data: '%s'", NULL, 0, p->completion_string);
if (eol < &buf[buf_data])
memset (s + strlen (s), ' ', eol - (s + strlen (s)));
break;
}
else
_panel_debug (p, DBG_RCV, "Receive Data Discarded: '%s'", NULL, 0, s);
Start_Next_Line:
s = eol;
while (isspace(0xFF & (*s)))
++s;
}
memmove (buf, s, strlen (s) + 1);
memmove (buf, s, buf_data - (s - buf) + 1);
buf_data = strlen (buf);
if (buf_data)
_panel_debug (p, DBG_RSP, "Remnant Buffer Contents: '%s'", NULL, 0, buf);
@ -2337,28 +2386,36 @@ Start_Next_Line:
_panel_debug (p, DBG_RSP, "State transitioning to Run", NULL, 0);
p->State = Run;
buf_data -= 20;
buf[buf_data] = '\0';
if (buf_data) {
memmove (buf, buf + 20, strlen (buf + 20) + 1);
buf_data = strlen (buf);
memmove (buf, buf + 20, buf_data + 1);
_panel_debug (p, DBG_RSP, "Remnant Buffer Contents: '%s'", NULL, 0, buf);
if (io_wait_done) { /* someone waiting for this? */
_panel_debug (p, DBG_RCV, "*Match Command Complete - Match signaling waiting thread", NULL, 0);
io_wait_done = 0;
p->io_waiting = 0;
p->completion_string = NULL;
pthread_cond_signal (&p->io_done);
/* Let this state transition propagate to the interested thread(s) */
/* before processing remaining buffered data */
pthread_mutex_unlock (&p->io_lock);
msleep (100);
pthread_mutex_lock (&p->io_lock);
}
}
else
buf[buf_data] = '\0';
if (io_wait_done) { /* someone waiting for this? */
_panel_debug (p, DBG_RCV, "*Match Command Complete - Match signaling waiting thread", NULL, 0);
io_wait_done = 0;
p->io_waiting = 0;
p->completion_string = NULL;
pthread_cond_signal (&p->io_done);
/* Let this state transition propagate to the interested thread(s) */
/* before processing remaining buffered data */
pthread_mutex_unlock (&p->io_lock);
msleep (100);
pthread_mutex_lock (&p->io_lock);
}
}
if ((p->State == Run) && (!strcmp (buf, sim_prompt))) {
_panel_debug (p, DBG_RSP, "State transitioning to Halt", NULL, 0);
_panel_debug (p, DBG_RSP, "State transitioning to Halt: io_wait_done: %d", NULL, 0, io_wait_done);
p->State = Halt;
free (p->halt_reason);
p->halt_reason = (char *)_panel_malloc (1 + strlen (p->io_response));
if (p->halt_reason == NULL) {
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
p->State = Error;
break;
}
strcpy (p->halt_reason, p->io_response);
}
if (io_wait_done) {
_panel_debug (p, DBG_RCV, "*Match Command Complete - Match signaling waiting thread", NULL, 0);
@ -2426,43 +2483,40 @@ while ((p->sock != INVALID_SOCKET) &&
msleep (500);
pthread_mutex_lock (&p->io_lock);
if (new_register) {
if (p->io_reg_query_pending == 0) {
size_t repeat_data = strlen (register_repeat_prefix) + /* prefix */
20 + /* max int width */
strlen (register_repeat_units) + /* units and spacing */
buf_data + /* command contents */
1 + /* carriage return */
strlen (register_repeat_start) + /* auto repeat begin */
1 + /* carriage return */
strlen (register_repeat_end) + /* auto repeat completion */
1 + /* carriage return */
1; /* NUL */
char *repeat = (char *)malloc (repeat_data);
char *c;
size_t repeat_data = strlen (register_repeat_prefix) + /* prefix */
20 + /* max int width */
strlen (register_repeat_units) + /* units and spacing */
buf_data + /* command contents */
1 + /* ; */
strlen (register_repeat_start) + /* auto repeat begin */
1 + /* ; */
strlen (register_repeat_end) + /* auto repeat completion */
1 + /* carriage return */
1; /* NUL */
char *repeat = (char *)malloc (repeat_data);
char *c;
sprintf (repeat, "%s%d%s%s%*.*s", register_repeat_prefix,
p->usecs_between_callbacks,
register_repeat_units,
register_repeat_start,
(int)buf_data, (int)buf_data, buf);
pthread_mutex_unlock (&p->io_lock);
for (c = strchr (repeat, '\r'); c != NULL; c = strchr (c, '\r'))
*c = ';'; /* replace carriage returns with semicolons */
c = strstr (repeat, register_get_end); /* remove register_done_echo string and */
if (c) /* always true */
strcpy (c, register_repeat_end); /* replace it with the register_repeat_end string */
if (_panel_sendf (p, &cmd_stat, NULL, "%s", repeat)) {
pthread_mutex_lock (&p->io_lock);
free (repeat);
break;
}
c = strstr (buf, register_get_start); /* remove register_get_start string and anything before it */
if (c) { /* always true */
buf_data -= (c - buf) + strlen (register_get_start);
c += strlen (register_get_start);
}
sprintf (repeat, "%s%d%s%s%*.*s", register_repeat_prefix,
p->usecs_between_callbacks,
register_repeat_units,
register_repeat_start,
(int)buf_data, (int)buf_data, c);
pthread_mutex_unlock (&p->io_lock);
c = strstr (repeat, register_get_end); /* remove register_done_echo string and */
if (c) /* always true */
strcpy (c, register_repeat_end); /* replace it with the register_repeat_end string */
if (_panel_sendf (p, &cmd_stat, NULL, "%s", repeat)) {
pthread_mutex_lock (&p->io_lock);
free (repeat);
break;
}
else { /* already busy */
p->new_register = 1; /* retry later */
_panel_debug (p, DBG_XMT, "Waiting on prior command completion before specifying repeat interval", NULL, 0);
}
pthread_mutex_lock (&p->io_lock);
free (repeat);
}
/* when halted, we directly poll the halted system to get updated */
/* register state which may have changed due to panel activities */
@ -2545,7 +2599,7 @@ while (1) { /* format passed string, arg
if (len >= (int)(sim_panel_error_bufsize-1)) {
free (sim_panel_error_buf);
sim_panel_error_bufsize = sim_panel_error_bufsize * 2;
while ((int)sim_panel_error_bufsize < len + 1)
while ((int)sim_panel_error_bufsize < len + 2)
sim_panel_error_bufsize = sim_panel_error_bufsize * 2;
sim_panel_error_buf = (char *) malloc (sim_panel_error_bufsize);
if (sim_panel_error_buf == NULL) {
@ -2610,6 +2664,8 @@ if (completion_status || completion_string) {
}
pthread_mutex_lock (&p->io_lock);
p->completion_string = completion_string;
if (p->io_response_data)
_panel_debug (p, DBG_RCV, "Receive Data Discarded: ", p->io_response, p->io_response_data);
p->io_response_data = 0;
p->io_waiting = 1;
}

View File

@ -56,7 +56,7 @@ extern "C" {
#if !defined(__VAX) /* Unsupported platform */
#define SIM_FRONTPANEL_VERSION 11
#define SIM_FRONTPANEL_VERSION 12
/**
@ -284,6 +284,19 @@ sim_panel_exec_run (PANEL *panel);
int
sim_panel_exec_step (PANEL *panel);
/**
A simulator often displays some useful information as it stops
executing instructions.
sim_panel_halt_text - Returns the simulator output immediately prior
to the most recent transition to the Halt state.
*/
const char *
sim_panel_halt_text (PANEL *panel);
/**
When a front panel application wants to describe conditions that
@ -472,6 +485,34 @@ sim_panel_get_history (PANEL *panel,
char *buffer);
/**
A front panel application might want some details of simulator
and/or device behavior that is provided by a particular simulator
via debug information. Debugging for particular device(s)
and/or simulator debug settings can be controlled via the
sim_panel_device_debug_mode API.
*/
/**
sim_panel_device_debug_mode
device the device whose debug mode is to change
set_untset 1 to set debug flags, 0 to clear debug flags
mode_bits character string with different debug mode bits
to enable or disable. An empty string will
enable or disable all mode bits for the specified
device
*/
int
sim_panel_device_debug_mode (PANEL *panel,
const char *device,
int set_unset,
const char *mode_bits);
/**
When a front panel application needs to change the media

View File

@ -52,6 +52,7 @@ extern "C" {
#if defined (_WIN32) /* Windows */
#include <winsock2.h>
#include <winerror.h>
#elif !defined (__OS2__) || defined (__EMX__) /* VMS, Mac, Unix, OS/2 EMX */
#include <sys/types.h> /* for fcntl, getpid */

View File

@ -167,8 +167,10 @@ static uint32 sim_throt_ms_start = 0;
static uint32 sim_throt_ms_stop = 0;
static uint32 sim_throt_type = 0;
static uint32 sim_throt_val = 0;
static uint32 sim_throt_drift_pct = SIM_THROT_DRIFT_PCT_DFLT;
static uint32 sim_throt_state = SIM_THROT_STATE_INIT;
static double sim_throt_cps;
static double sim_throt_peak_cps;
static double sim_throt_inst_start;
static uint32 sim_throt_sleep_time = 0;
static int32 sim_throt_wait = 0;
@ -910,7 +912,7 @@ if (!rtc_avail) /* no timer? */
return rtc_currd[tmr];
if (sim_calb_tmr != tmr) {
rtc_currd[tmr] = (int32)(sim_timer_inst_per_sec()/ticksper);
sim_debug (DBG_CAL, &sim_timer_dev, "calibrated calibrated tmr=%d against internal system tmr=%d, tickper=%d (result: %d)\n", tmr, sim_calb_tmr, ticksper, rtc_currd[tmr]);
sim_debug (DBG_CAL, &sim_timer_dev, "calibrated tmr=%d against internal system tmr=%d, tickper=%d (result: %d)\n", tmr, sim_calb_tmr, ticksper, rtc_currd[tmr]);
return rtc_currd[tmr];
}
new_rtime = sim_os_msec (); /* wall time */
@ -1076,7 +1078,7 @@ fprintf (st, "Minimum Host Sleep Time: %d ms (%dHz)\n", sim_os_sleep_min_m
if (sim_os_sleep_min_ms != sim_os_sleep_inc_ms)
fprintf (st, "Minimum Host Sleep Incr Time: %d ms\n", sim_os_sleep_inc_ms);
fprintf (st, "Host Clock Resolution: %d ms\n", sim_os_clock_resoluton_ms);
fprintf (st, "Execution Rate: %s instructions/sec\n", sim_fmt_numeric (inst_per_sec));
fprintf (st, "Execution Rate: %s cycles/sec\n", sim_fmt_numeric (inst_per_sec));
if (sim_idle_enab) {
fprintf (st, "Idling: Enabled\n");
fprintf (st, "Time before Idling starts: %d seconds\n", sim_idle_stable);
@ -1260,6 +1262,8 @@ REG sim_throttle_reg[] = {
{ DRDATAD (THROT_STATE, sim_throt_state, 32, ""), PV_RSPC|REG_RO},
{ DRDATAD (THROT_SLEEP_TIME, sim_throt_sleep_time, 32, ""), PV_RSPC|REG_RO},
{ DRDATAD (THROT_WAIT, sim_throt_wait, 32, ""), PV_RSPC|REG_RO},
{ DRDATAD (THROT_DELAY, sim_idle_stable, 32, "Seconds before throttling starts"), PV_RSPC},
{ DRDATAD (THROT_DRIFT_PCT, sim_throt_drift_pct, 32, "Percent of throttle drift before correction"), PV_RSPC},
{ NULL }
};
@ -1671,9 +1675,12 @@ else {
break;
case SIM_THROT_PCT:
fprintf (st, "Throttle: %d%%\n", sim_throt_val);
if (sim_throt_wait)
if (sim_throt_wait) {
fprintf (st, "Throttle: %d%% of %s cycles per second\n", sim_throt_val, sim_fmt_numeric (sim_throt_peak_cps));
fprintf (st, "Throttling by sleeping for: %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait);
}
else
fprintf (st, "Throttle: %d%%\n", sim_throt_val);
break;
case SIM_THROT_SPC:
@ -1695,9 +1702,20 @@ return SCPE_OK;
void sim_throt_sched (void)
{
sim_throt_state = SIM_THROT_STATE_INIT;
if (sim_throt_type)
sim_activate (&sim_throttle_unit, SIM_THROT_WINIT);
if (sim_throt_type != SIM_THROT_NONE) {
if (sim_throt_state == SIM_THROT_STATE_THROTTLE) { /* Previously calibrated? */
/* Reset recalibration reference times */
sim_throt_ms_start = sim_os_msec ();
sim_throt_inst_start = sim_gtime ();
/* Start with prior calibrated delay */
sim_activate (&sim_throttle_unit, sim_throt_wait);
}
else {
/* Start calibration initially */
sim_throt_state = SIM_THROT_STATE_INIT;
sim_activate (&sim_throttle_unit, SIM_THROT_WINIT);
}
}
}
void sim_throt_cancel (void)
@ -1718,16 +1736,41 @@ t_stat sim_throt_svc (UNIT *uptr)
{
int32 tmr;
uint32 delta_ms;
double a_cps, d_cps;
double a_cps, d_cps, delta_inst;
switch (sim_throt_state) {
case SIM_THROT_STATE_INIT: /* take initial reading */
if ((sim_calb_tmr != -1) && (rtc_hz[sim_calb_tmr] != 0)) {
if (rtc_calibrations[sim_calb_tmr] < sim_idle_stable) {
sim_throt_ms_start = sim_os_msec ();
sim_throt_inst_start = sim_gtime ();
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc(INIT) Deferring until stable (%d more seconds)\n", (int)(sim_idle_stable - rtc_calibrations[sim_calb_tmr]));
return sim_activate (uptr, rtc_hz[sim_calb_tmr]*rtc_currd[sim_calb_tmr]);
}
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc(INIT) Computing Throttling values based on the last second's execution rate\n");
sim_throt_state = SIM_THROT_STATE_TIME;
if (sim_throt_peak_cps < (double)(rtc_hz[sim_calb_tmr] * rtc_currd[sim_calb_tmr]))
sim_throt_peak_cps = (double)rtc_hz[sim_calb_tmr] * rtc_currd[sim_calb_tmr];
return sim_throt_svc (uptr);
}
else
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc(INIT) Calibrated timer not available. Falling back to legacy method\n");
sim_idle_ms_sleep (sim_idle_rate_ms); /* start on a tick boundary to calibrate */
sim_throt_ms_start = sim_os_msec ();
sim_throt_inst_start = sim_gtime();
sim_throt_inst_start = sim_gtime ();
if (sim_throt_type != SIM_THROT_SPC) { /* dynamic? */
sim_throt_wait = SIM_THROT_WST;
switch (sim_throt_type) {
case SIM_THROT_PCT:
sim_throt_wait = (int32)((sim_throt_peak_cps * sim_throt_val) / 100.0);
break;
case SIM_THROT_KCYC:
sim_throt_wait = sim_throt_val * 1000;
break;
case SIM_THROT_MCYC:
sim_throt_wait = sim_throt_val * 1000000;
break;
}
sim_throt_state = SIM_THROT_STATE_TIME; /* next state */
}
else { /* Non dynamic? */
@ -1741,34 +1784,43 @@ switch (sim_throt_state) {
case SIM_THROT_STATE_TIME: /* take final reading */
sim_throt_ms_stop = sim_os_msec ();
delta_ms = sim_throt_ms_stop - sim_throt_ms_start;
delta_inst = sim_gtime () - sim_throt_inst_start;
if (delta_ms < SIM_THROT_MSMIN) { /* not enough time? */
if (sim_throt_wait >= 100000000) { /* too many inst? */
if (delta_inst >= 100000000.0) { /* too many inst? */
sim_throt_state = SIM_THROT_STATE_INIT; /* fails in 32b! */
sim_printf ("Can't throttle. Host CPU is too fast with a minimum sleep time of %d ms\n", sim_idle_rate_ms);
sim_set_throt (0, NULL); /* disable throttling */
return SCPE_OK;
}
sim_idle_ms_sleep (sim_idle_rate_ms); /* start on a tick boundart to calibrate */
sim_throt_wait = sim_throt_wait * SIM_THROT_WMUL;
sim_throt_ms_start = sim_os_msec ();
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Not enough time. %d ms executing %.f instructions.\n",
(int)delta_ms, delta_inst);
sim_throt_wait = (int32)(delta_inst * SIM_THROT_WMUL);
sim_throt_inst_start = sim_gtime();
sim_idle_ms_sleep (sim_idle_rate_ms); /* start on a tick boundart to calibrate */
sim_throt_ms_start = sim_os_msec ();
}
else { /* long enough */
a_cps = ((double) sim_throt_wait) * 1000.0 / (double) delta_ms;
a_cps = (((double) delta_inst) * 1000.0) / (double) delta_ms;
if (sim_throt_type == SIM_THROT_MCYC) /* calc desired cps */
d_cps = (double) sim_throt_val * 1000000.0;
else if (sim_throt_type == SIM_THROT_KCYC)
d_cps = (double) sim_throt_val * 1000.0;
else d_cps = (a_cps * ((double) sim_throt_val)) / 100.0;
if (d_cps >= a_cps) {
else
if (sim_throt_type == SIM_THROT_KCYC)
d_cps = (double) sim_throt_val * 1000.0;
else
d_cps = (sim_throt_peak_cps * sim_throt_val) / 100.0;
if (d_cps > a_cps) {
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() CPU too slow. Values a_cps = %f, d_cps = %f\n",
a_cps, d_cps);
sim_throt_state = SIM_THROT_STATE_INIT;
sim_printf ("*********** WARNING ***********\n");
sim_printf ("Host CPU is too slow to simulate %s instructions per second\n", sim_fmt_numeric(d_cps));
sim_printf ("Host CPU can only simulate %s instructions per second\n", sim_fmt_numeric(sim_throt_peak_cps));
sim_printf ("Throttling disabled.\n");
sim_set_throt (0, NULL);
return SCPE_OK;
}
while (1) {
sim_throt_wait = (int32) /* time between waits */
sim_throt_wait = (int32) /* cycles between sleeps */
((a_cps * d_cps * ((double) sim_throt_sleep_time)) /
(1000.0 * (a_cps - d_cps)));
if (sim_throt_wait >= SIM_THROT_WMIN) /* long enough? */
@ -1785,11 +1837,18 @@ switch (sim_throt_state) {
sim_throt_cps = d_cps; /* save the desired rate */
/* Run through all timers and adjust the calibration for each */
/* one that is running to reflect the throttle rate */
for (tmr=0; tmr<=SIM_NTIMERS; tmr++)
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
if (rtc_hz[tmr]) { /* running? */
rtc_gtime[tmr] = sim_gtime(); /* save instruction time */
rtc_currd[tmr] = (int32)(sim_throt_cps / rtc_hz[tmr]);/* use throttle calibration */
rtc_ticks[tmr] = rtc_hz[tmr] - 1; /* force clock calibration on next tick */
rtc_rtime[tmr] = sim_throt_ms_start - 1000 + 1000/rtc_hz[tmr];/* adjust calibration parameters to reflect throttled rate */
rtc_gtime[tmr] = sim_throt_inst_start - sim_throt_cps + sim_throt_cps/rtc_hz[tmr];
rtc_nxintv[tmr] = 1000;
rtc_based[tmr] = rtc_currd[tmr];
if (sim_clock_unit[tmr])
sim_activate_abs (sim_clock_unit[tmr], rtc_currd[tmr]);/* reschedule next tick */
}
}
}
break;
@ -1803,23 +1862,48 @@ switch (sim_throt_state) {
if (sim_throt_type != SIM_THROT_SPC) { /* when not dynamic throttling */
if (sim_throt_type == SIM_THROT_MCYC) /* calc desired cps */
d_cps = (double) sim_throt_val * 1000000.0;
else if (sim_throt_type == SIM_THROT_KCYC)
d_cps = (double) sim_throt_val * 1000.0;
else d_cps = (a_cps * ((double) sim_throt_val)) / 100.0;
if (fabs(100.0 * (d_cps - a_cps) / a_cps) > (double)SIM_THROT_DRIFT_PCT) {
sim_throt_wait = sim_throt_val;
sim_throt_state = SIM_THROT_STATE_TIME;/* next state to recalibrate */
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Recalibrating throttle based on values a_cps = %f, d_cps = %f\n",
a_cps, d_cps);
else
if (sim_throt_type == SIM_THROT_KCYC)
d_cps = (double) sim_throt_val * 1000.0;
else
d_cps = (sim_throt_peak_cps * sim_throt_val) / 100.0;
if (fabs(100.0 * (d_cps - a_cps) / d_cps) > (double)sim_throt_drift_pct) {
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Recalibrating throttle based on values a_cps = %f, d_cps = %f deviating by %.2f%% from the desired value\n",
a_cps, d_cps, fabs(100.0 * (d_cps - a_cps) / d_cps));
if ((a_cps > d_cps) && /* too fast? */
((100.0 * (a_cps - d_cps) / d_cps) > (100 - sim_throt_drift_pct))) {
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Restarting calibrating throttle going too fast: a_cps = %f, d_cps = %f deviating by %.2f%% from the desired value\n",
a_cps, d_cps, fabs(100.0 * (d_cps - a_cps) / d_cps));
while (1) {
sim_throt_wait = (int32) /* cycles between sleeps */
((sim_throt_peak_cps * d_cps * ((double) sim_throt_sleep_time)) /
(1000.0 * (sim_throt_peak_cps - d_cps)));
if (sim_throt_wait >= SIM_THROT_WMIN)/* long enough? */
break;
sim_throt_sleep_time += sim_os_sleep_inc_ms;
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Wait too small, increasing sleep time to %d ms. Values a_cps = %f, d_cps = %f, wait = %d\n",
sim_throt_sleep_time, sim_throt_peak_cps, d_cps, sim_throt_wait);
}
}
else { /* slow or within reasonable range */
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Adjusting wait before sleep interval by %d\n",
(int32)(((d_cps - a_cps) * (double)sim_throt_wait) / d_cps));
sim_throt_wait += (int32)(((d_cps - a_cps) * (double)sim_throt_wait) / d_cps);
}
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Throttle values a_cps = %f, d_cps = %f, wait = %d, sleep = %d ms\n",
a_cps, d_cps, sim_throt_wait, sim_throt_sleep_time);
sim_throt_cps = d_cps; /* save the desired rate */
sim_throt_ms_start = sim_os_msec ();
sim_throt_inst_start = sim_gtime();
}
sim_throt_inst_start = sim_gtime();
}
else { /* record instruction rate */
sim_throt_cps = (int32)a_cps;
sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Recalibrating Special %d/%u Cycles Per Second of %f\n",
sim_throt_wait, sim_throt_sleep_time, sim_throt_cps);
sim_throt_inst_start = sim_gtime();
sim_throt_ms_start = sim_os_msec ();
}
sim_throt_ms_start = sim_os_msec ();
}
break;
}
@ -2033,6 +2117,7 @@ pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - starting\n");
pthread_mutex_lock (&sim_timer_lock);
sim_timer_thread_running = TRUE;
pthread_cond_signal (&sim_timer_startup_cond); /* Signal we're ready to go */
while (sim_asynch_timer && sim_is_running) {
struct timespec start_time, stop_time;
@ -2106,6 +2191,7 @@ while (sim_asynch_timer && sim_is_running) {
else {/* Something wants to adjust the queue since the wait condition was signaled */
}
}
sim_timer_thread_running = FALSE;
pthread_mutex_unlock (&sim_timer_lock);
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - exiting\n");
@ -2268,7 +2354,6 @@ if (sim_asynch_timer) {
pthread_attr_destroy( &attr);
pthread_cond_wait (&sim_timer_startup_cond, &sim_timer_lock); /* Wait for thread to stabilize */
pthread_cond_destroy (&sim_timer_startup_cond);
sim_timer_thread_running = TRUE;
}
pthread_mutex_unlock (&sim_timer_lock);
#endif
@ -2324,7 +2409,6 @@ if (sim_timer_thread_running) {
pthread_cond_signal (&sim_timer_wake);
pthread_mutex_unlock (&sim_timer_lock);
pthread_join (sim_timer_thread, NULL);
sim_timer_thread_running = FALSE;
/* Any wallclock queued events are now migrated to the normal event queue */
while (sim_wallclock_queue != QUEUE_LIST_END) {
UNIT *uptr = sim_wallclock_queue;
@ -2478,12 +2562,14 @@ if ((sim_asynch_timer) &&
}
if (prvptr == NULL) { /* inserting at head */
uptr->a_next = QUEUE_LIST_END; /* Temporarily mark as active */
while (sim_wallclock_entry) { /* wait for any prior entry has been digested */
sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after(%s, %.0f usecs) - queue insert entry %s busy waiting for 1ms\n",
sim_uname(uptr), usec_delay, sim_uname(sim_wallclock_entry));
pthread_mutex_unlock (&sim_timer_lock);
sim_os_ms_sleep (1);
pthread_mutex_lock (&sim_timer_lock);
if (sim_timer_thread_running) {
while (sim_wallclock_entry) { /* wait for any prior entry has been digested */
sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after(%s, %.0f usecs) - queue insert entry %s busy waiting for 1ms\n",
sim_uname(uptr), usec_delay, sim_uname(sim_wallclock_entry));
pthread_mutex_unlock (&sim_timer_lock);
sim_os_ms_sleep (1);
pthread_mutex_lock (&sim_timer_lock);
}
}
sim_wallclock_entry = uptr;
pthread_mutex_unlock (&sim_timer_lock);

View File

@ -84,17 +84,17 @@ int clock_gettime(int clock_id, struct timespec *tp);
#define SIM_IDLE_STDFLT 20 /* dft sec for stability */
#define SIM_IDLE_STMAX 600 /* max sec for stability */
#define SIM_THROT_WINIT 1000 /* cycles to skip */
#define SIM_THROT_WST 10000 /* initial wait */
#define SIM_THROT_WMUL 4 /* multiplier */
#define SIM_THROT_WMIN 50 /* min wait */
#define SIM_THROT_DRIFT_PCT 5 /* drift percentage for recalibrate */
#define SIM_THROT_MSMIN 10 /* min for measurement */
#define SIM_THROT_NONE 0 /* throttle parameters */
#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 */
#define SIM_THROT_WINIT 1000 /* cycles to skip */
#define SIM_THROT_WST 10000 /* initial wait */
#define SIM_THROT_WMUL 4 /* multiplier */
#define SIM_THROT_WMIN 50 /* min wait */
#define SIM_THROT_DRIFT_PCT_DFLT 5 /* drift percentage for recalibrate */
#define SIM_THROT_MSMIN 10 /* min for measurement */
#define SIM_THROT_NONE 0 /* throttle parameters */
#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 */
#define SIM_THROT_STATE_INIT 0 /* Starting */
#define SIM_THROT_STATE_TIME 1 /* Checking Time */
#define SIM_THROT_STATE_THROTTLE 2 /* Throttling */

View File

@ -339,6 +339,8 @@
#include "sim_tmxr.h"
#include "scp.h"
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#include <ctype.h>
#include <math.h>
@ -490,7 +492,6 @@ if (lp->txpb) {
lp->txpb = NULL;
}
memset (lp->rbr, 0, lp->rxbsz); /* clear break status array */
return;
}
@ -561,7 +562,6 @@ if (unwritten == 0) /* buffer now empty? */
lp->xmte = 1; /* reenable transmission if paused */
lp->txcnt -= (int32)strlen (msgbuf); /* adjust statistics */
return;
}
@ -580,7 +580,6 @@ static void tmxr_report_disconnection (TMLN *lp)
if (lp->notelnet)
return;
tmxr_linemsgf (lp, "\r\nDisconnected from the %s simulator\r\n\n", sim_name);/* report disconnection */
return;
}
static int32 loop_write_ex (TMLN *lp, char *buf, int32 length, t_bool prefix_datagram)
@ -702,28 +701,28 @@ static int32 tmxr_write (TMLN *lp, int32 length)
int32 written;
int32 i = lp->txbpr;
if ((lp->txbps) && (sim_gtime () < lp->txnexttime) && (sim_is_running))
return 0;
if (lp->loopback)
return loop_write (lp, &(lp->txb[i]), length);
if (lp->serport) { /* serial port connection? */
if ((sim_gtime () < lp->txnexttime) && (sim_is_running))
return 0;
written = sim_write_serial (lp->serport, &(lp->txb[i]), length);
if ((written > 0) && (sim_is_running))
lp->txnexttime = floor (sim_gtime () + (written * lp->txdelta * sim_timer_inst_per_sec ()));
return written;
}
else { /* Telnet connection */
written = sim_write_sock (lp->sock, &(lp->txb[i]), length);
if (written == SOCKET_ERROR) /* did an error occur? */
if (written == SOCKET_ERROR) { /* did an error occur? */
if (lp->datagram)
return written; /* ignore errors on datagram sockets */
else
return -1; /* return error indication */
else
return written;
}
}
if ((written > 0) && (lp->txbps) && (sim_is_running))
lp->txnexttime = floor (sim_gtime () + ((written * lp->txdelta * sim_timer_inst_per_sec ()) / TMXR_RX_BPS_UNIT_SCALE));
return written;
}
@ -743,7 +742,6 @@ for ( ; p < lp->rxbpi; p++) { /* work from "p" through
lp->rbr[p] = 0; /* clear potential break from vacated slot */
lp->rxbpi = lp->rxbpi - 1; /* drop buffer insert index */
return;
}
@ -992,15 +990,11 @@ if (mp->last_poll_time == 0) { /* first poll initializa
mp->poll_interval = TMXR_DEFAULT_CONNECT_POLL_INTERVAL;
if (!(uptr->dynflags & TMUF_NOASYNCH)) { /* if asynch not disabled */
uptr->dynflags |= UNIT_TM_POLL; /* tag as polling unit */
sim_cancel (uptr);
}
for (i=0; i < mp->lines; i++) {
uptr = mp->ldsc[i].uptr ? mp->ldsc[i].uptr : mp->uptr;
if (!(mp->uptr->dynflags & TMUF_NOASYNCH)) { /* if asynch not disabled */
uptr->dynflags |= UNIT_TM_POLL; /* tag as polling unit */
sim_cancel (uptr);
sim_cancel (mp->ldsc[i].uptr);
}
}
}
@ -1683,9 +1677,11 @@ if ((lp->conn && lp->rcve) && /* conn & enb & */
} /* end if conn */
if (lp->rxbpi == lp->rxbpr) /* empty? zero ptrs */
lp->rxbpi = lp->rxbpr = 0;
if (lp->rxbps) {
if (val)
lp->rxnexttime = floor (sim_gtime () + ((lp->rxdelta * sim_timer_inst_per_sec ())/lp->rxbpsfactor));
if (val) { /* Got something? */
if (lp->rxbps)
lp->rxnexttime = floor (sim_gtime () + ((lp->rxdelta * sim_timer_inst_per_sec ()) / lp->rxbpsfactor));
else
lp->rxnexttime = floor (sim_gtime () + ((lp->mp->uptr->wait * sim_timer_inst_per_sec ()) / TMXR_RX_BPS_UNIT_SCALE));
}
tmxr_debug_return(lp, val);
return val;
@ -2000,7 +1996,6 @@ for (i = 0; i < mp->lines; i++) { /* loop thru lines */
if (lp->rxbpi == lp->rxbpr) /* if buf empty, */
lp->rxbpi = lp->rxbpr = 0; /* reset pointers */
} /* end for */
return;
}
@ -2055,8 +2050,10 @@ if ((lp->txbfd && !lp->notelnet) || (TXBUF_AVAIL(lp) > 1)) {/* room for char (+
if ((TN_IAC == (u_char) chr) && (!lp->notelnet)) /* char == IAC in telnet session? */
TXBUF_CHAR (lp, TN_IAC); /* stuff extra IAC char */
TXBUF_CHAR (lp, chr); /* buffer char & adv pointer */
if ((!lp->txbfd) && (TXBUF_AVAIL (lp) <= TMXR_GUARD))/* near full? */
lp->xmte = 0; /* disable line */
if (((!lp->txbfd) &&
(TXBUF_AVAIL (lp) <= TMXR_GUARD)) || /* near full? */
(lp->txbps)) /* or we're rate limiting output */
lp->xmte = 0; /* disable line transmit until space available or character time has passed */
if (lp->txlog) { /* log if available */
extern TMLN *sim_oline; /* Make sure to avoid recursion */
TMLN *save_oline = sim_oline; /* when logging to a socket */
@ -2066,10 +2063,11 @@ if ((lp->txbfd && !lp->notelnet) || (TXBUF_AVAIL(lp) > 1)) {/* room for char (+
sim_oline = save_oline; /* resture output socket */
}
sim_exp_check (&lp->expect, chr); /* process expect rules as needed */
if ((sim_interval > 0) && /* not called within sim_process_event? */
(lp->txbps) && (lp->txdelta > 1000)) { /* and rate limiting output slower than 1000 cps */
if (!sim_is_running) { /* attach message or other non simulation time message? */
tmxr_send_buffered_data (lp); /* put data on wire */
sim_os_ms_sleep((lp->txdelta - 1000) / 1000); /* wait an approximate character delay */
sim_os_ms_sleep(((lp->txbps) && (lp->txdelta > 1000)) ? /* rate limiting output slower than 1000 cps */
(lp->txdelta - 1000) / 1000 :
10); /* wait an approximate character delay */
}
return SCPE_OK; /* char sent */
}
@ -2159,10 +2157,12 @@ for (i = 0; i < mp->lines; i++) { /* loop thru lines */
tmxr_rqln (lp))
_sim_activate (ruptr, 0);
#endif
lp->xmte = 1; /* enable line transmit */
if ((lp->xmte == 0) &&
((lp->txbps == 0) ||
(lp->txnexttime >= sim_gtime ())))
lp->xmte = 1; /* enable line transmit */
}
} /* end for */
return;
}
@ -2900,10 +2900,11 @@ return r;
Implementation note:
Only devices which poll on a unit different from the unit provided
- This routine must be called before the MUX is attached.
- Only devices which poll on a unit different from the unit provided
at MUX attach time need call this function. Calling this API is
necessary for asynchronous multiplexer support and unnecessary
otherwise.
necessary for asynchronous multiplexer support and if speed limited
behaviors are desired.
*/
@ -2915,7 +2916,8 @@ mp->ldsc[line].uptr = uptr_poll;
return SCPE_OK;
}
/* Declare which unit polls for output
/* Declare which unit performs output transmission in its unit service
routine for a particular line.
Inputs:
*mp = the mux
@ -2925,12 +2927,15 @@ return SCPE_OK;
Outputs:
none
Implementation note:
Implementation notes:
Only devices which poll on a unit different from the unit provided
- This routine must be called before the MUX is attached.
- Only devices which poll on a unit different from the unit provided
at MUX attach time need call this function ABD different from the
unit which polls for input. Calling this API is necessary for
asynchronous multiplexer support and unnecessary otherwise.
asynchronous multiplexer support and if speed limited behaviors are
desired.
*/
@ -3689,13 +3694,21 @@ if (!async || (uptr->flags & TMUF_NOASYNCH)) /* if asynch disabled */
#else
uptr->dynflags |= TMUF_NOASYNCH; /* tag as no asynch */
#endif
uptr->dynflags |= UNIT_TM_POLL; /* tag as polling unit */
if (mp->dptr) {
for (i=0; i<mp->lines; i++) {
mp->ldsc[i].expect.dptr = mp->dptr;
mp->ldsc[i].expect.dbit = TMXR_DBG_EXP;
mp->ldsc[i].send.dptr = mp->dptr;
mp->ldsc[i].send.dbit = TMXR_DBG_SEND;
if (mp->ldsc[i].uptr == NULL)
mp->ldsc[i].uptr = mp->uptr;
mp->ldsc[i].uptr->tmxr = (void *)mp;
mp->ldsc[i].uptr->dynflags |= UNIT_TM_POLL; /* tag as polling unit */
if (mp->ldsc[i].o_uptr == NULL)
mp->ldsc[i].o_uptr = mp->ldsc[i].uptr;
mp->ldsc[i].o_uptr->tmxr = (void *)mp;
mp->ldsc[i].o_uptr->dynflags |= UNIT_TM_POLL; /* tag as polling unit */
}
}
tmxr_add_to_open_list (mp);
@ -3770,6 +3783,8 @@ else {
fprintf (st, " - %stelnet", lp->notelnet ? "no" : "");
if (lp->uptr && (lp->uptr != lp->mp->uptr))
fprintf (st, " - Unit: %s", sim_uname (lp->uptr));
if (lp->o_uptr && (lp->o_uptr != lp->mp->uptr) && (lp->o_uptr != lp->uptr))
fprintf (st, " - Output Unit: %s", sim_uname (lp->o_uptr));
if (mp->modem_control != lp->modem_control)
fprintf(st, ", ModemControl=%s", lp->modem_control ? "enabled" : "disabled");
if (lp->loopback)
@ -3885,38 +3900,94 @@ uptr->filename = NULL;
uptr->tmxr = NULL;
mp->last_poll_time = 0;
for (i=0; i < mp->lines; i++) {
UNIT *uptr = mp->ldsc[i].uptr ? mp->ldsc[i].uptr : mp->uptr;
UNIT *o_uptr = mp->ldsc[i].o_uptr ? mp->ldsc[i].o_uptr : mp->uptr;
uptr->dynflags &= ~UNIT_TM_POLL; /* no polling */
o_uptr->dynflags &= ~UNIT_TM_POLL; /* no polling */
mp->ldsc[i].uptr->tmxr = NULL;
mp->ldsc[i].uptr->dynflags &= ~UNIT_TM_POLL; /* no polling */
mp->ldsc[i].o_uptr->tmxr = NULL;
mp->ldsc[i].o_uptr->dynflags &= ~UNIT_TM_POLL; /* no polling */
}
uptr->flags &= ~(UNIT_ATT); /* not attached */
uptr->dynflags &= ~(UNIT_TM_POLL|TMUF_NOASYNCH); /* no polling, not asynch disabled */
return SCPE_OK;
}
static int32 _tmxr_activate_delay (UNIT *uptr, int32 interval)
{
TMXR *mp = (TMXR *)uptr->tmxr;
int32 i, sooner = interval, due;
double sim_gtime_now = sim_gtime ();
for (i=0; i<mp->lines; i++) {
TMLN *lp = &mp->ldsc[i];
if ((uptr == lp->uptr) && /* read polling unit? */
(lp->rxbps) && /* while rate limiting? */
(tmxr_rqln_bare (lp, FALSE))) { /* with pending input data */
if (lp->rxnexttime > sim_gtime_now)
due = (int32)(lp->rxnexttime - sim_gtime_now);
else
due = sim_processing_event ? 1 : 0; /* avoid potential infinite loop if called from service routine */
sooner = MIN(sooner, due);
}
if ((uptr == lp->o_uptr) && /* output completion unit? */
(lp->txbps) && /* while rate limiting */
(tmxr_tqln(lp))) { /* with queued output data */
if (lp->txnexttime > sim_gtime_now)
due = (int32)(lp->txnexttime - sim_gtime_now);
else
due = sim_processing_event ? 1 : 0; /* avoid potential infinite loop if called from service routine */
sooner = MIN(sooner, due);
}
}
return sooner;
}
t_stat tmxr_activate (UNIT *uptr, int32 interval)
{
int32 sooner;
if (uptr->dynflags & UNIT_TMR_UNIT)
return sim_timer_activate (uptr, interval);
#if defined(SIM_ASYNCH_MUX)
if ((!(uptr->dynflags & UNIT_TM_POLL)) ||
(!sim_asynch_enabled)) {
return _sim_activate (uptr, interval);
return sim_timer_activate (uptr, interval); /* Handle the timer case */
if (!(uptr->dynflags & UNIT_TM_POLL))
return _sim_activate (uptr, interval); /* Handle the non mux case */
sooner = _tmxr_activate_delay (uptr, interval);
if (sooner != interval) {
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s after %d instructions rather than %d instructions\n", sim_uname (uptr), sooner, interval);
return _sim_activate (uptr, sooner); /* Handle the busy case */
}
#if defined(SIM_ASYNCH_MUX)
if (!sim_asynch_enabled)
return _sim_activate (uptr, interval);
return SCPE_OK;
#else
return _sim_activate (uptr, interval);
#endif
}
t_stat tmxr_activate_abs (UNIT *uptr, int32 interval)
{
AIO_VALIDATE; /* Can't call asynchronously */
sim_cancel (uptr);
return tmxr_activate (uptr, interval);
}
t_stat tmxr_activate_after (UNIT *uptr, uint32 usecs_walltime)
{
int32 sooner;
if (uptr->dynflags & UNIT_TMR_UNIT)
return _sim_activate_after (uptr, (double)usecs_walltime); /* Handle the timer case */
if (!(uptr->dynflags & UNIT_TM_POLL))
return _sim_activate_after (uptr, (double)usecs_walltime); /* Handle the non mux case */
sooner = _tmxr_activate_delay (uptr, 0x7FFFFFFF);
if (sooner != 0x7FFFFFFF) {
if (sooner < 0) {
sooner = _tmxr_activate_delay (uptr, 0x7FFFFFFF);
}
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s after %d instructions rather than %u usecs\n", sim_uname (uptr), sooner, usecs_walltime);
return _sim_activate (uptr, sooner); /* Handle the busy case directly */
}
#if defined(SIM_ASYNCH_MUX)
if ((!(uptr->dynflags & UNIT_TM_POLL)) ||
(!sim_asynch_enabled)) {
if (!sim_asynch_enabled)
return _sim_activate_after (uptr, (double)usecs_walltime);
}
return SCPE_OK;
@ -3927,18 +3998,10 @@ return _sim_activate_after (uptr, (double)usecs_walltime);
t_stat tmxr_activate_after_abs (UNIT *uptr, uint32 usecs_walltime)
{
#if defined(SIM_ASYNCH_MUX)
if ((!(uptr->dynflags & UNIT_TM_POLL)) ||
(!sim_asynch_enabled)) {
return _sim_activate_after_abs (uptr, (double)usecs_walltime);
}
return SCPE_OK;
#else
return _sim_activate_after_abs (uptr, (double)usecs_walltime);
#endif
sim_cancel (uptr);
return tmxr_activate_after (uptr, usecs_walltime);
}
t_stat tmxr_clock_coschedule (UNIT *uptr, int32 interval)
{
int32 tmr = sim_rtcn_calibrated_tmr ();
@ -3953,45 +4016,27 @@ sim_cancel (uptr);
return tmxr_clock_coschedule (uptr, interval);
}
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
t_stat tmxr_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 ticks)
{
TMXR *mp = (TMXR *)uptr->tmxr;
int32 interval = ticks * sim_rtcn_tick_size (tmr);
int32 sooner;
if (uptr->dynflags & UNIT_TMR_UNIT)
return sim_clock_coschedule_tmr (uptr, tmr, ticks); /* Handle the timer case */
if (!(uptr->dynflags & UNIT_TM_POLL))
return sim_clock_coschedule_tmr (uptr, tmr, ticks); /* Handle the non mux case */
sooner = _tmxr_activate_delay (uptr, interval);
if (sooner != interval) {
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s after %d instructions rather than %d ticks (%d instructions)\n", sim_uname (uptr), sooner, ticks, interval);
return _sim_activate (uptr, sooner); /* Handle the busy case directly */
}
#if defined(SIM_ASYNCH_MUX)
if ((!(uptr->dynflags & UNIT_TM_POLL)) ||
(!sim_asynch_enabled)) {
if (!sim_asynch_enabled) {
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "coscheduling %s after interval %d ticks\n", sim_uname (uptr), ticks);
return sim_clock_coschedule (uptr, tmr, ticks);
}
return SCPE_OK;
#else
if (mp) {
int32 i, soon = interval;
double sim_gtime_now = sim_gtime ();
for (i = 0; i < mp->lines; i++) {
TMLN *lp = &mp->ldsc[i];
if (tmxr_rqln_bare (lp, FALSE)) {
int32 due;
if (lp->rxbps)
if (lp->rxnexttime > sim_gtime_now)
due = (int32)(lp->rxnexttime - sim_gtime_now);
else
due = sim_processing_event ? 1 : 0; /* avoid potential infinite loop if called from service routine */
else
due = (int32)((uptr->wait * sim_timer_inst_per_sec ())/TMXR_RX_BPS_UNIT_SCALE);
soon = MIN(soon, due);
}
}
if (soon != interval) {
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s after %d instructions\n", sim_uname (uptr), soon);
return _sim_activate (uptr, soon);
}
}
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "coscheduling %s after interval %d ticks\n", sim_uname (uptr), ticks);
return sim_clock_coschedule_tmr (uptr, tmr, ticks);
#endif
@ -4224,7 +4269,6 @@ void tmxr_msg (SOCKET sock, const char *msg)
{
if ((sock) && (sock != INVALID_SOCKET))
sim_write_sock (sock, msg, (int32)strlen (msg));
return;
}
@ -4238,7 +4282,6 @@ while (*msg) {
sim_os_ms_sleep (10);
++msg;
}
return;
}
@ -4299,7 +4342,6 @@ for (i = 0; i < len; ++i) {
}
if (buf != stackbuf)
free (buf);
return;
}
@ -4368,7 +4410,6 @@ if (lp->expect.buf)
sim_exp_showall (st, &lp->expect);
if (lp->txlog)
fprintf (st, " Logging to %s\n", lp->txlogname);
return;
}
@ -4398,6 +4439,15 @@ else {
fprintf (st, " packet data queued/packets sent = %d/%d",
tmxr_tpqln (lp), lp->txpcnt);
fprintf (st, "\n");
if ((lp->rxbps) || (lp->txbps)) {
if ((lp->rxbps == lp->txbps))
fprintf (st, " speed = %u", lp->rxbps);
else
fprintf (st, " speed = %u/%u", lp->rxbps, lp->txbps);
if (lp->rxbpsfactor / TMXR_RX_BPS_UNIT_SCALE > 1.0)
fprintf (st, "*%.0f", lp->rxbpsfactor / TMXR_RX_BPS_UNIT_SCALE);
fprintf (st, " bps\n");
}
}
if (lp->txbfd)
fprintf (st, " output buffer size = %d\n", lp->txbsz);
@ -4408,7 +4458,6 @@ if (lp->txdrp)
fprintf (st, " dropped = %d\n", lp->txdrp);
if (lp->txstall)
fprintf (st, " stalled = %d\n", lp->txstall);
return;
}

View File

@ -279,6 +279,7 @@ t_stat tmxr_show_cstat (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_show_lines (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc);
t_stat tmxr_activate (UNIT *uptr, int32 interval);
t_stat tmxr_activate_abs (UNIT *uptr, int32 interval);
t_stat tmxr_activate_after (UNIT *uptr, uint32 usecs_walltime);
t_stat tmxr_activate_after_abs (UNIT *uptr, uint32 usecs_walltime);
t_stat tmxr_clock_coschedule (UNIT *uptr, int32 interval);
@ -314,6 +315,7 @@ void _tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsiz
#endif
#if (!defined(NOT_MUX_USING_CODE))
#define sim_activate tmxr_activate
#define sim_activate_abs tmxr_activate_abs
#define sim_activate_after tmxr_activate_after
#define sim_activate_after_abs tmxr_activate_after_abs
#define sim_clock_coschedule tmxr_clock_coschedule