simh-testsetgenerator/PDP10/kx10_dpy.c
Richard Cornwell 1cb2f3b96c KA10: Fix divide error on KS10, add in some devices.
Fix divide of 0 on KS10 processor.
       Fix write access for auxiliary processor memory.
       Updated support new PIDP10 panel.
       Allow eight Unibux ports on the TEN device.
       Added GE DATANET-760 device to PDP6
       Removed USER mode restriction for idle detection.
       Added Data Disc 6600 Television Display System.
2024-05-21 17:06:39 -04:00

809 lines
25 KiB
C

/* ka10_dpy.c: 340 display subsystem simulator w/ PDP-6 344 interface!
Copyright (c) 2018, 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
PHILIP BUDNE 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 Philip Budne shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Richard Cornwell.
*/
/*
* NOTE!!! Currently only supports 340 display using the type 344 interface
* for PDP-6 described in
* http://www.bitsavers.org/pdf/dec/graphics/H-340_Type_340_Precision_Incremental_CRT_System_Nov64.pdf
*
* The MIT file .INFO.;340 INFO says:
* ;CONI BITS OF THE 340 ARE:
* ;2.9-2.7 MODE
* ;2.4 VECT CONT LP(????)
* ;2.3 VERTICAL EDGE HIT
* ;2.2 LIGHT PEN HIT
* ;2.1 HORIZONTAL EDGE HIT
* ;1.9 STOP
* ;1.8 DONE (CAUSES DATA INTERUPT)
* ;1.6-1.4 SPECIAL PIA
* ;1.3-1.1 DATA PIA
* ;340 CONO BITS ARE:
* ;2.3 CLEAR NO INK MODE
* ;2.2 SET NO INK MODE (IN NO INK MODE, NO INTENSIFICATION CAN \
* OCCUR)
* ;2.1 CLEAR HALF WORD MODE
* ;1.9 SET HALF WORD MODE
* ;1.8 RESUME DISPLAY (TO CONTINUE AFTER A SPECIAL INTERUPT)
* ;1.7 INTIALIZE
* ;1.6-1.4 SPECIAL PIA
* ;1.3-1.1 DATA PIA
* ITS uses the "resume display" bit, so it has been implemented here.
*
* 340C was used in the PDP-10 VB10C display system
* http://bitsavers.informatik.uni-stuttgart.de/pdf/dec/pdp10/periph/VB10C_Interactive_Graphics_Terminal_Jul70.pdf
* "The basic hardware system consists of a 340/C display connected
* directly to PDP-1O memory through a special memory channel. Several
* important features included in the VB-10/C display are memory
* protection and relocation, slave mode operation, raster mode, and
* subroutining."
*
* reading 6.03 VBCSER
* http://pdp-10.trailing-edge.com/dec-10-omona-u-mc9/01/vbcser.mac.html
* There appear to be differences in the DIS (130) CONI/O bits:
* CONI
* 47400 are "DISPLAY INTERRUPT" bits
* 45000 are "ILLEGAL ADDRESS OR EDGE FLAG" (same VE/HE??)
* 40000 is "ILLEGAL ADDR"
* 2000 is LP HIT (same)
* 400 is STOP (same
* CONO
* 20000 "lock display out of memory"
* 100 init? (same)
* 40 "clear flags"
* 20 "resume" (stored @DISIN4)
* 7 PI channel?
* DISCON = CHAN + 140 (continue?)
* *NO* DATAO or BLKO to device 130!
*
* It appears that the reloc/protect mechanism is on I/O device 134.
* (referred to by number, not symbol!)
* DATAO sets reloc/protect, start addr
* possibly:
* high order 8 protection bits are left justified in left half
* high order 8 relocation bits are left justified in right half
*
* Other PDP-6/10 display interfaces:
*
* http://bitsavers.trailing-edge.com/pdf/dec/graphics/348_Manual_1964.pdf
* Type 348 interface to Type 30A or 30E displays.
* "To the display, the interface looks like a PDP-1 computer"
*
* Also VP10/VR30 (phone book p. 487):
* control word format:
* INTENSITY(*),,0 ("4 dimmest, thru 13 brightest" default is 10)
* YPOS,,XPOS (10 bit positions)
*
* (*)6.03 DISSER.MAC says:
* ONLY FOR VP10 and TYPE 30.
* N IS 3 BITS WIDE FOR 30, 2 BITS WIDE FOR VP10.
*
* 348 manual p.10 says: "The three flip-flops are treated as a two bit
* signed binary number. Negative numbers are in two's complement form.
* The most negative number (100) will produce the least intensity.
* The largest positive number (011) results in the greatest intensity.
*/
#include "kx10_defs.h"
#include "sim_video.h"
#include <math.h>
#ifndef NUM_DEVS_DPY
#define NUM_DEVS_DPY 0
#endif
#if (NUM_DEVS_DPY > 0)
#include "display/type340.h"
#include "display/display.h"
#define DPY_DEVNUM 0130
#define FULLSCREEN (1 << (UNIT_V_UF))
#define RRZ(W) ((W) & RMASK)
#define XWD(L,R) ((((uint64)(L))<<18)|((uint64)(R)))
#if PDP6 | KA | KI
extern uint64 SW; /* switch register */
#endif
/*
* number of (real?) microseconds between svc calls
* used to age display, poll for WS events
* and delay "data" interrupt
* (VB10C could steal cycles)
*/
#define DPY_CYCLE_US 50
/*
* number of DPY_CYCLES to delay int
* too small and host CPU doesn't run enough!
*/
#define INT_COUNT (100/DPY_CYCLE_US)
#define STAT_REG u3
#define INT_COUNTDOWN u4
#define XPOS us9 /* from LP hit */
#define YPOS us10 /* from LP hit */
/* STAT_REG */
#define STAT_VALID 01000000 /* internal: invisible to PDP-10 */
/* CONI/CONO */
/* http://www.bitsavers.org/pdf/dec/graphics/H-340_Type_340_Precision_Incremental_CRT_System_Nov64.pdf p 2-14 */
#define CONO_MASK 0000077 /* bits changed by CONO */
#define CONI_MASK 0007677 /* bits read by CONI */
#define CONI_INT_SPEC 0007400 /* I- "special conditions" */
#define CONI_INT_VE 0004000 /* I- b24: VER EDGE */
#define CONI_INT_LP 0002000 /* I- b25: LIGHT PEN */
#define CONI_INT_HE 0001000 /* I- b26: HOR EDGE */
#define CONI_INT_SI 0000400 /* I- b27: STOP INT */
#define CONI_INT_DONE 0000200 /* I- b28: done with second half */
#define CONO_RESUME 0000200 /* -O b28: resume after special int */
#define CONO_INIT 0000100 /* -O b29: init display */
#define CONX_SC 0000070 /* IO special channel */
#define CONX_DC 0000007 /* IO data channel */
#define CONX_SC_SHIFT 3
#define CONX_DC_SHIFT 0
/* make sure ST340_XXX bits match CONI_INT_XXX bits */
#if (ST340_VEDGE^CONI_INT_VE)|(ST340_LPHIT^CONI_INT_LP)|(ST340_HEDGE^CONI_INT_HE)|(ST340_STOP_INT^CONI_INT_SI)
#error ST340 bits do not match CONI_INT bits!!
#endif
t_stat dpy_devio(uint32 dev, uint64 *data);
t_stat dpy_svc (UNIT *uptr);
t_stat dpy_reset (DEVICE *dptr);
const char *dpy_description (DEVICE *dptr);
DIB dpy_dib[] = {
{ DPY_DEVNUM, 1, &dpy_devio, NULL }};
UNIT dpy_unit[] = {
{ UDATA (&dpy_svc, UNIT_IDLE, DPY_CYCLE_US) }
};
#define UPTR(UNIT) (dpy_unit+(UNIT))
MTAB dpy_mod[] = {
{ FULLSCREEN, FULLSCREEN, "FULLSCREEN", "FULLSCREEN", NULL, NULL, NULL,
"Display in fullscreen"},
{ FULLSCREEN, 0, NULL, "WINDOW", NULL, NULL, NULL,
"Display in window"},
{ 0 }
};
DEVICE dpy_dev = {
"DPY", dpy_unit, NULL, dpy_mod,
NUM_DEVS_DPY, 0, 0, 0, 0, 0,
NULL, NULL, dpy_reset,
NULL, NULL, NULL,
&dpy_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_DISPLAY, 0, dev_debug,
NULL, NULL, NULL, NULL, NULL, &dpy_description
};
const char *dpy_description (DEVICE *dptr)
{
return "Type 340 Display on Type 344 interface";
}
/* until it's done just one place! */
static void dpy_set_int_done(UNIT *uptr)
{
uptr->INT_COUNTDOWN = INT_COUNT;
}
/* update interrupt request */
static void check_interrupt (UNIT *uptr)
{
if (uptr->STAT_REG & CONI_INT_SPEC) {
uint32 sc = uptr->STAT_REG & CONX_SC;
set_interrupt(DPY_DEVNUM, sc >> CONX_SC_SHIFT);
} else if (uptr->STAT_REG & CONI_INT_DONE) {
uint32 dc = uptr->STAT_REG & CONX_DC;
set_interrupt(DPY_DEVNUM, dc>>CONX_DC_SHIFT);
} else {
clr_interrupt(DPY_DEVNUM);
}
}
/* return true if display not stopped */
int dpy_update_status (UNIT *uptr, ty340word status, int done)
{
int running = !(status & ST340_STOPPED);
/* sub in lastest bits from display */
uptr->STAT_REG &= ~CONI_INT_SPEC;
uptr->STAT_REG |= status & CONI_INT_SPEC;
/* data interrupt sent from svc routine, so CPU can run */
if (done && running) {
/* XXX also set in "rfd" callback: decide! */
dpy_set_int_done(uptr);
}
check_interrupt(uptr);
return running;
}
t_stat dpy_devio(uint32 dev, uint64 *data) {
int unit = (dev - DPY_DEVNUM) >> 2;
UNIT *uptr;
int32 inst;
if (unit < 0 || unit >= NUM_DEVS_DPY)
return SCPE_OK;
uptr = UPTR(unit);
if (!(uptr->STAT_REG & STAT_VALID)) {
dpy_update_status(uptr, ty340_status(), 0);
sim_activate_after(uptr, DPY_CYCLE_US);
uptr->STAT_REG |= STAT_VALID;
uptr->INT_COUNTDOWN = 0;
}
switch (dev & 3) {
case CONI:
*data = (uint64)(uptr->STAT_REG & CONI_MASK);
/*
* MIT AI only, See Hardware Memo 1
* https://github.com/larsbrinkhoff/its-archives/blob/master/ailab/ITS_Hardware_Memo_1.pdf
* Set sign bit if device assigned to this CPU (KA or PDP-6)
* (Thanks to Lars for figuring this out!)
*/
*data |= SMASK; /* always assigned to us */
sim_debug(DEBUG_CONI, &dpy_dev, "DPY %03o CONI PC=%06o %012llo\n",
dev, PC, *data);
break;
case CONO:
clr_interrupt(dev);
uptr->STAT_REG &= ~CONO_MASK;
uptr->STAT_REG |= *data & CONO_MASK;
if (*data & CONO_INIT)
dpy_update_status( uptr, ty340_reset(&dpy_dev), 1);
if (*data & CONO_RESUME) {
/* This bit is not documented in "H-340 Type 340 Precision
Incremental CRT System". It is in the MIT file .INFO.;
340 INFO, and ITS does depend on it. */
ty340_clear(CONI_INT_VE | CONI_INT_LP | CONI_INT_HE);
dpy_update_status( uptr, ty340_status(), 0);
}
sim_debug(DEBUG_CONO, &dpy_dev, "DPY %03o CONO %06o PC=%06o %06o\n",
dev, (uint32)*data, PC, uptr->STAT_REG & ~STAT_VALID);
if (!sim_is_active(uptr))
sim_activate_after(uptr, DPY_CYCLE_US);
break;
case DATAO:
uptr->STAT_REG &= ~CONI_INT_DONE;
uptr->INT_COUNTDOWN = 0;
/* if fed using BLKO from interrupt vector, PC will be wrong! */
sim_debug(DEBUG_DATAIO, &dpy_dev, "DPY %03o DATO %012llo PC=%06o\n",
dev, *data, PC);
inst = (uint32)LRZ(*data);
if (dpy_update_status(uptr, ty340_instruction(inst), 0)) {
/* still running */
inst = (uint32)RRZ(*data);
dpy_update_status(uptr, ty340_instruction(inst), 1);
}
if (!sim_is_active(uptr))
sim_activate_after(uptr, DPY_CYCLE_US);
break;
case DATAI:
*data = XWD(uptr->YPOS, uptr->XPOS);
sim_debug(DEBUG_DATAIO, &dpy_dev, "DPY %03o DATI %06o,,%06o PC=%06o\n",
dev, uptr->YPOS, uptr->XPOS, PC);
break;
}
return SCPE_OK;
}
/* Timer service - */
t_stat dpy_svc (UNIT *uptr)
{
if (!display_is_blank() || uptr->INT_COUNTDOWN > 0)
sim_activate_after(uptr, DPY_CYCLE_US); /* requeue! */
display_age(DPY_CYCLE_US, 0); /* age the display */
if (uptr->INT_COUNTDOWN && --uptr->INT_COUNTDOWN == 0) {
uptr->STAT_REG |= CONI_INT_DONE;
check_interrupt (uptr);
}
return SCPE_OK;
}
#define JOY_MAX_UNITS 4
#define JOY_MAX_AXES 4
#define JOY_MAX_BUTTONS 4
static int joy_axes[JOY_MAX_UNITS * JOY_MAX_AXES];
static int joy_buttons[JOY_MAX_UNITS * JOY_MAX_BUTTONS];
static void dpy_joy_motion(int which, int axis, int value)
{
if (which < JOY_MAX_UNITS && axis < JOY_MAX_AXES) {
joy_axes[which * JOY_MAX_AXES + axis] = value;
}
}
static void dpy_joy_button(int which, int button, int state)
{
if (which < JOY_MAX_UNITS && button < JOY_MAX_BUTTONS) {
joy_buttons[which * JOY_MAX_BUTTONS + button] = state;
}
}
#if ITS
static int dpy_keyboard (SIM_KEY_EVENT *ev)
{
sim_debug(DEBUG_DATA, &dpy_dev, "Key %d %s\n",
ev->key, ev->state == SIM_KEYPRESS_DOWN ? "down" : "up");
if (ev->state == SIM_KEYPRESS_UP && ev->key == SIM_KEY_F11) {
vid_set_fullscreen (!vid_is_fullscreen ());
return 1;
}
return 0;
}
#endif
/* Reset routine */
t_stat dpy_reset (DEVICE *dptr)
{
if (dptr->flags & DEV_DIS) {
display_close(dptr);
} else {
#if ITS
if (stk_dev.flags & DEV_DIS) {
sim_debug(DEBUG_DETAIL, &dpy_dev, "Grabbing keyboard\n");
vid_display_kb_event_process = dpy_keyboard;
}
#endif
display_reset();
ty340_reset(dptr);
vid_set_fullscreen (dpy_unit[0].flags & FULLSCREEN);
vid_register_gamepad_motion_callback (dpy_joy_motion);
vid_register_gamepad_button_callback (dpy_joy_button);
}
sim_cancel (&dpy_unit[0]); /* deactivate unit */
return SCPE_OK;
}
/****************
* callbacks from type340.c
*/
/* not used with Type 344 interface */
ty340word
ty340_fetch(ty340word addr)
{
return 0;
}
/* not used with Type 344 interface */
void
ty340_store(ty340word addr, ty340word value)
{
}
void
ty340_lp_int(ty340word x, ty340word y)
{
/*
* real hardware pauses display until the CPU reads out coords
* w/ DATAI which then continues the display
*/
dpy_unit[0].XPOS = x;
dpy_unit[0].YPOS = y;
dpy_update_status(dpy_unit, ty340_status(), 0);
}
void
ty340_rfd(void) { /* request for data */
#ifdef TY340_NODISPLAY
puts("ty340_rfd");
#endif
dpy_set_int_done(dpy_unit);
}
void
cpu_get_switches(unsigned long *p1, unsigned long *p2) {
#if PDP6 | KA | KI
*p1 = LRZ(SW);
*p2 = RRZ(SW);
#endif
}
void
cpu_set_switches(unsigned long w1, unsigned long w2) {
#if PDP6 | KA | KI
SW = XWD(w1,w2);
#endif
}
/*
* MIT Spacewar console switches
* WCNSLS is the mnemonic defined/used in the SPCWAR sources
*/
#if NUM_DEVS_WCNSLS > 0
#define WCNSLS_DEVNUM 0420
#define UNIT_JOY (1 << DEV_V_UF) /* Use USB gaming devices. */
#define UNIT_CSCOPE (1 << (DEV_V_UF+1)) /* Enable color scope. */
t_stat wcnsls_devio(uint32 dev, uint64 *data);
t_stat wcnsls_svc (UNIT *uptr);
t_stat wcnsls_reset (DEVICE *dptr);
const char *wcnsls_description (DEVICE *dptr);
static uint64 dev420_cono = 0;
static uint8 cscope_r = 0;
static uint8 cscope_g = 0;
static uint8 cscope_b = 0;
static VID_DISPLAY *cscope_display = NULL;
static uint32 fade[512 * 512];
static uint32 dot[7 * 7];
DIB wcnsls_dib[] = {
{ WCNSLS_DEVNUM, 1, &wcnsls_devio, NULL }};
MTAB wcnsls_mod[] = {
{ UNIT_JOY, UNIT_JOY, "JOYSTICK", "JOYSTICK", NULL, NULL, NULL,
"Use USB joysticks"},
{ UNIT_CSCOPE, UNIT_CSCOPE, "CSCOPE", "CSCOPE", NULL, NULL, NULL,
"Enable color scope"},
{ 0 }
};
UNIT wcnsls_unit[] = {
{ UDATA (wcnsls_svc, UNIT_IDLE, 0) }};
REG wcnsls_reg[] = {
{ORDATA(CONO, dev420_cono, 18)},
{0}
};
DEVICE wcnsls_dev = {
"WCNSLS", wcnsls_unit, wcnsls_reg, wcnsls_mod,
NUM_DEVS_WCNSLS, 0, 0, 0, 0, 0,
NULL, NULL, wcnsls_reset,
NULL, NULL, NULL,
&wcnsls_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug,
NULL, NULL, NULL, NULL, NULL, &wcnsls_description
};
const char *wcnsls_description (DEVICE *dptr)
{
return "MIT Spacewar Consoles, and DEC color scope";
}
/* Device 420 CONO bits. */
#define CONO_BLUE 0000020 /* Color scope blue enable */
#define CONO_SPCWAR 0000040 /* Spacewar consoles */
#define CONO_GREEN 0002000 /* Color scope green enable */
#define CONO_RANDOM 0004000 /* Random switches */
#define CONO_RED 0200000 /* Color scope red enable */
#define CONO_KNIGHT 0400000 /* Switches in TK's office */
/*
* map 32-bit "spacewar_switches" value to what PDP-6/10 game expects
* (four 9-bit bytes)
*/
/* bits inside the bytes */
#define CCW 0400LL /* counter clockwise (L) */
#define CW 0200LL /* clockwise (R) */
#define THRUST 0100LL
#define HYPER 040LL
#define FIRE 020LL
/* shift values for the players' bytes */
#define UR 0 /* upper right: enterprise "top plug" */
#define LR 9 /* lower right: klingon "second plug" */
#define LL 18 /* lower left: thin ship "third plug" */
#define UL 27 /* upper left: fat ship "bottom plug" */
#define JOY_TRIG 5000
#define JOY0 (JOY_MAX_AXES*0)
#define JOY1 (JOY_MAX_AXES*1)
#define JOY2 (JOY_MAX_AXES*2)
#define JOY3 (JOY_MAX_AXES*3)
#define BUT0 (JOY_MAX_BUTTONS*0)
#define BUT1 (JOY_MAX_BUTTONS*1)
#define BUT2 (JOY_MAX_BUTTONS*2)
#define BUT3 (JOY_MAX_BUTTONS*3)
static void
cscope_init (void)
{
int i;
fade[0] = vid_map_rgba_window (cscope_display, 0, 0, 0, 240);
for (i = 1; i < 512 * 512; i++)
fade[i] = fade[0];
}
static void
cscope_plot(int x, int y)
{
int i, j;
for (i = 0; i < 7; i++) {
for (j = 0; j < 7; j++) {
int dx = i - 3, dy = j - 3;
int r2 = dx*dx + dy*dy;
double focus = 0.2;
double intensity = 0xFF/15.0;
double alpha = 0xFF*exp(-focus*r2);
dot[i + 7*j] = vid_map_rgba_window (cscope_display,
(uint8)(intensity*(cscope_r << 4)),
(uint8)(intensity*(cscope_g << 4)),
(uint8)(intensity*(cscope_b << 4)),
(uint8)alpha);
}
}
vid_draw_window (cscope_display, x - 3, 511 - y - 3, 7, 7, dot);
}
static uint64 joystick_switches (void)
{
uint64 switches = 0777777777777LL;
if (joy_axes[JOY0] > JOY_TRIG)
switches &= ~(CCW << UR);
else if (joy_axes[JOY0] < -JOY_TRIG)
switches &= ~(CW << UR);
if (joy_axes[JOY0+1] < -JOY_TRIG)
switches &= ~(THRUST << UR);
if (joy_buttons[BUT0])
switches &= ~(FIRE << UR);
if (joy_buttons[BUT0+1])
switches &= ~(HYPER << UR);
if (joy_axes[JOY1] > JOY_TRIG)
switches &= ~(CCW << LR);
else if (joy_axes[JOY1] < -JOY_TRIG)
switches &= ~(CW << LR);
if (joy_axes[JOY1+1] < -JOY_TRIG)
switches &= ~(THRUST << LR);
if (joy_buttons[BUT1])
switches &= ~(FIRE << LR);
if (joy_buttons[BUT1+1])
switches &= ~(HYPER << LR);
if (joy_axes[JOY2] > JOY_TRIG)
switches &= ~(CCW << LL);
else if (joy_axes[JOY2] < -JOY_TRIG)
switches &= ~(CW << LL);
if (joy_axes[JOY2+1] < -JOY_TRIG)
switches &= ~(THRUST << LL);
if (joy_buttons[BUT2])
switches &= ~(FIRE << LL);
if (joy_buttons[BUT2+1])
switches &= ~(HYPER << LL);
if (joy_axes[JOY3] > JOY_TRIG)
switches &= ~((uint64)CCW << UL);
else if (joy_axes[JOY3] < -JOY_TRIG)
switches &= ~((uint64)CW << UL);
if (joy_axes[JOY3+1] < -JOY_TRIG)
switches &= ~((uint64)THRUST << UL);
if (joy_buttons[BUT3])
switches &= ~((uint64)FIRE << UL);
if (joy_buttons[BUT3+1])
switches &= ~(HYPER << UL);
return switches;
}
static uint64 keyboard_switches (void)
{
uint64 switches = 0777777777777LL; /* 1 is off */
#if 1
#define DEBUGSW(X) (void)0
#else
#define DEBUGSW(X) printf X
#endif
#define SWSW(UC, LC, BIT, POS36, FUNC36) \
if (spacewar_switches & BIT) { \
switches &= ~(((uint64)FUNC36)<<POS36); \
DEBUGSW(("mapping %#o %s %s to %03o<<%d\r\n", \
(uint32)BIT, #POS36, #FUNC36, FUNC36, POS36)); \
}
SPACEWAR_SWITCHES;
#undef SWSW
if (spacewar_switches)
DEBUGSW(("in %#lo out %#llo\r\n", spacewar_switches, switches));
return switches;
}
t_stat wcnsls_svc (UNIT *uptr)
{
vid_refresh_window (cscope_display);
vid_draw_window (cscope_display, 0, 0, 512, 512, fade);
sim_activate_after (uptr, 33333);
return SCPE_OK;
}
t_stat
wcnsls_reset (DEVICE *dptr)
{
t_stat r;
if (sim_switches & SWMASK('P') || dptr->flags & DEV_DIS ||
(wcnsls_unit->flags & UNIT_CSCOPE) == 0) {
sim_cancel (wcnsls_unit);
if (cscope_display != NULL)
vid_close_window (cscope_display);
cscope_display = NULL;
} else if (cscope_display == NULL) {
r = vid_open_window (&cscope_display, dptr, "Color scope", 512, 512, 0);
if (r != SCPE_OK)
return r;
/* Allow time for window to open and data structures to settle. */
sim_os_sleep (1);
r = vid_set_alpha_mode (cscope_display, SIM_ALPHA_BLEND);
if (r != SCPE_OK)
return r;
sim_activate_abs (wcnsls_unit, 0);
cscope_init ();
}
return SCPE_OK;
}
t_stat wcnsls_devio(uint32 dev, uint64 *data) {
switch (dev & 3) {
case CONO:
/* CONO WCNSLS,40 ;enable spacewar consoles */
sim_debug (DEBUG_CONO, &wcnsls_dev, "%06llo\n", *data);
dev420_cono = *data;
if (dev420_cono & CONO_RED)
cscope_r = (dev420_cono >> 12) & 017;
if (dev420_cono & CONO_GREEN)
cscope_g = (dev420_cono >> 6) & 017;
if (dev420_cono & CONO_BLUE)
cscope_b = dev420_cono & 017;
break;
case DATAO:
sim_debug (DEBUG_DATAIO, &wcnsls_dev, "DATAO %012llo\n", *data);
if (wcnsls_unit->flags & UNIT_CSCOPE)
cscope_plot((*data >> 9) & 0777, *data & 0777);
break;
case DATAI:
if (dev420_cono & CONO_SPCWAR) {
if (wcnsls_unit->flags & UNIT_JOY) {
*data = joystick_switches ();
} else {
*data = keyboard_switches ();
}
}
sim_debug(DEBUG_DATAIO, &wcnsls_dev, "WCNSLS %03o DATI %012llo PC=%06o\n",
dev, *data, PC);
break;
}
return SCPE_OK;
}
/*
* Old MIT Spacewar console switches
*/
#if NUM_DEVS_OCNSLS > 0
#define OCNSLS_DEVNUM 0724
t_stat ocnsls_devio(uint32 dev, uint64 *data);
const char *ocnsls_description (DEVICE *dptr);
DIB ocnsls_dib[] = {
{ OCNSLS_DEVNUM, 1, &ocnsls_devio, NULL }};
UNIT ocnsls_unit[] = {
{ UDATA (NULL, UNIT_IDLE, 0) }};
DEVICE ocnsls_dev = {
"OCNSLS", ocnsls_unit, NULL, NULL,
NUM_DEVS_OCNSLS, 0, 0, 0, 0, 0,
NULL, NULL, NULL,
NULL, NULL, NULL,
&ocnsls_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, NULL,
NULL, NULL, NULL, NULL, NULL, &ocnsls_description
};
const char *ocnsls_description (DEVICE *dptr)
{
return "Old MIT Spacewar Consoles";
}
#define OHYPER 0004LL /* Hyperspace. */
#define OFIRE 0010LL /* Fire torpedo. */
#define OCW 0020LL /* Turn clockwise. */
#define OCCW 0040LL /* Turn counter clockwise. */
#define SLOW 0100LL /* Weak thrust. */
#define FAST 0200LL /* Strong thrust. */
#define BEACON 020000LL /* Aiming beacon. */
static uint64 old_switches (void)
{
uint64 switches = 0;
if (joy_axes[JOY0] > JOY_TRIG)
switches |= OCCW;
else if (joy_axes[JOY0] < -JOY_TRIG)
switches |= OCW;
if (joy_axes[JOY0+1] < -JOY_TRIG)
switches |= FAST;
if (joy_axes[JOY0+1] > JOY_TRIG)
switches |= SLOW;
if (joy_buttons[BUT0])
switches |= OFIRE;
if (joy_buttons[BUT0+1])
switches |= OHYPER;
if (joy_buttons[BUT0+2])
switches |= BEACON;
if (joy_axes[JOY1] > JOY_TRIG)
switches |= OCCW << 18;
else if (joy_axes[JOY1] < -JOY_TRIG)
switches |= OCW << 18;
if (joy_axes[JOY1+1] < -JOY_TRIG)
switches |= FAST << 18;
if (joy_axes[JOY1+1] > JOY_TRIG)
switches |= SLOW << 18;
if (joy_buttons[BUT1])
switches |= OFIRE << 18;
if (joy_buttons[BUT1+1])
switches |= OHYPER << 18;
if (joy_buttons[BUT1+2])
switches |= BEACON << 18;
return switches;
}
t_stat ocnsls_devio(uint32 dev, uint64 *data) {
switch (dev & 3) {
case DATAI:
*data = old_switches ();
break;
case CONI:
*data = 0;
break;
}
return SCPE_OK;
}
#endif
#endif
#endif