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.
809 lines
25 KiB
C
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
|