1113 lines
46 KiB
C
1113 lines
46 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
|
|
|
|
Related documents:
|
|
|
|
AZ-GLFAB-MN - VAXstation II Technical Manual, BA23 Enclosure (Appendix C)
|
|
*/
|
|
|
|
#if !defined(VAX_620)
|
|
|
|
#include "vax_defs.h"
|
|
#include "sim_video.h"
|
|
#include "vax_2681.h"
|
|
#include "vax_lk.h"
|
|
#include "vax_vs.h"
|
|
|
|
/* CSR - control/status register */
|
|
|
|
BITFIELD vc_csr_bits[] = {
|
|
BIT(MOD), /* Monitor size (1 -> VR260(19"), 0 -> (15") */
|
|
#define CSR_V_MOD 0
|
|
#define CSR_MOD (1<<CSR_V_MOD)
|
|
BITNCF(1), /* unused */
|
|
BIT(VID), /* Video output Enable */
|
|
#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 Enable */
|
|
#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 (0->AND, 1->OR) */
|
|
|
|
#define VSYNC_TIME 8000 /* vertical sync interval */
|
|
|
|
#define IOLN_QVSS 0100
|
|
|
|
extern int32 tmxr_poll; /* calibrated delay */
|
|
|
|
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 (0->AND, 1->OR) */
|
|
t_bool vc_cur_v = FALSE; /* Last cursor visible */
|
|
t_bool vc_cur_new_data = FALSE; /* New Cursor image data */
|
|
t_bool vc_input_captured = FALSE; /* Mouse and Keyboard input captured in video window */
|
|
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; /* Scanline map */
|
|
uint32 *vc_buf = NULL; /* Video memory */
|
|
uint32 *vc_lines = NULL; /* Video Display Lines */
|
|
uint8 vc_cur[256]; /* Cursor image */
|
|
uint32 vc_palette[2]; /* Monochrome palette */
|
|
t_bool vc_active = FALSE;
|
|
|
|
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_detach (UNIT *dptr);
|
|
t_stat vc_set_enable (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat vc_set_capture (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat vc_show_capture (FILE* st, UNIT* uptr, int32 val, CONST 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, const char *cptr);
|
|
const 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 Bitmaps */
|
|
|
|
#define DBG_REG 0x0100 /* register activity */
|
|
#define DBG_CRTC 0x0200 /* crtc register activity */
|
|
#define DBG_CURSOR 0x0400 /* Cursor content, function and visibility activity */
|
|
#define DBG_TCURSOR 0x0800 /* Cursor content, function and visibility activity */
|
|
#define DBG_SCANL 0x1000 /* Scanline map 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, "Register activity"},
|
|
{"CRTC", DBG_CRTC, "CRTC register activity"},
|
|
{"CURSOR", DBG_CURSOR, "Cursor content, function and visibility activity"},
|
|
{"TCURSOR", DBG_TCURSOR, "Cursor content, function and visibility activity"},
|
|
{"SCANL", DBG_SCANL, "Scanline map activity"},
|
|
{"DUART", DBG_INT0, "interrupt 0"},
|
|
{"VSYNC", DBG_INT1, "interrupt 1"},
|
|
{"MOUSE", DBG_INT2, "interrupt 2"},
|
|
{"CSTRT", DBG_INT3, "interrupt 3"},
|
|
{"MBA", DBG_INT4, "interrupt 4"},
|
|
{"MBB", DBG_INT5, "interrupt 5"},
|
|
{"MBC", DBG_INT6, "interrupt 6"},
|
|
{"SPARE", DBG_INT7, "interrupt 7"},
|
|
{"INT", DBG_INT0|DBG_INT1|DBG_INT2|DBG_INT3|DBG_INT4|DBG_INT5|DBG_INT6|DBG_INT7, "interrupt 0-7"},
|
|
{"VMOUSE", SIM_VID_DBG_MOUSE, "Video Mouse"},
|
|
{"VCURSOR", SIM_VID_DBG_CURSOR, "Video Cursor"},
|
|
{"VKEY", SIM_VID_DBG_KEY, "Video Key"},
|
|
{"VVIDEO", SIM_VID_DBG_VIDEO, "Video 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") },
|
|
{ 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, TRUE, NULL, "CAPTURE",
|
|
&vc_set_capture, &vc_show_capture, NULL, "Enable Captured Input Mode" },
|
|
{ MTAB_XTD|MTAB_VDV, FALSE, NULL, "NOCAPTURE",
|
|
&vc_set_capture, NULL, NULL, "Disable Captured Input Mode" },
|
|
{ MTAB_XTD|MTAB_VDV, TRUE, "OSCURSOR", NULL,
|
|
NULL, &vc_show_capture, NULL, "Display Input Capture mode" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "VIDEO", NULL,
|
|
NULL, &vid_show_video, NULL, "Display the host system video capabilities" },
|
|
{ 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, &vc_detach,
|
|
&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, NULL,
|
|
{ { &lk_wr, &lk_rd }, { &vs_wr, &vs_rd } }
|
|
};
|
|
|
|
const 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 */
|
|
};
|
|
|
|
const char *vc_crtc_regnames[] = {
|
|
"HTOT", /* Horizontal Total The total number of character times in a line, minus 1 */
|
|
"HDSP", /* Horizontal Displayed The total number of displayed characters in a line. */
|
|
"HPOS", /* HSYNC Position Defines the number of character times until HSYNC (horizontal sync). */
|
|
"HVWD", /* HSYNC/VSYNC Widths Four bits each are used to define the HSYNC
|
|
pulse width and the VSYNC (vertical sync) pulse width. */
|
|
"VTOT", /* Vertical Total Total number of character rows on the screen, minus 1. */
|
|
"VTOA", /* Vertical Total Adjust The number of scan lines to complete the screen. */
|
|
"VDSP", /* Vertical Displayed The number of character rows displayed. */
|
|
"VPOS", /* VSYNC Position The number of character rows until VSYNC. */
|
|
"MODE", /* Mode Controls addressing, interlace, and cursor. */
|
|
"MSCN", /* Maximum Scan Line The number of scan lines in a character row, minus 1. */
|
|
"CSCS", /* Cursor Scan Start Defines the scan line at which the cursor starts. */
|
|
"CSCE", /* Cursor Scan End Defines where the cursor ends. */
|
|
"SAH", /* Start Address High Defines the RAM location where video refresh */
|
|
"SAL", /* Start Address Low begins. */
|
|
"CAH", /* Cursor Address High Defines the cursor position in RAM. */
|
|
"CAL", /* Cursor Address Low */
|
|
"LPPL", /* Light Pen Position High Contains the position of the light pen. */
|
|
"LPPH", /* Light Pen Position Low */
|
|
"18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"
|
|
};
|
|
|
|
|
|
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;
|
|
sim_debug (DBG_CRTC, &vc_dev, "CRTC-Addr Read: %d - %s\n", vc_crtc_p, vc_crtc_regnames[vc_crtc_p & CRTCP_REG]);
|
|
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 */
|
|
sim_debug (DBG_CRTC, &vc_dev, "CRTC-Data:%s[%d] Read: 0x%x\n", vc_crtc_regnames[crtc_rg], crtc_rg, *data);
|
|
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;
|
|
uint32 old_data;
|
|
|
|
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 */
|
|
}
|
|
old_data = vc_csr;
|
|
vc_csr = (vc_csr & ~CSR_RW) | (data & CSR_RW);
|
|
if ((vc_csr ^ old_data) & CSR_FNC) {
|
|
sim_debug (DBG_CURSOR, &vc_dev, "Cursor Function changed to: %s\n", CUR_F ? "OR" : "AND");
|
|
}
|
|
break;
|
|
|
|
case 1: /* Cursor X */
|
|
vc_curx = data;
|
|
sim_debug (SIM_VID_DBG_MOUSE, &vc_dev, "Cursor-X set: %d\n", vc_curx);
|
|
vid_set_cursor_position (CUR_X, CUR_Y);
|
|
break;
|
|
|
|
case 2: /* Mouse position */
|
|
break;
|
|
|
|
case 4: /* CRTC addr ptr */
|
|
vc_crtc_p = (vc_crtc_p & ~CRTCP_RW) | (data & CRTCP_RW);
|
|
sim_debug (DBG_CRTC, &vc_dev, "CRTC-Addr Set: %d - %s\n", vc_crtc_p, vc_crtc_regnames[vc_crtc_p & CRTCP_REG]);
|
|
break;
|
|
|
|
case 5: /* CRTC data */
|
|
crtc_rg = vc_crtc_p & CRTCP_REG;
|
|
old_data = vc_crtc[crtc_rg];
|
|
vc_crtc[crtc_rg] = data & BMASK;
|
|
sim_debug (DBG_CRTC, &vc_dev, "CRTC-Data:%s[%d] Set: 0x%x\n", vc_crtc_regnames[crtc_rg], crtc_rg, vc_crtc[crtc_rg]);
|
|
if (crtc_rg == CRTC_CAH) {
|
|
sim_debug (SIM_VID_DBG_MOUSE, &vc_dev, "Cursor-Y-High set (%d). Y value: %d\n", vc_crtc[crtc_rg], CUR_Y);
|
|
vid_set_cursor_position (CUR_X, CUR_Y);
|
|
}
|
|
if (crtc_rg == CRTC_CAL) {
|
|
sim_debug (SIM_VID_DBG_MOUSE, &vc_dev, "Cursor-Y-Low set (%d). Y value: %d\n", vc_crtc[crtc_rg], CUR_Y);
|
|
}
|
|
if (crtc_rg == CRTC_MSCN) {
|
|
sim_debug (SIM_VID_DBG_MOUSE, &vc_dev, "Maximum Scan Line set (%d). Y value: %d\n", vc_crtc[crtc_rg], CUR_Y);
|
|
}
|
|
if (crtc_rg == CRTC_CSCS) {
|
|
if (0x20 & (old_data ^ vc_crtc[crtc_rg])) {
|
|
sim_debug (DBG_CURSOR, &vc_dev, "Visibility Changed to: %s\n", CUR_V ? "Visible" : "Invisible");
|
|
}
|
|
sim_debug (SIM_VID_DBG_MOUSE, &vc_dev, "CSCS set (%d). Y value: %d\n", vc_crtc[crtc_rg], CUR_Y);
|
|
}
|
|
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
|
|
/*
|
|
Masking the vector with 0x1FC is probably storing
|
|
one more bit than the original hardware did.
|
|
Doing this allows a maximal simulated hardware
|
|
configuration use a reasonable vector where real
|
|
hardware could never be assembled with that many
|
|
devices.
|
|
*/
|
|
vc_intc.vec[vc_intc.ptr] = data & 0x1FC; /* 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 &= ~ICM_M_RP | ((data << 3) & ICM_M_RP); /* mode<06:05> = data<03:02> */
|
|
if (((data & 0x3) == 0x1) || ((data & 0x3) == 2))
|
|
vc_intc.mode &= ~ICM_MM | ((data << 7) & ICM_MM);
|
|
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;
|
|
}
|
|
|
|
int32 vc_mem_rd (int32 pa)
|
|
{
|
|
uint32 rg = (pa >> 2) & 0xFFFF;
|
|
|
|
return (pa & 0x2) ? (vc_buf[rg] >> 16) : vc_buf[rg] & WMASK;
|
|
}
|
|
|
|
void vc_mem_wr (int32 pa, int32 val, int32 mode)
|
|
{
|
|
uint32 rg = (pa >> 2) & 0xFFFF;
|
|
uint32 nval, t;
|
|
int32 lnt = (mode == WRITE) ? 2 : 1;
|
|
int32 i;
|
|
int32 sc = (pa & 3) << 3;
|
|
uint32 scrln, bufln;
|
|
uint32 idx;
|
|
uint32 mask = (mode == WRITE)? WMASK : BMASK;
|
|
|
|
t = vc_buf[rg];
|
|
nval = ((val & mask) << sc) | (t & ~(mask << sc));
|
|
|
|
if (rg >= 0xFFF8) { /* cursor image */
|
|
idx = (pa << 3) & 0xFF; /* get byte index */
|
|
if (sim_deb) {
|
|
char binary[40];
|
|
int32 i;
|
|
|
|
for (i=0; i<8*lnt; i++)
|
|
binary[i] = '0' + ((val & (1 << i)) != 0);
|
|
binary[i] = '\0';
|
|
sim_debug (DBG_CURSOR, &vc_dev, "Cursor Data at 0x%X set to 0x%0*X - %s\n", rg, 2*lnt, val, binary);
|
|
}
|
|
for (i = 0; i < (lnt << 3); i++)
|
|
vc_cur[idx++] = (val >> i) & 1; /* 1bpp to 8bpp */
|
|
vc_cur_new_data = TRUE;
|
|
}
|
|
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 */
|
|
sim_debug (DBG_SCANL, &vc_dev, "Scan Line 0x%X set to 0x%X\n", scrln, bufln);
|
|
|
|
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] &= ~VCMAP_VLD; /* invalidate map */
|
|
}
|
|
}
|
|
vc_buf[rg] = nval;
|
|
}
|
|
|
|
static SIM_INLINE void vc_invalidate (uint32 y1, uint32 y2)
|
|
{
|
|
uint32 ln;
|
|
|
|
if ((!vc_input_captured) && (!(vc_dev.dctrl & DBG_CURSOR)))
|
|
return;
|
|
for (ln = y1; ln < y2; ln++)
|
|
vc_map[ln] &= ~VCMAP_VLD; /* invalidate map entry */
|
|
}
|
|
|
|
static void vc_set_vid_cursor (t_bool visible, int func, uint8 *cur_bits)
|
|
{
|
|
uint8 data[2*16];
|
|
uint8 mask[2*16];
|
|
int i, d, m;
|
|
|
|
sim_debug (DBG_CURSOR, &vc_dev, "vc_set_vid_cursor(%s, %s)\n", visible ? "Visible" : "Invisible", func ? "OR" : "AND");
|
|
memset (data, 0, sizeof(data));
|
|
memset (mask, 0, sizeof(mask));
|
|
for (i=0; i<16*16; i++) {
|
|
if (func) { /* OR */
|
|
if (cur_bits[i]) {
|
|
/* White */
|
|
d = 0; m = 1;
|
|
}
|
|
else {
|
|
/* Transparent */
|
|
d = 0; m = 0;
|
|
}
|
|
}
|
|
else { /* AND */
|
|
if (cur_bits[i]) {
|
|
/* Black */
|
|
d = 1; m = 1;
|
|
}
|
|
else {
|
|
/* Transparent */
|
|
d = 0; m = 0;
|
|
}
|
|
}
|
|
data[i>>3] |= d<<(7-(i&7));
|
|
mask[i>>3] |= m<<(7-(i&7));
|
|
}
|
|
if ((vc_dev.dctrl & DBG_CURSOR) && (vc_dev.dctrl & DBG_TCURSOR)) {
|
|
/* box the cursor image */
|
|
for (i=0; i<16*16; i++) {
|
|
if ((0 == i>>4) || (0xF == i>>4) || (0 == (i&0xF)) || (0xF == (i&0xF))) {
|
|
data[i>>3] |= 1<<(7-(i&7));
|
|
mask[i>>3] |= 1<<(7-(i&7));
|
|
}
|
|
if ((1 == i>>4) || (0xE == i>>4) || (1 == (i&0xF)) || (0xE == (i&0xF))) {
|
|
data[i>>3] &= ~(1<<(7-(i&7)));
|
|
mask[i>>3] |= 1<<(7-(i&7));
|
|
}
|
|
}
|
|
}
|
|
vid_set_cursor (visible, 16, 16, data, mask, 0, 0);
|
|
}
|
|
|
|
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 & (ICM_MM | ICM_IM)) == ICM_MM) { /* 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];
|
|
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)
|
|
{
|
|
SIM_MOUSE_EVENT mev;
|
|
SIM_KEY_EVENT kev;
|
|
t_bool updated = FALSE; /* flag for refresh */
|
|
uint32 lines;
|
|
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) || /* moved (X)? or */
|
|
(vc_cur_f != CUR_F) || /* mask changed? or */
|
|
(vc_cur_new_data)) { /* cursor image changed? */
|
|
vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */
|
|
}
|
|
|
|
if ((!vc_input_captured) && /* OS cursor? AND*/
|
|
((vc_cur_f != CUR_F) || /* (mask changed? OR */
|
|
(vc_cur_new_data) || /* cursor image changed? OR) */
|
|
(vc_cur_v != CUR_V))) { /* visibility changed?) */
|
|
vc_set_vid_cursor (CUR_V, CUR_F, vc_cur);
|
|
}
|
|
|
|
vc_cur_x = CUR_X; /* store cursor data */
|
|
vc_cur_y = CUR_Y;
|
|
vid_set_cursor_position (vc_cur_x, vc_cur_y);
|
|
vc_cur_v = CUR_V;
|
|
vc_cur_f = CUR_F;
|
|
vc_cur_new_data = FALSE;
|
|
|
|
if (vid_poll_kb (&kev) == SCPE_OK) /* poll keyboard */
|
|
lk_event (&kev); /* push event */
|
|
if (vid_poll_mouse (&mev) == SCPE_OK) { /* poll mouse */
|
|
xpos = vc_mpos & 0xFF; /* get current mouse position */
|
|
ypos = (vc_mpos >> 8) & 0xFF;
|
|
dx = mev.x_rel; /* get relative movement */
|
|
dy = -mev.y_rel;
|
|
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 */
|
|
|
|
vc_csr |= (CSR_MSA | CSR_MSB | CSR_MSC); /* reset button states */
|
|
if (mev.b3_state) /* set new button states */
|
|
vc_csr &= ~CSR_MSA;
|
|
if (mev.b2_state)
|
|
vc_csr &= ~CSR_MSB;
|
|
if (mev.b1_state)
|
|
vc_csr &= ~CSR_MSC;
|
|
|
|
vs_event (&mev); /* push event */
|
|
}
|
|
|
|
lines = 0;
|
|
for (ln = 0; ln < VC_YSIZE; ln++) {
|
|
if ((vc_map[ln] & VCMAP_VLD) == 0) { /* line invalid? */
|
|
off = vc_map[ln] * 32; /* get video buf offset */
|
|
for (col = 0; col < VC_XSIZE; col++)
|
|
vc_lines[ln*VC_XSIZE + col] = vc_palette[(vc_buf[off + (col >> 5)] >> (col & 0x1F)) & 1];
|
|
/* 1bpp to 32bpp */
|
|
if (CUR_V && /* cursor visible && need to draw cursor? */
|
|
(vc_input_captured || (vc_dev.dctrl & DBG_CURSOR))) {
|
|
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) >= VC_XSIZE) /* Part of cursor off screen? */
|
|
continue; /* Skip */
|
|
if (CUR_F) /* mask function */
|
|
vc_lines[ln*VC_XSIZE + CUR_X + col] = vc_palette[(vc_lines[ln*VC_XSIZE + CUR_X + col] == vc_palette[1]) | (cur[col] & 1)];
|
|
else
|
|
vc_lines[ln*VC_XSIZE + CUR_X + col] = vc_palette[(vc_lines[ln*VC_XSIZE + CUR_X + col] == vc_palette[1]) & (~cur[col] & 1)];
|
|
}
|
|
}
|
|
}
|
|
vc_map[ln] |= VCMAP_VLD; /* set valid */
|
|
if ((ln == (VC_YSIZE-1)) || /* if end of window OR */
|
|
(vc_map[ln+1] & VCMAP_VLD)) { /* next is already valid? */
|
|
vid_draw (0, ln-lines, VC_XSIZE, lines+1, vc_lines+(ln-lines)*VC_XSIZE); /* update region */
|
|
lines = 0;
|
|
}
|
|
else
|
|
lines++;
|
|
updated = TRUE;
|
|
}
|
|
}
|
|
|
|
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 = ICM_MM;
|
|
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) {
|
|
if (vc_active) {
|
|
free (vc_buf);
|
|
vc_buf = NULL;
|
|
free (vc_lines);
|
|
vc_lines = NULL;
|
|
free (vc_map);
|
|
vc_map = NULL;
|
|
vc_active = FALSE;
|
|
return vid_close ();
|
|
}
|
|
else
|
|
return SCPE_OK;
|
|
}
|
|
|
|
if (!vid_active) {
|
|
r = vid_open (dptr, NULL, VC_XSIZE, VC_YSIZE, vc_input_captured ? SIM_VID_INPUTCAPTURED : 0);/* display size & capture mode */
|
|
if (r != SCPE_OK)
|
|
return r;
|
|
vc_buf = (uint32 *) calloc (VC_MEMSIZE, sizeof (uint32));
|
|
if (vc_buf == NULL) {
|
|
vid_close ();
|
|
return SCPE_MEM;
|
|
}
|
|
vc_lines = (uint32 *) calloc (VC_XSIZE*VC_YSIZE, sizeof (uint32));
|
|
if (vc_lines == NULL) {
|
|
free (vc_buf);
|
|
vid_close ();
|
|
return SCPE_MEM;
|
|
}
|
|
vc_map = (uint32 *) calloc (VC_XSIZE, sizeof (uint32));
|
|
if (vc_map == NULL) {
|
|
free (vc_lines);
|
|
vc_lines = NULL;
|
|
free (vc_buf);
|
|
vid_close ();
|
|
return SCPE_MEM;
|
|
}
|
|
vc_palette[0] = vid_map_rgb (0x00, 0x00, 0x00); /* black */
|
|
vc_palette[1] = vid_map_rgb (0xFF, 0xFF, 0xFF); /* white */
|
|
vc_active = TRUE;
|
|
sim_printf ("QVSS Display Created. ");
|
|
vc_show_capture (stdout, NULL, 0, NULL);
|
|
if (sim_log)
|
|
vc_show_capture (sim_log, NULL, 0, NULL);
|
|
sim_printf ("\n");
|
|
}
|
|
sim_activate_abs (&vc_unit, tmxr_poll);
|
|
return auto_config (NULL, 0); /* run autoconfig */
|
|
}
|
|
|
|
t_stat vc_detach (UNIT *uptr)
|
|
{
|
|
if ((vc_dev.flags & DEV_DIS) == 0) {
|
|
vc_dev.flags |= DEV_DIS;
|
|
vc_reset(&vc_dev);
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat vc_set_enable (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
return cpu_set_model (NULL, 0, (val ? "VAXSTATION" : "MICROVAX"), NULL);
|
|
}
|
|
|
|
t_stat vc_set_capture (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
if (vid_active)
|
|
return sim_messagef (SCPE_ALATT, "Capture Mode Can't be changed with device enabled\n");
|
|
vc_input_captured = val;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat vc_show_capture (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
|
|
{
|
|
if (vc_input_captured) {
|
|
fprintf (st, "Captured Input Mode, ");
|
|
vid_show_release_key (st, uptr, val, desc);
|
|
}
|
|
else
|
|
fprintf (st, "Uncaptured Input Mode");
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat vc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const 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;
|
|
}
|
|
|
|
const char *vc_description (DEVICE *dptr)
|
|
{
|
|
return "VCB01 Monochrome Graphics Adapter";
|
|
}
|
|
|
|
#else /* defined(VAX_620) */
|
|
static const char *dummy_declaration = "Something to compile";
|
|
#endif /* !defined(VAX_620) */
|