233 lines
7.5 KiB
C
233 lines
7.5 KiB
C
/* kx10_dk.c: PDP-10 DK subsystem simulator
|
|
|
|
Copyright (c) 2013-2020, Richard Cornwell
|
|
|
|
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
|
|
RICHARD CORNWELL 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 Richard Cornwell 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.
|
|
|
|
*/
|
|
|
|
#include "kx10_defs.h"
|
|
|
|
#ifndef NUM_DEVS_DK
|
|
#define NUM_DEVS_DK 0
|
|
#endif
|
|
|
|
#if (NUM_DEVS_DK > 0)
|
|
|
|
#define DK_DEVNUM 070
|
|
#define STAT_REG u3
|
|
#define CLK_REG u4
|
|
#define INT_REG u5
|
|
#define CLK_TIM u6
|
|
|
|
/* CONO */
|
|
#define PIA 000007
|
|
#define CLK_CLR_FLG 000010 /* Clear Clock flag */
|
|
#define CLK_CLR_OVF 000020 /* Clear OVFL flag */
|
|
#define CLK_SET_EN 000040 /* Enable Clock */
|
|
#define CLK_CLR_EN 000100 /* Disable Clock */
|
|
#define CLK_SET_PI 000200 /* Set PI Control Flip-Flop */
|
|
#define CLK_CLR_PI 000400 /* Clear PI Control Flip-Flop */
|
|
#define CLK_GEN_CLR 001000 /* Clear control */
|
|
#define CLK_ADD_ONE 002000 /* Bump clock */
|
|
#define CLK_SET_FLG 004000 /* Set Clock Flag */
|
|
#define CLK_SET_OVF 010000 /* Set OVFL Flag */
|
|
|
|
/* CONI */
|
|
#define CLK_FLG 000010
|
|
#define CLK_OVF 000020
|
|
#define CLK_EN 000040
|
|
#define CLK_PI 000200
|
|
#define CLK_EXT 001000
|
|
|
|
t_stat dk_devio(uint32 dev, uint64 *data);
|
|
void dk_test (UNIT *uptr);
|
|
t_stat dk_svc (UNIT *uptr);
|
|
const char *dk_description (DEVICE *dptr);
|
|
|
|
DIB dk_dib[] = {
|
|
{ DK_DEVNUM, 1, &dk_devio, NULL },
|
|
{ DK_DEVNUM + 4, 1, &dk_devio, NULL}};
|
|
|
|
UNIT dk_unit[] = {
|
|
{UDATA (&dk_svc, UNIT_IDLE, 0) },
|
|
#if (NUM_DEVS_DK > 1)
|
|
{UDATA (&dk_svc, UNIT_IDLE, 0) },
|
|
#endif
|
|
};
|
|
|
|
DEVICE dk_dev = {
|
|
"DK", dk_unit, NULL, NULL,
|
|
NUM_DEVS_DK, 0, 0, 0, 0, 0,
|
|
NULL, NULL, NULL,
|
|
NULL, NULL, NULL,
|
|
&dk_dib, DEV_DISABLE | DEV_DEBUG | DEV_DIS, 0, dev_debug,
|
|
NULL, NULL, NULL, NULL, NULL, &dk_description
|
|
};
|
|
|
|
t_stat dk_devio(uint32 dev, uint64 *data) {
|
|
int unit = (dev - DK_DEVNUM) >> 2;
|
|
UNIT *uptr;
|
|
double us;
|
|
int32 t;
|
|
|
|
if (unit < 0 || unit >= NUM_DEVS_DK)
|
|
return SCPE_OK;
|
|
uptr = &dk_unit[unit];
|
|
switch (dev & 3) {
|
|
case CONI:
|
|
*data = (uint64)(uptr->STAT_REG);
|
|
*data |= ((uint64)uptr->INT_REG) << 18;
|
|
sim_debug(DEBUG_CONI, &dk_dev, "DK %03o CONI %06o PC=%o %06o\n",
|
|
dev, (uint32)*data, PC, uptr->CLK_REG);
|
|
break;
|
|
|
|
case CONO:
|
|
/* Adjust U3 */
|
|
clr_interrupt(dev);
|
|
uptr->STAT_REG &= ~07;
|
|
if (*data & CLK_GEN_CLR) {
|
|
uptr->CLK_REG = 0;
|
|
uptr->STAT_REG = 0;
|
|
sim_cancel(uptr);
|
|
}
|
|
uptr->STAT_REG |= (uint32)(*data & 07);
|
|
|
|
if (*data & CLK_ADD_ONE) {
|
|
if ((uptr->STAT_REG & CLK_EN) == 0) {
|
|
uptr->CLK_REG++;
|
|
dk_test(uptr);
|
|
}
|
|
}
|
|
|
|
if (*data & CLK_SET_EN)
|
|
uptr->STAT_REG |= CLK_EN;
|
|
if (*data & CLK_CLR_EN)
|
|
uptr->STAT_REG &= ~CLK_EN;
|
|
if (*data & CLK_SET_OVF)
|
|
uptr->STAT_REG |= CLK_OVF;
|
|
if (*data & CLK_CLR_OVF)
|
|
uptr->STAT_REG &= ~CLK_OVF;
|
|
if (*data & CLK_SET_FLG)
|
|
uptr->STAT_REG |= CLK_FLG;
|
|
if (*data & CLK_CLR_FLG)
|
|
uptr->STAT_REG &= ~CLK_FLG;
|
|
if (*data & CLK_SET_PI)
|
|
uptr->STAT_REG |= CLK_PI;
|
|
if (*data & CLK_CLR_PI)
|
|
uptr->STAT_REG &= ~CLK_PI;
|
|
|
|
if ((uptr->STAT_REG & CLK_EN) != 0 &&
|
|
(uptr->STAT_REG & (CLK_FLG|CLK_OVF))) {
|
|
set_interrupt(dev, uptr->STAT_REG);
|
|
}
|
|
|
|
set_clock:
|
|
if (sim_is_active(uptr)) { /* Save current clock time */
|
|
us = sim_activate_time_usecs(uptr);
|
|
uptr->CLK_REG += uptr->CLK_TIM - (uint32)(us / 10.0);
|
|
sim_cancel(uptr);
|
|
}
|
|
if (uptr->INT_REG == uptr->CLK_REG) {
|
|
uptr->STAT_REG |= CLK_FLG;
|
|
set_interrupt(dev, uptr->STAT_REG);
|
|
}
|
|
if (uptr->STAT_REG & CLK_EN) {
|
|
if (uptr->INT_REG < uptr->CLK_REG) /* Count until overflow */
|
|
uptr->CLK_TIM = 01000000;
|
|
else
|
|
uptr->CLK_TIM = uptr->INT_REG;
|
|
t = uptr->CLK_TIM - uptr->CLK_REG;
|
|
us = (double)(t) * 10.0;
|
|
sim_activate_after_d(uptr, us);
|
|
} else {
|
|
sim_cancel(uptr);
|
|
}
|
|
sim_debug(DEBUG_CONO, &dk_dev, "DK %03o CONO %06o PC=%06o %06o\n",
|
|
dev, (uint32)*data, PC, uptr->STAT_REG);
|
|
break;
|
|
|
|
case DATAO:
|
|
uptr->INT_REG = (uint32)(*data & RMASK);
|
|
sim_debug(DEBUG_DATAIO, &dk_dev, "DK %03o DATO %012llo PC=%06o\n",
|
|
dev, *data, PC);
|
|
goto set_clock;
|
|
|
|
case DATAI:
|
|
if (sim_is_active(uptr)) { /* Save current clock time */
|
|
double us = sim_activate_time_usecs(uptr);
|
|
uptr->CLK_REG += uptr->CLK_TIM - (uint32)(us / 10.0);
|
|
sim_cancel(uptr);
|
|
}
|
|
*data = (uint64)(uptr->CLK_REG);
|
|
sim_debug(DEBUG_DATAIO, &dk_dev, "DK %03o DATI %012llo PC=%06o\n",
|
|
dev, *data, PC);
|
|
goto set_clock;
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Bump counter by 1 */
|
|
void dk_test (UNIT *uptr)
|
|
{
|
|
int dev;
|
|
double us;
|
|
int32 t;
|
|
|
|
if (uptr->CLK_REG & (~RMASK))
|
|
uptr->STAT_REG |= CLK_OVF;
|
|
uptr->CLK_REG &= RMASK;
|
|
if (uptr->INT_REG == uptr->CLK_REG) {
|
|
uptr->STAT_REG |= CLK_FLG;
|
|
uptr->CLK_REG = 0;
|
|
}
|
|
if (uptr->STAT_REG & (CLK_FLG|CLK_OVF)) {
|
|
dev = ((uptr - dk_unit) << 2) + DK_DEVNUM;
|
|
set_interrupt(dev, uptr->STAT_REG);
|
|
}
|
|
if (uptr->STAT_REG & CLK_EN) {
|
|
if (uptr->INT_REG < uptr->CLK_REG) /* Count until overflow */
|
|
uptr->CLK_TIM = 01000000;
|
|
else
|
|
uptr->CLK_TIM = uptr->INT_REG;
|
|
t = uptr->CLK_TIM - uptr->CLK_REG;
|
|
us = (double)(t) * 10.0;
|
|
sim_activate_after_d(uptr, us);
|
|
}
|
|
}
|
|
|
|
/* Timer service - */
|
|
t_stat dk_svc (UNIT *uptr)
|
|
{
|
|
uptr->CLK_REG = uptr->CLK_TIM;
|
|
dk_test (uptr);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
const char *dk_description (DEVICE *dptr)
|
|
{
|
|
return "DK10 Timer module";
|
|
}
|
|
|
|
|
|
#endif
|