This fix makes sure that builds are clean when SDLlib is available at compile time for this system.
903 lines
35 KiB
C
903 lines
35 KiB
C
/* vax_vc.c: QVSS video simulator (VCB01)
|
|
|
|
Copyright (c) 2011-2013, Matt Burke
|
|
|
|
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 AUTHOR 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 author.
|
|
|
|
vc Qbus video subsystem
|
|
|
|
08-Nov-2013 MB Implemented mouse position register
|
|
06-Nov-2013 MB Increased the speed of v-sync interrupts, which
|
|
was too slow for some O/S drivers.
|
|
11-Jun-2013 MB First version
|
|
*/
|
|
|
|
#if !defined(VAX_620)
|
|
|
|
#include "vax_defs.h"
|
|
#include "sim_video.h"
|
|
#include "vax_2681.h"
|
|
|
|
/* CSR - control/status register */
|
|
|
|
BITFIELD vc_csr_bits[] = {
|
|
BIT(MOD), /* Monitor size */
|
|
#define CSR_V_MDO 0
|
|
#define CSR_MOD (1<<CSR_V_MDO)
|
|
BITNCF(1), /* unused */
|
|
BIT(VID), /* Video output en */
|
|
#define CSR_V_VID 2
|
|
#define CSR_VID (1<<CSR_V_VID)
|
|
BIT(FNC), /* Cursor function */
|
|
#define CSR_V_FNC 3
|
|
#define CSR_FNC (1<<CSR_V_FNC)
|
|
BIT(VRB), /* Video readback en */
|
|
#define CSR_V_VRB 4
|
|
#define CSR_VRB (1<<CSR_V_VRB)
|
|
BIT(TST), /* Test bit */
|
|
#define CSR_V_TST 5
|
|
#define CSR_TST (1<<CSR_V_TST)
|
|
BIT(IEN), /* Interrupt Enable */
|
|
#define CSR_V_IEN 6
|
|
#define CSR_IEN (1<<CSR_V_IEN)
|
|
BIT(CUR), /* Cursor active */
|
|
#define CSR_V_CUR 7
|
|
#define CSR_CUR (1<<CSR_V_CUR)
|
|
BIT(MSA), /* Mouse Button A */
|
|
#define CSR_V_MSA 8
|
|
#define CSR_MSA (1<<CSR_V_MSA)
|
|
BIT(MSA), /* Mouse Button B */
|
|
#define CSR_V_MSB 9
|
|
#define CSR_MSB (1<<CSR_V_MSB)
|
|
BIT(MSA), /* Mouse Button C */
|
|
#define CSR_V_MSC 10
|
|
#define CSR_MSC (1<<CSR_V_MSC)
|
|
BITF(MA,8), /* Memory Bank Switch (Base Address) */
|
|
#define CSR_V_MA 11
|
|
#define CSR_S_MA 4
|
|
#define CSR_M_MA (((1<<CSR_S_MA)-1)<<CSR_V_MA)
|
|
BITNCF(1), /* unused */
|
|
ENDBITS
|
|
};
|
|
#define CSR_RW (CSR_IEN|CSR_TST|CSR_VRB|CSR_FNC|CSR_VID)
|
|
|
|
/* ICSR - interrupt controller command/status register */
|
|
|
|
BITFIELD vc_icsr_bits[] = {
|
|
BITF(IRRVEC,3), /* IRR Vector */
|
|
#define ICSR_V_IRRVEC 0
|
|
#define ICSR_S_IRRVEC 3
|
|
#define ICSR_M_IRRVEC (((1<<ICSR_S_IRRVEC)-1)<<ICSR_V_IRRVEC)
|
|
BIT(MMS), /* Master Mask */
|
|
#define ICSR_V_MMS 3
|
|
#define ICSR_MMS (1<<ICSR_V_MMS)
|
|
BIT(INM), /* Interrupt Mode */
|
|
#define ICSR_V_INM 4
|
|
#define ICSR_INM (1<<ICSR_V_INM)
|
|
BIT(PRM), /* Priority Mode */
|
|
#define ICSR_V_PRM 5
|
|
#define ICSR_PRM (1<<ICSR_V_PRM)
|
|
BIT(ENA), /* Enable */
|
|
#define ICSR_V_ENA 6
|
|
#define ICSR_ENA (1<<ICSR_V_ENA)
|
|
BIT(GRI), /* Group Interrupt */
|
|
#define ICSR_V_GRI 7
|
|
#define ICSR_GRI (1<<ICSR_V_GRI)
|
|
BITNCF(8), /* unused */
|
|
ENDBITS
|
|
};
|
|
|
|
|
|
const char *vc_icm_rp_names[] = {"ISR", "IMR", "IRR", "ACR"};
|
|
|
|
/* mode - interrupt controller mode register */
|
|
|
|
BITFIELD vc_ic_mode_bits[] = {
|
|
BIT(PM), /* Priority Mode */
|
|
#define ICM_V_PM 0
|
|
#define ICM_PM (1<<ICM_V_PM)
|
|
BIT(PM), /* Vector Selection */
|
|
#define ICM_V_VS 1
|
|
#define ICM_VS (1<<ICM_V_VS)
|
|
BIT(IM), /* Interrupt Mode */
|
|
#define ICM_V_IM 2
|
|
#define ICM_IM (1<<ICM_V_IM)
|
|
BIT(GIP), /* Group Interrupt Polarity */
|
|
#define ICM_V_GIP 3
|
|
#define ICM_GIP (1<<ICM_V_GIP)
|
|
BIT(REQP), /* Interrupt Request Polarity */
|
|
#define ICM_V_REQP 4
|
|
#define ICM_REQP (1<<ICM_V_REQP)
|
|
BITFNAM(RP,2,vc_icm_rp_names), /* Register Preselect */
|
|
#define ICM_V_RP 5
|
|
#define ICM_S_RP 2
|
|
#define ICM_M_RP (((1<<ICM_S_RP)-1)<<ICM_V_RP)
|
|
BIT(MM), /* Master Mask */
|
|
#define ICM_V_MM 7
|
|
#define ICM_MM (1<<ICM_V_MM)
|
|
ENDBITS
|
|
};
|
|
|
|
#define CRTCP_REG 0x001F /* CRTC internal register address */
|
|
#define CRTCP_VB 0x0020 /* Vertical blank */
|
|
#define CRTCP_LPF 0x0040 /* Light pen register full */
|
|
#define CRTCP_US 0x0080 /* Update strobe */
|
|
#define CRTCP_RW CRTCP_REG
|
|
|
|
#define CRTC_HTOT 0 /* Horizontal total */
|
|
#define CRTC_HDSP 1 /* Horizontal displayed */
|
|
#define CRTC_HPOS 2 /* HSYNC position */
|
|
#define CRTC_HVWD 3 /* HSYNC/VSYNC widths */
|
|
#define CRTC_VTOT 4 /* Vertical total */
|
|
#define CRTC_VTOA 5 /* Vertical total adjust */
|
|
#define CRTC_VDSP 6 /* Vertical displayed */
|
|
#define CRTC_VPOS 7 /* VSYNC position */
|
|
#define CRTC_MODE 8 /* Mode */
|
|
#define CRTC_MSCN 9 /* Maximum scan line */
|
|
#define CRTC_CSCS 10 /* Cursor scan start */
|
|
#define CRTC_CSCE 11 /* Cursor scan end */
|
|
#define CRTC_SAH 12 /* Start address high */
|
|
#define CRTC_SAL 13 /* Start address low */
|
|
#define CRTC_CAH 14 /* Cursor address high */
|
|
#define CRTC_CAL 15 /* Cursor address low */
|
|
#define CRTC_LPPL 16 /* Light pen position low */
|
|
#define CRTC_LPPH 17 /* Light pen position high */
|
|
#define CRTC_SIZE 18 /* Number of registers */
|
|
|
|
#define IRQ_DUART 0 /* UART chip */
|
|
#define IRQ_VSYNC 1 /* VSYNC */
|
|
#define IRQ_MOUSE 2 /* Mouse movement */
|
|
#define IRQ_CSTRT 3 /* Cursor start */
|
|
#define IRQ_MBA 4 /* Mouse button A */
|
|
#define IRQ_MBB 5 /* Mouse button B */
|
|
#define IRQ_MBC 6 /* Mouse button C */
|
|
#define IRQ_SPARE 7 /* (spare) */
|
|
|
|
#define VC_XSIZE 1024 /* screen size */
|
|
#define VC_YSIZE 864
|
|
#define VC_MEMSIZE (1u << 16) /* video memory size */
|
|
|
|
#define VC_MOVE_MAX 49 /* mouse movement max (per update) */
|
|
|
|
#define VCMAP_VLD 0x80000000 /* valid */
|
|
#define VCMAP_LN 0x00000FFF /* buffer line */
|
|
|
|
#define VC_OFF(x,y) ((x >> 5) | (y << 5)) /* index into framebuffer */
|
|
#define CUR_X (vc_curx & 0x3FF) /* cursor X */
|
|
#define CUR_Y ((vc_crtc[CRTC_CAH] * \
|
|
(vc_crtc[CRTC_MSCN] + 1)) + \
|
|
vc_crtc[CRTC_CSCS]) /* cursor Y */
|
|
#define CUR_V ((vc_crtc[CRTC_CSCS] & 0x20) == 0) /* cursor visible */
|
|
#define CUR_F (vc_csr & CSR_FNC) /* cursor function */
|
|
|
|
#define VSYNC_TIME 8000 /* vertical sync interval */
|
|
|
|
#define IOLN_QVSS 0100
|
|
|
|
extern int32 int_req[IPL_HLVL];
|
|
extern int32 tmxr_poll; /* calibrated delay */
|
|
|
|
extern t_stat lk_wr (uint8 c);
|
|
extern t_stat lk_rd (uint8 *c);
|
|
extern t_stat vs_wr (uint8 c);
|
|
extern t_stat vs_rd (uint8 *c);
|
|
|
|
struct vc_int_t {
|
|
uint32 ptr;
|
|
uint32 vec[8]; /* Interrupt vectors */
|
|
uint32 irr; /* Interrupt request */
|
|
uint32 imr; /* Interrupt mask */
|
|
uint32 isr; /* Interrupt status */
|
|
uint32 acr; /* Auto-clear mask */
|
|
uint32 mode;
|
|
};
|
|
|
|
struct vc_int_t vc_intc; /* Interrupt controller */
|
|
|
|
uint32 vc_csr = 0; /* Control/status */
|
|
uint32 vc_curx = 0; /* Cursor X-position */
|
|
uint32 vc_cur_x = 0; /* Last cursor X-position */
|
|
uint32 vc_cur_y = 0; /* Last cursor Y-position */
|
|
uint32 vc_cur_f = 0; /* Last cursor function */
|
|
t_bool vc_cur_v = FALSE; /* Last cursor visible */
|
|
uint32 vc_mpos = 0; /* Mouse position */
|
|
uint32 vc_crtc[CRTC_SIZE]; /* CRTC registers */
|
|
uint32 vc_crtc_p = 0; /* CRTC pointer */
|
|
uint32 vc_icdr = 0; /* Interrupt controller data */
|
|
uint32 vc_icsr = 0; /* Interrupt controller status */
|
|
uint32 vc_map[1024]; /* Scanline map */
|
|
uint32 *vc_buf = NULL; /* Video memory */
|
|
uint8 vc_cur[256]; /* Cursor image */
|
|
|
|
DEVICE vc_dev;
|
|
t_stat vc_rd (int32 *data, int32 PA, int32 access);
|
|
t_stat vc_wr (int32 data, int32 PA, int32 access);
|
|
t_stat vc_svc (UNIT *uptr);
|
|
t_stat vc_reset (DEVICE *dptr);
|
|
t_stat vc_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc);
|
|
void vc_setint (int32 src);
|
|
int32 vc_inta (void);
|
|
void vc_clrint (int32 src);
|
|
void vc_uart_int (uint32 set);
|
|
t_stat vc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
|
char *vc_description (DEVICE *dptr);
|
|
|
|
|
|
/* QVSS data structures
|
|
|
|
vc_dev QVSS device descriptor
|
|
vc_unit QVSS unit list
|
|
vc_reg QVSS register list
|
|
vc_mod QVSS modifier list
|
|
*/
|
|
|
|
DIB vc_dib = {
|
|
IOBA_AUTO, IOLN_QVSS, &vc_rd, &vc_wr,
|
|
2, IVCL (QVSS), VEC_AUTO, { &vc_inta, &vc_inta }
|
|
};
|
|
|
|
/* Debugging Bisim_tmaps */
|
|
|
|
#define DBG_REG 0x0100 /* register activity */
|
|
#define DBG_INT0 0x0001 /* interrupt 0 */
|
|
#define DBG_INT1 0x0002 /* interrupt 1 */
|
|
#define DBG_INT2 0x0004 /* interrupt 2 */
|
|
#define DBG_INT3 0x0008 /* interrupt 3 */
|
|
#define DBG_INT4 0x0010 /* interrupt 4 */
|
|
#define DBG_INT5 0x0020 /* interrupt 5 */
|
|
#define DBG_INT6 0x0040 /* interrupt 6 */
|
|
#define DBG_INT7 0x0080 /* interrupt 7 */
|
|
#define DBG_INT 0x00FF /* interrupt 0-7 */
|
|
|
|
DEBTAB vc_debug[] = {
|
|
{"REG", DBG_REG},
|
|
{"DUART", DBG_INT0},
|
|
{"VSYNC", DBG_INT1},
|
|
{"MOUSE", DBG_INT2},
|
|
{"CSTRT", DBG_INT3},
|
|
{"MBA", DBG_INT4},
|
|
{"MBB", DBG_INT5},
|
|
{"MBC", DBG_INT6},
|
|
{"SPARE", DBG_INT7},
|
|
{"INT", DBG_INT0|DBG_INT1|DBG_INT2|DBG_INT3|DBG_INT4|DBG_INT5|DBG_INT6|DBG_INT7},
|
|
{"VMOUSE", SIM_VID_DBG_MOUSE},
|
|
{"VKEY", SIM_VID_DBG_KEY},
|
|
{"VVIDEO", SIM_VID_DBG_VIDEO},
|
|
{0}
|
|
};
|
|
|
|
UNIT vc_unit = { UDATA (&vc_svc, UNIT_IDLE, 0) };
|
|
|
|
REG vc_reg[] = {
|
|
{ HRDATADF (CSR, vc_csr, 16, "Control and status register", vc_csr_bits) },
|
|
{ HRDATAD (CURX, vc_curx, 9, "Cursor X-position") },
|
|
{ HRDATAD (MPOS, vc_mpos, 16, "Mouse position register") },
|
|
{ HRDATAD (ICDR, vc_icdr, 16, "Interrupt controller data register") },
|
|
{ HRDATADF (ICSR, vc_icsr, 16, "Interrupt controller command/status register", vc_icsr_bits) },
|
|
{ HRDATAD (IRR, vc_intc.irr, 8, "Interrupt controller request") },
|
|
{ HRDATAD (IMR, vc_intc.imr, 8, "Interrupt controller mask") },
|
|
{ HRDATAD (ISR, vc_intc.isr, 8, "Interrupt controller status") },
|
|
{ HRDATAD (ACR, vc_intc.acr, 8, "Interrupt controller Auto-clear mask") },
|
|
{ HRDATADF (MODE, vc_intc.mode, 8, "Interrupt controller mode", vc_ic_mode_bits) },
|
|
{ HRDATA (IPTR, vc_intc.ptr, 8), REG_HRO },
|
|
{ BRDATA (VEC, vc_intc.vec, 16, 32, 8) },
|
|
{ BRDATAD (CRTC, vc_crtc, 16, 8, CRTC_SIZE, "CRTC registers") },
|
|
{ HRDATAD (CRTCP, vc_crtc_p, 8, "CRTC pointer") },
|
|
{ BRDATAD (MAP, vc_map, 16, 16, 1024, "Scanline map") },
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB vc_mod[] = {
|
|
{ MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLE",
|
|
&vc_set_enable, NULL, NULL, "Enable VCB01 (QVSS)" },
|
|
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLE",
|
|
&vc_set_enable, NULL, NULL, "Disable VCB01 (QVSS)" },
|
|
{ MTAB_XTD|MTAB_VDV, 0, "RELEASEKEY", NULL,
|
|
NULL, &vid_show_release_key, NULL, "Display the window focus release key" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 004, "ADDRESS", "ADDRESS",
|
|
&set_addr, &show_addr, NULL, "Bus address" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", "VECTOR",
|
|
&set_vec, &show_vec, NULL, "Interrupt vector" },
|
|
{ 0 }
|
|
};
|
|
|
|
DEVICE vc_dev = {
|
|
"QVSS", &vc_unit, vc_reg, vc_mod,
|
|
1, DEV_RDX, 20, 1, DEV_RDX, 8,
|
|
NULL, NULL, &vc_reset,
|
|
NULL, NULL, NULL,
|
|
&vc_dib, DEV_DIS | DEV_QBUS | DEV_DEBUG, 0,
|
|
vc_debug, NULL, NULL, &vc_help, NULL, NULL,
|
|
&vc_description
|
|
};
|
|
|
|
UART2681 vc_uart = {
|
|
&vc_uart_int,
|
|
{ { &lk_wr, &lk_rd }, { &vs_wr, &vs_rd } }
|
|
};
|
|
|
|
char *vc_regnames[] = {
|
|
"CSR", /* +0 */
|
|
"CUR-X", /* +2 */
|
|
"MPOS", /* +4 */
|
|
"", /* +6 spare */
|
|
"CRTCA", /* +8 */
|
|
"CRTCD", /* +10 */
|
|
"ICDR", /* +12 */
|
|
"ICSR", /* +14 */
|
|
"", /* +16 spare */
|
|
"", /* +18 spare */
|
|
"", /* +20 spare */
|
|
"", /* +22 spare */
|
|
"", /* +24 spare */
|
|
"", /* +26 spare */
|
|
"", /* +28 spare */
|
|
"", /* +30 spare */
|
|
"UART1A2A", /* +32 */
|
|
"UARTSTCLA", /* +34 */
|
|
"UARTCMDA", /* +36 */
|
|
"UARTBUFA", /* +38 */
|
|
"", /* +40 spare */
|
|
"UARTIMSK", /* +42 */
|
|
"", /* +44 spare */
|
|
"", /* +46 spare */
|
|
"UART1B2B", /* +48 */
|
|
"UARTSTCLB", /* +50 */
|
|
"UARTCMDB", /* +52 */
|
|
"UARTBUFB", /* +54 */
|
|
"", /* +56 spare */
|
|
"", /* +56 spare */
|
|
"", /* +58 spare */
|
|
"", /* +60 spare */
|
|
"", /* +62 spare */
|
|
};
|
|
|
|
t_stat vc_rd (int32 *data, int32 PA, int32 access)
|
|
{
|
|
uint32 rg = (PA >> 1) & 0x1F;
|
|
uint32 crtc_rg, i;
|
|
|
|
*data = 0;
|
|
switch (rg) {
|
|
|
|
case 0: /* CSR */
|
|
*data = vc_csr;
|
|
break;
|
|
|
|
case 1: /* Cursor X */
|
|
*data = 0;
|
|
break;
|
|
|
|
case 2: /* Mouse position */
|
|
*data = vc_mpos;
|
|
break;
|
|
|
|
case 4: /* CRTC addr ptr */
|
|
*data = vc_crtc_p;
|
|
break;
|
|
|
|
case 5: /* CRTC data */
|
|
crtc_rg = vc_crtc_p & CRTCP_REG;
|
|
*data = vc_crtc[crtc_rg];
|
|
if ((crtc_rg == CRTC_LPPL) || (crtc_rg == CRTC_LPPH))
|
|
vc_crtc_p &= ~CRTCP_LPF; /* Clear light pen full */
|
|
break;
|
|
|
|
case 6: /* ICDR */
|
|
switch ((vc_intc.mode & ICM_M_RP) >> ICM_V_RP) {
|
|
|
|
case 0: /* ISR */
|
|
*data = vc_intc.isr;
|
|
break;
|
|
|
|
case 1: /* IMR */
|
|
*data = vc_intc.imr;
|
|
break;
|
|
|
|
case 2: /* IRR */
|
|
*data = vc_intc.irr;
|
|
break;
|
|
|
|
case 3: /* ACR */
|
|
*data = vc_intc.acr;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 7: /* ICSR */
|
|
*data = vc_icsr | 0x40; /* Chip enabled */
|
|
*data |= (vc_intc.mode & ICM_PM) ? 0x20 : 0; /* Priority mode */
|
|
*data |= (vc_intc.mode & ICM_IM) ? 0x10 : 0; /* Interrupt mode */
|
|
*data |= (vc_intc.mode & ICM_MM) ? 0x8 : 0; /* Master mask */
|
|
if (vc_icsr & 0x80) { /* Group int pending */
|
|
for (i = 0; i < 8; i++) {
|
|
if (vc_intc.isr & (1u << i)) {
|
|
*data |= i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 16: /* UART mode 1A,2A */
|
|
case 17: /* UART status/clock A */
|
|
case 18: /* UART command A */
|
|
case 19: /* UART tx/rx buf A */
|
|
case 21: /* UART interrupt status/mask */
|
|
case 24: /* UART mode 1B,2B */
|
|
case 25: /* UART status/clock B */
|
|
case 26: /* UART command B */
|
|
case 27: /* UART tx/rx buf B */
|
|
*data = ua2681_rd (&vc_uart, (rg - 16));
|
|
break;
|
|
|
|
default: /* Spares */
|
|
break;
|
|
} /* end switch PA */
|
|
sim_debug (DBG_REG, &vc_dev, "vc_rd(%s) data=0x%04X\n", vc_regnames[(PA >> 1) & 0x1F], *data);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat vc_wr (int32 data, int32 PA, int32 access)
|
|
{
|
|
uint32 rg = (PA >> 1) & 0x1F;
|
|
uint32 crtc_rg;
|
|
|
|
sim_debug (DBG_REG, &vc_dev, "vc_wr(%s) data=0x%04X\n", vc_regnames[(PA >> 1) & 0x1F], data);
|
|
switch (rg) {
|
|
|
|
case 0: /* CSR */
|
|
if ((data & CSR_IEN) && ((vc_csr & CSR_IEN) == 0)) {
|
|
sim_cancel (&vc_unit); /* reactivate with short delay */
|
|
sim_activate (&vc_unit, VSYNC_TIME); /* in case software checks for vsync */
|
|
}
|
|
vc_csr = (vc_csr & ~CSR_RW) | (data & CSR_RW);
|
|
break;
|
|
|
|
case 1: /* Cursor X */
|
|
vc_curx = data;
|
|
break;
|
|
|
|
case 2: /* Mouse position */
|
|
break;
|
|
|
|
case 4: /* CRTC addr ptr */
|
|
vc_crtc_p = (vc_crtc_p & ~CRTCP_RW) | (data & CRTCP_RW);
|
|
break;
|
|
|
|
case 5: /* CRTC data */
|
|
crtc_rg = vc_crtc_p & CRTCP_REG;
|
|
vc_crtc[crtc_rg] = data & BMASK;
|
|
break;
|
|
|
|
case 6: /* ICDR */
|
|
if (vc_intc.ptr == 8) /* IMR */
|
|
vc_intc.imr = data & 0xFFFF;
|
|
else if (vc_intc.ptr == 9) /* ACR */
|
|
vc_intc.acr = data & 0xFFFF;
|
|
else
|
|
vc_intc.vec[vc_intc.ptr] = data & 0xFFFF; /* Vector */
|
|
break;
|
|
|
|
case 7: /* ICSR */
|
|
switch ((data >> 4) & 0xF) {
|
|
|
|
case 0: /* Reset */
|
|
vc_intc.imr = 0xFF;
|
|
vc_intc.irr = 0;
|
|
vc_intc.isr = 0;
|
|
vc_intc.acr = 0;
|
|
break;
|
|
|
|
case 2: /* Clear IRR & IMR */
|
|
if (data & 0x8) { /* one bit */
|
|
vc_intc.irr &= ~(1u << (data & 0x7));
|
|
vc_intc.imr &= ~(1u << (data & 0x7));
|
|
}
|
|
else { /* all bits */
|
|
vc_intc.irr = 0;
|
|
vc_intc.imr = 0;
|
|
}
|
|
break;
|
|
|
|
case 3: /* Set IMR */
|
|
if (data & 0x8) /* one bit */
|
|
vc_intc.imr |= (1u << (data & 0x7));
|
|
else /* all bits */
|
|
vc_intc.imr = 0xFF;
|
|
break;
|
|
|
|
case 4: /* Clear IRR */
|
|
if (data & 0x8) /* one bit */
|
|
vc_intc.irr &= ~(1u << (data & 0x7));
|
|
else /* all bits */
|
|
vc_intc.irr = 0;
|
|
break;
|
|
|
|
case 6: /* Clear highest priority ISR */
|
|
break;
|
|
|
|
case 7: /* Clear ISR */
|
|
if (data & 0x8) /* one bit */
|
|
vc_intc.isr &= ~(1u << (data & 0x7));
|
|
else /* all bits */
|
|
vc_intc.isr = 0;
|
|
break;
|
|
|
|
case 8: /* Load mode bits */
|
|
case 9:
|
|
vc_intc.mode &= ~0x1F | (data & 0x1F);
|
|
break;
|
|
|
|
case 10: /* Control mode bits */
|
|
vc_intc.mode &= ~0x60 | ((data << 3) & 0x60); /* mode<06:05> = data<03:02> */
|
|
if (((data & 0x3) == 0x1) || ((data & 0x3) == 2))
|
|
vc_intc.mode &= ~0x80 | ((data << 7) & 0x80);
|
|
break;
|
|
|
|
case 11: /* Preselect IMR */
|
|
vc_intc.ptr = 8;
|
|
break;
|
|
|
|
case 12: /* Preselect ACR */
|
|
vc_intc.ptr = 9;
|
|
break;
|
|
|
|
case 14: /* Preselect response mem */
|
|
vc_intc.ptr = (data & 0x7);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 16: /* UART mode 1A,2A */
|
|
case 17: /* UART status/clock A */
|
|
case 18: /* UART command A */
|
|
case 19: /* UART tx/rx buf A (keyboard) */
|
|
case 21: /* UART interrupt status/mask */
|
|
case 24: /* UART mode 1B,2B */
|
|
case 25: /* UART status/clock B */
|
|
case 26: /* UART command B */
|
|
case 27: /* UART tx/rx buf B (mouse) */
|
|
ua2681_wr (&vc_uart, (rg - 16), data);
|
|
break;
|
|
|
|
default: /* Spares */
|
|
break;
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
extern jmp_buf save_env;
|
|
extern int32 p1;
|
|
|
|
int32 vc_mem_rd (int32 pa)
|
|
{
|
|
uint32 rg = (pa >> 2) & 0xFFFF;
|
|
|
|
if (!vc_buf) /* QVSS disabled? */
|
|
MACH_CHECK (MCHK_READ); /* Invalid memory reference */
|
|
|
|
return vc_buf[rg];
|
|
}
|
|
|
|
void vc_mem_wr (int32 pa, int32 val, int32 lnt)
|
|
{
|
|
uint32 rg = (pa >> 2) & 0xFFFF;
|
|
uint32 nval;
|
|
int32 i;
|
|
int32 sc;
|
|
uint32 scrln, bufln;
|
|
uint32 idx;
|
|
|
|
if (!vc_buf) /* QVSS disabled? */
|
|
MACH_CHECK (MCHK_WRITE); /* Invalid memory reference */
|
|
|
|
if (lnt < L_LONG) {
|
|
uint32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF;
|
|
uint32 t = vc_buf[rg];
|
|
sc = (pa & 3) << 3;
|
|
nval = ((val & mask) << sc) | (t & ~(mask << sc));
|
|
}
|
|
else nval = (uint32)val;
|
|
|
|
if (rg >= 0xFFF8) { /* cursor image */
|
|
idx = (pa << 3) & 0xFF; /* get byte index */
|
|
for (i = 0; i < (lnt << 3); i++)
|
|
vc_cur[idx++] = (val >> i) & 1; /* 1bpp to 8bpp */
|
|
}
|
|
else if (rg >= 0xFE00) { /* scanline map */
|
|
if (vc_buf[rg] != nval) {
|
|
scrln = (pa >> 1) & 0x3FF; /* screen line */
|
|
sc = (scrln & 1) ? 16 : 0; /* odd line? (upper word) */
|
|
bufln = (nval >> sc) & 0x7FF; /* buffer line */
|
|
vc_map[scrln] = bufln; /* update map */
|
|
|
|
if (lnt > L_WORD) { /* remapping 2 lines? */
|
|
scrln++; /* next screen line */
|
|
bufln = (val >> 16) & 0x7FF; /* buffer line */
|
|
vc_map[scrln] = bufln; /* update map */
|
|
}
|
|
}
|
|
}
|
|
bufln = rg / 32;
|
|
for (scrln = 0; scrln < 1024; scrln++) {
|
|
if ((vc_map[scrln] & 0x7FF) == bufln) {
|
|
vc_map[scrln] = vc_map[scrln] & ~VCMAP_VLD; /* invalidate map */
|
|
}
|
|
}
|
|
vc_buf[rg] = nval;
|
|
}
|
|
|
|
SIM_INLINE void vc_invalidate (uint32 y1, uint32 y2)
|
|
{
|
|
uint32 ln;
|
|
for (ln = y1; ln < y2; ln++)
|
|
vc_map[ln] = vc_map[ln] & ~VCMAP_VLD; /* invalidate map entry */
|
|
}
|
|
|
|
void vc_checkint (void)
|
|
{
|
|
uint32 i;
|
|
uint32 msk = (vc_intc.irr & ~vc_intc.imr); /* unmasked interrutps */
|
|
vc_icsr &= ~(ICSR_GRI|ICSR_M_IRRVEC); /* clear GRI & vector */
|
|
|
|
if ((vc_intc.mode & 0x80) && ~(vc_intc.mode & 0x4)) { /* group int MM & not polled */
|
|
for (i = 0; i < 8; i++) {
|
|
if (msk & (1u << i)) {
|
|
vc_icsr |= (ICSR_GRI | i);
|
|
}
|
|
}
|
|
if ((vc_csr & CSR_IEN) && (vc_icsr & ICSR_GRI)) {
|
|
if (!(int_req[IPL_QVSS] & (INT_QVSS))) {
|
|
sim_debug (DBG_INT, &vc_dev, "vc_checkint(SET_INT) icsr=0x%x\n", vc_icsr);
|
|
}
|
|
SET_INT (QVSS);
|
|
}
|
|
else {
|
|
if ((int_req[IPL_QVSS] & (INT_QVSS))) {
|
|
sim_debug (DBG_INT, &vc_dev, "vc_checkint(CLR_INT)\n");
|
|
}
|
|
CLR_INT (QVSS);
|
|
}
|
|
}
|
|
else {
|
|
if ((int_req[IPL_QVSS] & (INT_QVSS))) {
|
|
sim_debug (DBG_INT, &vc_dev, "vc_checkint(CLR_INT)\n");
|
|
}
|
|
CLR_INT (QVSS);
|
|
}
|
|
}
|
|
|
|
void vc_clrint (int32 src)
|
|
{
|
|
uint32 msk = (1u << src);
|
|
vc_intc.irr &= ~msk;
|
|
vc_intc.isr &= ~msk;
|
|
sim_debug (msk, &vc_dev, "vc_clrint(%d)\n", src);
|
|
vc_checkint ();
|
|
}
|
|
|
|
void vc_setint (int32 src)
|
|
{
|
|
uint32 msk = (1u << src);
|
|
vc_intc.irr |= msk;
|
|
sim_debug (msk, &vc_dev, "vc_setint(%d)\n", src);
|
|
vc_checkint ();
|
|
}
|
|
|
|
void vc_uart_int (uint32 set)
|
|
{
|
|
if (set)
|
|
vc_setint (IRQ_DUART);
|
|
else
|
|
vc_clrint (IRQ_DUART);
|
|
}
|
|
|
|
int32 vc_inta (void)
|
|
{
|
|
uint32 i;
|
|
uint32 msk = (vc_intc.irr & ~vc_intc.imr); /* unmasked interrutps */
|
|
int32 result;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
if (msk & (1u << i)) {
|
|
vc_intc.irr &= ~(1u << i);
|
|
if (vc_intc.acr & (1u << i))
|
|
vc_intc.isr &= ~(1u << i);
|
|
else vc_intc.isr |= (1u << i);
|
|
vc_checkint();
|
|
result = (vc_intc.vec[i] + VEC_Q);
|
|
sim_debug (DBG_INT, &vc_dev, "Int Ack Vector: 0%03o (0x%X)\n", result, result);
|
|
return result;
|
|
}
|
|
}
|
|
sim_debug (DBG_INT, &vc_dev, "Int Ack Vector: 0%03o\n", 0);
|
|
return 0; /* no intr req */
|
|
}
|
|
|
|
t_stat vc_svc (UNIT *uptr)
|
|
{
|
|
t_bool updated = FALSE; /* flag for refresh */
|
|
uint32 line[1024];
|
|
uint32 ln, col, off;
|
|
int32 xpos, ypos, dx, dy;
|
|
uint8 *cur;
|
|
|
|
vc_crtc_p = vc_crtc_p ^ CRTCP_VB; /* Toggle VBI */
|
|
vc_crtc_p = vc_crtc_p | CRTCP_LPF; /* Light pen full */
|
|
|
|
if (vc_cur_v != CUR_V) { /* visibility changed? */
|
|
if (CUR_V) /* visible? */
|
|
vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */
|
|
else
|
|
vc_invalidate (vc_cur_y, (vc_cur_y + 16)); /* invalidate old pos */
|
|
}
|
|
else if (vc_cur_y != CUR_Y) { /* moved (Y)? */
|
|
vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */
|
|
vc_invalidate (vc_cur_y, (vc_cur_y + 16)); /* invalidate old pos */
|
|
}
|
|
else if ((vc_cur_x != CUR_X) || (vc_cur_f != CUR_F)) { /* moved (X) or mask changed? */
|
|
vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */
|
|
}
|
|
|
|
vc_cur_x = CUR_X; /* store cursor data */
|
|
vc_cur_y = CUR_Y;
|
|
vc_cur_v = CUR_V;
|
|
vc_cur_f = CUR_F;
|
|
|
|
xpos = vc_mpos & 0xFF; /* get current mouse position */
|
|
ypos = (vc_mpos >> 8) & 0xFF;
|
|
dx = vid_mouse_xrel; /* get relative movement */
|
|
dy = vid_mouse_yrel;
|
|
if (dx > VC_MOVE_MAX) /* limit movement */
|
|
dx = VC_MOVE_MAX;
|
|
else if (dx < -VC_MOVE_MAX)
|
|
dx = -VC_MOVE_MAX;
|
|
if (dy > VC_MOVE_MAX)
|
|
dy = VC_MOVE_MAX;
|
|
else if (dy < -VC_MOVE_MAX)
|
|
dy = -VC_MOVE_MAX;
|
|
xpos += dx; /* add to counters */
|
|
ypos += dy;
|
|
vc_mpos = ((ypos & 0xFF) << 8) | (xpos & 0xFF); /* update register */
|
|
vid_mouse_xrel = 0; /* reset counters for next poll */
|
|
vid_mouse_yrel = 0;
|
|
|
|
vc_csr |= (CSR_MSA | CSR_MSB | CSR_MSC); /* reset button states */
|
|
if (vid_mouse_b3) /* set new button states */
|
|
vc_csr &= ~CSR_MSA;
|
|
if (vid_mouse_b2)
|
|
vc_csr &= ~CSR_MSB;
|
|
if (vid_mouse_b1)
|
|
vc_csr &= ~CSR_MSC;
|
|
|
|
for (ln = 0; ln < VC_YSIZE; ln++) {
|
|
if ((vc_map[ln] & VCMAP_VLD) == 0) { /* line invalid? */
|
|
off = vc_map[ln] * 32; /* get video buf offet */
|
|
for (col = 0; col < 1024; col++)
|
|
line[col] = vid_mono_palette[(vc_buf[off + (col >> 5)] >> (col & 0x1F)) & 1];
|
|
/* 1bpp to 32bpp */
|
|
if (CUR_V) { /* cursor visible? */
|
|
if ((ln >= CUR_Y) && (ln < (CUR_Y + 16))) { /* cursor on this line? */
|
|
cur = &vc_cur[((ln - CUR_Y) << 4)]; /* get image base */
|
|
for (col = 0; col < 16; col++) {
|
|
if ((CUR_X + col) >= 1024) /* Part of cursor off screen? */
|
|
continue; /* Skip */
|
|
if (CUR_F) /* mask function */
|
|
line[CUR_X + col] = vid_mono_palette[(line[CUR_X + col] == vid_mono_palette[1]) | (cur[col] & 1)];
|
|
else
|
|
line[CUR_X + col] = vid_mono_palette[(line[CUR_X + col] == vid_mono_palette[1]) & (~cur[col] & 1)];
|
|
}
|
|
}
|
|
}
|
|
vid_draw (0, ln, 1024, 1, &line[0]); /* update line */
|
|
updated = TRUE;
|
|
vc_map[ln] = vc_map[ln] | VCMAP_VLD; /* set valid */
|
|
}
|
|
}
|
|
|
|
if (updated) /* video updated? */
|
|
vid_refresh (); /* put to screen */
|
|
|
|
ua2681_svc (&vc_uart); /* service DUART */
|
|
vc_setint (IRQ_VSYNC); /* VSYNC int */
|
|
sim_clock_coschedule (uptr, tmxr_poll); /* reactivate */
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat vc_reset (DEVICE *dptr)
|
|
{
|
|
uint32 i;
|
|
t_stat r;
|
|
|
|
CLR_INT (QVSS); /* clear int req */
|
|
sim_cancel (&vc_unit); /* stop poll */
|
|
ua2681_reset (&vc_uart); /* reset DUART */
|
|
|
|
vc_intc.ptr = 0; /* interrupt controller */
|
|
vc_intc.irr = 0;
|
|
vc_intc.imr = 0xFF;
|
|
vc_intc.isr = 0;
|
|
vc_intc.acr = 0;
|
|
vc_intc.mode = 0x80;
|
|
vc_icsr = 0;
|
|
|
|
vc_csr = (((QVMBASE >> QVMAWIDTH) & ((1<<CSR_S_MA)-1)) << CSR_V_MA) | CSR_MOD;
|
|
vc_curx = 0;
|
|
vc_mpos = 0;
|
|
|
|
for (i = 0; i < CRTC_SIZE; i++)
|
|
vc_crtc[i] = 0;
|
|
vc_crtc[CRTC_CSCS] = 0x20; /* hide cursor */
|
|
vc_crtc_p = (CRTCP_LPF | CRTCP_VB);
|
|
|
|
if (dptr->flags & DEV_DIS) {
|
|
free (vc_buf);
|
|
vc_buf = NULL;
|
|
return vid_close ();
|
|
}
|
|
|
|
if (!vid_active) {
|
|
r = vid_open (dptr, VC_XSIZE, VC_YSIZE); /* display size */
|
|
if (r != SCPE_OK)
|
|
return r;
|
|
vc_buf = (uint32 *) calloc (VC_MEMSIZE, sizeof (uint32));
|
|
if (vc_buf == NULL) {
|
|
vid_close ();
|
|
return SCPE_MEM;
|
|
}
|
|
printf ("QVSS Display Created. ");
|
|
vid_show_release_key (stdout, NULL, 0, NULL);
|
|
printf ("\n");
|
|
if (sim_log) {
|
|
fprintf (sim_log, "QVSS Display Created. ");
|
|
vid_show_release_key (sim_log, NULL, 0, NULL);
|
|
fprintf (sim_log, "\n");
|
|
}
|
|
}
|
|
sim_activate_abs (&vc_unit, tmxr_poll);
|
|
return auto_config (NULL, 0); /* run autoconfig */
|
|
}
|
|
|
|
t_stat vc_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc)
|
|
{
|
|
return cpu_set_model (NULL, 0, (val ? "VAXSTATION" : "MICROVAX"), NULL);
|
|
}
|
|
|
|
t_stat vc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)
|
|
{
|
|
fprintf (st, "VCB01 Monochrome Video Subsystem (%s)\n\n", dptr->name);
|
|
fprintf (st, "Use the Control-Right-Shift key combination to regain focus from the simulated\n");
|
|
fprintf (st, "video display\n");
|
|
fprint_set_help (st, dptr);
|
|
fprint_show_help (st, dptr);
|
|
fprint_reg_help (st, dptr);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
char *vc_description (DEVICE *dptr)
|
|
{
|
|
return "VCB01 Monochrome Graphics Adapter";
|
|
}
|
|
|
|
#endif /* !VAX_620 */
|