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:
parent
328ddcc23c
commit
8f26b58deb
166
display/README
Normal file
166
display/README
Normal 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
12
display/build_mingw.bat
Normal 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
333
display/carbon.c
Normal 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
1068
display/display.c
Normal file
File diff suppressed because it is too large
Load Diff
144
display/display.h
Normal file
144
display/display.h
Normal 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
86
display/gmakefile
Normal 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
422
display/sim_ws.c
Normal 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
91
display/smakefile
Normal 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
192
display/test.c
Normal 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
706
display/type340.c
Normal 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
3824
display/vt11.c
Normal file
File diff suppressed because it is too large
Load Diff
144
display/vt11.h
Normal file
144
display/vt11.h
Normal 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
297
display/vtmacs.h
Normal 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
1465
display/vttest.c
Normal file
File diff suppressed because it is too large
Load Diff
422
display/win32.c
Normal file
422
display/win32.c
Normal 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
65
display/ws.h
Normal 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
494
display/x11.c
Normal 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
1036
display/xy.c
Normal file
File diff suppressed because it is too large
Load Diff
486
scp.c
486
scp.c
@ -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
4
scp.h
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
10
sim_defs.h
10
sim_defs.h
@ -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 */
|
||||
|
||||
16
sim_disk.c
16
sim_disk.c
@ -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 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
110
sim_ether.c
110
sim_ether.c
@ -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 */
|
||||
|
||||
288
sim_frontpanel.c
288
sim_frontpanel.c
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
166
sim_timer.c
166
sim_timer.c
@ -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);
|
||||
|
||||
22
sim_timer.h
22
sim_timer.h
@ -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 */
|
||||
|
||||
235
sim_tmxr.c
235
sim_tmxr.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user