1525 lines
48 KiB
C
1525 lines
48 KiB
C
/* vax4xx_ve.c: SPX video simulator
|
|
|
|
Copyright (c) 2019, 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.
|
|
|
|
ve SPX colour video
|
|
*/
|
|
|
|
#include "vax_defs.h"
|
|
#include "sim_video.h"
|
|
#include "vax_lk.h"
|
|
#include "vax_vs.h"
|
|
|
|
#include "vax_ka4xx_spx_bin.h"
|
|
|
|
#define VE_XSIZE 1280 /* visible width */
|
|
#define VE_YSIZE 1024 /* visible height */
|
|
|
|
#define VE_BXSIZE 1280 /* buffer width */
|
|
#define VE_BYSIZE 2048 /* buffer height */
|
|
#define VE_BUFSIZE 0x280000 /* number of bytes */
|
|
#define VE_ORSC 3 /* screen origin multiplier */
|
|
|
|
#define PUTL(b,x,v) b[x+3] = (v >> 24) & 0xFF; \
|
|
b[x+2] = (v >> 16) & 0xFF; \
|
|
b[x+1] = (v >> 8) & 0xFF; \
|
|
b[x] = v & 0xFF
|
|
#define PUTW(b,x,v) b[x+1] = (v >> 8) & 0xFF; \
|
|
b[x] = v & 0xFF
|
|
#define GETL(b,x) ((b[x+3] << 24) | \
|
|
(b[x+2] << 16) | \
|
|
(b[x+1] << 8) | \
|
|
b[x])
|
|
#define GETW(b,x) ((b[x+1] << 8)|b[x])
|
|
|
|
#define CURSOR_X_OFFSET 216
|
|
#define CURSOR_Y_OFFSET 33
|
|
|
|
#define CMD_TEST 0x8000
|
|
#define CMD_HSHI 0x4000
|
|
#define CMD_VBHI 0x2000
|
|
#define CMD_LODSA 0x1000
|
|
#define CMD_FORG2 0x0800
|
|
#define CMD_ENRG2 0x0400
|
|
#define CMD_FORG1 0x0200
|
|
#define CMD_ENRG1 0x0100
|
|
#define CMD_XHWID 0x0080
|
|
#define CMD_XHCL1 0x0040
|
|
#define CMD_XHCLP 0x0020
|
|
#define CMD_XHAIR 0x0010
|
|
#define CMD_FOPB 0x0008
|
|
#define CMD_ENPB 0x0004
|
|
#define CMD_FOPA 0x0002
|
|
#define CMD_ENPA 0x0001
|
|
|
|
#define TBC_CMD_F0EN 0x00000001
|
|
#define TBC_CMD_F0DS 0x00000002
|
|
#define TBC_CMD_F0OP 0x00000004
|
|
#define TBC_CMD_F0IN 0x00000008
|
|
|
|
#define TBC_CMD_FIFOEN(x) (TBC_CMD_F0EN << ((x * 5) + ((x == 3) ? 1 : 0)))
|
|
#define TBC_CMD_FIFODIS(x) (TBC_CMD_F0DS << ((x * 5) + ((x == 3) ? 1 : 0)))
|
|
#define TBC_CMD_FIFOOUT(x) (TBC_CMD_F0OP << ((x * 5) + ((x == 3) ? 1 : 0)))
|
|
#define TBC_CMD_FIFOIN(x) (TBC_CMD_F0IN << ((x * 5) + ((x == 3) ? 1 : 0)))
|
|
|
|
#define TBC_CMD_F1EN 0x00000020
|
|
#define TBC_CMD_F1DS 0x00000040
|
|
#define TBC_CMD_F2EN 0x00000400
|
|
#define TBC_CMD_F2DS 0x00000800
|
|
#define TBC_CMD_F3EN 0x00010000
|
|
#define TBC_CMD_F3DS 0x00020000
|
|
#define TBC_CMD_F3IN 0x00080000
|
|
#define TBC_CMD_STRW 0x40000000
|
|
#define TBC_CMD_STRR 0x80000000
|
|
|
|
#define TBC_CSR_F0DR 0x00100000
|
|
#define TBC_CSR_F1DR 0x00200000
|
|
#define TBC_CSR_F2DR 0x00400000
|
|
#define TBC_CSR_F3DR 0x00800000
|
|
#define TBC_CSR_F0EN 0x00010000
|
|
#define TBC_CSR_F1EN 0x00020000
|
|
#define TBC_CSR_F2EN 0x00040000
|
|
#define TBC_CSR_F3EN 0x00080000
|
|
|
|
#define TBC_CSR_FIFODIR(x) (TBC_CSR_F0DR << x)
|
|
#define TBC_CSR_FIFOEN(x) (TBC_CSR_F0EN << x)
|
|
#define TBC_CSR_STRDIR 0x00000400
|
|
#define TBC_CSR_STRSTAT 0x00000800
|
|
|
|
#define INTSTS_F0_GE_THRSH 0x00000100
|
|
#define INTSTS_F0_LT_THRSH 0x00000200
|
|
|
|
#define GET_FIFO(x) ((x >> 3) - 2)
|
|
#define FIFO_LEN 0x4000
|
|
|
|
extern int32 tmxr_poll;
|
|
extern int32 ka_cfgtst;
|
|
extern uint32 vc_org;
|
|
extern uint32 vc_last_org;
|
|
|
|
struct fifo_reg_t {
|
|
uint32 buf[FIFO_LEN >> 2];
|
|
uint32 put_ptr;
|
|
uint32 get_ptr;
|
|
uint32 count;
|
|
uint32 threshold;
|
|
uint32 semaphore;
|
|
};
|
|
|
|
typedef struct fifo_reg_t FIFO_REG;
|
|
|
|
uint32 bt459_addr = 0;
|
|
uint32 bt459_cmap_p = 0;
|
|
uint32 bt459_cmap[3];
|
|
uint32 cp_fb_format = 0;
|
|
uint32 cp_int_status = 0;
|
|
uint32 cp_int_mask = 0;
|
|
uint32 gf_fb_format = 0;
|
|
uint32 spx_xstart = 0;
|
|
uint32 spx_ystart = 0;
|
|
uint32 spx_xend = 0;
|
|
uint32 spx_yend = 0;
|
|
uint32 spx_dstpix = 0;
|
|
uint32 spx_srcpix = 0;
|
|
uint32 spx_fg = 0;
|
|
uint32 spx_cmd = 0;
|
|
uint32 spx_rmask = 0;
|
|
uint32 spx_wmask = 0;
|
|
uint32 spx_smask = 0;
|
|
uint32 spx_dmask = 0;
|
|
uint32 spx_strx = 0;
|
|
uint32 spx_stry = 0;
|
|
uint32 spx_destloop = 0;
|
|
uint32 spx_upc = 0; /* micro pc */
|
|
uint32 spx_status = 0;
|
|
uint32 tbc_csr = 0;
|
|
FIFO_REG tbc_fifo[4];
|
|
uint32 tbc_table = 0;
|
|
uint32 tbc_timing_setup = 0;
|
|
uint32 spx_timing_csr = 0;
|
|
uint32 tbc_ltrr = 0;
|
|
uint32 tbc_timing = 0;
|
|
t_bool ve_input_captured = FALSE; /* Mouse and Keyboard input captured in video window */
|
|
uint8 *ve_buf = NULL; /* Video memory */
|
|
uint32 *ve_lines = NULL; /* Video Display Lines */
|
|
uint32 ve_palette[256];
|
|
t_bool ve_updated[VE_YSIZE];
|
|
t_bool ve_active = FALSE;
|
|
|
|
t_stat ve_svc (UNIT *uptr);
|
|
t_stat ve_micro_svc (UNIT *uptr);
|
|
t_stat ve_reset (DEVICE *dptr);
|
|
t_stat ve_detach (UNIT *dptr);
|
|
t_stat ve_set_enable (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat ve_set_capture (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
t_stat ve_show_capture (FILE* st, UNIT* uptr, int32 val, CONST void* desc);
|
|
t_stat ve_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
|
const char *ve_description (DEVICE *dptr);
|
|
int32 tbc_rd (int32 rg);
|
|
void tbc_wr (int32 rg, int32 val, int32 lnt);
|
|
int32 scn_rd (int32 rg);
|
|
void scn_wr (int32 rg, int32 val, int32 lnt);
|
|
|
|
|
|
/* VE data structures
|
|
|
|
ve_dev VE device descriptor
|
|
ve_unit VE unit descriptor
|
|
ve_reg VE register list
|
|
*/
|
|
|
|
DIB ve_dib = {
|
|
VE_ROM_INDEX, BOOT_CODE_ARRAY, BOOT_CODE_SIZE
|
|
};
|
|
|
|
UNIT ve_unit[] = {
|
|
{ UDATA (&ve_svc, UNIT_IDLE, 0) },
|
|
{ UDATA (&ve_micro_svc, UNIT_IDLE+UNIT_DIS, 0) }
|
|
};
|
|
|
|
REG ve_reg[] = {
|
|
{ NULL }
|
|
};
|
|
|
|
/* Debugging Bitmaps */
|
|
|
|
#define DBG_REG 0x0100 /* register activity */
|
|
#define DBG_ROP 0x0200 /* raster operations */
|
|
|
|
DEBTAB ve_debug[] = {
|
|
{"REG", DBG_REG, "Register activity"},
|
|
{"ROP", DBG_ROP, "Raster operations"},
|
|
{"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 }
|
|
};
|
|
|
|
MTAB ve_mod[] = {
|
|
{ MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLE",
|
|
&ve_set_enable, NULL, NULL, "Enable VCB01 (QVSS)" },
|
|
{ MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLE",
|
|
&ve_set_enable, NULL, NULL, "Disable VCB01 (QVSS)" },
|
|
{ MTAB_XTD|MTAB_VDV, TRUE, NULL, "CAPTURE",
|
|
&ve_set_capture, &ve_show_capture, NULL, "Enable Captured Input Mode" },
|
|
{ MTAB_XTD|MTAB_VDV, FALSE, NULL, "NOCAPTURE",
|
|
&ve_set_capture, NULL, NULL, "Disable Captured Input Mode" },
|
|
{ MTAB_XTD|MTAB_VDV, TRUE, "OSCURSOR", NULL,
|
|
NULL, &ve_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" },
|
|
{ 0 }
|
|
};
|
|
|
|
DEVICE ve_dev = {
|
|
"VE", ve_unit, ve_reg, ve_mod,
|
|
2, 10, 31, 1, DEV_RDX, 8,
|
|
NULL, NULL, &ve_reset,
|
|
NULL, NULL, &ve_detach,
|
|
&ve_dib, DEV_DIS | DEV_DEBUG, 0,
|
|
ve_debug, NULL, NULL, &ve_help, NULL, NULL,
|
|
&ve_description
|
|
};
|
|
|
|
/* VE routines
|
|
|
|
ve_rd I/O page read
|
|
ve_wr I/O page write
|
|
ve_svc process event
|
|
ve_reset process reset
|
|
ve_detach process detach
|
|
*/
|
|
|
|
int32 ve_rd (int32 pa)
|
|
{
|
|
int32 rg = ((pa - 0x38000000) >> 2);
|
|
uint32 data = 0;
|
|
|
|
if (pa >= 0x39bc0000) { /* ROMCFG */
|
|
data = 0xC0000202; /* from real hardware */
|
|
sim_debug (DBG_REG, &ve_dev, "rom_cfg %X rd %X at %08X\n", pa, data, fault_PC);
|
|
return data;
|
|
}
|
|
if (pa >= 0x39b20000) {
|
|
rg = rg & 0xFFF;
|
|
if (pa >= 0x39b23000) {
|
|
sim_debug (DBG_REG, &ve_dev, "direct_fifo 3 %X rd at %08X\n", pa, fault_PC);
|
|
return 0;
|
|
}
|
|
else if (pa >= 0x39b22000) {
|
|
sim_debug (DBG_REG, &ve_dev, "direct_fifo 2 %X rd at %08X\n", pa, fault_PC);
|
|
return 0;
|
|
}
|
|
else if (pa >= 0x39b21000) {
|
|
sim_debug (DBG_REG, &ve_dev, "direct_fifo 1 %X rd at %08X\n", pa, fault_PC);
|
|
return 0;
|
|
}
|
|
else {
|
|
data = tbc_fifo[0].buf[rg];
|
|
sim_debug (DBG_REG, &ve_dev, "direct_fifo 0 %X rd %X at %08X\n", pa, data, fault_PC);
|
|
return data;
|
|
}
|
|
}
|
|
if (pa >= 0x39b1c000) {
|
|
sim_debug (DBG_REG, &ve_dev, "bt459 cmap %X rd\n", (bt459_addr & 0xFF));
|
|
return 0;
|
|
}
|
|
if (pa >= 0x39b18000) {
|
|
sim_debug (DBG_REG, &ve_dev, "bt459 reg %X rd\n", bt459_addr);
|
|
return 0;
|
|
}
|
|
if (pa == 0x39b14000) {
|
|
/* sim_debug (DBG_REG, &ve_dev, "bt459 adrh %08X rd %X\n", pa); */
|
|
return (bt459_addr >> 8) & 0xFF;
|
|
}
|
|
if (pa == 0x39b10000) {
|
|
/* sim_debug (DBG_REG, &ve_dev, "bt459 adrl %08X rd %X\n", pa); */
|
|
return bt459_addr & 0xFF;
|
|
}
|
|
if (pa >= 0x39b00000) {
|
|
/* sim_debug (DBG_REG, &ve_dev, "spx reg1 %08X rd %X\n", pa); */
|
|
rg = rg & 0xFF;
|
|
data = tbc_rd (rg);
|
|
return data;
|
|
}
|
|
/* if (pa >= 0x39300000) { */
|
|
if ((pa & 0xFF000000) >= 0x39000000) {
|
|
/* sim_debug (DBG_REG, &ve_dev, "spx reg2 %08X rd %X\n", pa); */
|
|
rg = rg & 0xFF;
|
|
/* if (pa >= 0x39303000) { */
|
|
if ((pa & 0xFF00FFFF) > 0x39003000) {
|
|
switch (rg) {
|
|
case 0x5B: /* STATUS */
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc cmdalt rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x5C:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc write_mask rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x5D:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc read_mask rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
default:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc %08X rd\n", pa);
|
|
break;
|
|
}
|
|
}
|
|
/* else if (pa >= 0x39302000) { */
|
|
else if ((pa & 0xFF00FFFF) > 0x39002000) {
|
|
return scn_rd (rg);
|
|
}
|
|
else {
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc %08X rd at %08X\n", pa, fault_PC);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
rg = pa & 0x3FFFFF;
|
|
return (GETL (ve_buf, rg) & spx_rmask);
|
|
}
|
|
|
|
void ve_wr (int32 pa, int32 val, int32 lnt)
|
|
{
|
|
int32 rg = ((pa - 0x38000000) >> 2);
|
|
uint32 scrln;
|
|
|
|
if (pa >= 0x39b20000) {
|
|
rg = rg & 0xFFF;
|
|
if (pa >= 0x39b23000) {
|
|
sim_debug (DBG_REG, &ve_dev, "direct_fifo 3 %X wr %X\n", pa, val);
|
|
return;
|
|
}
|
|
else if (pa >= 0x39b22000) {
|
|
sim_debug (DBG_REG, &ve_dev, "direct_fifo 2 %X wr %X\n", pa, val);
|
|
return;
|
|
}
|
|
else if (pa >= 0x39b21000) {
|
|
sim_debug (DBG_REG, &ve_dev, "direct_fifo 1 %X wr %X\n", pa, val);
|
|
return;
|
|
}
|
|
else {
|
|
sim_debug (DBG_REG, &ve_dev, "direct_fifo 0 %X wr %X\n", pa, val);
|
|
tbc_fifo[0].buf[rg] = val;
|
|
return;
|
|
}
|
|
}
|
|
if (pa >= 0x39b1c000) {
|
|
/* sim_debug (DBG_REG, &ve_dev, "bt459 cmap %X wr %X\n", bt459_addr, val); */
|
|
bt459_cmap[bt459_cmap_p++] = val;
|
|
if (bt459_cmap_p == 3) {
|
|
bt459_cmap_p = 0;
|
|
sim_debug (DBG_REG, &ve_dev, "bt459 cmap %X wr %X, %X, %X at %08X\n", (bt459_addr & 0xFF), bt459_cmap[0], bt459_cmap[1], bt459_cmap[2], fault_PC);
|
|
ve_palette[(bt459_addr & 0xFF)] = vid_map_rgb (bt459_cmap[0], bt459_cmap[1], bt459_cmap[2]);
|
|
sim_debug (DBG_REG, &ve_dev, "ve_palette[%d] = 0x%08X\n", (bt459_addr & 0xFF), ve_palette[(bt459_addr & 0xFF)]);
|
|
bt459_addr++;
|
|
if (bt459_addr == 0x100) bt459_addr = 0;
|
|
}
|
|
return;
|
|
}
|
|
if (pa >= 0x39b18000) {
|
|
sim_debug (DBG_REG, &ve_dev, "bt459 reg %X wr %X\n", bt459_addr, val);
|
|
return;
|
|
}
|
|
if (pa == 0x39b14000) {
|
|
bt459_addr = (bt459_addr & 0xFF) | ((val & 0xFF) << 8);
|
|
/* sim_debug (DBG_REG, &ve_dev, "bt459 adrh %08X wr %X (%X)\n", pa, val, bt459_addr); */
|
|
return;
|
|
}
|
|
if (pa == 0x39b10000) {
|
|
bt459_addr = (bt459_addr & ~0xFF) | (val & 0xFF);
|
|
/* sim_debug (DBG_REG, &ve_dev, "bt459 adrl %08X wr %X (%X)\n", pa, val, bt459_addr); */
|
|
return;
|
|
}
|
|
if (pa >= 0x39b00000) {
|
|
/* sim_debug (DBG_REG, &ve_dev, "tbc reg %X wr %X (%08X)\n", rg, val, pa); */
|
|
rg = rg & 0xFF;
|
|
tbc_wr (rg, val, lnt);
|
|
return;
|
|
}
|
|
if (pa >= 0x39300000) {
|
|
/* sim_debug (DBG_REG, &ve_dev, "spx reg %X wr %X (%08X)\n", rg, val, pa); */
|
|
rg = rg & 0xFF;
|
|
if (pa > 0x39303000) {
|
|
switch (rg) {
|
|
case 0x5B: /* STATUS */
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc cmdalt wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x5C:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc write_mask wr %X at %08X\n", val, fault_PC);
|
|
spx_wmask = val;
|
|
break;
|
|
|
|
case 0x5D:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc read_mask wr %X at %08X\n", val, fault_PC);
|
|
spx_rmask = val;
|
|
break;
|
|
|
|
default:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc %08X wr %X\n", pa, val);
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
scn_wr (rg, val, lnt);
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
if (pa >= 0x39000000) {
|
|
/* sim_debug (DBG_REG, &ve_dev, "spx reg %X wr %X (%08X)\n", rg, val, pa); */
|
|
rg = rg & 0xFF;
|
|
scn_wr (rg, val, lnt);
|
|
return;
|
|
}
|
|
|
|
rg = pa & 0x3FFFFF;
|
|
|
|
if (lnt > L_WORD) {
|
|
PUTL (ve_buf, rg, (val & spx_wmask));
|
|
}
|
|
else if (lnt > L_BYTE) {
|
|
PUTW (ve_buf, rg, (val & ((pa & 2) ? (spx_wmask >> 16) : spx_wmask)));
|
|
}
|
|
else
|
|
ve_buf[rg] = (val & (spx_wmask >> ((pa & 3) << 3)));
|
|
|
|
scrln = ((rg / VE_BXSIZE) + (vc_org << VE_ORSC));
|
|
if (scrln < VE_YSIZE)
|
|
ve_updated[scrln] = TRUE; /* flag as updated */
|
|
return;
|
|
}
|
|
|
|
void ve_put_fifo (uint32 id, uint32 data)
|
|
{
|
|
if (tbc_fifo[id].count > 0) {
|
|
tbc_fifo[id].buf[tbc_fifo[id].put_ptr++] = data;
|
|
if (tbc_fifo[id].put_ptr == FIFO_LEN)
|
|
tbc_fifo[id].put_ptr = 0;
|
|
tbc_fifo[id].count = tbc_fifo[id].count - 4;
|
|
if (tbc_fifo[id].count >= tbc_fifo[id].threshold) {
|
|
}
|
|
}
|
|
}
|
|
|
|
void ve_get_fifo (uint32 id, uint32 *data)
|
|
{
|
|
if (tbc_fifo[id].count < FIFO_LEN) {
|
|
*data = tbc_fifo[id].buf[tbc_fifo[id].get_ptr++];
|
|
if (tbc_fifo[id].get_ptr == FIFO_LEN)
|
|
tbc_fifo[id].get_ptr = 0;
|
|
tbc_fifo[id].count = tbc_fifo[id].count + 4;
|
|
}
|
|
else
|
|
*data = 0;
|
|
}
|
|
|
|
void ve_clear_fifo (uint32 id)
|
|
{
|
|
tbc_fifo[id].put_ptr = 0;
|
|
tbc_fifo[id].get_ptr = 0;
|
|
tbc_fifo[id].count = FIFO_LEN;
|
|
}
|
|
|
|
int32 tbc_rd (int32 rg)
|
|
{
|
|
uint32 data = 0;
|
|
|
|
switch (rg) {
|
|
case 0x0:
|
|
data = tbc_csr;
|
|
sim_debug (DBG_REG, &ve_dev, "tbc csr rd %X at %08X\n", data, fault_PC);
|
|
break;
|
|
|
|
case 0x1:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc cmd rd at %08X\n", fault_PC); /* no read? */
|
|
break;
|
|
|
|
case 0x3:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc diag rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x4:
|
|
/* sim_debug (DBG_REG, &ve_dev, "tbc cp_fb_format rd at %08X\n", fault_PC); */
|
|
data = cp_fb_format;
|
|
break;
|
|
|
|
case 0x5:
|
|
/* sim_debug (DBG_REG, &ve_dev, "tbc cp_int_mask rd at %08X\n", fault_PC); */
|
|
data = cp_int_mask;
|
|
break;
|
|
|
|
case 0x6:
|
|
/* sim_debug (DBG_REG, &ve_dev, "tbc cp_int_status rd at %08X\n", fault_PC); */
|
|
data = cp_int_status;
|
|
break;
|
|
|
|
case 0x8:
|
|
/* sim_debug (DBG_REG, &ve_dev, "tbc gf_fb_format rd at %08X\n", fault_PC); */
|
|
data = gf_fb_format;
|
|
break;
|
|
|
|
case 0x9:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc gf_int_mask rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0xA:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc gf_int_status rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x10: /* FIFO0 Data */
|
|
case 0x18:
|
|
case 0x20:
|
|
case 0x28:
|
|
ve_get_fifo (GET_FIFO(rg), &data);
|
|
if (tbc_csr & TBC_CSR_STRSTAT) { /* stream in progress? */
|
|
if (tbc_fifo[GET_FIFO(rg)].count >= tbc_fifo[GET_FIFO(rg)].threshold)
|
|
sim_activate (&ve_unit[1], 200); /* get more data */
|
|
}
|
|
sim_debug (DBG_REG, &ve_dev, "tbc fifo%d data rd %X at %08X\n", GET_FIFO(rg), data, fault_PC);
|
|
break;
|
|
|
|
case 0x11:
|
|
case 0x19:
|
|
case 0x21:
|
|
case 0x29:
|
|
data = tbc_fifo[GET_FIFO(rg)].put_ptr;
|
|
break;
|
|
|
|
case 0x12:
|
|
case 0x1A:
|
|
case 0x22:
|
|
case 0x2A:
|
|
data = tbc_fifo[GET_FIFO(rg)].get_ptr;
|
|
break;
|
|
|
|
case 0x13: /* FIFO0 Count */
|
|
case 0x1B:
|
|
case 0x23:
|
|
case 0x2B:
|
|
data = tbc_fifo[GET_FIFO(rg)].count;
|
|
sim_debug (DBG_REG, &ve_dev, "tbc fifo%d count rd %X at %08X\n", GET_FIFO(rg), data, fault_PC);
|
|
break;
|
|
|
|
case 0x14:
|
|
case 0x1C:
|
|
case 0x24:
|
|
case 0x2C:
|
|
data = tbc_fifo[GET_FIFO(rg)].threshold;
|
|
sim_debug (DBG_REG, &ve_dev, "tbc fifo%d threshold rd %X at %08X\n", GET_FIFO(rg), data, fault_PC);
|
|
break;
|
|
|
|
case 0x15:
|
|
case 0x1D:
|
|
case 0x25:
|
|
case 0x2D:
|
|
data = tbc_fifo[GET_FIFO(rg)].semaphore;
|
|
sim_debug (DBG_REG, &ve_dev, "tbc fifo%d semaphore rd %X at %08X\n", GET_FIFO(rg), data, fault_PC);
|
|
break;
|
|
|
|
case 0x40:
|
|
tbc_timing = tbc_timing ^ 0x14000;
|
|
data = tbc_timing;
|
|
sim_debug (DBG_REG, &ve_dev, "tbc timing_csr rd %X at %08X\n", data, fault_PC);
|
|
break;
|
|
|
|
case 0x41:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc hsync rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x42:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc hsync2 rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x43:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc early_hblank rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x44:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc vsync rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x45:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc vblank rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x46:
|
|
data = tbc_table;
|
|
sim_debug (DBG_REG, &ve_dev, "tbc table rd %X at %08X\n", data, fault_PC);
|
|
break;
|
|
|
|
case 0x47:
|
|
data = tbc_timing_setup;
|
|
sim_debug (DBG_REG, &ve_dev, "tbc timing_setup rd %X at %08X\n", data, fault_PC);
|
|
break;
|
|
|
|
case 0x48:
|
|
data = tbc_ltrr;
|
|
tbc_ltrr++;
|
|
if (tbc_ltrr == 5) tbc_ltrr = 0;
|
|
sim_debug (DBG_REG, &ve_dev, "tbc ltrr rd %X at %08X\n", data, fault_PC);
|
|
break;
|
|
|
|
case 0x50:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc sp_bus_loop rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
default:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc %X rd at %08X\n", rg, fault_PC);
|
|
break;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
void tbc_wr (int32 rg, int32 val, int32 lnt)
|
|
{
|
|
uint32 i;
|
|
|
|
switch (rg) {
|
|
case 0x0:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc csr wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x1:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc cmd wr %X at %08X\n", val, fault_PC);
|
|
for (i = 0; i < 4; i++) {
|
|
if (val & TBC_CMD_FIFOEN(i)) {
|
|
tbc_csr |= TBC_CSR_FIFOEN(i);
|
|
sim_debug (DBG_REG, &ve_dev, "fifo %d enable\n", i);
|
|
}
|
|
else if (val & TBC_CMD_FIFODIS(i)) {
|
|
tbc_csr &= ~TBC_CSR_FIFOEN(i);
|
|
sim_debug (DBG_REG, &ve_dev, "fifo %d disable\n", i);
|
|
}
|
|
if (val & TBC_CMD_FIFOOUT(i)) {
|
|
tbc_csr |= TBC_CSR_FIFODIR(i);
|
|
sim_debug (DBG_REG, &ve_dev, "fifo %d output\n", i);
|
|
}
|
|
else if (val & TBC_CMD_FIFOIN(i)) {
|
|
tbc_csr &= ~TBC_CSR_FIFODIR(i);
|
|
sim_debug (DBG_REG, &ve_dev, "fifo %d input\n", i);
|
|
}
|
|
}
|
|
if (val & 0x800000) { /* Input FIFO Load */
|
|
tbc_csr = (tbc_csr & ~0x3) | ((val >> 21) & 0x3);
|
|
}
|
|
if (val & 0x4000000) { /* Output FIFO Load */
|
|
tbc_csr = (tbc_csr & ~0x300) | ((val >> 16) & 0x300);
|
|
}
|
|
/* NOTE:
|
|
* Set STREAM_STATUS and STREAM direction for the
|
|
* following commands.
|
|
* 0 = INPUT (to card)
|
|
* 1 = OUTPUT (from card)
|
|
*/
|
|
if (val & TBC_CMD_STRW) {
|
|
sim_debug (DBG_REG, &ve_dev, "stream write\n");
|
|
tbc_csr |= TBC_CSR_STRDIR; /* stream write */
|
|
tbc_csr |= TBC_CSR_STRSTAT; /* stream active */
|
|
}
|
|
else if (val & TBC_CMD_STRR) {
|
|
sim_debug (DBG_REG, &ve_dev, "stream read\n");
|
|
tbc_csr &= ~TBC_CSR_STRDIR; /* stream read */
|
|
tbc_csr |= TBC_CSR_STRSTAT; /* stream active */
|
|
}
|
|
else {
|
|
sim_debug (DBG_REG, &ve_dev, "stream disable\n");
|
|
tbc_csr &= ~TBC_CSR_STRDIR;
|
|
tbc_csr &= ~TBC_CSR_STRSTAT; /* stream inactive */
|
|
}
|
|
break;
|
|
|
|
case 0x3:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc diag wr %X at %08X\n", val, fault_PC);
|
|
if (val & 0x10) { /* synchronous reset */
|
|
for (i = 0; i < 4; i++) {
|
|
ve_clear_fifo (i);
|
|
}
|
|
sim_debug (DBG_REG, &ve_dev, "tbc reset\n");
|
|
bt459_cmap_p = 0;
|
|
}
|
|
else if (val & 0x1) {
|
|
ve_clear_fifo (0);
|
|
sim_debug (DBG_REG, &ve_dev, "fifo0 reset\n");
|
|
}
|
|
else if (val & 0x2) {
|
|
ve_clear_fifo (1);
|
|
sim_debug (DBG_REG, &ve_dev, "fifo1 reset\n");
|
|
}
|
|
else if (val & 0x4) {
|
|
ve_clear_fifo (2);
|
|
sim_debug (DBG_REG, &ve_dev, "fifo2 reset\n");
|
|
}
|
|
else if (val & 0x8) {
|
|
ve_clear_fifo (3);
|
|
sim_debug (DBG_REG, &ve_dev, "fifo3 reset\n");
|
|
}
|
|
break;
|
|
|
|
case 0x4:
|
|
/* sim_debug (DBG_REG, &ve_dev, "tbc cp_fb_format wr %X at %08X\n", val, fault_PC); */
|
|
cp_fb_format = val;
|
|
break;
|
|
|
|
case 0x5:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc cp_int_mask wr %X at %08X\n", val, fault_PC);
|
|
cp_int_mask = val;
|
|
break;
|
|
|
|
case 0x6:
|
|
/* sim_debug (DBG_REG, &ve_dev, "tbc cp_int_status wr %X at %08X\n", val, fault_PC); */
|
|
cp_int_status = (cp_int_status & ~val);
|
|
break;
|
|
|
|
case 0x8:
|
|
/* sim_debug (DBG_REG, &ve_dev, "tbc gf_fb_format wr %X at %08X\n", val, fault_PC); */
|
|
gf_fb_format = val;
|
|
break;
|
|
|
|
case 0x9:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc gf_int_mask wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0xA:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc gf_int_status wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x10: /* FIFO0 Data */
|
|
case 0x18:
|
|
case 0x20:
|
|
case 0x28:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc fifo%d data wr %X at %08X (ptr = %d)\n", GET_FIFO(rg), val, fault_PC, tbc_fifo[GET_FIFO(rg)].put_ptr);
|
|
ve_put_fifo (GET_FIFO(rg), val);
|
|
if (tbc_csr & TBC_CSR_STRSTAT) { /* stream in progress? */
|
|
if (tbc_fifo[GET_FIFO(rg)].count < tbc_fifo[GET_FIFO(rg)].threshold)
|
|
sim_activate (&ve_unit[1], 200); /* flush data */
|
|
}
|
|
break;
|
|
|
|
case 0x11:
|
|
case 0x19:
|
|
case 0x21:
|
|
case 0x29:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc fifo%d put_ptr wr %X at %08X\n", GET_FIFO(rg), val, fault_PC);
|
|
tbc_fifo[GET_FIFO(rg)].put_ptr = val;
|
|
break;
|
|
|
|
case 0x12:
|
|
case 0x1A:
|
|
case 0x22:
|
|
case 0x2A:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc fifo%d get_ptr wr %X at %08X\n", GET_FIFO(rg), val, fault_PC);
|
|
/* tbc_fifo[GET_FIFO(rg)].get_ptr = val; */
|
|
break;
|
|
|
|
case 0x13: /* FIFO0 Count */
|
|
case 0x1B:
|
|
case 0x23:
|
|
case 0x2B:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc fifo%d count wr %X at %08X\n", GET_FIFO(rg), val, fault_PC);
|
|
tbc_fifo[GET_FIFO(rg)].count = val;
|
|
break;
|
|
|
|
case 0x14:
|
|
case 0x1C:
|
|
case 0x24:
|
|
case 0x2C:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc fifo%d threshold wr %X at %08X\n", GET_FIFO(rg), val, fault_PC);
|
|
tbc_fifo[GET_FIFO(rg)].threshold = val;
|
|
break;
|
|
|
|
case 0x15:
|
|
case 0x1D:
|
|
case 0x25:
|
|
case 0x2D:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc fifo%d semaphore wr %X at %08X\n", GET_FIFO(rg), val, fault_PC);
|
|
tbc_fifo[GET_FIFO(rg)].semaphore = val;
|
|
break;
|
|
|
|
case 0x40:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc timing_csr wr %X at %08X\n", val, fault_PC);
|
|
tbc_timing = val;
|
|
break;
|
|
|
|
case 0x41:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc hsync wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x42:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc hsync2 wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x43:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc early_hblank wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x44:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc vsync wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x45:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc vblank wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x46:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc table wr %X at %08X\n", val, fault_PC);
|
|
tbc_table = val;
|
|
break;
|
|
|
|
case 0x47:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc timing_setup wr %X at %08X\n", val, fault_PC);
|
|
tbc_timing_setup = val;
|
|
break;
|
|
|
|
case 0x48:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc ltrr wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x50:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc sp_bus_loop wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
default:
|
|
sim_debug (DBG_REG, &ve_dev, "tbc %X wr %X at %08X\n", rg, val, fault_PC);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int32 scn_rd (int32 rg)
|
|
{
|
|
uint32 data = 0;
|
|
|
|
switch (rg) {
|
|
case 0x40: /* STATUS */
|
|
data = spx_status;
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc status rd %X at %08X\n", data, fault_PC);
|
|
break;
|
|
|
|
case 0x46:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc config rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x7F:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc micropc rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0xFE:
|
|
/* sim_debug (DBG_REG, &ve_dev, "scanproc microlo rd at %08X\n", fault_PC); */
|
|
break;
|
|
|
|
case 0x4B:
|
|
/* sim_debug (DBG_REG, &ve_dev, "scanproc microhi rd at %08X\n", fault_PC); */
|
|
break;
|
|
|
|
case 0x80:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc rowframe rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x0:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc rowframe_mask rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x64:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc maingreg0 rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x24:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc mainreg0_mask rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x82:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc winoffset rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x7B:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc command rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x74:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc xstart rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x75:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc ystart rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x76:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc xend rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x77:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc yend rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x78:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc dstpix rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x38:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc dstpix1 rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x79:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc srcpix rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x39:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc srcpix1 rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x67:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc main3 rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x7A:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc stride rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x7C:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc srcmask rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x7D:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc dstmask rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x98:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc fg rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x99:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc bg rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
case 0x9C:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc destloop rd at %08X\n", fault_PC);
|
|
break;
|
|
|
|
default:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc %X rd at %08X\n", rg, fault_PC);
|
|
break;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
void scn_wr (int32 rg, int32 val, int32 lnt)
|
|
{
|
|
switch (rg) {
|
|
case 0x40: /* STATUS */
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc status wr %X at %08X\n", val, fault_PC);
|
|
spx_status = (spx_status & ~val);
|
|
break;
|
|
|
|
case 0x46:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc config wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x7F:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc micropc wr %X at %08X\n", val, fault_PC);
|
|
spx_upc = val & 0xFFFF;
|
|
sim_activate (&ve_unit[1], 200);
|
|
break;
|
|
|
|
case 0xFE:
|
|
/* sim_debug (DBG_REG, &ve_dev, "scanproc microlo wr %X at %08X\n", val, fault_PC); */
|
|
break;
|
|
|
|
case 0x4B:
|
|
/* sim_debug (DBG_REG, &ve_dev, "scanproc microhi wr %X at %08X\n", val, fault_PC); */
|
|
break;
|
|
|
|
case 0x80:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc rowframe wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x0:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc rowframe_mask wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x64:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc maingreg0 wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x24:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc mainreg0_mask wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x82:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc winoffset wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x7B:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc command wr %X at %08X\n", val, fault_PC);
|
|
spx_cmd = val;
|
|
break;
|
|
|
|
case 0xF4:
|
|
case 0x74:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc xstart wr %X at %08X\n", val, fault_PC);
|
|
spx_xstart = val;
|
|
break;
|
|
|
|
case 0xF5:
|
|
case 0x75:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc ystart wr %X at %08X\n", val, fault_PC);
|
|
spx_ystart = val;
|
|
break;
|
|
|
|
case 0xF6:
|
|
case 0x76:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc xend wr %X at %08X\n", val, fault_PC);
|
|
spx_xend = val;
|
|
break;
|
|
|
|
case 0xF7:
|
|
case 0x77:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc yend wr %X at %08X\n", val, fault_PC);
|
|
spx_yend = val;
|
|
break;
|
|
|
|
case 0x78:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc dstpix wr %X at %08X\n", val, fault_PC);
|
|
spx_dstpix = val;
|
|
break;
|
|
|
|
case 0x38:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc dstpix1 wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x79:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc srcpix wr %X at %08X\n", val, fault_PC);
|
|
spx_srcpix = val;
|
|
break;
|
|
|
|
case 0x39:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc srcpix1 wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x67:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc main3 wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0xFA:
|
|
case 0x7A:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc stride wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x7C:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc srcmask wr %X at %08X\n", val, fault_PC);
|
|
spx_smask = val;
|
|
break;
|
|
|
|
case 0x7D:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc dstmask wr %X at %08X\n", val, fault_PC);
|
|
spx_dmask = val;
|
|
break;
|
|
|
|
case 0xD8:
|
|
case 0x98:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc fg wr %X at %08X\n", val, fault_PC);
|
|
spx_fg = val;
|
|
break;
|
|
|
|
case 0x99:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc bg wr %X at %08X\n", val, fault_PC);
|
|
break;
|
|
|
|
case 0x9C:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc destloop wr %X at %08X\n", val, fault_PC);
|
|
spx_destloop = val;
|
|
break;
|
|
|
|
default:
|
|
sim_debug (DBG_REG, &ve_dev, "scanproc %X wr %X\n", rg, val);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void spx_fill_rect (void)
|
|
{
|
|
uint32 xstart, xend, ystart, yend;
|
|
uint32 dstpix;
|
|
uint32 x, y;
|
|
|
|
xstart = (spx_xstart >> 16);
|
|
ystart = (spx_ystart >> 16);
|
|
xend = (spx_xend >> 16);
|
|
yend = (spx_yend >> 16);
|
|
if (spx_cmd & 0x400) /* absolute coordinates */
|
|
dstpix = 0;
|
|
else
|
|
dstpix = spx_dstpix & 0xFFFFFF;
|
|
|
|
sim_debug (DBG_ROP, &ve_dev, "fill_rect: xs = %d, xe = %d, ys = %d, ye = %d, dx = %d, dy = %d, fg = %X\n",
|
|
xstart, xend, ystart, yend, (dstpix % 1280), (dstpix / 1280), (spx_fg & 0xFF));
|
|
|
|
if (xend > VE_BXSIZE) /* clip X */
|
|
xend = VE_BXSIZE;
|
|
if (yend > VE_BYSIZE) /* clip Y */
|
|
yend = VE_BYSIZE;
|
|
|
|
if ((spx_destloop & 0xFFFF) != 0x2006) {
|
|
for (y = ystart; y < yend; y++) {
|
|
for (x = xstart; x < xend; x++) {
|
|
ve_buf[((y * 1280) + x + dstpix)] = (spx_fg & 0xFF);
|
|
}
|
|
if (y < VE_YSIZE)
|
|
ve_updated[y] = TRUE; /* FIXME: map to screen line */
|
|
}
|
|
}
|
|
cp_int_status |= 0x2;
|
|
}
|
|
|
|
void spx_copy_rect (void)
|
|
{
|
|
uint32 xstart, xend, ystart, yend;
|
|
uint32 srcpix, dstpix;
|
|
uint32 x, y;
|
|
|
|
xstart = (spx_xstart >> 16);
|
|
ystart = (spx_ystart >> 16);
|
|
xend = (spx_xend >> 16);
|
|
yend = (spx_yend >> 16);
|
|
srcpix = spx_srcpix & 0xFFFFFF;
|
|
if (spx_cmd & 0x400) /* absolute coordinates */
|
|
dstpix = 0;
|
|
else
|
|
dstpix = spx_dstpix & 0xFFFFFF;
|
|
|
|
sim_debug (DBG_ROP, &ve_dev, "copy_rect: xs = %d, xe = %d, ys = %d, ye = %d, sx = %d, sy = %d, dx = %d, dy = %d\n",
|
|
xstart, xend, ystart, yend, (srcpix % 1280), (srcpix / 1280), (dstpix % 1280), (dstpix / 1280));
|
|
|
|
if (xend > VE_BXSIZE) /* clip X */
|
|
xend = VE_BXSIZE;
|
|
if (yend > VE_BYSIZE) /* clip Y */
|
|
yend = VE_BYSIZE;
|
|
|
|
for (y = ystart; y < yend; y++) {
|
|
for (x = xstart; x < xend; x++) {
|
|
ve_buf[((y * 1280) + x + dstpix)] = \
|
|
(ve_buf[((y * 1280) + x + dstpix)] & ~spx_dmask) | \
|
|
(ve_buf[(((y - ystart) * 1280) + (x - xstart) + srcpix)] & spx_smask);
|
|
}
|
|
if (y < VE_YSIZE)
|
|
ve_updated[y] = TRUE; /* FIXME: map to screen line */
|
|
}
|
|
cp_int_status |= 0x2;
|
|
}
|
|
|
|
void spx_stream_data ()
|
|
{
|
|
uint32 xstart, xend, ystart, yend;
|
|
uint32 dstpix;
|
|
uint32 data, i;
|
|
|
|
xstart = (spx_xstart >> 16);
|
|
ystart = (spx_ystart >> 16);
|
|
xend = (spx_xend >> 16);
|
|
yend = (spx_yend >> 16);
|
|
|
|
if (spx_cmd & 0x400) /* absolute coordinates */
|
|
dstpix = 0;
|
|
else
|
|
dstpix = spx_dstpix & 0xFFFFFF;
|
|
spx_strx = xstart;
|
|
spx_stry = ystart;
|
|
|
|
sim_debug (DBG_ROP, &ve_dev, "stream_data: xs = %d, xe = %d, ys = %d, ye = %d, dx = %d, dy = %d\n",
|
|
xstart, xend, ystart, yend, (dstpix % 1280), (dstpix / 1280));
|
|
|
|
if (tbc_csr & TBC_CSR_STRDIR) { /* write */
|
|
while (tbc_fifo[0].count < FIFO_LEN) {
|
|
ve_get_fifo (0, &data);
|
|
for (i = 0; i < 4; i++) {
|
|
sim_debug (DBG_REG, &ve_dev, "buffer[%X] = %X\n", ((spx_stry * 1280) + spx_strx + dstpix), ((data >> (i << 3)) & 0xFF));
|
|
ve_buf[((spx_stry * 1280) + spx_strx + dstpix)] = ((data >> (i << 3)) & 0xFF);
|
|
spx_strx++;
|
|
if (spx_stry < VE_YSIZE)
|
|
ve_updated[spx_stry] = TRUE;
|
|
if (spx_strx > xend) {
|
|
spx_strx = xstart;
|
|
spx_stry++;
|
|
}
|
|
if (spx_stry > yend) {
|
|
cp_int_status |= 0x2; /* Done */
|
|
spx_status |= 0x100; /* Done */
|
|
tbc_csr &= ~TBC_CSR_STRSTAT;
|
|
sim_debug (DBG_REG, &ve_dev, "stream done\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else { /* read */
|
|
while (tbc_fifo[0].count > 0) {
|
|
data = 0;
|
|
for (i = 0; i < 4; i++) {
|
|
if (spx_strx > xend) {
|
|
spx_strx = xstart;
|
|
spx_stry++;
|
|
}
|
|
if (spx_stry > yend) break;
|
|
/* sim_debug (DBG_REG, &ve_dev, "buffer[%X] = %X\n", ((spx_stry * 1280) + spx_strx + dstpix), ((val >> (i << 3)) & spx_wmask & 0xFF)); */
|
|
data |= (((ve_buf[((spx_stry * 1280) + spx_strx + dstpix)]) & spx_rmask & 0xFF) << (i << 3));
|
|
spx_strx++;
|
|
|
|
if (spx_stry > yend) {
|
|
cp_int_status |= 0x2;
|
|
return;
|
|
}
|
|
}
|
|
ve_put_fifo (0, data);
|
|
}
|
|
}
|
|
}
|
|
|
|
t_stat ve_micro_svc (UNIT *uptr)
|
|
{
|
|
switch (spx_upc) {
|
|
|
|
case 0x23AE:
|
|
case 0x2019:
|
|
spx_fill_rect ();
|
|
break;
|
|
|
|
case 0x1F:
|
|
case 0x239C: /* Read? */
|
|
case 0x23A2: /* Bitmap write? */
|
|
case 0x53:
|
|
spx_stream_data ();
|
|
break;
|
|
|
|
case 0x23CB:
|
|
case 0xA9:
|
|
spx_copy_rect ();
|
|
break;
|
|
|
|
case 0x2153: /* Load microcode? */
|
|
break;
|
|
|
|
default:
|
|
sim_debug (DBG_REG, &ve_dev, "unknown scanproc micropc %X\n", spx_upc);
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
static SIM_INLINE void ve_invalidate (uint32 y1, uint32 y2)
|
|
{
|
|
uint32 ln;
|
|
|
|
for (ln = y1; ln < y2; ln++)
|
|
ve_updated[ln] = TRUE; /* flag as updated */
|
|
}
|
|
|
|
t_stat ve_svc (UNIT *uptr)
|
|
{
|
|
SIM_MOUSE_EVENT mev;
|
|
SIM_KEY_EVENT kev;
|
|
t_bool updated = FALSE; /* flag for refresh */
|
|
uint32 lines;
|
|
uint32 ln, col, off;
|
|
uint32 i, c;
|
|
uint32 rg, val;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (tbc_csr & TBC_CSR_FIFOEN(i)) {
|
|
if (tbc_fifo[i].count >= tbc_fifo[i].threshold)
|
|
cp_int_status |= (INTSTS_F0_GE_THRSH << (4 * i));
|
|
else
|
|
cp_int_status |= (INTSTS_F0_LT_THRSH << (4 * i));
|
|
if ((tbc_fifo[i].count & 1) == 0) {
|
|
while (tbc_fifo[i].count < FIFO_LEN) { /* while fifo not empty */
|
|
/* NOTE:
|
|
* if ((tbc_csr & STREAM_STATUS) && ((tbc_csr & STREAM_DIRECTION) == INPUT))
|
|
* stream to bitmap
|
|
* else if ((tbc_csr & STREAM_STATUS) && ((tbc_csr & STREAM_DIRECTION) == OUTPUT))
|
|
* stream from bitmap
|
|
* else
|
|
* register writes
|
|
*/
|
|
sim_debug (DBG_REG, &ve_dev, "get_ptr = %d, put_ptr = %d\n", tbc_fifo[i].get_ptr, tbc_fifo[i].put_ptr);
|
|
if ((tbc_csr & TBC_CSR_STRSTAT) == 0) {
|
|
ve_get_fifo (i, &rg);
|
|
switch ((rg >> 20) & 0x3) {
|
|
case 0: /* SCN reg SWZ=0 */
|
|
case 1: /* SCN reg SWZ=1 */
|
|
rg = (rg >> 2) & 0xFF;
|
|
ve_get_fifo (i, &val);
|
|
sim_debug (DBG_REG, &ve_dev, "scn_wr(%X, %X)\n", rg, val);
|
|
scn_wr (rg, val, L_LONG);
|
|
break;
|
|
|
|
case 2: /* TBC reg */
|
|
rg = (rg >> 2) & 0xFF;
|
|
ve_get_fifo (i, &val);
|
|
sim_debug (DBG_REG, &ve_dev, "tbc_wr(%X, %X)\n", rg, val);
|
|
tbc_wr (rg, val, L_LONG);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
cp_int_status |= 0x10; /* VBLANK Finish */
|
|
cp_int_status |= 0x1; /* Ready */
|
|
spx_status |= 0x200; /* Ready */
|
|
|
|
if (vid_poll_kb (&kev) == SCPE_OK) /* poll keyboard */
|
|
lk_event (&kev); /* push event */
|
|
if (vid_poll_mouse (&mev) == SCPE_OK) /* poll mouse */
|
|
vs_event (&mev); /* push event */
|
|
|
|
if (vc_org != vc_last_org) /* origin moved? */
|
|
ve_invalidate (0, (VE_YSIZE - 1)); /* redraw whole screen */
|
|
|
|
vc_last_org = vc_org; /* store video origin */
|
|
|
|
lines = 0;
|
|
for (ln = 0; ln < VE_YSIZE; ln++) {
|
|
if (ve_updated[ln]) { /* line invalid? */
|
|
off = ((ln + (vc_org << VE_ORSC)) * VE_BXSIZE); /* get video buf offet */
|
|
for (col = 0; col < VE_XSIZE; col++)
|
|
ve_lines[ln*VE_XSIZE + col] = ve_palette[ve_buf[off + col]];
|
|
/* 8bpp to 32bpp */
|
|
#if 0
|
|
if (CUR_V) { /* cursor visible? */
|
|
if ((ln >= CUR_Y) && (ln < (CUR_Y + 16))) { /* cursor on this line? */
|
|
plna = &vc_cur[(CUR_PLNA + ln - CUR_Y)];/* get plane A base */
|
|
plnb = &vc_cur[(CUR_PLNB + ln - CUR_Y)];/* get plane B base */
|
|
for (col = 0; col < 16; col++) {
|
|
if ((CUR_X + col) >= VC_XSIZE) /* Part of cursor off screen? */
|
|
continue; /* Skip */
|
|
if (vc_cmd & CMD_FOPA) /* force plane A to 1? */
|
|
bita = 1;
|
|
else if (vc_cmd & CMD_ENPA) /* plane A enabled? */
|
|
bita = (*plna >> col) & 1;
|
|
else bita = 0;
|
|
if (vc_cmd & CMD_FOPB) /* force plane B to 1? */
|
|
bitb = 1;
|
|
else if (vc_cmd & CMD_ENPB) /* plane B enabled? */
|
|
bitb = (*plnb >> col) & 1;
|
|
else bitb = 0;
|
|
line[CUR_X + col] = ve_palette[((line[CUR_X + col] == ve_palette[1]) & ~bitb) ^ bita];
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
ve_updated[ln] = FALSE; /* set valid */
|
|
if ((ln == (VE_YSIZE-1)) || /* if end of window OR */
|
|
(ve_updated[ln+1] == FALSE)) { /* next is already valid? */
|
|
vid_draw (0, ln-lines, VE_XSIZE, lines+1, ve_lines+(ln-lines)*VE_XSIZE); /* update region */
|
|
lines = 0;
|
|
}
|
|
else
|
|
lines++;
|
|
updated = TRUE;
|
|
}
|
|
}
|
|
|
|
if (updated) /* video updated? */
|
|
vid_refresh (); /* put to screen */
|
|
|
|
if (cp_int_status & cp_int_mask)
|
|
SET_INT (VC2);
|
|
sim_activate (uptr, tmxr_poll);
|
|
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
|
|
return c;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat ve_reset (DEVICE *dptr)
|
|
{
|
|
t_stat r;
|
|
uint32 i;
|
|
|
|
CLR_INT (VC2);
|
|
sim_cancel (&ve_unit[0]); /* deactivate units */
|
|
sim_cancel (&ve_unit[1]);
|
|
|
|
bt459_addr = 0;
|
|
cp_fb_format = 0;
|
|
cp_int_status = 0;
|
|
cp_int_mask = 0;
|
|
gf_fb_format = 0;
|
|
spx_xstart = 0;
|
|
spx_ystart = 0;
|
|
spx_xend = 0;
|
|
spx_yend = 0;
|
|
spx_dstpix = 0;
|
|
spx_srcpix = 0;
|
|
bt459_cmap_p = 0;
|
|
bt459_cmap[0] = 0;
|
|
bt459_cmap[1] = 0;
|
|
bt459_cmap[2] = 0;
|
|
spx_fg = 0;
|
|
tbc_csr = 0;
|
|
spx_cmd = 0;
|
|
spx_rmask = 0;
|
|
spx_wmask = 0;
|
|
spx_smask = 0;
|
|
spx_dmask = 0;
|
|
spx_strx = 0;
|
|
spx_stry = 0;
|
|
spx_destloop = 0;
|
|
tbc_timing = 0;
|
|
spx_status = 0;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
ve_clear_fifo (i);
|
|
|
|
for (i = 0; i < VE_YSIZE; i++)
|
|
ve_updated[i] = FALSE;
|
|
|
|
if (dptr->flags & DEV_DIS) {
|
|
if (ve_active) {
|
|
free (ve_buf);
|
|
ve_buf = NULL;
|
|
free (ve_lines);
|
|
ve_lines = NULL;
|
|
ve_active = FALSE;
|
|
return vid_close ();
|
|
}
|
|
else
|
|
return SCPE_OK;
|
|
}
|
|
|
|
if (!vid_active && !ve_active) {
|
|
r = vid_open (dptr, NULL, VE_XSIZE, VE_YSIZE, ve_input_captured ? SIM_VID_INPUTCAPTURED : 0);/* display size & capture mode */
|
|
if (r != SCPE_OK)
|
|
return r;
|
|
ve_buf = (uint8 *) calloc (VE_BUFSIZE, sizeof (uint8));
|
|
if (ve_buf == NULL) {
|
|
vid_close ();
|
|
return SCPE_MEM;
|
|
}
|
|
ve_lines = (uint32 *) calloc (VE_XSIZE*VE_YSIZE, sizeof (uint32));
|
|
if (ve_lines == NULL) {
|
|
free (ve_buf);
|
|
ve_buf = NULL;
|
|
vid_close ();
|
|
return SCPE_MEM;
|
|
}
|
|
sim_printf ("SPX Video Display Created. ");
|
|
ve_show_capture (stdout, NULL, 0, NULL);
|
|
if (sim_log)
|
|
ve_show_capture (sim_log, NULL, 0, NULL);
|
|
sim_printf ("\n");
|
|
ve_active = TRUE;
|
|
}
|
|
sim_activate_abs (&ve_unit[0], tmxr_poll);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat ve_detach (UNIT *uptr)
|
|
{
|
|
if ((ve_dev.flags & DEV_DIS) == 0) {
|
|
ve_dev.flags |= DEV_DIS;
|
|
ve_reset(&ve_dev);
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat ve_set_enable (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
|
{
|
|
return cpu_set_model (NULL, 0, (val ? "VAXSTATIONSPX" : "MICROVAX"), NULL);
|
|
}
|
|
|
|
t_stat ve_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");
|
|
ve_input_captured = val;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat ve_show_capture (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
|
|
{
|
|
if (ve_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 ve_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
|
{
|
|
fprintf (st, "SPX Colour 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 *ve_description (DEVICE *dptr)
|
|
{
|
|
return "SPX Colour Graphics Adapter";
|
|
}
|