From a33dd110181a31917739bc0a6e14cb39bad0bc18 Mon Sep 17 00:00:00 2001 From: Lars Brinkhoff Date: Fri, 31 Jan 2020 08:52:32 +0100 Subject: [PATCH 1/3] KA10: Update IMX device. - Add interrupt handling. - Add MPX. - Take input from USB devices. --- PDP10/ka10_imx.c | 255 ++++++++++++++++++++++++++++++++++++++++++++--- PDP10/kx10_dpy.c | 2 + 2 files changed, 243 insertions(+), 14 deletions(-) diff --git a/PDP10/ka10_imx.c b/PDP10/ka10_imx.c index 918a500..626a90c 100644 --- a/PDP10/ka10_imx.c +++ b/PDP10/ka10_imx.c @@ -1,6 +1,6 @@ /* ka10_imx.c: Input multplexor for A/D. - Copyright (c) 2018, Lars Brinkhoff + Copyright (c) 2018,2020, Lars Brinkhoff Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ #include #include "kx10_defs.h" +#include "sim_video.h" #ifndef NUM_DEVS_IMX #define NUM_DEVS_IMX 0 @@ -47,33 +48,78 @@ #define IMX_CHANNEL 0000177 -t_stat imx_devio(uint32 dev, uint64 *data); -const char *imx_description (DEVICE *dptr); +#define JOY_MAX_UNITS 4 +#define JOY_MAX_AXES 4 +#define JOY_NO_CHAN (IMX_CHANNEL + 1) + +t_stat imx_devio(uint32 dev, uint64 *data); +t_stat imx_svc (UNIT *uptr); +t_stat imx_reset (DEVICE *dptr); +const char *imx_description (DEVICE *dptr); +#if MPX_DEV +t_stat imx_set_mpx (UNIT *uptr, int32 val, CONST char *cptr, void *desc) ; +t_stat imx_show_mpx (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +#endif +t_stat imx_show_channel (FILE* st, UNIT* uptr, int32 val, CONST void* desc); +t_stat imx_set_channel (UNIT* uptr, int32 val, CONST char* cptr, void* desc); static uint64 status = IMX_ASSIGNED; +static uint64 imx_data; +static uint64 imx_samples; static int initial_channel = 0; static int current_channel = 0; +static int imx_mpx_lvl; + +static int imx_inputs[0200]; +static int imx_map[JOY_MAX_UNITS][JOY_MAX_AXES]; UNIT imx_unit[] = { - {UDATA(NULL, UNIT_DISABLE, 0)}, /* 0 */ + { UDATA (&imx_svc, UNIT_IDLE, 0) } }; DIB imx_dib = {IMX_DEVNUM, 1, &imx_devio, NULL}; MTAB imx_mod[] = { +#if MPX_DEV + {MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "MPX", "MPX", + &imx_set_mpx, &imx_show_mpx, NULL}, +#endif + {MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "CHANNEL", "CHANNEL", + &imx_set_channel, &imx_show_channel, NULL}, { 0 } }; DEVICE imx_dev = { "IMX", imx_unit, NULL, imx_mod, 1, 8, 0, 1, 8, 36, - NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, imx_reset, NULL, NULL, NULL, &imx_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, NULL, NULL, NULL, NULL, NULL, NULL, &imx_description }; +static void imx_joy_motion(int which, int axis, int value) +{ + int chan; + + if (which < JOY_MAX_UNITS && axis < JOY_MAX_AXES) { + chan = imx_map[which][axis]; + if (chan == JOY_NO_CHAN) + return; + + value += 32768; + + if (chan < 0) { + chan = -chan; + value = 65535 - value; + } + imx_inputs[chan] = value >> 5; + sim_debug(DEBUG_DETAIL, &imx_dev, "Channel %d value %o\n", + chan, imx_inputs[chan]); + } +} + static int imx_sample (void) { - int sample = 2048; + int sample = imx_inputs[current_channel]; if (status & IMX_SEQUENCE) current_channel = (current_channel + 1) & IMX_CHANNEL; else @@ -81,36 +127,217 @@ static int imx_sample (void) return sample; } +static void imx_activate (void) +{ + int micros; + + if (status & IMX_DONE) { + sim_cancel (imx_unit); + sim_debug(DEBUG_IRQ, &imx_dev, "Cancel\n"); + return; + } + + micros = (status >> 16) & 0377; + if (micros < 10) + micros = 10; + sim_activate_after (imx_unit, micros); + sim_debug(DEBUG_IRQ, &imx_dev, "Activate\n"); +} + +t_stat imx_reset (DEVICE *dptr) +{ + static int init = 1; + int i, j; + + if (dptr->flags & DEV_DIS) { + imx_samples = 0; + imx_data = 0; + + for (i = 0; i <= IMX_CHANNEL; i++) + imx_inputs[i] = 1000; + + for (i = 0; i < JOY_MAX_UNITS; i++) { + for (j = 0; j < JOY_MAX_UNITS; j++) + imx_map[i][j] = JOY_NO_CHAN; + } + } else { + if (init) { + vid_register_gamepad_motion_callback (imx_joy_motion); + init = 0; + } + } + return SCPE_OK; +} + t_stat imx_devio(uint32 dev, uint64 *data) { DEVICE *dptr = &imx_dev; switch(dev & 07) { case CONO|4: - status &= ~IMX_CONO; + sim_debug(DEBUG_CONO, &imx_dev, "%06llo\n", *data); + status &= ~(IMX_CONO|IMX_DONE); status |= *data & IMX_CONO; + imx_data = 0; + imx_samples = 0; current_channel = initial_channel; + clr_interrupt (IMX_DEVNUM); + imx_activate (); break; case CONI|4: - status |= IMX_DONE; *data = status & IMX_CONI; + sim_debug(DEBUG_CONI, &imx_dev, "%012llo\n", *data); break; case DATAO|4: + sim_debug(DEBUG_DATAIO, &imx_dev, "DATAO %012llo\n", *data); initial_channel = *data & IMX_CHANNEL; break; case DATAI|4: - *data = imx_sample(); - if (status & IMX_PACK) { - *data <<= 24; - *data |= imx_sample() << 12; - *data |= imx_sample(); - } + *data = imx_data; + sim_debug(DEBUG_DATAIO, &imx_dev, "DATAI %012llo\n", *data); + imx_data = 0; + imx_samples = 0; + status &= ~IMX_DONE; + clr_interrupt (IMX_DEVNUM); + sim_debug(DEBUG_IRQ, &imx_dev, "Clear interrupt\n"); + imx_activate (); break; } return SCPE_OK; } +t_stat imx_svc (UNIT *uptr) +{ + int max_samples; + + if (status & IMX_PACK) { + max_samples = 3; + } else { + max_samples = 1; + } + + if (imx_samples < max_samples) { + imx_data <<= 12; + imx_data |= imx_sample(); + imx_samples++; + } + + if (imx_samples == max_samples) { + status |= IMX_DONE; + if (status & 7) { + set_interrupt_mpx (IMX_DEVNUM, status & 7, imx_mpx_lvl); + sim_debug(DEBUG_IRQ, &imx_dev, "Raise interrupt\n"); + } + } + + imx_activate (); + + return SCPE_OK; +} + +#if MPX_DEV +/* set MPX level number */ +t_stat imx_set_mpx (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + int32 mpx; + t_stat r; + + if (cptr == NULL) + return SCPE_ARG; + mpx = (int32) get_uint (cptr, 8, 8, &r); + if (r != SCPE_OK) + return r; + imx_mpx_lvl = mpx; + return SCPE_OK; +} + +t_stat imx_show_mpx (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + if (uptr == NULL) + return SCPE_IERR; + + fprintf (st, "MPX=%o", imx_mpx_lvl); + return SCPE_OK; +} +#endif + +t_stat imx_set_channel (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + int chan, unit, axis, negate = 0; + char gbuf[CBUFSIZE]; + CONST char *tptr; + t_stat r; + + if (cptr == NULL || *cptr == 0) + return SCPE_ARG; + + tptr = get_glyph (cptr, gbuf, ';'); + if (tptr == NULL) + return SCPE_ARG; + chan = (int) get_uint (gbuf, 8, IMX_CHANNEL, &r); + if (r != SCPE_OK) + return r; + + tptr = get_glyph (tptr, gbuf, ';'); + if (tptr == NULL || strncasecmp (gbuf, "unit", 4) != 0) + return SCPE_ARG; + unit = (int) get_uint (gbuf + 4, 10, JOY_MAX_UNITS - 1, &r); + if (r != SCPE_OK) + return r; + + tptr = get_glyph (tptr, gbuf, ';'); + if (strncasecmp (gbuf, "axis", 4) != 0) + return SCPE_ARG; + axis = (int) get_uint (gbuf + 4, 10, JOY_MAX_AXES - 1, &r); + if (r != SCPE_OK) + return r; + + if (*tptr != 0) { + if (strcasecmp (tptr, "negate") != 0) + return SCPE_ARG; + negate = 1; + } + + if (negate) + chan = -chan; + imx_map[unit][axis] = chan; + + return SCPE_OK; +} + +t_stat imx_show_channel (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + int nothing = 1; + const char *negate, *comma = ""; + int chan, i, j; + + if (uptr == NULL) + return SCPE_IERR; + + for (i = 0; i < JOY_MAX_UNITS; i++) { + for (j = 0; j < JOY_MAX_AXES; j++) { + chan = imx_map[i][j]; + if (chan != JOY_NO_CHAN) { + if (chan < 0) { + chan = -chan; + negate = ";NEGATE"; + } else + negate = ""; + + fprintf (st, "%sCHANNEL=%d;JOY%d;AXIS%d%s", comma, chan, i, j, negate); + comma = ", "; + nothing = 0; + } + } + } + + if (nothing) + fprintf (st, "CHANNEL=(NO MAPPINGS)"); + + return SCPE_OK; +} + const char *imx_description (DEVICE *dptr) { return "A/D input multiplexor"; diff --git a/PDP10/kx10_dpy.c b/PDP10/kx10_dpy.c index a950a39..4fb94b4 100644 --- a/PDP10/kx10_dpy.c +++ b/PDP10/kx10_dpy.c @@ -306,6 +306,7 @@ static int joy_buttons[JOY_MAX_UNITS * JOY_MAX_BUTTONS]; static void dpy_joy_motion(int which, int axis, int value) { + int result = FALSE; if (which < JOY_MAX_UNITS && axis < JOY_MAX_AXES) { joy_axes[which * JOY_MAX_AXES + axis] = value; } @@ -313,6 +314,7 @@ static void dpy_joy_motion(int which, int axis, int value) static void dpy_joy_button(int which, int button, int state) { + int result = FALSE; if (which < JOY_MAX_UNITS && button < JOY_MAX_BUTTONS) { joy_buttons[which * JOY_MAX_UNITS + button] = state; } From 52b008dc014e821321de304c5362ab551c5411e3 Mon Sep 17 00:00:00 2001 From: Lars Brinkhoff Date: Mon, 24 Feb 2020 20:58:18 +0100 Subject: [PATCH 2/3] DISPLAY: Keep track of device using the display. Don't let someone close the display if they're not the one having opened it. --- display/display.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/display/display.c b/display/display.c index c3abcb5..346f9c7 100644 --- a/display/display.c +++ b/display/display.c @@ -369,6 +369,7 @@ static long queue_interval; #define Y(P) (((P) - points) / xpixels) static int initialized = 0; +static void *device = NULL; /* Current display device. */ /* * global set by O/S display level to indicate "light pen tip switch activated" @@ -979,6 +980,7 @@ display_init(enum display_type type, int sf, void *dptr) initialized = 1; init_failed = 0; /* hey, we made it! */ + device = dptr; return 1; failed: @@ -992,10 +994,14 @@ display_close(void *dptr) if (!initialized) return; + if (device != dptr) + return; + free (points); ws_shutdown(); initialized = 0; + device = NULL; } void From 5e99c2b53e7e8699ad920f3ed246fafed2bf950f Mon Sep 17 00:00:00 2001 From: Lars Brinkhoff Date: Mon, 24 Feb 2020 20:59:07 +0100 Subject: [PATCH 3/3] VIDEO: SDL init/quit gamecontroller subsystem implies joystick. --- sim_video.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/sim_video.c b/sim_video.c index a4fedf4..482346b 100644 --- a/sim_video.c +++ b/sim_video.c @@ -564,19 +564,24 @@ static t_stat vid_init_controllers (void) vid_gamepad_ok = (ver.major > 2 || (ver.major == 2 && (ver.minor > 0 || ver.patch >= 4))); - SDL_InitSubSystem(SDL_INIT_JOYSTICK); if (vid_gamepad_ok) SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER); + else + SDL_InitSubSystem(SDL_INIT_JOYSTICK); if (SDL_JoystickEventState (SDL_ENABLE) < 0) { - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); + if (vid_gamepad_ok) + SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); + else + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); return SCPE_IOERR; } if (vid_gamepad_ok && SDL_GameControllerEventState (SDL_ENABLE) < 0) { - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); + if (vid_gamepad_ok) + SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); + else + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); return SCPE_IOERR; } @@ -661,8 +666,10 @@ if (vid_active) { vid_gamepad_inited = 0; memset (motion_callback, 0, sizeof motion_callback); memset (button_callback, 0, sizeof button_callback); - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); + if (vid_gamepad_ok) + SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); + else + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); vid_active = FALSE; if (vid_ready) {