/* vax4xx_va.c: GPX 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. va GPX colour video */ #include "vax_defs.h" #include "sim_video.h" #include "vax_gpx.h" #include "vax_lk.h" #include "vax_vs.h" #if VA_PLANES == 4 #include "vax_ka4xx_4pln_bin.h" #else #include "vax_ka4xx_8pln_bin.h" #define BT458 1 #endif #define VA_ADP_OF 0x0000 /* address processor */ #define VA_FCC_OF 0x0100 /* FIFO compression chip */ #define VA_DAC_OF 0x0180 /* D/A converter */ #define VA_CCR_OF 0x0200 /* cursor chip */ #define VA_CBR_OF 0x0280 /* colour board readback */ #define VA_FFW_OF 0x4000 /* FIFO window */ #define VA_TMP_OF 0x40 #define INT_FCC 1 #define CUR_X_OF 216 #define CUR_Y_OF 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 CUR_X ((va_xpos < CUR_X_OF) ? 0 : (va_xpos - CUR_X_OF)) #define CUR_Y ((va_ypos < CUR_Y_OF) ? 0 : (va_ypos - CUR_Y_OF)) #define CUR_V ((va_ccmd & CMD_LODSA) == 0) #define CUR_F (0) #define CUR_PLNA 0 #define CUR_PLNB 16 #if defined(BT458) #define CUR_COL 4 #define CUR_HOT (VA_BPP + 1) #define CUR_BG (VA_BPP + 2) #define CUR_FG (VA_BPP + 3) #else #define CUR_COL 8 #define CUR_HOT (VA_BPP + VA_BPP + 1) #define CUR_BG (VA_BPP + VA_BPP + 2) #define CUR_FG (VA_BPP + VA_BPP + 3) #endif #define RAM_SIZE (1u << 16) /* FIFO RAM */ #define FCCCSR_PACK 0x0100 /* byte/word */ #define FCCCSR_WR 0x5F83 #define FCCCSR_V_MODE 9 #define FCCCSR_M_MODE 0x3 #define GET_MODE(x) ((x >> FCCCSR_V_MODE) & FCCCSR_M_MODE) #define MODE_HALT 0 #define MODE_DL 1 #define MODE_BTP 2 #define MODE_PTB 3 /* Debugging Bitmaps */ #define DBG_FCC 0x0001 /* fifo compression chip activity */ #define DBG_CURSOR 0x0002 /* Cursor content, function and visibility activity */ /* FIFO compression chip registers */ #define FCC_CCSR 0x0 /* colour board CSR */ #define FCC_ICSR 0x1 /* interrupt CSR */ #define FCC_FCSR 0x2 /* FIFO CSR */ #define FCC_FWU 0x3 /* FIFO words used */ #define FCC_FT 0x4 /* FIFO threshold */ #define FCC_RSVD 0x5 /* reserved */ #define FCC_PUT 0x6 /* FIFO put pointer */ #define FCC_GET 0x7 /* FIFO get pointer */ #define FCC_DIAG 0x8 /* diag */ #define FCC_CMPA 0x9 /* CMPA */ #define FCC_CMPB 0xA /* CMPB */ #define FCC_CMPC 0xB /* CPMC - PLA address */ #define FCC_MAXREG 0xB extern int32 int_req[IPL_HLVL]; extern int32 tmxr_poll; /* calibrated delay */ extern int32 fault_PC; extern int32 trpirq; uint16 va_ram[RAM_SIZE]; uint32 va_fcc_csr = 0; uint32 va_fcc_int = 0; uint32 va_fcc_fcsr = 0; uint32 va_fcc_data = 0; uint32 va_fcc_sc = 0; int32 va_fcc_fifo_sz = 0; /* data size */ int32 va_fcc_fifo_th = 0; /* threshold */ uint32 va_fcc_fifo_wp = 0; /* write pointer */ uint32 va_fcc_fifo_rp = 0; /* read pointer */ uint32 va_ccmd = 0; /* cursor command reg */ uint32 va_xpos = 0; /* cursor x position */ uint32 va_ypos = 0; /* cursor y position */ uint32 va_xmin1 = 0; /* region 1 left edge */ uint32 va_xmax1 = 0; /* region 1 right edge */ uint32 va_ymin1 = 0; /* region 1 top edge */ uint32 va_ymax1 = 0; /* region 1 bottom edge */ uint32 va_xmin2 = 0; /* region 2 left edge */ uint32 va_xmax2 = 0; /* region 2 right edge */ uint32 va_ymin2 = 0; /* region 2 top edge */ uint32 va_ymax2 = 0; /* region 2 bottom edge */ uint16 va_cur[32]; /* cursor image data */ uint32 va_cur_p = 0; /* cursor image pointer */ uint32 va_cur_x = 0; /* Last cursor X-position */ uint32 va_cur_y = 0; /* Last cursor Y-position */ uint32 va_cur_f = 0; /* Last cursor function */ t_bool va_cur_v = FALSE; /* Last cursor visible */ t_bool va_active = FALSE; t_bool va_updated[2048]; t_bool va_input_captured = FALSE; /* Mouse and Keyboard input captured in video window */ uint32 *va_buf = NULL; /* Video memory */ uint32 *va_lines = NULL; /* Video Display Lines */ #if defined(BT458) uint32 va_palette[VA_BPP + CUR_COL]; /* Colour palette (screen, cursor)*/ uint32 va_cmap2[VA_BPP + CUR_COL]; /* Colour palette (screen, cursor)*/ #else uint32 va_palette[VA_BPP + VA_BPP + CUR_COL]; /* Colour palette (fg, bg, cursor)*/ #endif uint32 va_dla = 0; /* display list addr */ int32 va_yoff = 0; int32 va_dpln = 0; uint32 va_white = 0; uint32 va_black = 0; uint32 va_bt458_addr = 0; uint32 va_cmap_p = 0; uint32 va_cmap[3]; const char *va_fcc_rgd[] = { /* FIFO compression chip registers */ "Colour Board CSR", "Interrupt CSR", "FIFO CSR", "FIFO Words Used", "FIFO Threshold", "Reserved", "FIFO Put Pointer", "FIFO Get Pointer", "Diag", "CMPA", "CMPB", "CMPC - PLA Address" }; const char *va_dac_rgd[] = { /* D/A converter registers */ "Active Region Colour 0", "Active Region Colour 1", "Active Region Colour 2", "Active Region Colour 3", "Active Region Colour 4", "Active Region Colour 5", "Active Region Colour 6", "Active Region Colour 7", "Active Region Colour 8", "Active Region Colour 9", "Active Region Colour 10", "Active Region Colour 11", "Active Region Colour 12", "Active Region Colour 13", "Active Region Colour 14", "Active Region Colour 15", "Background Colour 0", "Background Colour 1", "Background Colour 2", "Background Colour 3", "Background Colour 4", "Background Colour 5", "Background Colour 6", "Background Colour 7", "Background Colour 8", "Background Colour 9", "Background Colour 10", "Background Colour 11", "Background Colour 12", "Background Colour 13", "Background Colour 14", "Background Colour 15", "Reserved", "Active Cursor Colour A", "Active Cursor Colour B", "Active Cursor Colour C", "Reserved", "Background Cursor Colour A", "Background Cursor Colour B", "Background Cursor Colour C", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Mode", "Delay Adjust - Sync", "Delay Adjust - Blank", "Delay Adjust - Active Region" }; const char *va_ccr_rgd[] = { /* cusror chip registers */ "Command Register", "X Position", "Y Position", "X Minimum 1", "X Maximum 1", "Y Minimum 1", "Y Maximum 1", "Reserved", "Reserved", "Reserved", "Reserved", "X Minimum 2", "X Maximum 2", "Y Minimum 2", "Y Maximum 2", "Cursor Bitmap" }; t_stat va_svc (UNIT *uptr); t_stat va_dmasvc (UNIT *uptr); t_stat va_reset (DEVICE *dptr); t_stat va_attach (UNIT *uptr, CONST char *cptr); t_stat va_detach (UNIT *uptr); t_stat va_set_enable (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat va_set_capture (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat va_show_capture (FILE* st, UNIT* uptr, int32 val, CONST void* desc); t_stat va_set_yoff (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat va_show_yoff (FILE* st, UNIT* uptr, int32 val, CONST void* desc); t_stat va_set_dpln (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat va_show_dpln (FILE* st, UNIT* uptr, int32 val, CONST void* desc); t_stat va_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); const char *va_description (DEVICE *dptr); void va_dlist (void); extern int32 eval_int (void); /* GPX data structures va_dev GPX device descriptor va_unit GPX unit list va_reg GPX register list va_mod GPX modifier list */ DIB va_dib = { VA_ROM_INDEX, BOOT_CODE_ARRAY, BOOT_CODE_SIZE }; UNIT va_unit[] = { { UDATA (&va_svc, UNIT_IDLE, 0) }, { UDATA (&va_dmasvc, UNIT_IDLE+UNIT_DIS, 0) }, }; REG va_reg[] = { { HRDATAD (AADCT, va_adp[ADP_ADCT], 16, "address counter") }, { HRDATAD (AREQ, va_adp[ADP_REQ], 16, "request enable") }, { HRDATAD (AINT, va_adp[ADP_INT], 16, "interrupt enable") }, { HRDATAD (ASTAT, va_adp[ADP_STAT], 16, "status") }, { HRDATAD (AMDE, va_adp[ADP_MDE], 16, "mode") }, { NULL } }; MTAB va_mod[] = { { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLE", &va_set_enable, NULL, NULL, "Enable GPX" }, { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLE", &va_set_enable, NULL, NULL, "Disable GPX" }, { MTAB_XTD|MTAB_VDV, TRUE, NULL, "CAPTURE", &va_set_capture, &va_show_capture, NULL, "Enable Captured Input Mode" }, { MTAB_XTD|MTAB_VDV, FALSE, NULL, "NOCAPTURE", &va_set_capture, NULL, NULL, "Disable Captured Input Mode" }, { MTAB_XTD|MTAB_VDV, TRUE, "OSCURSOR", NULL, NULL, &va_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, 0, "OFFSET", "OFFSET=n", &va_set_yoff, &va_show_yoff, NULL, "Display the Y offset" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "DPLANE", "DPLANE=n", &va_set_dpln, &va_show_dpln, NULL, "Display the debug plane" }, { 0 } }; DEVICE va_dev = { "VA", va_unit, va_reg, va_mod, 2, DEV_RDX, 20, 1, DEV_RDX, 8, NULL, NULL, &va_reset, NULL, NULL, &va_detach, &va_dib, DEV_DIS, 0, NULL, NULL, NULL, &va_help, NULL, NULL, &va_description }; void va_fcc_fifo_clr (void) { sim_debug (DBG_FCC, &va_dev, "fcc_fifo_clr\n"); va_fcc_fifo_wp = 0; /* reset pointers */ va_fcc_fifo_rp = 0; va_fcc_fifo_sz = 0; /* empty */ } void va_fcc_fifo_wr (uint32 val) { sim_debug (DBG_FCC, &va_dev, "fcc_fifo_wr: %d, %X (%d) at %08X\n", va_fcc_fifo_wp, val, (va_fcc_fifo_sz + 1), fault_PC); if (va_fcc_fifo_sz == RAM_SIZE) { /* writing full fifo? */ sim_debug (DBG_FCC, &va_dev, "fcc fifo overflow\n"); return; /* should not get here */ } va_ram[va_fcc_fifo_wp++] = val; /* store value */ if (va_fcc_fifo_wp == RAM_SIZE) /* pointer wrap? */ va_fcc_fifo_wp = 0; va_fcc_fifo_sz++; } uint32 va_fcc_fifo_rd (void) { uint32 val; if (va_fcc_fifo_sz == 0) { /* reading empty fifo */ sim_debug (DBG_FCC, &va_dev, "fcc fifo underflow\n"); return 0; /* should not get here */ } val = va_ram[va_fcc_fifo_rp++]; /* get value */ sim_debug (DBG_FCC, &va_dev, "fcc_fifo_rd: %d, %X (%d) at %08X\n", (va_fcc_fifo_rp - 1), val, va_fcc_fifo_sz, fault_PC); if (va_fcc_fifo_rp == RAM_SIZE) /* pointer wrap? */ va_fcc_fifo_rp = 0; va_fcc_fifo_sz--; if (va_fcc_fifo_sz == 0) va_fcc_fifo_clr (); return val; } void va_ccr_wr (int32 pa, int32 val, int32 lnt) { int32 rg = (pa >> 1) & 0x1F; if (rg <= 0xF) sim_debug (DBG_REG, &va_dev, "ccr_wr: %s, %X at %08X\n", va_ccr_rgd[rg], val, fault_PC); else sim_debug (DBG_REG, &va_dev, "ccr_wr: %X, %X at %08X\n", rg, val, fault_PC); switch (rg) { case 0: /* CUR_CMD */ #if 0 if ((val & CMD_TEST) == 0) { if (val & (CMD_ENRG2|CMD_FORG2|CMD_ENRG1|CMD_FORG1|CMD_FOPB|CMD_FOPA)) ka_cfgtst = ka_cfgtst & ~(1 << 4); else ka_cfgtst = ka_cfgtst | (1 << 4); } else ka_cfgtst = ka_cfgtst | (1 << 4); #endif if ((va_ccmd ^ val) & CMD_LODSA) /* toggle sprite display? */ va_cur_p = 0; /* reset array ptr */ va_ccmd = val; break; case 1: /* CUR_XPOS */ va_xpos = val; break; case 2: /* CUR_YPOS */ va_ypos = val; break; case 3: /* CUR_XMIN_1 */ va_xmin1 = val; break; case 4: /* CUR_XMAX_1 */ va_xmax1 = val; break; case 5: /* CUR_YMIN_1 */ va_ymin1 = val; break; case 6: /* CUR_YMAX_1 */ va_ymax1 = val; break; case 11: /* CUR_XMIN_2 */ va_xmin2 = val; break; case 12: /* CUR_XMAX_2 */ va_xmax2 = val; break; case 13: /* CUR_YMIN_2 */ va_ymin2 = val; break; case 14: /* CUR_YMAX_2 */ va_ymax2 = val; break; case 15: /* CUR_LOAD */ va_cur[va_cur_p++] = val; if (va_cur_p == 32) va_cur_p--; break; } } #if defined(BT458) int32 va_dac_rd (int32 pa) { uint32 rg = (pa >> 1) & 0x3F; uint32 data = 0; switch (rg) { case 0: /* address */ data = va_bt458_addr; break; case 1: /* colour map */ if (va_cmap_p == 0) { va_cmap[0] = va_cmap2[va_bt458_addr] & 0xFF; va_cmap[1] = (va_cmap2[va_bt458_addr] >> 8) & 0xFF; va_cmap[2] = (va_cmap2[va_bt458_addr] >> 16) & 0xFF; } data = va_cmap[va_cmap_p++]; if (va_cmap_p == 3) { va_cmap_p = 0; va_bt458_addr++; va_bt458_addr = va_bt458_addr & 0xFF; } break; case 2: /* control */ va_bt458_addr++; va_bt458_addr = va_bt458_addr & 0x7; break; case 3: /* overlay map */ if (va_cmap_p == 0) { va_cmap[0] = va_cmap2[VA_BPP + va_bt458_addr] & 0xFF; va_cmap[1] = (va_cmap2[VA_BPP + va_bt458_addr] >> 8) & 0xFF; va_cmap[2] = (va_cmap2[VA_BPP + va_bt458_addr] >> 16) & 0xFF; } data = va_cmap[va_cmap_p++]; if (va_cmap_p == 3) { va_cmap_p = 0; va_bt458_addr++; va_bt458_addr = va_bt458_addr & 0x7; } break; } return data; } void va_dac_wr (int32 pa, int32 val, int32 lnt) { uint32 rg = (pa >> 1) & 0x3F; int32 i; switch (rg) { case 0: /* address */ va_bt458_addr = val & 0xFF; va_cmap_p = 0; break; case 1: /* colour map */ va_cmap[va_cmap_p++] = val; if (va_cmap_p == 3) { va_cmap_p = 0; va_palette[va_bt458_addr] = vid_map_rgb (va_cmap[0], va_cmap[1], va_cmap[2]); va_cmap2[va_bt458_addr] = va_cmap[0]; va_cmap2[va_bt458_addr] |= (va_cmap[1] << 8); va_cmap2[va_bt458_addr] |= (va_cmap[2] << 16); for (i = 0; i < VA_YSIZE; i++) va_updated[i] = TRUE; va_bt458_addr++; va_bt458_addr = va_bt458_addr & 0xFF; } break; case 2: /* control */ va_bt458_addr++; va_bt458_addr = va_bt458_addr & 0x7; break; case 3: /* overlay map */ va_cmap[va_cmap_p++] = val; if (va_cmap_p == 3) { va_cmap_p = 0; va_palette[VA_BPP + va_bt458_addr] = vid_map_rgb (va_cmap[0], va_cmap[1], va_cmap[2]); va_cmap2[VA_BPP + va_bt458_addr] = va_cmap[0]; va_cmap2[VA_BPP + va_bt458_addr] |= (va_cmap[1] << 8); va_cmap2[VA_BPP + va_bt458_addr] |= (va_cmap[2] << 16); for (i = 0; i < VA_YSIZE; i++) va_updated[i] = TRUE; va_bt458_addr++; va_bt458_addr = va_bt458_addr & 0x7; } break; } } #else int32 va_dac_rd (int32 pa) { uint32 rg = (pa >> 1) & 0x3F; uint32 data = 0; if (rg <= 0x33) sim_debug (DBG_REG, &va_dev, "dac_rd: %s, %X at %08X\n", va_dac_rgd[rg], data, fault_PC); else sim_debug (DBG_REG, &va_dev, "dac_rd: %X, %X at %08X\n", rg, data, fault_PC); return data; } void va_dac_wr (int32 pa, int32 val, int32 lnt) { uint32 rg = (pa >> 1) & 0x3F; int32 red, grn, blu, i; if (rg <= 0x33) sim_debug (DBG_REG, &va_dev, "dac_wr: %s, %X at %08X\n", va_dac_rgd[rg], val, fault_PC); else sim_debug (DBG_REG, &va_dev, "dac_wr: %X, %X at %08X\n", rg, val, fault_PC); if (rg < 0x28) { /* active colour map? */ rg = rg & 0xF; red = val & 0xF; blu = (val >> 4) & 0xF; grn = (val >> 8) & 0xF; red = red | (red << 4); /* 12 bit to 24 bit */ blu = blu | (blu << 4); grn = grn | (grn << 4); va_palette[rg] = vid_map_rgb (red, grn, blu); for (i = 0; i < VA_YSIZE; i++) va_updated[i] = TRUE; } } #endif int32 va_fcc_rd (int32 pa) { uint32 rg = (pa >> 1) & 0xF; uint32 data = 0; switch (rg) { case FCC_CCSR: /* colour board CSR */ data = va_fcc_csr; if (va_adp[ADP_REQ] & va_adp[ADP_STAT]) data = data | 0x2000; /* Adder requesting I/O */ break; case FCC_ICSR: /* interrupt CSR */ data = va_fcc_int; break; case FCC_FCSR: /* FIFO CSR */ data = va_fcc_fcsr; if (va_fcc_fifo_sz == RAM_SIZE) data = data | 0x8000; /* FIFO full */ else if (va_fcc_fifo_sz == 0) data = data | 0x80; /* FIFO empty */ else if (va_fcc_fifo_sz < 0) data = data | 0x4; /* FIFO data is wrapping around */ switch (GET_MODE (va_fcc_csr)) { case MODE_BTP: if (va_fcc_fifo_wp == va_fcc_fifo_th) data = data | 0x4000; /* FIFO pointers at threshold */ break; case MODE_PTB: case MODE_DL: if (va_fcc_fifo_rp == va_fcc_fifo_th) data = data | 0x4000; /* FIFO pointers at threshold */ break; } break; case FCC_FWU: /* FIFO words used */ if (va_fcc_fifo_sz < 0) data = 0xC000 - (va_fcc_fifo_rp - va_fcc_fifo_wp); else data = va_fcc_fifo_sz; break; case FCC_FT: /* threshold */ data = va_fcc_fifo_th; break; case FCC_PUT: /* put pointer */ data = va_fcc_fifo_wp; break; case FCC_GET: /* get pointer */ data = va_fcc_fifo_rp; break; default: data = 0; break; } if (rg <= FCC_MAXREG) sim_debug (DBG_REG, &va_dev, "fcc_rd: %s, %X at %08X\n", va_fcc_rgd[rg], data, fault_PC); else sim_debug (DBG_REG, &va_dev, "fcc_rd: %X, %X at %08X\n", rg, data, fault_PC); return data; } void va_fcc_wr (int32 pa, int32 val, int32 lnt) { uint32 rg = (pa >> 1) & 0xF; if (rg <= FCC_MAXREG) sim_debug (DBG_REG, &va_dev, "fcc_wr: %s, %X at %08X\n", va_fcc_rgd[rg], val, fault_PC); else sim_debug (DBG_REG, &va_dev, "fcc_wr: %X, %X at %08X\n", rg, val, fault_PC); switch (rg) { case FCC_CCSR: /* colour board CSR */ if (GET_MODE (val) != MODE_DL) va_dla = 0; va_fcc_csr = (va_fcc_csr & ~FCCCSR_WR); va_fcc_csr = va_fcc_csr | (val & FCCCSR_WR); if (val & 0x4000) { /* flush FIFO? */ #if 0 va_fcc_fifo_wp = 0; va_fcc_fifo_rp = 0; va_fcc_fifo_sz = 0; if (va_fcc_fifo_sz < va_fcc_fifo_th) #endif va_fcc_int |= 0x80; /* interrupt */ } if (GET_MODE (va_fcc_csr) != MODE_HALT) va_dmasvc (&va_unit[1]); break; case FCC_ICSR: /* interrupt CSR */ if ((val & 0x42) == 0) CLR_INT (VC2); else if ((va_fcc_int & 0x3) == 0x1) /* pixel interrupt */ SET_INT (VC2); else if ((va_fcc_int & 0xC0) == 0x80) /* threshold interrupt */ SET_INT (VC2); va_fcc_int = va_fcc_int & ~(val & 0x81); /* W1C */ va_fcc_int = va_fcc_int & ~(0x42); /* WR */ va_fcc_int = va_fcc_int | (val & 0x42); break; case FCC_FCSR: /* FIFO CSR */ va_fcc_fcsr = val & 0xFFFF; break; case FCC_FWU: /* FIFO words used */ break; case FCC_FT: /* threshold */ va_fcc_fifo_th = val; break; case FCC_PUT: /* put pointer */ va_fcc_fifo_wp = val; va_fcc_fifo_sz = va_fcc_fifo_wp - va_fcc_fifo_rp; sim_debug (DBG_FCC, &va_dev, "Put pointer wr: mode = %d\n", GET_MODE (va_fcc_csr)); if ((GET_MODE (va_fcc_csr) != MODE_HALT) && (va_fcc_fifo_sz > 0)) va_dmasvc (&va_unit[1]); break; case FCC_GET: /* get pointer */ va_fcc_fifo_rp = val; va_fcc_fifo_sz = va_fcc_fifo_wp - va_fcc_fifo_rp; sim_debug (DBG_FCC, &va_dev, "Get pointer wr: mode = %d\n", GET_MODE (va_fcc_csr)); if ((GET_MODE (va_fcc_csr) != MODE_HALT) && (va_fcc_fifo_sz > 0)) va_dmasvc (&va_unit[1]); break; default: break; } } int32 va_rd (int32 pa) { int32 rg = (pa >> 1) & 0x7FFF; int32 data; if (rg >= VA_FFW_OF) { rg = rg & 0x3FFF; rg = rg | ((va_fcc_csr & 0x3) << 14); /* add A15,A16 */ data = va_ram[rg]; sim_debug (DBG_REG, &va_dev, "ffw_rd: %X, %X at %08X\n", rg, data, fault_PC); return data; } if (rg >= VA_CBR_OF) { #if defined(BT458) data = (VA_PLANES << 4); /* Brooktree 4 or 8-plane */ #else data = 0x00F0; /* original 4-plane */ #endif return data; } if (rg >= VA_CCR_OF) { data = 0; sim_debug (DBG_REG, &va_dev, "ccr_rd: %X, %X at %08X\n", pa, data, fault_PC); return data; } if (rg >= VA_DAC_OF) { data = va_dac_rd (pa); return data; } if (rg >= VA_FCC_OF) { data = va_fcc_rd (pa); return data; } if (rg >= VA_ADP_OF) { /* address processor */ data = va_adp_rd (rg); SET_IRQL; return data; } return 0; } void va_wr (int32 pa, int32 val, int32 lnt) { int32 nval; int32 rg = (pa >> 1) & 0x7FFF; int32 sc; if (rg >= VA_FFW_OF) { rg = rg & 0x3FFF; rg = rg | ((va_fcc_csr & 0x3) << 14); /* add A15,A16 */ if (lnt < L_WORD) { int32 t = va_ram[rg]; sc = (pa & 1) << 3; nval = ((val & BMASK) << sc) | (t & ~(BMASK << sc)); } else nval = val; va_ram[rg] = nval; sim_debug (DBG_REG, &va_dev, "ffw_wr: %X, %X at %08X\n", rg, val, fault_PC); return; } if (rg >= VA_CBR_OF) { sim_debug (DBG_REG, &va_dev, "cbr_wr: %X, %X at %08X\n", pa, val, fault_PC); return; } if (rg >= VA_CCR_OF) { va_ccr_wr (pa, val, lnt); return; } if (rg >= VA_DAC_OF) { va_dac_wr (pa, val, lnt); return; } if (rg >= VA_FCC_OF) { va_fcc_wr (pa, val, lnt); return; } if (rg >= VA_ADP_OF) { /* address processor */ va_adp_wr (rg, val); SET_IRQL; return; } } void va_dlist () { t_bool nodec = FALSE; uint32 inst, saved_inst; int32 val; saved_inst = (va_dla >> 16) & 0xFFFF; /* get saved instruction */ va_dla = va_dla & 0x0000FFFF; /* get saved address */ if ((va_dla < VA_TMP_OF) || (saved_inst & 0x2000)) { if (va_fcc_fifo_sz == 0) return; inst = va_fcc_fifo_rd (); } else inst = va_ram[va_dla++]; if (saved_inst & 0x1000) /* saved decode flag */ nodec = TRUE; sim_debug (DBG_ROP, &va_dev, "Begin display list\n"); sim_debug (DBG_ROP, &va_dev, "DLIST: %04X = %04X ", (va_dla == 0) ? 0 : (va_dla - 1), inst); for (;;) { if (nodec) { /* decode disabled? */ sim_debug (DBG_ROP, &va_dev, "(data - full word)\n"); va_adp_wr (ADP_ADCT, inst); /* write to adder (full word) */ nodec = FALSE; /* enable decode */ } else if (inst & 0x8000) { /* command? */ if (inst & 0x800) { if (va_dla < VA_TMP_OF) { if (va_fcc_fifo_sz == 0) break; va_dla = va_fcc_fifo_rd (); } else va_dla = va_ram[va_dla]; va_dla = va_dla & 0x1FFF; if (va_dla >= VA_TMP_OF) va_dla = va_dla | 0xC000; sim_debug (DBG_ROP, &va_dev, "(JMPTD @ %X)\n", va_dla); } else { sim_debug (DBG_ROP, &va_dev, "(command"); if (inst & 0x4000) sim_debug (DBG_ROP, &va_dev, ", write disable"); if (inst & 0x2000) /* read fifo? */ sim_debug (DBG_ROP, &va_dev, ", read fifo"); if (inst & 0x1000) /* decode disable? */ sim_debug (DBG_ROP, &va_dev, ", decode disable"); sim_debug (DBG_ROP, &va_dev, ")\n"); if ((inst & 0x4000) == 0) /* write enabled? */ va_adp_wr (ADP_ADCT, (0x8000 | (inst & 0xFFF))); /* update counter */ if (inst & 0x1000) /* decode disable? */ nodec = TRUE; if (inst & 0x2000) { /* read fifo? */ if (va_fcc_fifo_sz == 0) { va_dla = va_dla | (inst << 16); /* save current instruction */ break; } inst = va_fcc_fifo_rd (); sim_debug (DBG_ROP, &va_dev, "DLIST: fifo = %04X\n", inst); continue; } } } else if (inst & 0x4000) { /* write disable? */ if (inst & 0x2000) { /* read fifo? */ val = inst & 0x1FFF; val = 0x2000 - val; /* FIXME: # words is negative? */ sim_debug (DBG_ROP, &va_dev, "(PTB %d words)\n", val); for (; val > 0; val--) { if (va_fcc_fifo_sz == 0) break; inst = va_fcc_fifo_rd (); va_adp_wr (ADP_IDD, inst); } va_dla = 0; /* always returns to FIFO */ } else { va_dla = inst & 0x1FFF; if (va_dla >= VA_TMP_OF) va_dla = va_dla | 0xC000; sim_debug (DBG_ROP, &va_dev, "(JMPT @ %X)\n", va_dla); } } else { sim_debug (DBG_ROP, &va_dev, "(data)\n"); va_adp_wr (ADP_ADCT, (inst & 0x3FFF)); /* write to adder */ } if (va_dla < VA_TMP_OF) { if (va_fcc_fifo_sz == 0) break; inst = va_fcc_fifo_rd (); } else inst = va_ram[va_dla++]; sim_debug (DBG_ROP, &va_dev, "DLIST: %04X = %04X ", (va_dla == 0) ? 0 : (va_dla - 1), inst); } sim_debug (DBG_ROP, &va_dev, "Display list complete\n"); } void va_setint (int32 src) { switch (src) { case INT_FCC: /* DMA IRQ */ SET_INT (VC2); break; case INT_ADP: /* ADP IRQ */ SET_INT (VC1); break; } } static SIM_INLINE void va_invalidate (uint32 y1, uint32 y2) { uint32 ln; for (ln = y1; ln < y2; ln++) va_updated[ln] = TRUE; /* flag as updated */ } t_stat va_svc (UNIT *uptr) { SIM_MOUSE_EVENT mev; SIM_KEY_EVENT kev; t_bool updated = FALSE; /* flag for refresh */ uint32 lines; uint32 ln, col, off; uint16 *plna, *plnb; uint16 bita, bitb; uint32 c; va_adp_svc (uptr); if (va_cur_v != CUR_V) { /* visibility changed? */ if (CUR_V) /* visible? */ va_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */ else va_invalidate (va_cur_y, (va_cur_y + 16)); /* invalidate old pos */ } else if (va_cur_y != CUR_Y) { /* moved (Y)? */ va_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */ va_invalidate (va_cur_y, (va_cur_y + 16)); /* invalidate old pos */ } else if (va_cur_x != CUR_X) { /* moved (X)? */ va_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */ } va_cur_x = CUR_X; /* store cursor data */ va_cur_y = CUR_Y; va_cur_v = CUR_V; va_cur_f = CUR_F; 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 */ lines = 0; for (ln = 0; ln < VA_YSIZE; ln++) { if (va_updated[ln + va_yoff]) { /* line updated? */ off = (ln + va_yoff) * VA_XSIZE; /* get video buf offet */ if (va_dpln > 0) { for (col = 0; col < VA_XSIZE; col++) va_lines[ln*VA_XSIZE + col] = (va_buf[off + col] & va_dpln) ? va_white : va_black; } else { for (col = 0; col < VA_XSIZE; col++) va_lines[ln*VA_XSIZE + col] = va_palette[va_buf[off + col] & VA_PLANE_MASK]; } if (CUR_V && /* cursor visible && need to draw cursor? */ (va_input_captured || (va_dev.dctrl & DBG_CURSOR))) { if ((ln >= CUR_Y) && (ln < (CUR_Y + 16))) { /* cursor on this line? */ plna = &va_cur[(CUR_PLNA + ln - CUR_Y)];/* get plane A base */ plnb = &va_cur[(CUR_PLNB + ln - CUR_Y)];/* get plane B base */ for (col = 0; col < 16; col++) { if ((CUR_X + col) >= VA_XSIZE) /* Part of cursor off screen? */ continue; /* Skip */ if (va_ccmd & CMD_FOPA) /* force plane A to 1? */ bita = 1; else if (va_ccmd & CMD_ENPA) /* plane A enabled? */ bita = (*plna >> col) & 1; else bita = 0; if (va_ccmd & CMD_FOPB) /* force plane B to 1? */ bitb = 1; else if (va_ccmd & CMD_ENPB) /* plane B enabled? */ bitb = (*plnb >> col) & 1; else bitb = 0; if (bita & bitb) va_lines[ln*VA_XSIZE + CUR_X + col] = va_palette[CUR_FG]; else if (bita ^ bitb) va_lines[ln*VA_XSIZE + CUR_X + col] = va_palette[CUR_BG]; } } } va_updated[ln + va_yoff] = FALSE; /* set valid */ if ((ln == (VA_YSIZE-1)) || /* if end of window OR */ (va_updated[ln+va_yoff+1] == FALSE)) { /* next is already valid? */ vid_draw (0, ln-lines, VA_XSIZE, lines+1, va_lines+(ln-lines)*VA_XSIZE); /* update region */ lines = 0; } else lines++; updated = TRUE; } } if (updated) /* video updated? */ vid_refresh (); /* put to screen */ sim_activate (uptr, tmxr_poll); /* reactivate */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ return c; return SCPE_OK; } t_bool va_fcc_rdn (uint32 *data, uint32 bits) { int32 mask = (1u << bits) - 1; if (va_fcc_sc == 0) { /* need to read FIFO? */ if (va_fcc_fifo_sz == 0) /* empty? */ return FALSE; /* no more data to read */ va_fcc_data = va_fcc_fifo_rd (); } *data = (va_fcc_data >> va_fcc_sc) & mask; /* extract bits */ va_fcc_sc = (va_fcc_sc + bits) & 0xF; return TRUE; } t_bool va_fcc_wrn (uint32 data, uint32 bits) { int32 mask = (1u << bits) - 1; mask = mask << va_fcc_sc; va_fcc_data = va_fcc_data & ~mask; /* clear bits */ va_fcc_data = va_fcc_data | ((data << va_fcc_sc) & mask); /* insert bits */ va_fcc_sc = (va_fcc_sc + bits) & 0xF; if (va_fcc_sc == 0) { /* need to write FIFO? */ if (va_fcc_fifo_sz == RAM_SIZE) /* full? */ return FALSE; /* no more space to write */ va_fcc_fifo_wr (va_fcc_data); va_fcc_data = 0; } return TRUE; } void va_fcc_decomp (UNIT *uptr) { uint32 pix, last_pix, len1, len2, i, sc, temp; last_pix = 0xFF; for (;uptr->CMD != 0;) { if (!va_fcc_rdn (&pix, 4)) /* read pixel from FIFO */ return; va_fifo_wr (pix); /* output pixel */ if ((va_adp[ADP_STAT] & ADPSTAT_ITR) == 0) va_ptb (&va_unit[1], (va_unit[1].CMD == CMD_PTBZ)); if (pix == last_pix) { /* same as previous? */ if (!va_fcc_rdn (&len1, 4)) /* get run length */ return; len2 = 0; if (len1 & 0x8) { /* deferred? */ for (i = 0, sc = 0; i < (len1 & 0x7); i++) { if (!va_fcc_rdn (&temp, 4)) return; len2 = len2 | (temp << sc); sc = sc + 4; } } else len2 = len1 & 0x7; /* immediate */ for (i = 0; i < len2; i++) { va_fifo_wr (pix); /* output pixel */ if ((va_adp[ADP_STAT] & ADPSTAT_ITR) == 0) va_ptb (&va_unit[1], (va_unit[1].CMD == CMD_PTBZ)); } } last_pix = pix; } } void va_fcc_comp (UNIT *uptr) { uint32 pix, last_pix, len1, len2, temp; va_fcc_sc = 0; va_fcc_data = 0; if ((va_adp[ADP_STAT] & ADPSTAT_IRR) == 0) { va_btp (&va_unit[1], (va_unit[1].CMD == CMD_BTPZ)); if (va_adp[ADP_STAT] & ADPSTAT_AC) return; } last_pix = va_fifo_rd (); for (;;) { va_fcc_wrn (last_pix, 4); if ((va_adp[ADP_STAT] & ADPSTAT_IRR) == 0) { va_btp (&va_unit[1], (va_unit[1].CMD == CMD_BTPZ)); if (va_adp[ADP_STAT] & ADPSTAT_AC) return; } pix = va_fifo_rd (); va_fcc_wrn (pix, 4); len1 = 0; while (pix == last_pix) { if ((va_adp[ADP_STAT] & ADPSTAT_IRR) == 0) { va_btp (&va_unit[1], (va_unit[1].CMD == CMD_BTPZ)); if (va_adp[ADP_STAT] & ADPSTAT_AC) return; } pix = va_fifo_rd (); len1++; } if (len1 > 0) { len1--; if (len1 > 0x7) { temp = len1; for (len2 = 0; temp != 0; len2++) temp = temp >> 4; len2 = len2 | 0x8; va_fcc_wrn (len2, 4); for (;len1 != 0;) { va_fcc_wrn (len1 & 0xF, 4); len1 = len1 >> 4; } } else va_fcc_wrn (len1, 4); } last_pix = pix; } } int32 debug_flag = 0; t_stat va_dmasvc (UNIT *uptr) { uint16 data; if (GET_MODE (va_fcc_csr) == MODE_HALT) return SCPE_OK; sim_debug (DBG_FCC, &va_dev, "DMA service\n"); switch (GET_MODE (va_fcc_csr)) { case MODE_PTB: sim_debug (DBG_FCC, &va_dev, "DMA mode PTB\n"); if (va_fcc_csr & 0x1800) { /* compressed? */ va_fcc_decomp (uptr); } else if (va_fcc_csr & FCCCSR_PACK) { for (;uptr->CMD != 0;) { if ((va_adp[ADP_STAT] & ADPSTAT_ITR) == 0) va_ptb (&va_unit[1], (va_unit[1].CMD == CMD_PTBZ)); if (va_fcc_fifo_sz == 0) break; data = va_fcc_fifo_rd (); va_fifo_wr (data & BMASK); if ((va_adp[ADP_STAT] & ADPSTAT_ITR) == 0) va_ptb (&va_unit[1], (va_unit[1].CMD == CMD_PTBZ)); va_fifo_wr ((data >> 8) & BMASK); } } else { for (;uptr->CMD != 0;) { if ((va_adp[ADP_STAT] & ADPSTAT_ITR) == 0) va_ptb (&va_unit[1], (va_unit[1].CMD == CMD_PTBZ)); if (va_fcc_fifo_sz == 0) break; data = va_fcc_fifo_rd (); va_fifo_wr (data); } } va_ptb (&va_unit[1], (va_unit[1].CMD == CMD_PTBZ)); if (va_fcc_fifo_sz < va_fcc_fifo_th) va_fcc_int |= 0x80; if (uptr->CMD == 0) va_fcc_int |= 0x1; break; case MODE_BTP: sim_debug (DBG_FCC, &va_dev, "DMA mode BTP\n"); if ((va_fcc_csr & 0x1880) == 0x1800) { /* compressed, not diag? */ va_fcc_comp (uptr); } else if (va_fcc_csr & FCCCSR_PACK) { for (;;) { if ((va_adp[ADP_STAT] & ADPSTAT_IRR) == 0) { va_btp (&va_unit[1], (va_unit[1].CMD == CMD_BTPZ)); if (va_adp[ADP_STAT] & ADPSTAT_AC) break; } data = (va_fifo_rd () & BMASK); if ((va_adp[ADP_STAT] & ADPSTAT_IRR) == 0) { va_btp (&va_unit[1], (va_unit[1].CMD == CMD_BTPZ)); if (va_adp[ADP_STAT] & ADPSTAT_AC) break; } data |= ((va_fifo_rd () & BMASK) << 8); va_fcc_fifo_wr (data); } } else { for (;;) { if ((va_adp[ADP_STAT] & ADPSTAT_IRR) == 0) { va_btp (&va_unit[1], (va_unit[1].CMD == CMD_BTPZ)); if (va_adp[ADP_STAT] & ADPSTAT_AC) break; } data = va_fifo_rd (); va_fcc_fifo_wr (data); } } if (va_fcc_fifo_sz > va_fcc_fifo_th) va_fcc_int |= 0x80; if (uptr->CMD == 0) va_fcc_int |= 0x1; break; case MODE_DL: sim_debug (DBG_FCC, &va_dev, "DMA mode DL\n"); va_dlist (); if (va_fcc_fifo_sz < va_fcc_fifo_th) va_fcc_int |= 0x80; break; default: sim_debug (DBG_FCC, &va_dev, "DMA mode %X\n", GET_MODE(va_fcc_csr)); break; } sim_debug (DBG_FCC, &va_dev, "DMA service complete\n"); if ((va_fcc_int & 0x3) == 0x3) /* pixel interrupt */ va_setint (INT_FCC); else if ((va_fcc_int & 0xC0) == 0xC0) /* threshold interrupt */ va_setint (INT_FCC); return SCPE_OK; } t_stat va_reset (DEVICE *dptr) { int32 i; t_stat r; CLR_INT (VC2); /* clear int req */ sim_cancel (&va_unit[0]); /* stop poll */ sim_cancel (&va_unit[1]); va_adp_reset (dptr); va_fcc_fifo_clr (); va_fcc_csr = 0x8000; va_dla = 0; va_bt458_addr = 0; va_cmap_p = 0; for (i = 0; i < VA_YSIZE; i++) va_updated[i] = TRUE; if (dptr->flags & DEV_DIS) { if (va_active) { free (va_buf); va_buf = NULL; free (va_lines); va_lines = NULL; va_active = FALSE; return vid_close (); } else return SCPE_OK; } if (!vid_active) { r = vid_open (dptr, NULL, VA_XSIZE, VA_YSIZE, va_input_captured ? SIM_VID_INPUTCAPTURED : 0);/* display size & capture mode */ if (r != SCPE_OK) return r; va_buf = (uint32 *) calloc (VA_BUFSIZE, sizeof (uint32)); if (va_buf == NULL) { vid_close (); return SCPE_MEM; } va_lines = (uint32 *) calloc (VA_XSIZE * VA_YSIZE, sizeof (uint32)); if (va_lines == NULL) { free (va_buf); vid_close (); return SCPE_MEM; } #if defined (BT458) for (i = 0; i < (VA_BPP + CUR_COL); i++) va_palette[i] = vid_map_rgb (0x00, 0x00, 0x00); /* black */ va_palette[VA_BPP - 1] = vid_map_rgb (0xFF, 0xFF, 0xFF); /* white */ va_palette[CUR_FG] = vid_map_rgb (0xFF, 0xFF, 0xFF); #else for (i = 0; i < (VA_BPP + VA_BPP + CUR_COL); i++) va_palette[i] = vid_map_rgb (0x00, 0x00, 0x00); /* black */ va_palette[CUR_FG] = vid_map_rgb (0xFF, 0xFF, 0xFF); #endif va_black = vid_map_rgb (0x00, 0x00, 0x00); /* black */ va_white = vid_map_rgb (0xFF, 0xFF, 0xFF); /* white */ sim_printf ("GPX Display Created. "); va_show_capture (stdout, NULL, 0, NULL); if (sim_log) va_show_capture (sim_log, NULL, 0, NULL); sim_printf ("\n"); va_active = TRUE; } sim_activate_abs (&va_unit[0], tmxr_poll); return SCPE_OK; } t_stat va_detach (UNIT *uptr) { if ((va_dev.flags & DEV_DIS) == 0) { va_dev.flags |= DEV_DIS; va_reset(&va_dev); } return SCPE_OK; } t_stat va_set_yoff (UNIT *uptr, int32 val, CONST char *cptr, void *desc) { int32 i; t_stat r; if (cptr == NULL) return SCPE_ARG; va_yoff = (int32) get_uint (cptr, 10, 2048, &r); for (i = 0; i < VA_YSIZE; i++) va_updated[i + va_yoff] = TRUE; return r; } t_stat va_show_yoff (FILE* st, UNIT* uptr, int32 val, CONST void* desc) { fprintf (st, "%d", va_yoff); return SCPE_OK; } t_stat va_set_dpln (UNIT *uptr, int32 val, CONST char *cptr, void *desc) { int32 i; t_stat r; if (cptr == NULL) return SCPE_ARG; va_dpln = (int32) get_uint (cptr, 10, VA_PLANES, &r); if (va_dpln > 0) { va_dpln = va_dpln - 1; va_dpln = (1u << va_dpln); } for (i = 0; i < VA_YSIZE; i++) va_updated[i + va_yoff] = TRUE; return r; } t_stat va_show_dpln (FILE* st, UNIT* uptr, int32 val, CONST void* desc) { fprintf (st, "%d", va_dpln); return SCPE_OK; } t_stat va_set_enable (UNIT *uptr, int32 val, CONST char *cptr, void *desc) { return cpu_set_model (NULL, 0, (val ? "VAXSTATIONGPX" : "MICROVAX"), NULL); } t_stat va_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"); va_input_captured = val; return SCPE_OK; } t_stat va_show_capture (FILE* st, UNIT* uptr, int32 val, CONST void* desc) { if (va_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 va_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) { fprintf (st, "GPX 8-Bit 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 *va_description (DEVICE *dptr) { return "GPX Colour Graphics Adapter"; }