diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 2f7607ad6..96d669ae1 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -27,7 +27,7 @@ add_library(vid OBJECT agpgart.c video.c vid_table.c vid_cga.c vid_cga_comp.c vid_tkd8001_ramdac.c vid_att20c49x_ramdac.c vid_s3.c vid_s3_virge.c vid_ibm_rgb528_ramdac.c vid_sdac_ramdac.c vid_ogc.c vid_mga.c vid_nga.c vid_tvp3026_ramdac.c vid_att2xc498_ramdac.c vid_xga.c - vid_bochs_vbe.c) + vid_bochs_vbe.c vid_ps55da2.c ) if(G100) target_compile_definitions(vid PRIVATE USE_G100) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c new file mode 100644 index 000000000..13f823c83 --- /dev/null +++ b/src/video/vid_ps55da2.c @@ -0,0 +1,3153 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * IBM PS/55 Display Adapter II emulation. + * + * Authors: Akamaki. + * + * Copyright 2024 Akamaki. + */ + +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/mca.h> +#include <86box/rom.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_ps55da2.h> +#include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> +#include "cpu.h" + +#define DA2_FONTROM_PATH "roms/video/da2/PS55FNTJ.BIN" +#define DA2_FONTROM_SIZE 1024*1024 +#define DA2_MASK_MMIO 0x1ffff +#define DA2_MASK_GRAM 0x1ffff +#define DA2_MASK_CRAM 0xfff +#define DA2_MASK_GAIJIRAM 0x3ffff +#define DA2_PIXELCLOCK 58000000.0 +#define DA2_BLT_MEMSIZE 0x80 +#define DA2_BLT_REGSIZE 0x40 +#define DA2_DEBUG_BLTLOG_SIZE (DA2_BLT_REGSIZE + 1) +#define DA2_DEBUG_BLTLOG_MAX 256*1024 +#define DA2_DEBUG_BLT_NEVERUSED 0xfefefefe +#define DA2_DEBUG_BLT_USEDRESET 0xfefefe + +#define DA2_BLT_CIDLE 0 +#define DA2_BLT_CFILLRECT 1 +#define DA2_BLT_CFILLTILE 2 +#define DA2_BLT_CCOPYF 3 +#define DA2_BLT_CCOPYR 4 +#define DA2_BLT_CDONE 5 +#define DA2_BLT_CLOAD 6 +/* POS ID = 0xeffe : Display Adapter II, III, V */ +#define DA2_POSID_H 0xef +#define DA2_POSID_L 0xfe +/* + [Identification] + POS ID SYS ID + EFFFh * Display Adapter (PS/55 Model 5571-S0A) [Toledo] + E013h * Layout Display Terminal (PS/55-5571 RPQ model) [LDT] + EFFEh * Display Adapter II (I/O 3E0:0A = xx0x xxxx) [Atlas] + |- FFF2h Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5530Z-SX) + |- FDFEh Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5550-V2) + |- * Display Adapter III,V (I/O 3E0:0A = xx1x xxxx) + ECECh FF4Fh Display Adapter B1 (PS/55 Model 5531Z-SX) [Atlas-KENT] + |- * Display Adapter IV + ECCEh * Display Adapter IV + 901Fh * Display Adapter A2 + 901Dh * Display Adapter A1 [Atlas II] + 901Eh * Plasma Display Adapter + EFD8h * Display Adapter/J [Atlas-SP2] + + [Japanese DOS and Display Adapter compatibility] + | POS ID | Adapter Name | K3.31 | J4.04 | J5.02 | OS2 J1.3 | Win3 | + |------------|-----------------------------|:-----:|:-----:|:-----:|:--------:|:----:| + | EFFFh | Display Adapter | X | | | ? | | + | FFEDh | ? [Atlas EVT] | X | | | ? | | + | FFFDh | ? [LDT EVT] | X | | | ? | | + | EFFEh | Display Adapter II,III,V,B2 | X | X | X | X | X | + | E013h | ? [LDT] | X | X | X | X | | + | ECCEh | Display Adapter IV | | X | X | X | | + | ECECh | Display Adapter IV,B1 | | X | X | X | X | + | 9000-901Fh | Display Adapter A1,A2 | | X | X | | X | + | EFD8h | Display Adapter /J | | | X | X | X | +*/ +/* IO 3E0/3E1:0Ah Hardware Configuration Value L (imported from OS/2 DDK) */ +#define OldLSI 0x20 /* DA-2 or DA-3,5 */ +#define Mon_ID3 0x10 +#define FontCard 0x08 /* ? */ +/* IO 3E0/3E1:0Ah Hardware Configuration Value H (imported from OS/2 DDK) */ +#define AddPage 0x08 /* ? */ +#define Mon_ID2 0x04 +#define Mon_ID1 0x02 +#define Mon_ID0 0x01 +/* Monitor ID (imported from OS/2 DDK 1.2) */ +//#define StarbuckC 0x0A //1010b IBM 8514, 9518 color 1040x768 +//#define StarbuckM 0x09 //1001b x grayscale +//#define Lark_B 0x02 //0010b IBM 9517 color 1040x768 +//#define Dallas 0x0B //1011b IBM 8515, 9515 color 1040x740 B palette +/* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode is not supported). */ +#define Page_One 0x06 /* 80000h 110b */ +#define Page_Two 0x05 /* 100000h 101b */ +#define Page_Four 0x03 /* 200000h 011b */ + +/* DA2 Registers (imported from OS/2 DDK) */ +#define AC_REG 0x3EE +#define AC_DMAE 0x80 +#define AC_FONT_SEL 0x40 +#define FONT_BANK 0x3EF +#define LS_INDEX 0x3E0 +#define LS_DATA 0x3E1 +#define LS_RESET 0x00 +#define LS_MODE 0x02 +#define LS_STATUS 0x03 /* added */ +#define LS_MMIO 0x08 /* added */ +#define LS_CONFIG1 0x0a +#define LS_CONFIG2 0x0b /* added */ +#define LF_INDEX 0x3e2 +#define LF_DATA 0x3e3 +#define LF_MMIO_SEL 0x08 /* added */ +#define LF_MMIO_ADDR 0x0A /* added */ +#define LF_MMIO_MODE 0x0B /* added */ +#define LC_INDEX 0x3E4 +#define LC_DATA 0x3E5 +#define LC_HORIZONTAL_TOTAL 0x00 +#define LC_H_DISPLAY_ENABLE_END 0x01 +#define LC_START_H_BLANKING 0x02 +#define LC_END_H_BLANKING 0x03 +#define LC_START_HSYNC_PULSE 0x04 +#define LC_END_HSYNC_PULSE 0x05 +#define LC_VERTICAL_TOTALJ 0x06 +#define LC_CRTC_OVERFLOW 0x07 +#define LC_PRESET_ROW_SCANJ 0x08 +#define LC_MAXIMUM_SCAN_LINE 0x09 +#define LC_CURSOR_ROW_START 0x0A +#define LC_CURSOR_ROW_END 0x0B +#define LC_START_ADDRESS_HIGH 0x0C +#define LC_START_ADDRESS_LOW 0x0D +#define LC_CURSOR_LOC_HIGH 0x0E +#define LC_ROW_CURSOR_LOC 0x0E +#define LC_CURSOR_LOC_LOWJ 0x0F +#define LC_COLUMN_CURSOR_LOC 0x0F +#define LC_VERTICAL_SYNC_START 0x10 +#define LC_LIGHT_PEN_HIGH 0x10 +#define LC_VERTICAL_SYNC_END 0x11 +#define LC_LIGHT_PEN_LOW 0x11 +#define LC_V_DISPLAY_ENABLE_END 0x12 +#define LC_OFFSET 0x13 +#define LC_UNDERLINE_LOCATION 0x14 +#define LC_START_VERTICAL_BLANK 0x15 +#define LC_END_VERTICAL_BLANK 0x16 +#define LC_LC_MODE_CONTROL 0x17 +#define LC_LINE_COMPAREJ 0x18 +#define LC_START_H_DISPLAY_ENAB 0x19 +#define LC_START_V_DISPLAY_ENAB 0x1A +#define LC_VIEWPORT_COMMAND 0x1B +#define LC_VIEWPORT_SELECT 0x1C +#define LC_VIEWPORT_PRIORITY 0x1D +#define LC_COMMAND 0x1E +#define LC_COMPATIBILITY 0x1F +#define LC_VIEWPORT_NUMBER 0x1F +#define LV_PORT 0x3E8 +#define LV_PALETTE_0 0x00 +#define LV_MODE_CONTROL 0x10 +#define LV_OVERSCAN_COLOR 0x11 +#define LV_COLOR_PLANE_ENAB 0x12 +#define LV_PANNING 0x13 +#define LV_VIEWPORT1_BG 0x14 +#define LV_VIEWPORT2_BG 0x15 +#define LV_VIEWPORT3_BG 0x16 +#define LV_BLINK_COLOR 0x17 +#define LV_BLINK_CODE 0x18 +#define LV_GR_CURSOR_ROTATION 0x19 +#define LV_GR_CURSOR_COLOR 0x1A +#define LV_GR_CURSOR_CONTROL 0x1B +#define LV_COMMAND 0x1C +#define LV_VP_BORDER_LINE 0x1D +#define LV_SYNC_POLARITY 0x1F +#define LV_CURSOR_CODE_0 0x20 +#define LV_GRID_COLOR_0 0x34 +#define LV_GRID_COLOR_1 0x35 +#define LV_GRID_COLOR_2 0x36 +#define LV_GRID_COLOR_3 0x37 +#define LV_ATTRIBUTE_CNTL 0x38 +#define LV_CURSOR_COLOR 0x3A +#define LV_CURSOR_CONTROL 0x3B +#define LV_RAS_STATUS_VIDEO 0x3C +#define LV_PAS_STATUS_CNTRL 0x3D +#define LV_IDENTIFICATION 0x3E +#define LV_OUTPUT 0x3E +#define LV_COMPATIBILITY 0x3F +#define LG_INDEX 0x3EA +#define LG_DATA 0x3EB +#define LG_SET_RESETJ 0x00 +#define LG_ENABLE_SRJ 0x01 +#define LG_COLOR_COMPAREJ 0x02 +#define LG_DATA_ROTATION 0x03 +#define LG_READ_MAP_SELECT 0x04 +#define LG_MODE 0x05 +#define LG_COMPLEMENT 0x06 +#define LG_COLOR_DONT_CARE 0x07 +#define LG_BIT_MASK_LOW 0x08 +#define LG_BIT_MASK_HIGH 0x09 +#define LG_MAP_MASKJ 0x0A +#define LG_COMMAND 0x0B +#define LG_SET_RESET_2 0x10 + +#ifdef ENABLE_DA2_LOG +int da2_do_log = ENABLE_DA2_LOG; + +static void +da2_log(const char* fmt, ...) +{ + va_list ap; + + if (da2_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define da2_log(fmt, ...) +#endif +#ifndef RELEASE_BUILD +# define ENABLE_DA2_DEBUGBLT 1 +#endif + +typedef struct da2_t +{ + //mem_mapping_t vmapping; + mem_mapping_t cmapping; + + //uint8_t crtcreg; + uint8_t ioctl[16]; + uint8_t fctl[32]; + uint16_t crtc[128]; + uint8_t gdcreg[64]; + uint8_t reg3ee[16]; + int gdcaddr; + uint8_t attrregs[0x40]; + int attraddr, attrff; + int attr_palette_enable; + //uint8_t seqregs[64]; + int outflipflop; + int inflipflop; + int iolatch; + + int ioctladdr; + int fctladdr; + int crtcaddr; + + uint8_t miscout; + //int vidclock; + + uint32_t decode_mask; + uint32_t vram_max; + uint32_t vram_mask; + + uint32_t gdcla[8]; + //int gdcramlatched; + uint32_t gdcinput[8]; + uint32_t gdcsrc[8]; + uint32_t debug_vramold[8]; + + uint8_t dac_mask, dac_status; + int dac_read, dac_write, dac_pos; + int dac_r, dac_g; + + //IO 3DAh Input Status Register 2 + uint8_t cgastat; + + uint8_t plane_mask; + + int fb_only; + + int fast; + uint8_t colourcompare, colournocare; + int readmode, writemode, readplane; + uint8_t writemask; + uint32_t charseta, charsetb; + + uint8_t egapal[16]; + uint32_t pallook[512]; + PALETTE vgapal; + + int vtotal, dispend, vsyncstart, split, vblankstart; + int hdisp, hdisp_old, htotal, hdisp_time, rowoffset; + int lowres, interlace; + int rowcount; + double clock; + uint32_t ma_latch, ca_adj; + + uint64_t dispontime, dispofftime; + pc_timer_t timer; + uint64_t da2const; + + uint8_t scrblank; + + int dispon; + int hdisp_on; + + uint32_t ma, maback, ca; + int vc; + int sc; + int linepos, vslines, linecountff, oddeven; + int con, cursoron, blink, blinkconf; + int scrollcache; + int char_width; + + int firstline, lastline; + int firstline_draw, lastline_draw; + int displine; + + /* Attribute Buffer E0000-E0FFFh (4 KB) */ + uint8_t *cram; + /* (cram size - 1) >> 3 = 0xFFF */ + //uint32_t cram_display_mask; + /* APA Buffer A0000-BFFFFh (128 KB) */ + uint8_t *vram; + /* addr >> 12 = xx000h */ + uint8_t *changedvram; + /* (vram size - 1) >> 3 = 0x1FFFF */ + uint32_t vram_display_mask; + uint32_t banked_mask; + + uint32_t write_bank, read_bank; + + int fullchange; + + //int video_res_x, video_res_y, video_bpp; + //int video_res_override; /*If clear then SVGA code will set above variables, if + // set then card code will*/ + //int frames, writelines; + + void (*render)(struct da2_t* da2); + //void (*recalctimings_ex)(struct da2_t* da2); + + //void (*video_out)(uint16_t addr, uint8_t val, void* p); + //uint8_t(*video_in) (uint16_t addr, void* p); + + /*If set then another device is driving the monitor output and the SVGA + card should not attempt to display anything */ + int override; + //void* p; + + /*Used to implement CRTC[0x17] bit 2 hsync divisor*/ + //int hsync_divisor; + + /* end VGA compatible regs*/ + struct + { + int enable; + mem_mapping_t mapping; + uint8_t ram[256 * 1024]; + uint8_t font[DA2_FONTROM_SIZE]; + } mmio; + + mem_mapping_t linear_mapping; + + uint32_t bank[2]; + uint32_t mask; + + int type; + + struct { + int bitshift_destr; + int raster_op; + uint8_t payload[DA2_BLT_MEMSIZE]; + int32_t reg[DA2_BLT_REGSIZE];//must be signed int + int32_t* debug_reg;//for debug + int debug_reg_ip;//for debug + int payload_addr; + pc_timer_t timer; + int64_t timerspeed; + int exec; + int indata; + int32_t destaddr; + int32_t srcaddr; + int32_t size_x, tile_w; + int32_t size_y; + int16_t destpitch; + int16_t srcpitch; + int32_t fcolor; + int32_t maskl, maskr; + int x, y; + } bitblt; + + FILE* mmdbg_fp; + FILE* mmrdbg_fp; + uint32_t mmdbg_vidaddr; + uint32_t mmrdbg_vidaddr; + + uint8_t pos_regs[8]; + svga_t *mb_vga; + + int vidsys_ena; + + int old_pos2; +} da2_t; + +void da2_recalctimings(da2_t* da2); +static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p); +void da2_bitblt_exec(void* p); +void da2_updatevidselector(da2_t* da2); +void da2_reset_ioctl(da2_t* da2); +static void da2_reset(void* priv); + +typedef union { + uint32_t d; + uint8_t b[4]; +} DA2_VidSeq32; + +typedef struct { + uint32_t p8[8]; +} pixel32; + +/* safety read for internal functions */ +uint32_t DA2_readvram_s(uint32_t addr, da2_t* da2) +{ + if (addr & ~da2->vram_mask) return -1; + return da2->vram[addr]; +} + +void DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32* srcpx, da2_t* da2) +{ + uint32_t writepx[8]; + destaddr &= 0xfffffffe;/* align to word address to work bit shift correctly */ + //da2_log("DA2_WPDWB addr %x mask %x rop %x shift %d\n", destaddr, mask, da2->bitblt.raster_op, da2->bitblt.bitshift_destr); + da2->changedvram[(da2->vram_display_mask & destaddr) >> 12] = changeframecount; + da2->changedvram[(da2->vram_display_mask & (destaddr+1)) >> 12] = changeframecount; + destaddr <<= 3; + /* read destination data with big endian order */ + for (int i = 0; i < 8; i++) + writepx[i] = DA2_readvram_s((destaddr + 24) | i, da2) + | (DA2_readvram_s((destaddr + 16) | i, da2) << 8) + | (DA2_readvram_s((destaddr + 8) | i, da2) << 16) + | (DA2_readvram_s((destaddr + 0) | i, da2) << 24); + + DA2_VidSeq32 mask32in; mask32in.d = (uint32_t)mask; + DA2_VidSeq32 mask32; mask32.d = 0; + mask32.b[3] = mask32in.b[0]; + mask32.b[2] = mask32in.b[1]; + mask32.d &= 0xffff0000; + for (int i = 0; i < 8; i++) + { + if (da2->bitblt.bitshift_destr > 0) + srcpx->p8[i] <<= 16 - da2->bitblt.bitshift_destr; + switch (da2->bitblt.raster_op) { + case 0x00: /* None */ + writepx[i] &= ~mask32.d; + writepx[i] |= srcpx->p8[i] & mask32.d; + break; + case 0x01: /* AND */ + writepx[i] &= srcpx->p8[i] | ~mask32.d; + break; + case 0x02: /* OR */ + writepx[i] |= srcpx->p8[i] & mask32.d; + break; + case 0x03: /* XOR */ + writepx[i] ^= srcpx->p8[i] & mask32.d; + break; + } + } + for (int i = 0; i < 8; i++) { + da2->vram[(da2->vram_mask & destaddr) | i] = (writepx[i] >> 24) & 0xff; + da2->vram[(da2->vram_mask & (destaddr + 8)) | i] = (writepx[i] >> 16) & 0xff; + } +} + +void DA2_DrawColorWithBitmask(uint32_t destaddr, uint8_t color, uint16_t mask, da2_t* da2) +{ + pixel32 srcpx; + //fill data with input color + for (int i = 0; i < 8; i++) + srcpx.p8[i] = (color & (1 << i)) ? 0xffffffff : 0;//read in word + + DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); +} +/* +Param Desc +01 Color +03 Bit Shift +04 Select plane? +05 Dir(10 or 11) + Command?(40 or 48) +08 Mask Left +09 Mask Right +0A Plane Mask? +0B ROP?(8h or 200h + 0-3h) +0D +20 Exec (1) +21 ? +22 ? +23 Tile W +28 Tile H +29 Dest Addr +2A Src Addr +2B Tile Addr +33 Size W +35 Size H + +*/ +void DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) +{ + pixel32 srcpx; + srcaddr &= 0xfffffffe; + srcaddr <<= 3; + for (int i = 0; i < 8; i++) + srcpx.p8[i] = DA2_readvram_s((srcaddr + 24) | i, da2) + | (DA2_readvram_s((srcaddr + 16) | i, da2) << 8) + | (DA2_readvram_s((srcaddr + 8) | i, da2) << 16) + | (DA2_readvram_s((srcaddr + 0) | i, da2) << 24);//read in word + + DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); +} +uint8_t pixel1tohex(uint32_t addr, int index, da2_t* da2) { + uint8_t pixeldata = 0; + for (int j = 0; j < 8; j++) { + if (da2->vram[(da2->vram_mask & (addr << 3)) | j] & (1 << (7 - index))) pixeldata++; + } + return pixeldata; +} +void print_pixelbyte(uint32_t addr, da2_t* da2) { + for (int i = 0; i < 8; i++) + { + da2_log("%X", pixel1tohex(addr, i, da2)); + } +} + +void da2_bitblt_load(da2_t* da2) +{ + uint32_t value32; + uint64_t value64; + //da2_log("BITBLT loading params\n"); + //da2_log("BitBlt memory:\n"); + //if (da2->bitblt.payload[0] != 0) + // for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) + // { + // int i = j * 8; + // da2_log("%02x %02x %02x %02x %02x %02x %02x %02x \n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + // da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); + // } + int i = 0; + while (i < DA2_BLT_MEMSIZE) + { + if (da2->bitblt.reg[0x20] & 0x1) + break; + switch (da2->bitblt.payload[i]) { + case 0x88: + case 0x89: + case 0x95: + value32 = da2->bitblt.payload[i + 3]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 2]; + //da2_log("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; + i += 3; + break; + case 0x91: + value32 = da2->bitblt.payload[i + 5]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 4]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 3]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 2]; + //da2_log("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; + i += 5; + break; + case 0x99: + value64 = da2->bitblt.payload[i + 7]; + value64 <<= 8; + value64 = da2->bitblt.payload[i + 6]; + value64 <<= 8; + value64 = da2->bitblt.payload[i + 5]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 4]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 3]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 2]; + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; + //da2_log("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + //da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); + i += 7; + break; + case 0x00: + break; + default: + da2_log("da2_ParseBLT: Unknown PreOP!\n"); + break; + } + i++; + } + da2->bitblt.exec = DA2_BLT_CIDLE; + /* clear payload memory */ + memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + da2->bitblt.payload_addr = 0; + /* [89] 20: 0001 (1) then execute payload */ + if (da2->bitblt.reg[0x20] & 0x1) + { +#ifdef ENABLE_DA2_DEBUGBLT + for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { + //if(da2->bitblt.reg[i] != 0xfefe && da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2_log("%02x: %04x (%d)\n",i, da2->bitblt.reg[i], da2->bitblt.reg[i]); + } + for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { + da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip + i] = da2->bitblt.reg[i]; + } + da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * (da2->bitblt.debug_reg_ip + 1) - 1] = 0; + da2->bitblt.debug_reg_ip++; + if (da2->bitblt.debug_reg_ip >= DA2_DEBUG_BLTLOG_MAX) da2->bitblt.debug_reg_ip = 0; +#endif + da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f);//set bit shift + da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03;//01 AND, 03 XOR + da2_log("bitblt execute 05: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); + for (int i = 0; i <= 0xb; i++) + da2_log("%02x ", da2->gdcreg[i]); + da2_log("\n"); + + da2->bitblt.destaddr = da2->bitblt.reg[0x29]; + da2->bitblt.size_x = da2->bitblt.reg[0x33]; + da2->bitblt.size_y = da2->bitblt.reg[0x35]; + da2->bitblt.destpitch = da2->bitblt.reg[0x21]; + da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; + if (da2->bitblt.reg[0x2F] == 0x90) //destaddr -= 2, length += 1; + { + da2->bitblt.destaddr -= 2; + da2->bitblt.size_x += 1; + da2->bitblt.destpitch -= 2; + da2->bitblt.srcpitch -= 2; + } + da2->bitblt.fcolor = da2->bitblt.reg[0x0]; + da2->bitblt.maskl = da2->bitblt.reg[0x8]; + da2->bitblt.maskr = da2->bitblt.reg[0x9]; + da2->bitblt.x = 0; + da2->bitblt.y = 0; + da2->bitblt.exec = DA2_BLT_CDONE; + timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + + if (da2->bitblt.reg[0x2f] < 0x80)//MS Paint 3.1 will cause hang up in 256 color mode + { + da2_log("bitblt not executed 2f:%x\n", da2->bitblt.reg[0x2f]); + da2->bitblt.exec = DA2_BLT_CDONE; + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) {//Fill a rectangle (or draw a line) + da2_log("fillrect x=%d, y=%d, w=%d, h=%d, c=%d, 2f=%x, rowcount=%x\n", + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.reg[0x0], da2->bitblt.reg[0x2F], da2->rowoffset * 2); + da2->bitblt.exec = DA2_BLT_CFILLRECT; + da2->bitblt.destaddr += 2; + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x0040 && da2->bitblt.reg[0x3D] == 0x40) {//Tiling a rectangle ??(transfer tile data multiple times) os/2 only + da2->bitblt.exec = DA2_BLT_CFILLTILE; + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; + da2->bitblt.tile_w = da2->bitblt.reg[0x28]; + da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) {//Tiling a rectangle (transfer tile data multiple times) + da2->bitblt.exec = DA2_BLT_CFILLTILE; + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; + da2->bitblt.tile_w = da2->bitblt.reg[0x28]; + da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) {//Block transfer (range copy) + da2->bitblt.exec = DA2_BLT_CCOPYF; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; + da2->bitblt.destaddr += 2; + da2_log("copy block src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) {//Block copy but reversed direction + da2->bitblt.exec = DA2_BLT_CCOPYR; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; + da2->bitblt.destaddr -= 2; + da2->bitblt.srcaddr -= 2; + da2_log("copy blockR src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + //da2_log(" mask8=%x, mask9=%x\n", da2->bitblt.reg[0x8], da2->bitblt.reg[0x9]); + } + //do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle + while (timer_is_enabled(&da2->bitblt.timer) && da2->bitblt.exec != DA2_BLT_CDONE) + { + da2_bitblt_exec(da2); + } + } +} +void da2_bitblt_exec(void* p) +{ + da2_t* da2 = (da2_t*)p; + timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + //da2_log("blt %x %x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); + switch (da2->bitblt.exec) + { + case DA2_BLT_CIDLE: + timer_disable(&da2->bitblt.timer); + break; + case DA2_BLT_CLOAD: + da2_bitblt_load(da2); + da2->bitblt.indata = 0; + break; + case DA2_BLT_CFILLRECT: + //da2_log("%x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + } + else if (da2->bitblt.x == 0) { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr += 2; + break; + case DA2_BLT_CFILLTILE: + int32_t tileaddr = da2->bitblt.srcaddr + (da2->bitblt.y % da2->bitblt.tile_w) * 2; + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + } + else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr += 2; + break; + case DA2_BLT_CCOPYF: + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + da2->bitblt.srcaddr += da2->bitblt.srcpitch + 2; + } + else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr += 2; + break; + case DA2_BLT_CCOPYR: + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr -= da2->bitblt.destpitch; + da2->bitblt.srcaddr -= da2->bitblt.srcpitch; + da2->bitblt.destaddr -= 2; + da2->bitblt.srcaddr -= 2; + } + else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr -= 2; + da2->bitblt.srcaddr -= 2; + break; + case DA2_BLT_CDONE: + //initialize regs with fefefefeh, clear regs with fefeh for debug dump + for (int i = 0; i < DA2_BLT_REGSIZE; i++) { + if (da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; + } + if(da2->bitblt.indata) da2->bitblt.exec = DA2_BLT_CLOAD; + else da2->bitblt.exec = DA2_BLT_CIDLE; + break; + } +} +void da2_out(uint16_t addr, uint16_t val, void *p) +{ + da2_t *da2 = (da2_t *)p; + int oldval; +/* +3E0 3E1 Sequencer Registers (undoc) +3E2 3E3 Font Registers (undoc) +3E4 3E5 CRT Control Registers (undoc) +3E8 3E9 Attribute Controller Registers (undoc) +3EA 3EB 3EC Graphics Contoller Registers +*/ + switch (addr) + { + case 0x3c6: /* PEL Mask */ + da2->dac_mask = val; + break; + case 0x3C7: /* Read Address */ + da2->dac_read = val; + da2->dac_pos = 0; + break; + case 0x3C8: /* Write Address */ + da2->dac_write = val; + da2->dac_read = val - 1; + da2->dac_pos = 0; + break; + case 0x3C9: /* Data */ + //da2_log("DA2 Out addr %03X idx %d:%d val %02X %04X:%04X esdi %04X:%04X\n", addr, da2->dac_write, da2->dac_pos, val, cs >> 4, cpu_state.pc, ES, DI); + //da2_log("DS %X\n",DS); + da2->dac_status = 0; + da2->fullchange = changeframecount; + switch (da2->dac_pos) + { + case 0: + da2->dac_r = val; + da2->dac_pos++; + break; + case 1: + da2->dac_g = val; + da2->dac_pos++; + break; + case 2: + da2->vgapal[da2->dac_write].r = da2->dac_r; + da2->vgapal[da2->dac_write].g = da2->dac_g; + da2->vgapal[da2->dac_write].b = val; + //if (da2->ramdac_type == RAMDAC_8BIT) + // da2->pallook[da2->dac_write] = makecol32(da2->vgapal[da2->dac_write].r, da2->vgapal[da2->dac_write].g, da2->vgapal[da2->dac_write].b); + //else + da2->pallook[da2->dac_write] = makecol32((da2->vgapal[da2->dac_write].r & 0x3f) * 4, (da2->vgapal[da2->dac_write].g & 0x3f) * 4, (da2->vgapal[da2->dac_write].b & 0x3f) * 4); + da2->dac_pos = 0; + da2->dac_write = (da2->dac_write + 1) & 255; + break; + } + break; + case LS_INDEX: + da2->ioctladdr = val; + break; + case LS_DATA: + //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->ioctladdr, val, cs >> 4, cpu_state.pc); + if (da2->ioctladdr > 0xf) return; + //if (da2->ioctl[da2->ioctladdr & 15] != val) + // da2_log("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc); + oldval = da2->ioctl[da2->ioctladdr]; + //if (da2->ioctladdr == 0x3) return;//monitor color + da2->ioctl[da2->ioctladdr] = val; + if (oldval != val) { + if (da2->ioctladdr == LS_RESET && val & 0x01) /* Mode register */ + da2_reset_ioctl(da2); + else if (da2->ioctladdr == LS_MODE && ((oldval ^ val) & 0x03)) /* Mode register */ + { + da2->fullchange = changeframecount; + da2_recalctimings(da2); + da2_updatevidselector(da2); + } + else if (da2->ioctladdr == LS_MMIO && (!(val & 0x01))) /* MMIO register */ + { + da2->bitblt.indata = 1; + if (da2->bitblt.exec == DA2_BLT_CIDLE) + { + da2->bitblt.exec = DA2_BLT_CLOAD; + timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + } + } + } + break; + case LF_INDEX: + da2->fctladdr = val; + break; + case LF_DATA: + //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); + if (da2->fctladdr > 0x1f) return; + oldval = da2->fctl[da2->fctladdr]; + da2->fctl[da2->fctladdr] = val; + if (da2->fctladdr == 0 && oldval != val) + { + da2->fullchange = changeframecount; + da2_recalctimings(da2); + } + break; + case LC_INDEX: + da2->crtcaddr = val; + break; + case LC_DATA: + if (da2->crtcaddr > 0x1f) return; + if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ)) + da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); + if (!(da2->crtc[da2->crtcaddr] ^ val)) return; + switch (da2->crtcaddr) { + case LC_CRTC_OVERFLOW: + //return; + break; + case LC_MAXIMUM_SCAN_LINE: + if (!(da2->ioctl[LS_MODE] & 0x01)) val = 0; + break; + case LC_START_ADDRESS_HIGH: + //if (da2->crtc[0x1c] & 0x40) return; + break; + case LC_VERTICAL_TOTALJ: /* Vertical Total */ + case LC_VERTICAL_SYNC_START: /* Vertical Retrace Start Register */ + case LC_V_DISPLAY_ENABLE_END: /* Vertical Display End Register */ + case LC_START_VERTICAL_BLANK: /* Start Vertical Blank Register */ + //val = 0x400; //for debugging bitblt + break; + case LC_VIEWPORT_SELECT: /* ViewPort Select? */ + //return; + break; + case LC_VIEWPORT_NUMBER: /* Compatibility? */ + break; + } + da2->crtc[da2->crtcaddr] = val; + switch (da2->crtcaddr) { + case LC_H_DISPLAY_ENABLE_END: + case LC_VERTICAL_TOTALJ: + case LC_MAXIMUM_SCAN_LINE: + case LC_START_ADDRESS_HIGH: + case LC_START_ADDRESS_LOW: + case LC_VERTICAL_SYNC_START: + case LC_V_DISPLAY_ENABLE_END: + case LC_START_VERTICAL_BLANK: + case LC_END_VERTICAL_BLANK: + case LC_VIEWPORT_PRIORITY: + da2->fullchange = changeframecount; + da2_recalctimings(da2); + break; + default: + break; + } + break; + case LV_PORT: + da2_log("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc); + if (!da2->attrff) + { + // da2->attraddr = val & 31; + da2->attraddr = val & 0x3f; + if ((val & 0x20) != (da2->attr_palette_enable & 0x20)) + { + da2->fullchange = 3; + da2->attr_palette_enable = val & 0x20; + da2_recalctimings(da2); + } + //da2_log("set attraddr: %X\n", da2->attraddr); + } + else + { + if ((da2->attraddr == LV_PANNING) && (da2->attrregs[LV_PANNING] != val)) + da2->fullchange = changeframecount; + if (da2->attrregs[da2->attraddr & 0x3f] != val) + da2_log("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrregs[da2->attraddr & 0x3f], val); + da2->attrregs[da2->attraddr & 0x3f] = val; + //da2_log("set attrreg %x: %x\n", da2->attraddr & 31, val); + if (da2->attraddr < 16) + da2->fullchange = changeframecount; + //if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr == 0x14 || da2->attraddr < 0x10) + if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr < 0x10) + { + for (int c = 0; c < 16; c++) + { + //if (da2->attrregs[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = (da2->attrregs[c] & 0xf) | ((da2->attrregs[0x14] & 0xf) << 4); + //else da2->egapal[c] = (da2->attrregs[c] & 0x3f) | ((da2->attrregs[0x14] & 0xc) << 4); + if (da2->attrregs[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = da2->attrregs[c] & 0xf; + else da2->egapal[c] = da2->attrregs[c] & 0x3f; + } + } + if (da2->attraddr == LV_COLOR_PLANE_ENAB) + { + if ((val & 0xff) != da2->plane_mask) + da2->fullchange = changeframecount; + da2->plane_mask = val & 0xff; + } + if (da2->attraddr == LV_CURSOR_CONTROL) + { + switch (val & 0x18) { + case 0x08://fast blink + da2->blinkconf = 0x10; + break; + case 0x18://slow blink + da2->blinkconf = 0x20; + break; + default://no blink + da2->blinkconf = 0xff; + break; + } + } + switch (da2->attraddr) + { + case LV_MODE_CONTROL: + case LV_ATTRIBUTE_CNTL: + case LV_COMPATIBILITY: + da2_recalctimings(da2); + break; + default: + break; + } + } + da2->attrff ^= 1; + break; + case LG_INDEX: + da2->gdcaddr = val; + break; + case LG_DATA: + //if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); + //if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI); + switch (da2->gdcaddr & 0x1f) + { + case LG_READ_MAP_SELECT: + da2->readplane = val & 0x7; + break; + case LG_MODE: + da2->writemode = val & 3; + break; + case LG_MAP_MASKJ: + da2->writemask = val & 0xff; + break; + case LG_COMMAND: + break; + case LG_SET_RESET_2: + da2_log("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val); + return; + } + da2->gdcreg[da2->gdcaddr & 15] = val & 0xff; + break; + //case 0x3ed: /* used by Windows 3.1 display driver */ + // da2->gdcreg[5] = val & 0xff; + // break; + default: + da2_log("DA2? Out addr %03X val %02X\n", addr, val); + break; + } +} + +uint16_t da2_in(uint16_t addr, void *p) +{ + da2_t * da2 = (da2_t *)p; + //svga_t *svga = &da2->svga; + uint16_t temp; + +// if (addr != 0x3da) da2_log("IN gd5429 %04X\n", addr); + switch (addr) + { + case 0x3c3: + temp = 0; + break; + case 0x3c6: temp = da2->dac_mask; + break; + case 0x3c7: temp = da2->dac_status; + break; + case 0x3c8: temp = da2->dac_write; + break; + case 0x3c9: + da2->dac_status = 3; + switch (da2->dac_pos) + { + case 0: + da2->dac_pos++; + temp = da2->vgapal[da2->dac_read].r & 0x3f; + break; + case 1: + da2->dac_pos++; + temp = da2->vgapal[da2->dac_read].g & 0x3f; + break; + case 2: + da2->dac_pos = 0; + da2->dac_read = (da2->dac_read + 1) & 255; + temp = da2->vgapal[(da2->dac_read - 1) & 255].b & 0x3f; + break; + } + break; + case LS_INDEX: + temp = da2->ioctladdr; + break; + case LS_DATA: + //da2->ioctl[3] = 0x80;//3E1h:3 bit 7 color monitor, bit 3 busy(GC) bit 0 busy (IO?) + if (da2->ioctladdr > 0xf) return 0xff; + temp = da2->ioctl[da2->ioctladdr]; + if (da2->ioctladdr == LS_STATUS) { /* Status register */ + //da2_log("Read 3E1 DAC status: %d, %d, %d\n", da2->vgapal[0].r, da2->vgapal[0].g, da2->vgapal[0].b); + //da2_log("attr palette: "); + //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->attrregs[i]); + //da2_log("\n"); + //da2_log("vram A0000h: "); + //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->vram[i]); + //da2_log("\n"); + //da2_log("vram B8000h: "); + //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->vram[0x18000 + i]); + //da2_log("\n"); + //da2_log("vram E0000h: "); + //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->cram[i]); + //da2_log("\n"); + if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 0x50 && da2->attrregs[LV_COMPATIBILITY] & 0x08) + temp &= 0x7F; /* Inactive when the RGB output voltage is high(or the cable is not connected to the color monitor). */ + else + temp |= 0x80; /* Active when the RGB output voltage is lowand the cable is connected to the color monitor. + If the cable or the monitor is wrong, it becomes inactive. */ + temp &= 0xf6;//idle + if (da2->bitblt.exec != DA2_BLT_CIDLE) + { + //da2_log("exec:%d\n", da2->bitblt.exec); + temp |= 0x08;//wait(bit 3 + bit 0) + //if (!da2->bitblt.timer.enabled) + //{ + // da2_log("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc); + // timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + //} + } + if (da2->bitblt.indata) + temp |= 0x01; + //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); + } + //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); + break; + case LF_INDEX: + temp = da2->fctladdr; + break; + case LF_DATA: + if (da2->fctladdr > 0x1f) return 0xff; + temp = da2->fctl[da2->fctladdr]; + break; + case LC_INDEX: + temp = da2->crtcaddr; + break; + case LC_DATA: + if (da2->crtcaddr > 0x1f) return 0xff; + temp = da2->crtc[da2->crtcaddr]; + break; + case LV_PORT: + temp = da2->attraddr | da2->attr_palette_enable; + break; + case 0x3E9: + if (da2->attraddr == LV_RAS_STATUS_VIDEO) /* this may equiv to 3ba / 3da Input Status Register 1 */ + { + if (da2->cgastat & 0x01) + da2->cgastat &= ~0x30; + else + da2->cgastat ^= 0x30; + temp = da2->cgastat; + } + else + temp = da2->attrregs[da2->attraddr]; + //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->attraddr, temp, cs >> 4, cpu_state.pc); + da2->attrff = 0; /* reset flipflop (VGA does not reset flipflop) */ + break; + case LG_INDEX: + temp = da2->gdcaddr; + break; + case LG_DATA: + temp = da2->gdcreg[da2->gdcaddr & 0x1f]; + da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc); + break; + } + //da2_log("DA2 In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; +} +/* +* Write I/O +* out b(idx), out b(data), out b(data) +* out b(idx), out w(data) +* out b(idx), out w(data), out b(data) +* out w(idx) +* Read I/O +* out b(idx), in b(data) +* out b(idx), in b, in b(data) +* out b(idx), in w(data) +*/ +void da2_outb(uint16_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //da2_log("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); + da2->inflipflop = 0; + switch (addr) + { + case LS_DATA: + case LF_DATA: + case LC_DATA: + case LG_DATA: + if (da2->outflipflop) + { + /* out b(idx), out b(data), out b(data) */ + da2->iolatch |= (uint16_t)val << 8; + da2->outflipflop = 0; + } + else + {// + da2->iolatch = val; + da2->outflipflop = 1; + } + break; + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + default: + da2->iolatch = val; + da2->outflipflop = 0; + break; + } + da2_out(addr, da2->iolatch, da2); +} +void da2_outw(uint16_t addr, uint16_t val, void* p) +{ + //da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_t* da2 = (da2_t*)p; + da2->inflipflop = 0; + switch (addr) + { + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + da2_out(addr, val & 0xff, da2); + da2->iolatch = val >> 8; + da2_out(addr + 1, da2->iolatch, da2); + da2->outflipflop = 1; + break; + case LV_PORT: + da2->attrff = 0; + da2_out(addr, val & 0xff, da2); + da2_out(addr, val >> 8, da2); + da2->outflipflop = 0; + break; + case 0x3EC: + //da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_out(LG_DATA, val >> 8, da2); + break; + case 0x3ED: + da2->gdcaddr = LG_MODE; + da2_out(LG_DATA, val, da2); + break; + case LS_DATA: + case LF_DATA: + case LC_DATA: + case LG_DATA: + default: + da2_out(addr, val, da2); + da2->outflipflop = 0; + break; + case 0x3EE: + da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2->reg3ee[val & 0xff] = val >> 8; + break; + } +} +uint8_t da2_inb(uint16_t addr, void* p) +{ + uint8_t temp; + da2_t* da2 = (da2_t*)p; + da2->outflipflop = 0; + switch (addr) + { + case LC_DATA: + if (da2->inflipflop) + { + /* out b(idx), in b(low data), in b(high data) */ + temp = da2->iolatch >> 8; + da2->inflipflop = 0; + } + else + {// + da2->iolatch = da2_in(addr, da2); + temp = da2->iolatch & 0xff; + da2->inflipflop = 1; + } + break; + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + case LS_DATA: + case LF_DATA: + case LG_DATA: + default: + temp = da2_in(addr, da2) & 0xff; + da2->inflipflop = 0; + break; + } + //da2_log("DA2 Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; +} +uint16_t da2_inw(uint16_t addr, void* p) +{ + //uint16_t temp; + da2_t* da2 = (da2_t*)p; + da2->inflipflop = 0; + da2->outflipflop = 0; + return da2_in(addr, da2); +} +/* IO 03DAh : Input Status Register 2 for DOSSHELL in DOS J4.0 */ +uint8_t da2_in_ISR(uint16_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + uint8_t temp = 0; + if (addr == 0x3da) { + if (da2->cgastat & 0x01) + da2->cgastat &= ~0x30; + else + da2->cgastat ^= 0x30; + temp = da2->cgastat; + } + //da2_log("DA2D In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; +} + +void da2_out_ISR(uint16_t addr, uint8_t val, void* p) +{ + //da2_t* da2 = (da2_t*)p; + da2_log("DA2D Out %04X %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); +} + +/* +The IBM 5550 character mode addresses video memory between E0000h and E0FFFh. + [Character drawing] + SBCS: + 1 2 ... 13 + 1 | H.Grid + |---------------- + 2 | Space + 3 V| + .| + G| Font Pattern + r| (12x24 pixels) + i| + d| +26 |________________ +27 Space + ---------------- +28 Underscore ] + ---------------- >Cursor Position +29 ] + + DBCS: + 1 2 ... 13 1 2 ... 12 13 + 1 | H.Grid | H.Grid | + -|--------------------------|- + 2 | Space | Space | + -|--------------------------|- + 3 V| | |S + .| | |p + G| Font Pattern |a + r| (24x24 pixels) |c + i| | |e + d| | | +26 |_____________|____________| +27 | Space | Space + ------------------------------ +28 | Underscore | Underscore ] + ------------------------------ >Cursor Position +29 | | ] + + [Attributes] + Video mode 08h: + 7 6 5 4 3 2 1 0 + Blink |Under |HGrid |VGrid |Bright|Revers|FntSet|DBCS/SBCS| + + Video mode 0Eh: + -Blue |-Green|HGrid |VGrid |-Red |Revers|FntSet|DBCS/SBCS| + + Bit 1 switches the font bank to the Extended SBCS. DOS K3.x loads APL characters from $SYSEX24.FNT into it. + DOS Bunsho Program transfers 1/2 and 1/4 fonts fron the font ROM to the Extended SBCS. + This bit is not used for DBCS, but some apps set it as that column is right half of DBCS. + +[Font ROM Map (DA2)] +The Font ROM is accessed via 128 KB memory window located on A0000-BFFFFh. +I don't know how much data the actual Font ROM has. +Here information, I researched it by disassembling J-DOS. + +Bank 0 + 4800- * +Bank 1, 2, 3 + * - * +Bank 4 + * -0DB6Fh ( 4800-8DB6Fh;IBMJ 100-1F7Dh) : JIS X 0208 DBCS (24 x 24) +10000-16D1Fh (90000-96D1Fh;IBMJ 2000-2183h) : IBM Extended Characters +18000-1BFFFh (98000-9BFFFh;around IBMJ 21C7-22AAh) : JIS X 0201 SBCS (13 x 30) +1FD20- * +Bank 5 + * -0D09Fh (9FD20-AD09Fh;IBMJ 2384-2673h) : Gaiji 752 chs (maybe blank) +10000-13FFFh (B0000-B3FFFh;around IBMJ 271C-27FFh) : Extended SBCS (13 x 30) +14000-146FFh (B4000-B46FFh;IBMJ 2800-2818h) : Half-width box drawing characters (7 lines * 4 parts * 64 bytes) used by DOS Bunsho + (B9580-?;IBMJ 2930-295e?) : Full-width box drawing characters + + The signature 80h, 01h must be placed at Bank 0:1AFFEh to run OS/2 J1.3. + +[Gaiji RAM Map (DA2)] + Bank 0 00000-1FFFFh placed between A0000h-BFFFFh + 00000-1F7FFh(A0000-BF7FFh): Gaiji Non-resident (Kuten 103-114 ku,IBM: 2674-2ADBh) 1008 chs 128 bytes + 1F800-1FFFFh(BF800-BFFFFh): Gaiji Resident (SJIS: F040-F04Fh, IBM: 2384-2393h) 16 chs + + Bank 1 20000-3FFFFh placed between A0000h-BFFFFh + 20000-33FFFh(A0000-B3FFFh): Gaiji Resident (SJIS: F050-F39Ch, IBM: 2394-2613h) 640 chs + 34000-37FFFh(B4000-B7FFFh): Basic SBCS(00-FFh, ATTR bit 1 = off) + 38000-3AFFFh(B8000-BAFFFh): Gaiji Resident (SJIS: F39D-F3FCh, IBM: 2614-2673h) 96 chs + 3C000-3FFFFh(BC000-BFFFFh): Extended SBCS(00-FFh, ATTR bit 1 = on) + +[IBMJ code to Gaiji address conv tbl from DOS K3.3] + A B C + 2ADC, 2C5F, +5524 --> 8000 + 2614, 2673, +90EC --> B700 + 2384, 2613, +906C --> B3F0 + 0682, 1F7D, +0000 + + 8000 - 8183h 184h(388 characters) IBM Extended Characters + B3F0 - B75Fh 370h(880 characters) User-defined Characters +*/ + +/* Get character line pattern from jfont rom or gaiji volatile memory */ +uint32_t getfont_ps55dbcs(int32_t code, int32_t line, void* p) { + da2_t* da2 = (da2_t*)p; + uint32_t font = 0; + int32_t fline = line - 2;//Start line of drawing character (line >= 1 AND line < 24 + 1 ) + if (code >= 0x8000 && code <= 0x8183) code -= 0x6000;//shift for IBM extended characters (I don't know how the real card works.) + if (code < DA2_FONTROM_SIZE / 72 && fline >= 0 && fline < 24) { + font = da2->mmio.font[code * 72 + fline * 3]; //1111 1111 + font <<= 8; //1111 1111 0000 0000 + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0xf0; //1111 1111 2222 0000 + font >>= 1; //0111 1111 1222 2000 + font <<= 4; //0111 1111 1222 2000 0000 + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0x0f; //0111 1111 1222 2000 2222 + font <<= 8; //0111 1111 1222 2000 2222 0000 0000 + font |= da2->mmio.font[code * 72 + fline * 3 + 2]; //0111 1111 1222 2000 2222 3333 3333 + font <<= 4; //0111 1111 1222 2000 2222 3333 3333 0000 + //font >>= 1;//put blank at column 1 (and 26) + } + else if (code >= 0xb000 && code <= 0xb75f) + { + //convert code->address in gaiji memory + code -= 0xb000; + code *= 0x80; + //code += 0xf800; + font = da2->mmio.ram[code + line * 4]; + font <<= 8; + font |= da2->mmio.ram[code + line * 4 + 1]; + font <<= 8; + font |= da2->mmio.ram[code + line * 4 + 2]; + font <<= 8; + font |= da2->mmio.ram[code + line * 4 + 3]; + } + else if (code > DA2_FONTROM_SIZE) + font = 0xffffffff; + else + font = 0; + return font; +} + +/* Reverse the bit order of attribute code IRGB to BGRI(used in Mode 3 and Cursor Color) */ +uint8_t IRGBtoBGRI(uint8_t attr) +{ + attr = ((attr & 0x01) << 7) | ((attr & 0x02) << 5) | ((attr & 0x04) << 3) | ((attr & 0x08) << 1); + return attr >>= 4; +} +/* Get the foreground color from the attribute byte */ +uint8_t getPS55ForeColor(uint8_t attr, da2_t* da2) +{ + uint8_t foreground = ~attr & 0x08;// 0000 1000 + foreground <<= 2; //0010 0000 + foreground |= ~attr & 0xc0;// 1110 0000 + foreground >>= 4;//0000 1110 + if (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x40) foreground |= 0x01;//bright color palette + return foreground; +} + +void da2_render_blank(da2_t* da2) +{ + int x, xx; + + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + + for (x = 0; x < da2->hdisp; x++) + { + for (xx = 0; xx < 13; xx++) ((uint32_t*)buffer32->line[da2->displine])[(x * 13) + xx + 32] = 0; + } +} +/* Display Adapter Mode 8, E Drawing */ +static void da2_render_text(da2_t* da2) +{ + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + + if (da2->fullchange) + { + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + int x; + int drawcursor; + uint8_t chr, attr; + int fg, bg; + uint32_t chr_dbcs; + int chr_wide = 0; + //da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); + for (x = 0; x < da2->hdisp; x += 13) + { + chr = da2->cram[(da2->ma) & da2->vram_display_mask]; + attr = da2->cram[((da2->ma) + 1) & da2->vram_display_mask]; + //if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); + if (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80)//IO 3E8h, Index 1Dh + {//--Parse attribute byte in color mode-- + bg = 0;//bg color is always black (the only way to change background color is programming PAL) + fg = getPS55ForeColor(attr, da2); + if (attr & 0x04) {//reverse 0000 0100 + bg = fg; + fg = 0; + } + } + else + {//--Parse attribute byte in monochrome mode-- + if (attr & 0x08) fg = 3;//Highlight 0000 1000 + else fg = 2; + bg = 0;//Background is always color #0 (default is black) + if (!(~attr & 0xCC))//Invisible 11xx 11xx -> 00xx 00xx + { + fg = bg; + attr &= 0x33;//disable blinkking, underscore, highlight and reverse + } + if (attr & 0x04) {//reverse 0000 0100 + bg = fg; + fg = 0; + } + // Blinking 1000 0000 + fg = ((da2->blink & 0x20) || (!(attr & 0x80))) ? fg : bg; + //if(chr!=0x20) da2_log("chr: %x, %x, %x, %x, %x ", chr, attr, fg, da2->egapal[fg], da2->pallook[da2->egapal[fg]]); + } + //Draw character + for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];//draw blank + //draw -= 13; + // SBCS or DBCS left half + if (chr_wide == 0) { + if (attr & 0x01) chr_wide = 1; + //chr_wide = 0; + // Stay drawing If the char code is DBCS and not at last column. + if (chr_wide) { + //Get high DBCS code from the next video address + chr_dbcs = da2->cram[((da2->ma) + 2) & da2->vram_display_mask]; + chr_dbcs <<= 8; + chr_dbcs |= chr; + // Get the font pattern + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; + font <<= 1; + } + } + else { + // the char code is SBCS (ANK) + uint32_t fontbase; + if (attr & 0x02)//second map of SBCS font + fontbase = 0x3c000; + else + fontbase = 0x34000; + uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font + font <<= 8; + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font + //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + } + } + // right half of DBCS + else + { + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + chr_wide = 0; + } + //Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. + if (da2->sc == 27 && attr & 0x40 && ~da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) {//Underscore only in monochrome mode + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[fg]];//under line (white) + } + //Column 1 (Vertical Line) + if (attr & 0x10) { + p[0] = da2->pallook[da2->egapal[(da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[LV_GRID_COLOR_0]) : 2]];//vertical line (white) + } + if (da2->sc == 0 && attr & 0x20 && ~da2->attrregs[LV_PAS_STATUS_CNTRL]) {//HGrid + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[(da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[LV_GRID_COLOR_0]) : 2]];//horizontal line (white) + } + //Drawing text cursor + drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); + if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) + { + int cursorwidth = (da2->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); + int cursorcolor = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[LV_CURSOR_COLOR]) : 2;//Choose color 2 if mode 8 + fg = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); + bg = 0; + if (attr & 0x04) {//Color 0 if reverse + bg = fg; + fg = 0; + } + for (uint32_t n = 0; n < cursorwidth; n++) + if (p[n] == da2->pallook[da2->egapal[cursorcolor]] || da2->egapal[bg] == da2->egapal[cursorcolor]) + p[n] = (p[n] == da2->pallook[da2->egapal[bg]]) ? da2->pallook[da2->egapal[fg]] : da2->pallook[da2->egapal[bg]]; + else + p[n] = (p[n] == da2->pallook[da2->egapal[bg]]) ? da2->pallook[da2->egapal[cursorcolor]] : p[n]; + } + da2->ma += 2; + p += 13; + } + da2->ma &= da2->vram_display_mask; + //da2->writelines++; + } +} + +/* Display Adapter Mode 3 Drawing */ +static void da2_render_textm3(da2_t* da2) +{ + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + + if (da2->fullchange) + { + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + int x; + int drawcursor; + uint8_t chr, attr, extattr; + int fg, bg; + uint32_t chr_dbcs; + int chr_wide = 0; + //da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); + for (x = 0; x < da2->hdisp; x += 13) + { + chr = da2->vram[(0x18000 + (da2->ma)) & da2->vram_mask]; + attr = da2->vram[((0x18000 + (da2->ma)) + 1) & da2->vram_mask]; + extattr = da2->vram[((0x10000 + (da2->ma)) + 1) & da2->vram_mask]; + //if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (0x18000 + da2->ma << 1) & da2->vram_mask, chr, attr); + bg = attr >> 4; + //if (da2->blink) bg &= ~0x8; + //fg = (da2->blink || (!(attr & 0x80))) ? (attr & 0xf) : bg; + fg = attr & 0xf; + fg = IRGBtoBGRI(fg); + bg = IRGBtoBGRI(bg); + //Draw character + for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];//draw blank + // SBCS or DBCS left half + if (chr_wide == 0) { + if (extattr & 0x01) chr_wide = 1; + // Stay drawing if the char code is DBCS and not at last column. + if (chr_wide) { + //Get high DBCS code from the next video address + chr_dbcs = da2->vram[(0x18000 + (da2->ma) + 2) & da2->vram_mask]; + chr_dbcs <<= 8; + chr_dbcs |= chr; + // Get the font pattern + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; + font <<= 1; + } + } + else { + // the char code is SBCS (ANK) + uint32_t fontbase; + fontbase = 0x34000; + uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font + font <<= 8; + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font + //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + } + } + // right half of DBCS + else + { + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + chr_wide = 0; + } + //Drawing text cursor + drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); + if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) + { + //int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13); + //int cursorcolor = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[0x1a]) : 2;//Choose color 2 if mode 8 + //fg = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; + //bg = 0; + //if (attr & 0x04) {//Color 0 if reverse + // bg = fg; + // fg = 0; + //} + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[fg]];//under line (white) + } + da2->ma += 2; + p += 13; + } + da2->ma &= da2->vram_display_mask; + //da2->writelines++; + } +} + +void da2_render_color_4bpp(da2_t* da2) +{ + int changed_offset = da2->ma >> 12; + //da2_log("ma %x cf %x\n", da2->ma, changed_offset); + da2->plane_mask &= 0x0f;//safety + + if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) + { + int x; + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + //da2_log("d %X\n", da2->ma); + + for (x = 0; x <= da2->hdisp; x += 8)//hdisp = 1024 + { + uint8_t edat[8]; + uint8_t dat; + + //get 8 pixels from vram + da2->ma &= da2->vram_display_mask; + *(uint32_t*)(&edat[0]) = *(uint32_t*)(&da2->vram[da2->ma << 3]); + da2->ma += 1; + + dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)); + p[0] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)); + p[1] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)); + p[2] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)); + p[3] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)); + p[4] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)); + p[5] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)); + p[6] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)); + p[7] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + p += 8; + } + //da2->writelines++; + } +} + +void da2_render_color_8bpp(da2_t* da2) +{ + int changed_offset = da2->ma >> 12; + //da2_log("ma %x cf %x\n", da2->ma, changed_offset); + + if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) + { + int x; + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + //da2_log("d %X\n", da2->ma); + + for (x = 0; x <= da2->hdisp; x += 8)//hdisp = 1024 + { + uint8_t edat[8]; + uint8_t dat; + + //get 8 pixels from vram + da2->ma &= da2->vram_display_mask; + *(uint32_t*)(&edat[0]) = *(uint32_t*)(&da2->vram[da2->ma << 3]); + *(uint32_t*)(&edat[4]) = *(uint32_t*)(&da2->vram[(da2->ma << 3) + 4]); + da2->ma += 1; + + dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)) | + ((edat[4] >> 3) & (1 << 4)) | ((edat[5] >> 2) & (1 << 5)) | ((edat[6] >> 1) & (1 << 6)) | ((edat[7] >> 0) & (1 << 7)); + p[0] = da2->pallook[dat]; + dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)) | + ((edat[4] >> 2) & (1 << 4)) | ((edat[5] >> 1) & (1 << 5)) | ((edat[6] >> 0) & (1 << 6)) | ((edat[7] << 1) & (1 << 7)); + p[1] = da2->pallook[dat]; + dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)) | + ((edat[4] >> 1) & (1 << 4)) | ((edat[5] >> 0) & (1 << 5)) | ((edat[6] << 1) & (1 << 6)) | ((edat[7] << 2) & (1 << 7)); + p[2] = da2->pallook[dat]; + dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)) | + ((edat[4] >> 0) & (1 << 4)) | ((edat[5] << 1) & (1 << 5)) | ((edat[6] << 2) & (1 << 6)) | ((edat[7] << 3) & (1 << 7)); + p[3] = da2->pallook[dat]; + dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)) | + ((edat[4] << 1) & (1 << 4)) | ((edat[5] << 2) & (1 << 5)) | ((edat[6] << 3) & (1 << 6)) | ((edat[7] << 4) & (1 << 7)); + p[4] = da2->pallook[dat]; + dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)) | + ((edat[4] << 2) & (1 << 4)) | ((edat[5] << 3) & (1 << 5)) | ((edat[6] << 4) & (1 << 6)) | ((edat[7] << 5) & (1 << 7)); + p[5] = da2->pallook[dat]; + dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)) | + ((edat[4] << 3) & (1 << 4)) | ((edat[5] << 4) & (1 << 5)) | ((edat[6] << 5) & (1 << 6)) | ((edat[7] << 6) & (1 << 7)); + p[6] = da2->pallook[dat]; + dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)) | + ((edat[4] << 4) & (1 << 4)) | ((edat[5] << 5) & (1 << 5)) | ((edat[6] << 6) & (1 << 6)) | ((edat[7] << 7) & (1 << 7)); + p[7] = da2->pallook[dat]; + p += 8; + } + //da2->writelines++; + } +} + +void da2_updatevidselector(da2_t* da2) { + /* if VGA passthrough mode */ + da2_log("DA2 selector: %d\n", da2->ioctl[LS_MODE]); + if (da2->ioctl[LS_MODE] & 0x02) + { + da2->override = 1; + svga_set_override(da2->mb_vga, 0); + } + else + { + svga_set_override(da2->mb_vga, 1); + da2->override = 0; + } +} + + +void da2_recalctimings(da2_t* da2) +{ + double crtcconst; + double _dispontime, _dispofftime, disptime; + + da2->vtotal = da2->crtc[LC_VERTICAL_TOTALJ] & 0xfff;//w + da2->dispend = da2->crtc[LC_V_DISPLAY_ENABLE_END] & 0xfff;//w + da2->vsyncstart = da2->crtc[LC_VERTICAL_SYNC_START] & 0xfff;//w + da2->split = da2->crtc[LC_LINE_COMPAREJ] & 0xfff;//w Line Compare + da2->split = 0xfff; + da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff;//w + da2->hdisp = da2->crtc[LC_H_DISPLAY_ENABLE_END]; + + if (da2->crtc[LC_START_H_DISPLAY_ENAB] & 1) { + da2->hdisp--; + da2->dispend -= 29; + } + else { + //da2->vtotal += 2; + da2->dispend--; + //da2->vsyncstart++; + //da2->split++; + //da2->vblankstart++; + //da2->hdisp--; + } + + da2->htotal = da2->crtc[LC_HORIZONTAL_TOTAL]; + da2->htotal += 1; + + da2->rowoffset = da2->crtc[LC_OFFSET];//number of bytes in a scanline + + da2->clock = da2->da2const; + + da2->lowres = da2->attrregs[LC_VERTICAL_SYNC_START] & 0x40; + + da2->interlace = 0; + + //da2->ma_latch = ((da2->crtc[0xc] & 0x3ff) << 8) | da2->crtc[0xd];//w + b + da2->ca_adj = 0; + + da2->rowcount = da2->crtc[LC_MAXIMUM_SCAN_LINE]; + + da2->hdisp_time = da2->hdisp; + da2->render = da2_render_blank; + //determine display mode + //if (da2->attr_palette_enable && (da2->attrregs[0x1f] & 0x08)) + if (da2->attrregs[LV_COMPATIBILITY] & 0x08) + { + //if (da2->ioctl[0] & 0x01)//256 color mode + //{ + // da2_log("Set videomode to PS/55 8 bpp graphics.\n"); + // da2->vram_display_mask = 0x1ffff; + // da2->render = da2_render_color_8bpp; + //} + //else + if (!(da2->ioctl[LS_MODE] & 0x01)) {//16 color graphics mode + da2->hdisp *= 16; + da2->char_width = 13; + da2->hdisp_old = da2->hdisp; + //if (da2->plane_mask == 0x01) {//PS/55 monochrome + // da2_log("Set videomode to PS/55 Monochrome graphics.\n"); + // //da2->render = da2_render_mono; + // da2->render = da2_render_color_4bpp; + // da2->vram_display_mask = 0x1ffff; + //} + if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) {//PS/55 256 color + da2_log("Set videomode to PS/55 8 bpp graphics.\n"); + da2->render = da2_render_color_8bpp; + da2->vram_display_mask = DA2_MASK_GRAM; + } + else {//PS/55 8-color + da2_log("Set videomode to PS/55 4 bpp graphics.\n"); + da2->vram_display_mask = DA2_MASK_GRAM; + da2->render = da2_render_color_4bpp; + } + } + else {//text mode + if (da2->attrregs[LV_ATTRIBUTE_CNTL] & 1) {//PS/55 Mode 03 + da2_log("Set videomode to PS/55 Mode 03 text.\n"); + da2->render = da2_render_textm3; + da2->vram_display_mask = DA2_MASK_CRAM; + } + else {//PS/55 text(color/mono) + da2_log("Set videomode to PS/55 Mode 8/E text.\n"); + da2->render = da2_render_text; + da2->vram_display_mask = DA2_MASK_CRAM; + } + da2->hdisp *= 13; + da2->hdisp_old = da2->hdisp; + da2->char_width = 13; + } + } + else + { + da2_log("Set videomode to blank.\n"); + } + //if (!da2->scrblank && da2->attr_palette_enable) + //{ + //da2->render = da2_draw_text; + //} + + // da2_log("da2_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", da2_render, da2_render_text_40, da2_render_text_80, da2_render_8bpp_lowres, da2_render_8bpp_highres, da2_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); + + /*da2->char_width = 13;*///PS55TEXT = 13, GFX = 16 + //if (da2->recalctimings_ex) + // da2->recalctimings_ex(da2); + + if (da2->vblankstart < da2->dispend) + da2->dispend = da2->vblankstart; + + crtcconst = da2->clock * da2->char_width; + + disptime = da2->htotal; + _dispontime = da2->hdisp_time; + + da2_log("Disptime %f dispontime %f hdisp %i\n", disptime, _dispontime, da2->hdisp); + //if (da2->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + da2->dispontime = (uint64_t)_dispontime; + da2->dispofftime = (uint64_t)_dispofftime; + if (da2->dispontime < TIMER_USEC) + da2->dispontime = TIMER_USEC; + if (da2->dispofftime < TIMER_USEC) + da2->dispofftime = TIMER_USEC; + da2_log("da2 horiz total %i display end %i vidclock %f\n",da2->crtc[0],da2->crtc[1],da2->clock); + // da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); + // da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70); + + // da2_log("da2->render %08X\n", da2->render); +} + +uint8_t da2_mca_read(int port, void *p) +{ + da2_t *da2 = (da2_t *)p; + return da2->pos_regs[port & 7]; +} + +static void da2_mapping_update(da2_t *da2) +{ + if (!((da2->pos_regs[2] ^ da2->old_pos2) & 1)) return; + da2->old_pos2 = da2->pos_regs[2]; + //da2_recalc_mapping(da2); + if (da2->pos_regs[2] & 0x01) + { + da2_log("DA2 enable registers\n"); + for (int i = 0; i < 8; i++) + da2_log("DA2 POS[%d]: %x\n", i, da2->pos_regs[i]); + io_sethandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_sethandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_sethandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); + mem_mapping_enable(&da2->cmapping); + mem_mapping_enable(&da2->mmio.mapping); + timer_enable(&da2->timer); + } + else + { + da2_log("DA2 disable registers\n"); + timer_disable(&da2->timer); + mem_mapping_disable(&da2->cmapping); + mem_mapping_disable(&da2->mmio.mapping); + io_removehandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_removehandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_removehandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); + } +} + +void da2_mca_write(int port, uint8_t val, void *p) +{ + da2_t *da2 = (da2_t *)p; + + da2_log("da2_mca_write: port=%04x val=%02x\n", port, val); + + if (port < 0x102) + return; + da2->pos_regs[port & 7] = val; + + da2_mapping_update(da2); +} + +static uint8_t da2_mca_feedb(void* priv) +{ + const da2_t* da2 = (da2_t*)priv; + + return da2->pos_regs[2] & 0x01; +} + +static void da2_mca_reset(void *p) +{ + da2_t *da2 = (da2_t *)p; + da2_reset(da2); + da2_mca_write(0x102, 0, da2); +} +// +static void da2_gdcropB(uint32_t addr, da2_t* da2) { + for (int i = 0; i < 8; i++) { + if (da2->writemask & (1 << i)) { + //da2_log("da2_gdcropB o%x a%x d%x p%d m%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW]); + switch (da2->gdcreg[LG_COMMAND] & 0x03) + { + case 0: /*Set*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 1: /*AND*/ + //da2->vram[addr | i] = (da2->gdcinput[i] | ~da2->gdcreg[LG_BIT_MASK_LOW]) & da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 2: /*OR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 3: /*XOR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) ^ da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + } + } + } +} +static void da2_gdcropW(uint32_t addr, uint16_t bitmask, da2_t* da2) { + uint8_t bitmask_l = bitmask & 0xff; + uint8_t bitmask_h = bitmask >> 8; + for (int i = 0; i < 8; i++) { + if (da2->writemask & (1 << i)) { + //da2_log("da2_gdcropW m%x a%x d%x i%d ml%x mh%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[LG_BIT_MASK_HIGH]); + switch (da2->gdcreg[LG_COMMAND] & 0x03) + { + case 0: /*Set*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->gdcsrc[i] & ~bitmask_l); + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | ((da2->gdcsrc[i] >> 8) & ~bitmask_h); + da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 1: /*AND*/ + //da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask_l) & da2->gdcsrc[i]; + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) | ~bitmask_h) & (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) & (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 2: /*OR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | da2->gdcsrc[i]; + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) | (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 3: /*XOR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) ^ da2->gdcsrc[i]; + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) ^ (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) ^ (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + } + } + } +} + +static uint8_t da2_mmio_read(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + addr &= DA2_MASK_MMIO; + + if (da2->ioctl[LS_MMIO] & 0x10) { + if (da2->fctl[LF_MMIO_SEL] == 0x80) + //linear access + addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17); + else + { + //64k bank switch access + uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; + index <<= 8; + index |= da2->fctl[LF_MMIO_ADDR]; + addr += index * 0x40; + } + //da2_log("PS55_MemHnd: Read from mem %x, bank %x, addr %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); + switch (da2->fctl[LF_MMIO_MODE] & 0xf0) { + case 0xb0://Gaiji RAM + addr &= DA2_MASK_GAIJIRAM;//safety access + //da2_log("PS55_MemHnd_G: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 128, addr, da2->mmio.font[addr]); + return da2->mmio.ram[addr]; + break; + case 0x10://Font ROM + //da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); + if (addr > DA2_FONTROM_SIZE) return 0xff; + return da2->mmio.font[addr]; + break; + default: + return 0xff;//invalid memory access + break; + } + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 or 256 color mode + { + cycles -= video_timing_read_b; + //readmode 1 + //da2_log("da2_rp: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->readplane, addr); + for (int i = 0; i < 8; i++) + da2->gdcla[i] = da2->vram[(addr << 3) | i];//read in byte + //da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);//read in word + //da2->gdcramlatched = 1; + //da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); + if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 + uint8_t ret = 0; + + for (int i = 0; i < 8; i++) + { + if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))//color don't care register + ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xff : 0); + } + return ~ret; + } + else return da2->gdcla[da2->readplane]; + } + else //text mode 3 + { + cycles -= video_timing_read_b; + return da2->vram[addr]; + } +} +static uint16_t da2_mmio_readw(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + //da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); + if (da2->ioctl[LS_MMIO] & 0x10) { + return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + { + cycles -= video_timing_read_w; + addr &= DA2_MASK_MMIO; + for (int i = 0; i < 8; i++) + da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);//read vram into latch + //da2->gdcramlatched = 1; + ////debug + //if (((int)addr - (int)da2->mmrdbg_vidaddr) > 2 || (((int)da2->mmrdbg_vidaddr - (int)addr) > 2) || da2->mmrdbg_vidaddr == addr) + //{ + // fprintf(da2->mmrdbg_fp, "\nR %x ", addr); + // for (int i = 0; i <= 0xb; i++) + // fprintf(da2->mmrdbg_fp, "%02x ", da2->gdcreg[i]); + //} + //for (int i = 0; i < 16; i++) + //{ + // int pixeldata = 0; + // if (da2->gdcla[da2->readplane] & (1 << (15 - i))) pixeldata = 1; + // fprintf(da2->mmrdbg_fp, "%X", pixeldata); + //} + //da2->mmrdbg_vidaddr = addr; + //// + + if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 + uint16_t ret = 0; + + for (int i = 0; i < 8; i++) + { + if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))//color don't care register + ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xffff : 0); + } + return ~ret; + } + else + { + //da2_log("da2_Rw: %05x=%04x\n", addr, da2->gdcla[da2->readplane]); + return da2->gdcla[da2->readplane]; + } + } + else { + return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); + } +} + +static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //da2_log("da2_mmio_write %x %x\n", addr, val); + if ((addr & ~DA2_MASK_MMIO) != 0xA0000) return; + addr &= DA2_MASK_MMIO; + + if (da2->ioctl[LS_MMIO] & 0x10) { + //if(da2->ioctl[LS_MMIO] == 0x1f) da2_log("mw mem %x, addr %x, val %x, ESDI %x:%x DSSI %x:%x\n", da2->fctl[LF_MMIO_MODE], addr, val, ES, DI, DS, SI); + //Gaiji RAM + if (da2->fctl[LF_MMIO_SEL] == 0x80) + addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17);//xxxy yyyy yyyy yyyy yyyy + else + { + uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; + index <<= 8; + index |= da2->fctl[LF_MMIO_ADDR]; + addr += index * 0x40; + } + switch (da2->fctl[LF_MMIO_MODE]) { + case 0xb0://Gaiji RAM 1011 0000 + addr &= DA2_MASK_GAIJIRAM;//safety access + da2->mmio.ram[addr] = val; + break; + case 0x10://Font ROM 0001 0000 + //Read-Only + break; + case 0x00: + //da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); + addr &= 0x7f;//OS/2 write addr 1cf80-1cfc3, val xx + if (addr >= DA2_BLT_MEMSIZE) + { + da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + return; + } + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_addr++; + break; + default: + da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + break; + } + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + { + uint8_t wm = da2->writemask; + //da2_log("da2_gcB m%d a%x d%x\n", da2->writemode, addr, val); + //debug + //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + //{ + //if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) + //{ + // fprintf(da2->mmdbg_fp, "\nB %x ", addr); + // for (int i = 0; i <= 0xb; i++) + // fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); + //} + //for (int i = 0; i < 8; i++) + //{ + // int pixeldata = 0; + // if (val & (1 << (7 - i))) pixeldata = (da2->writemask & 0xf); + // fprintf(da2->mmdbg_fp, "%X", pixeldata); + //} + //da2->mmdbg_vidaddr = addr; + //} + + cycles -= video_timing_write_b; + + da2->changedvram[addr >> 12] = changeframecount; + addr <<= 3; + + //if (GCLATCHCOND) { + //if (da2->writemode == 2) { + for (int i = 0; i < 8; i++) + da2->gdcsrc[i] = da2->gdcla[i];//use latch + //} + //else { + // for (int i = 0; i < 8; i++) + // da2->gdcsrc[i] = da2->vram[addr | i];//read in byte from vram + //} + //da2->gdcramlatched = 0; + //da2_log("da2_Wb m%02x r%02x %05x:%02x %x:%x\n", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, cs >> 4, cpu_state.pc); + //da2_log("da2_Wb m%02x r%02x %05x:%02x=%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); + + if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) da2->gdcinput[i] = ~val; + else da2->gdcinput[i] = val; + da2_gdcropB(addr, da2); + return; + } + + switch (da2->writemode) + { + case 2: + //case 1: + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) da2->vram[addr | i] = da2->gdcsrc[i]; + break; + case 0: + if (da2->gdcreg[LG_DATA_ROTATION] & 7) + val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; + if (da2->gdcreg[LG_BIT_MASK_LOW] == 0xff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) da2->vram[addr | i] = val; + } + else + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + else da2->gdcinput[i] = val; + + for (int i = 0; i < 8; i++) + da2->debug_vramold[i] = da2->vram[addr | i];//use latch + da2_gdcropB(addr, da2); + //for (int i = 0; i < 8; i++) + // da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch + //// da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + //case 2: + case 1: + if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) da2->vram[addr | i] = (((val & (1 << i)) ? 0xff : 0) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + } + else + { + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0); + da2_gdcropB(addr, da2); + } + break; + case 3: + if (da2->gdcreg[LG_DATA_ROTATION] & 7) + val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; + wm = da2->gdcreg[LG_BIT_MASK_LOW]; + da2->gdcreg[LG_BIT_MASK_LOW] &= val; + + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + da2_gdcropB(addr, da2); + da2->gdcreg[LG_BIT_MASK_LOW] = wm; + break; + } + //da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); + } + else// mode 3h text + { + cycles -= video_timing_write_b; + da2->vram[addr] = val; + da2->fullchange = 2; + } +} +uint16_t rightRotate(uint16_t data, uint8_t count) +{ + return (data >> count) | (data << (sizeof(data) * 8 - count)); +} +static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + uint8_t wm = da2->writemask; + uint16_t bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; + bitmask <<= 8; + bitmask |= (uint16_t)da2->gdcreg[LG_BIT_MASK_LOW]; + //debug + //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + //{ + //if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) + //{ + // fprintf(da2->mmdbg_fp, "\nW %x ", addr); + // for (int i = 0; i <= 0xb; i++) + // fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); + //} + //for (int i = 0; i < 16; i++) + //{ + // int pixeldata = 0; + // if (val & (1 << (15 - i))) pixeldata = (da2->writemask & 0xf); + // fprintf(da2->mmdbg_fp, "%X", pixeldata); + //} + //da2->mmdbg_vidaddr = addr; + //} + //cycles -= video_timing_write_w; + //cycles_lost += video_timing_write_w; + + //da2_log("da2_gcW m%d a%x d%x\n", da2->writemode, addr, val); + //da2_log("da2_gcW %05X %02X %04X:%04X esdi %04X:%04X dssi %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); + + da2->changedvram[addr >> 12] = changeframecount; + da2->changedvram[(addr + 1) >> 12] = changeframecount; + addr <<= 3; + + //if (((da2->gdcreg[LG_COMMAND] & 0x03) || da2->writemode == 2) && da2->writemode != 1) { + //if (GCLATCHCOND) { + //if (da2->writemode == 2) { + for (int i = 0; i < 8; i++) + da2->gdcsrc[i] = da2->gdcla[i];//use latch + //} + //else { + // for (int i = 0; i < 8; i++) + // da2->gdcsrc[i] = (uint16_t)(da2->vram[addr | i]) | ((uint16_t)(da2->vram[(addr + 8) | i]) << 8);//read in word + //} + //da2->gdcramlatched = 0; + + if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) da2->gdcinput[i] = ~val; + else da2->gdcinput[i] = val; + da2_gdcropW(addr, bitmask, da2); + return; + } + //da2_log("da2_Ww m%02x r%02x %05x:%04x=%02x%02x%02x%02x,%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] + // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); + switch (da2->writemode)// writemode 0 or 2 rop(0b) 0 or 3 + { + case 2: + //case 1: + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) + { + da2->vram[addr | i] = da2->gdcsrc[i] & 0xff; + da2->vram[(addr + 8) | i] = da2->gdcsrc[i] >> 8; + } + break; + //case 2:win + + case 0: + if (da2->gdcreg[LG_DATA_ROTATION] & 15) + val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15);//val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; TODO this wont work + if (bitmask == 0xffff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) + { + da2->vram[addr | i] = val & 0xff; + da2->vram[(addr + 8) | i] = val >> 8; + } + } + else + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + else da2->gdcinput[i] = val; + + //for (int i = 0; i < 8; i++)//draft20240722 0211 + // da2->gdcla[i] = 0;//read in word + da2_gdcropW(addr, bitmask, da2); + // da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + //case 2: + case 1: + if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) + { + uint16_t wdata = (((val & (1 << i)) ? 0xffff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); + da2->vram[addr | i] = wdata & 0xff; + da2->vram[(addr + 8) | i] = wdata >> 8; + } + } + else + { + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = ((val & (1 << i)) ? 0xffff : 0); + da2_gdcropW(addr, bitmask, da2); + } + break; + case 3: + if (da2->gdcreg[LG_DATA_ROTATION] & 15) + val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15);//val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val];; TODO this wont work + wm = bitmask; + bitmask &= val; + + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + da2_gdcropW(addr, bitmask, da2); + bitmask = wm; + break; + } + //da2_log("%02x%02x%02x%02x,%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] + // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); +} +static void da2_mmio_writew(uint32_t addr, uint16_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //if ((addr & ~0x1ffff) != 0xA0000) return; + if (da2->ioctl[LS_MMIO] & 0x10) { + //da2_log("da2_mmio_writeW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + da2_mmio_write(addr, val & 0xff, da2); + da2_mmio_write(addr + 1, val >> 8, da2); + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + { + addr &= DA2_MASK_MMIO; + //return; + //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + da2_mmio_gc_writeW(addr, val, da2); + } + else {//mode 3h text + //if (addr & 0xff00 == 0) da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); + //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + da2_mmio_write(addr, val & 0xff, da2); + da2_mmio_write(addr + 1, val >> 8, da2); + } +} + +static void da2_code_write(uint32_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //if ((addr & ~0xfff) != 0xE0000) return; + addr &= DA2_MASK_CRAM; + da2->cram[addr] = val; + da2->fullchange = 2; +} +static void da2_code_writeb(uint32_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //da2_log("DA2_code_writeb: Write to %x, val %x\n", addr, val); + cycles -= video_timing_write_b; + da2_code_write(addr, val, da2); +} +static void da2_code_writew(uint32_t addr, uint16_t val, void* p) +{ + //da2_log("DA2_code_writew: Write to %x, val %x\n", addr, val); + da2_t* da2 = (da2_t*)p; + cycles -= video_timing_write_w; + da2_code_write(addr, val & 0xff, da2); + da2_code_write(addr + 1, val >> 8, da2); +} + +static uint8_t da2_code_read(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + if ((addr & ~DA2_MASK_CRAM) != 0xE0000) return 0xff; + addr &= DA2_MASK_CRAM; + return da2->cram[addr]; +} +static uint8_t da2_code_readb(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + cycles -= video_timing_read_b; + return da2_code_read(addr, da2); +} +static uint16_t da2_code_readw(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + cycles -= video_timing_read_w; + return da2_code_read(addr, da2) | (da2_code_read(addr + 1, da2) << 8); + //return 0; +} + +void da2_doblit(int y1, int y2, int wx, int wy, da2_t* da2) +{ + if (wx != xsize || wy != ysize) { + xsize = wx; + ysize = wy; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(32, 0, xsize, ysize); + frames++; + + video_res_x = wx; + video_res_y = wy; + video_bpp = 8; +} + +void da2_poll(void* priv) +{ + da2_t* da2 = (da2_t*)priv; + int x; + + if (!da2->linepos) + { + timer_advance_u64(&da2->timer, da2->dispofftime); + // if (output) printf("Display off %f\n",vidtime); + da2->cgastat |= 1; + da2->linepos = 1; + + if (da2->dispon) + { + da2->hdisp_on = 1; + + da2->ma &= da2->vram_display_mask; + if (da2->firstline == 2000) + { + da2->firstline = da2->displine; + video_wait_for_buffer(); + } + + //RENDER + if (!da2->override) + da2->render(da2); + + if (da2->lastline < da2->displine) + da2->lastline = da2->displine; + } + + //da2_log("%03i %06X %06X\n", da2->displine, da2->ma,da2->vram_display_mask); + da2->displine++; + if (da2->interlace) + da2->displine++; + if ((da2->cgastat & 8) && ((da2->displine & 0xf) == (da2->crtc[LC_VERTICAL_SYNC_END] & 0xf)) && da2->vslines) + { + //da2_log("Vsync off at line %i\n",displine); + da2->cgastat &= ~8; + } + da2->vslines++; + if (da2->displine > 1200) + da2->displine = 0; + // da2_log("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], + // displine, vc, ma); + } + else + { + // da2_log("VC %i ma %05X\n", da2->vc, da2->ma); + timer_advance_u64(&da2->timer, da2->dispontime); + + // if (output) printf("Display on %f\n",vidtime); + if (da2->dispon) + da2->cgastat &= ~1; + da2->hdisp_on = 0; + + da2->linepos = 0; + if (da2->sc == (da2->crtc[LC_VERTICAL_SYNC_END] & 31)) + da2->con = 0; + if (da2->dispon) + { + if (da2->sc == da2->rowcount) + { + da2->linecountff = 0; + da2->sc = 0; + + da2->maback += (da2->rowoffset << 1);// color = 0x50(80), mono = 0x40(64) + if (da2->interlace) + da2->maback += (da2->rowoffset << 1); + da2->maback &= da2->vram_display_mask; + da2->ma = da2->maback; + } + else + { + da2->sc++; + da2->sc &= 31; + da2->ma = da2->maback; + } + } + //da2->hsync_divisor = !da2->hsync_divisor; + + //disable for 256 color mode + //if (da2->hsync_divisor && (da2->crtc[0x17] & 4)) + // return; + + da2->vc++; + da2->vc &= 2047; + + if (da2->vc == da2->dispend) + { + //if (da2->vblank_start) + // da2->vblank_start(da2); + // da2_log("VC dispend\n"); + da2->dispon = 0; + //if (da2->crtc[10] & 0x20) da2->cursoron = 0; + //else da2->cursoron = da2->blink & 16; + if (da2->ioctl[LS_MODE] & 1) {//in text mode + if (da2->attrregs[LV_CURSOR_CONTROL] & 0x01)//cursor blinking + { + da2->cursoron = (da2->blink | 1) & da2->blinkconf; + } + else + { + da2->cursoron = 0; + } + if (!(da2->blink & (0x10 - 1)))//force redrawing for cursor and blink attribute + da2->fullchange = 2; + } + da2->blink++; + + for (x = 0; x < ((da2->vram_mask + 1) >> 12); x++) + { + if (da2->changedvram[x]) + da2->changedvram[x]--; + } + // memset(changedvram,0,2048); del + if (da2->fullchange) + { + da2->fullchange--; + //da2->fps++; + } + } + if (da2->vc == da2->vsyncstart) + { + int wx, wy; + // da2_log("VC vsync %i %i\n", da2->firstline_draw, da2->lastline_draw); + da2->dispon = 0; + da2->cgastat |= 8; + x = da2->hdisp; + + if (da2->interlace && !da2->oddeven) da2->lastline++; + if (da2->interlace && da2->oddeven) da2->firstline--; + + wx = x; + wy = da2->lastline - da2->firstline; + + da2_doblit(da2->firstline_draw, da2->lastline_draw + 1, wx, wy, da2); + + //readflash = 0; + + da2->firstline = 2000; + da2->lastline = 0; + + da2->firstline_draw = 2000; + da2->lastline_draw = 0; + + da2->oddeven ^= 1; + + changeframecount = da2->interlace ? 3 : 2; + da2->vslines = 0; + + //if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch + (da2->rowoffset << 1) + ((da2->crtc[5] & 0x60) >> 5); + //else da2->ma = da2->maback = da2->ma_latch + ((da2->crtc[5] & 0x60) >> 5); + //da2->ca = ((da2->crtc[0xe] << 8) | da2->crtc[0xf]) + ((da2->crtc[0xb] & 0x60) >> 5) + da2->ca_adj; + if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch; + else da2->ma = da2->maback = da2->ma_latch; + da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; + + da2->ma <<= 1; + da2->maback <<= 1; + da2->ca <<= 1; + + //if (!da2->video_res_override) + //{ + //da2->video_res_x = wx; + //da2->video_res_y = wy + 1; + + if (da2->ioctl[LS_MODE] & 1) /*Text mode*/ + { + //da2->video_res_x /= da2->char_width; + //da2->video_res_y /= (da2->crtc[9] & 31) + 1; + //da2->video_bpp = 0; + } + else + { + //if (da2->crtc[9] & 0x80) + // da2->video_res_y /= 2; + //if (!(da2->crtc[0x17] & 2)) + // da2->video_res_y *= 4; + //else if (!(da2->crtc[0x17] & 1)) + // da2->video_res_y *= 2; + //da2->video_res_y /= (da2->crtc[9] & 31) + 1; + //if (da2->render == da2_render_8bpp_lowres || + // da2->render == da2_render_15bpp_lowres || + // da2->render == da2_render_16bpp_lowres || + // da2->render == da2_render_24bpp_lowres || + // da2->render == da2_render_32bpp_lowres) + //da2->video_res_x /= 2; + + //switch (da2->gdcreg[5] & 0x60) + //{ + //case 0x00: da2->video_bpp = 4; break; + //case 0x20: da2->video_bpp = 2; break; + //case 0x40: case 0x60: da2->video_bpp = da2->bpp; break; + //} + //da2->video_bpp = da2->bpp; + } + //} + //if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma + (da2->rowoffset << 1); + + // da2_log("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,da2_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], da2_interlace, oddeven); + + //if (da2->vsync_callback) + // da2->vsync_callback(da2); + } + if (da2->vc == da2->vtotal) + { + // da2_log("VC vtotal\n"); + + + // printf("Frame over at line %i %i %i %i\n",displine,vc,da2_vsyncstart,da2_dispend); + da2->vc = 0; + da2->sc = da2->crtc[LC_PRESET_ROW_SCANJ] & 0x1f; + da2->dispon = 1; + da2->displine = (da2->interlace && da2->oddeven) ? 1 : 0; + da2->scrollcache = da2->attrregs[LV_PANNING] & 7; + //da2->linecountff = 0; + + //da2->hwcursor_on = 0; + //da2->hwcursor_latch = da2->hwcursor; + + //da2->overlay_on = 0; + //da2->overlay_latch = da2->overlay; + // da2_log("Latch HWcursor addr %08X\n", da2_hwcursor_latch.addr); + + // da2_log("ADDR %08X\n",hwcursor_addr); + } + if (da2->sc == (da2->crtc[LC_VERTICAL_SYNC_START] & 31)) + da2->con = 1; + } + // printf("2 %i\n",da2_vsyncstart); + //da2_log("da2_poll %i %i %i %i %i %i %i\n", ins, da2->dispofftime, da2->dispontime, da2->vidtime, cyc_total, da2->linepos, da2->vc); + //da2_log("r"); +} + +static void da2_loadfont(char* fname, void* p) { + da2_t* da2 = (da2_t*)p; + uint8_t buf; + //uint32_t code = 0; + uint64_t fsize; + if (!fname) return; + if (*fname == '\0') return; + FILE* mfile = rom_fopen(fname, "rb"); + if (!mfile) { + //da2_log("MSG: Can't open binary ROM font file: %s\n", fname); + return; + } + fseek(mfile, 0, SEEK_END); + fsize = ftell(mfile);//get filesize + fseek(mfile, 0, SEEK_SET); + if (fsize > DA2_FONTROM_SIZE) { + fsize = DA2_FONTROM_SIZE;//truncate read data + //da2_log("MSG: The binary ROM font is truncated: %s\n", fname); + //fclose(mfile); + //return 1; + } + uint32_t j = 0; + while (ftell(mfile) < fsize) { + fread(&buf, sizeof(uint8_t), 1, mfile); + da2->mmio.font[j] = buf; + j++; + } + fclose(mfile); + return; +} + +/* 12-bit DAC color palette for IBMJ Display Adapter with color monitor */ +static uint8_t ps55_palette_color[64][3] = +{ +{0x00,0x00,0x00},{0x00,0x00,0x2A},{0x00,0x2A,0x00},{0x00,0x2A,0x2A},{0x2A,0x00,0x00},{0x2A,0x00,0x2A},{0x2A,0x2A,0x00},{0x2A,0x2A,0x2A}, +{0x00,0x00,0x15},{0x00,0x00,0x3F},{0x00,0x2A,0x15},{0x00,0x2A,0x3F},{0x2A,0x00,0x15},{0x2A,0x00,0x3F},{0x2A,0x2A,0x15},{0x2A,0x2A,0x3F}, +{0x00,0x15,0x00},{0x00,0x15,0x2A},{0x00,0x3F,0x00},{0x00,0x3F,0x2A},{0x2A,0x15,0x00},{0x2A,0x15,0x2A},{0x2A,0x3F,0x00},{0x2A,0x3F,0x2A}, +{0x00,0x15,0x15},{0x00,0x15,0x3F},{0x00,0x3F,0x15},{0x00,0x3F,0x3F},{0x2A,0x15,0x15},{0x2A,0x15,0x3F},{0x2A,0x3F,0x15},{0x2A,0x3F,0x3F}, +{0x15,0x00,0x00},{0x15,0x00,0x2A},{0x15,0x2A,0x00},{0x15,0x2A,0x2A},{0x3F,0x00,0x00},{0x3F,0x00,0x2A},{0x3F,0x2A,0x00},{0x3F,0x2A,0x2A}, +{0x15,0x00,0x15},{0x15,0x00,0x3F},{0x15,0x2A,0x15},{0x15,0x2A,0x3F},{0x3F,0x00,0x15},{0x3F,0x00,0x3F},{0x3F,0x2A,0x15},{0x3F,0x2A,0x3F}, +{0x15,0x15,0x00},{0x15,0x15,0x2A},{0x15,0x3F,0x00},{0x15,0x3F,0x2A},{0x3F,0x15,0x00},{0x3F,0x15,0x2A},{0x3F,0x3F,0x00},{0x3F,0x3F,0x2A}, +{0x15,0x15,0x15},{0x15,0x15,0x3F},{0x15,0x3F,0x15},{0x15,0x3F,0x3F},{0x3F,0x15,0x15},{0x3F,0x15,0x3F},{0x3F,0x3F,0x15},{0x3F,0x3F,0x3F} +}; + +void da2_reset_ioctl(da2_t* da2) +{ + da2->ioctl[LS_RESET] = 0x00; /* Bit 0: Reset sequencer */ + da2_outw(LS_INDEX, 0x0302, da2); /* Index 02, Bit 1: VGA passthrough, Bit 0: Character Mode */ + da2_outw(LS_INDEX, 0x0008, da2); /* Index 08, Bit 0: Enable MMIO */ +} + +static void +da2_reset(void* priv) +{ + da2_t* da2 = (da2_t*)priv; + + /* Initialize drawing */ + da2->bitblt.exec = DA2_BLT_CIDLE; + da2->render = da2_render_blank; + da2_reset_ioctl(da2); + + da2->pos_regs[0] = DA2_POSID_L; /* Adapter Identification Byte (Low byte) */ + da2->pos_regs[1] = DA2_POSID_H; /* Adapter Identification Byte (High byte) */ + da2->pos_regs[2] = 0x40; /* Bit 7-5: 010=Mono, 100=Color, Bit 0 : Card Enable (they are changed by system software) */ + da2->ioctl[LS_CONFIG1] = OldLSI | Mon_ID3 | Page_Two; /* Configuration(Low) : DA - 2, Monitor ID 3, 1024 KB */ + da2->ioctl[LS_CONFIG2] = Mon_ID1; /* Configuration (High): Monitor ID 0-2 */ + da2->fctl[0] = 0x2b; /* 3E3h:0 */ + da2->fctl[LF_MMIO_MODE] = 0xb0; /* 3E3h:0bh */ + da2->attrregs[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ + da2->crtc[LC_HORIZONTAL_TOTAL] = 63; /* Horizontal Total */ + da2->crtc[LC_VERTICAL_TOTALJ] = 255; /* Vertical Total (These two must be set before the timer starts.) */ + da2->ma_latch = 0; + //da2->gdcramlatched = 0; + da2->interlace = 0; + da2->attrregs[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ + da2->attr_palette_enable = 0; /* disable attribute generator */ + + /* Set default color palette (Display driver of Win 3.1 won't reset palette) */ + da2_out(0x3c8, 0, da2); + for (int i = 0; i < 256; i++) { + da2_out(0x3c9, ps55_palette_color[i & 0x3F][0], da2); + da2_out(0x3c9, ps55_palette_color[i & 0x3F][1], da2); + da2_out(0x3c9, ps55_palette_color[i & 0x3F][2], da2); + } +} + +static void *da2_init() +{ + //Todo: init regs, gaiji memory, video memory, I/O handlers, font ROM + + if (svga_get_pri() == NULL) + return NULL; + svga_t *mb_vga = svga_get_pri(); + mb_vga->cable_connected = 0; + + da2_t* da2 = malloc(sizeof(da2_t)); + da2->mb_vga = mb_vga; + + da2->dispontime = 1000ull << 32; + da2->dispofftime = 1000ull << 32; + int memsize = 1024 * 1024; + da2->vram = malloc(memsize); + da2->vram_mask = memsize - 1; + //da2->gram_display_mask = (memsize - 1) >> 3; + da2->cram = malloc(0x1000); + //da2->cram_display_mask = 0x1000 - 1; + da2->vram_display_mask = DA2_MASK_CRAM; + da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h + da2_loadfont(DA2_FONTROM_PATH, da2); + + mca_add(da2_mca_read, da2_mca_write, da2_mca_feedb, da2_mca_reset, da2); + da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); + memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + memset(da2->bitblt.reg, 0xfe, DA2_BLT_REGSIZE * sizeof(uint32_t)); /* clear memory */ +#ifdef ENABLE_DA2_DEBUGBLT + da2->bitblt.debug_reg = malloc(DA2_DEBUG_BLTLOG_MAX * DA2_DEBUG_BLTLOG_SIZE); + da2->mmdbg_fp = fopen("da2_mmiowdat.txt", "w"); + da2->mmrdbg_fp = fopen("da2_mmiordat.txt", "w"); + da2->bitblt.debug_reg_ip = 0; +#endif + da2->bitblt.payload_addr = 0; + da2_reset(da2); + + mem_mapping_add(&da2->mmio.mapping, 0xA0000, 0x20000, da2_mmio_read, da2_mmio_readw, NULL, da2_mmio_write, da2_mmio_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); + //da2_log("DA2mmio new mapping: %X, base: %x, size: %x\n", &da2->mmio.mapping, da2->mmio.mapping.base, da2->mmio.mapping.size); + + mem_mapping_disable(&da2->mmio.mapping); + + mem_mapping_add(&da2->cmapping, 0xE0000, 0x1000, da2_code_readb, da2_code_readw, NULL, da2_code_writeb, da2_code_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); + + mem_mapping_disable(&da2->cmapping); + + timer_add(&da2->timer, da2_poll, da2, 0); + da2->bitblt.timerspeed = 1 * TIMER_USEC; /* Todo: Async bitblt won't work in OS/2 J1.3 Command Prompt */ + timer_add(&da2->bitblt.timer, da2_bitblt_exec, da2, 0); + + return da2; +} +static int da2_available() +{ + return rom_present(DA2_FONTROM_PATH); +} + +void da2_close(void *p) +{ + da2_t *da2 = (da2_t *)p; + + /* dump mem for debug */ +#ifndef RELEASE_BUILD + FILE* f; + f = fopen("da2_cram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->cram, 0x1000, 1, f); + fclose(f); + } + f = fopen("da2_vram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->vram, 1024*1024, 1, f); + fclose(f); + } + f = fopen("da2_gram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->mmio.ram, 256*1024, 1, f); + fclose(f); + } + f = fopen("da2_attrpal.dmp", "wb"); + if (f != NULL) { + fwrite(da2->attrregs, 32, 1, f); + fclose(f); + } + f = fopen("da2_dacrgb.dmp", "wb"); + if (f != NULL) { + fwrite(da2->vgapal, 3*256, 1, f); + fclose(f); + } + f = fopen("da2_daregs.txt", "w"); + if (f != NULL) { + for (int i=0;i<0x10;i++) + fprintf(f, "3e1(ioctl) %02X: %4X\n", i, da2->ioctl[i]); + for (int i = 0; i < 0x20; i++) + fprintf(f, "3e3(fctl) %02X: %4X\n", i, da2->fctl[i]); + for (int i = 0; i < 0x20; i++) + fprintf(f, "3e5(crtc) %02X: %4X\n", i, da2->crtc[i]); + for (int i = 0; i < 0x40; i++) + fprintf(f, "3e8(attr) %02X: %4X\n", i, da2->attrregs[i]); + for (int i = 0; i < 0x10; i++) + fprintf(f, "3eb(gcr) %02X: %4X\n", i, da2->gdcreg[i]); + for (int i = 0; i < 0x10; i++) + fprintf(f, "3ee(?) %02X: %4X\n", i, da2->reg3ee[i]); + fclose(f); + } +#ifdef ENABLE_DA2_DEBUGBLT + f = fopen("da2_bltdump.csv", "w"); + if (f != NULL && da2->bitblt.debug_reg_ip > 0) { + /* print header */ + for (int y = 0; y < DA2_DEBUG_BLTLOG_SIZE; y++) { + if (da2->bitblt.debug_reg[(da2->bitblt.debug_reg_ip - 1) * DA2_DEBUG_BLTLOG_SIZE + y] != DA2_DEBUG_BLT_NEVERUSED) + fprintf(f, "\"%02X\"\t", y); + } + fprintf(f, "\n"); + /* print data */ + for (int x = 0; x < da2->bitblt.debug_reg_ip; x++) { + for (int y = 0; y < DA2_DEBUG_BLTLOG_SIZE; y++) { + if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_NEVERUSED) + ; + else if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_USEDRESET) + fprintf(f, "\"\"\t"); + else + fprintf(f, "\"%X\"\t", da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y]); + } + fprintf(f, "\n"); + } + fclose(f); + } + if (da2->mmdbg_fp != NULL) fclose(da2->mmdbg_fp); + if (da2->mmrdbg_fp != NULL) fclose(da2->mmrdbg_fp); + free(da2->bitblt.debug_reg); +#endif +#endif + free(da2->cram); + free(da2->vram); + free(da2->changedvram); + free(da2); +} + +void da2_speed_changed(void *p) +{ + da2_t* da2 = (da2_t*)p; + da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); + da2_recalctimings(da2); +} + +void da2_force_redraw(void *p) +{ + da2_t* da2 = (da2_t*)p; + + da2->fullchange = changeframecount; +} + +//void da2_add_status_info(char *s, int max_len, void *p) +//{ +// da2_t* da2 = (da2_t*)p; +// char temps[128]; +// if (!(da2->pos_regs[2] & 0x01)) strcpy(temps, "Render: DA2 disabled\n"); +// else if (da2->render == da2_render_blank) strcpy(temps, "Render: DA2 blank\n"); +// else if (da2->render == da2_render_text) strcpy(temps, "Render: DA2 text (mode 8 or E)\n"); +// else if (da2->render == da2_render_textm3) strcpy(temps, "Render: DA2 EGA compatible text (mode 3)\n"); +// else if (da2->render == da2_render_color_4bpp) strcpy(temps, "Render: DA2 4 bpp graphics (mode A or D)\n"); +// else if (da2->render == da2_render_color_8bpp) strcpy(temps, "Render: DA2 8 bpp graphics (mode F)\n"); +// else strcpy(temps, "Render: DA2 unknown render\n"); +// strncat(s, temps, max_len); +// +// sprintf(temps, "Resolution : %i x %i\n", da2->video_res_x, da2->video_res_y); +// strncat(s, temps, max_len); +// +// sprintf(temps, "Refresh rate : %i Hz\n", da2->frames); +// da2->frames = 0; +// strncat(s, temps, max_len); +// +// sprintf(temps, "Render lines : %i\n\n", da2->writelines); +// da2->writelines = 0; +// strncat(s, temps, max_len); +//} + +const device_t ps55da2_device = { + .name = "IBM Display Adapter II (MCA)", + .internal_name = "ps55da2", + .flags = DEVICE_MCA, + .local = 0, + .init = da2_init, + .close = da2_close, + .reset = da2_reset, + { .available = da2_available }, + .speed_changed = da2_speed_changed, + .force_redraw = da2_force_redraw, + .config = NULL +}; + +void +da2_device_add(void) +{ + if (!da2_standalone_enabled) + return; + + if (machine_has_bus(machine, MACHINE_BUS_MCA)) + device_add(&ps55da2_device); + else + return; +} diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 93c1eb669..6d952ddb7 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -431,10 +431,24 @@ svga_in(uint16_t addr, void *priv) ret = svga->attrregs[svga->attraddr]; break; case 0x3c2: - if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) - ret = 0; + if (svga->cable_connected) + { + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) + ret = 0; + else + ret = 0x10; + } else - ret = 0x10; + { + // The Display Adapter has own Monitor Type Detection bit in the different I/O port (I/O 3E0h, 3E1h). + // When the monitor cable is connected to the Display Adapter, this port returns the value as no cable connection. + // The Power-on Self Test of PS/55 tries detecting the monitor on the planar VGA. + // If it fails, then the POST reads the NVRAM set by the reference diskette, and sets the BIOS Data Area (Mem 487h, 489h). + if (svga->vgapal[0].r >= 10 || svga->vgapal[0].g >= 10 || svga->vgapal[0].b >= 10) + ret = 0; + else + ret = 0x10; + } break; case 0x3c3: ret = vga_on; @@ -1359,6 +1373,8 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 32; svga->translate_address = NULL; + + svga->cable_connected = 1; svga->ksc5601_english_font_type = 0; vga_on = 1; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index b6e1bd2f9..cda3f95e0 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -367,6 +367,8 @@ video_post_reset(void) if (xga_standalone_enabled) xga_device_add(); + if (da2_standalone_enabled) + da2_device_add(); /* Reset the graphics card (or do nothing if it was already done by the machine's init function). */ video_reset(gfxcard[0]); diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index 8b2e761a3..699cfe85e 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -103,6 +103,39 @@ vga_in(uint16_t addr, void *priv) return temp; } +void vga_disable(void* p) +{ + vga_t* vga = (vga_t*)p; + svga_t* svga = &vga->svga; + + pclog("vga_disable %04X:%04X\n", cs >> 4, cpu_state.pc); + io_removehandler(0x03a0, 0x0040, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + mem_mapping_disable(&svga->mapping); + svga->vga_enabled = 0; +} + +void vga_enable(void* p) +{ + vga_t* vga = (vga_t*)p; + svga_t* svga = &vga->svga; + + pclog("vga_enable %04X:%04X\n", cs >> 4, cpu_state.pc); + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + if (!(svga->miscout & 1)) + io_sethandler(0x03a0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + mem_mapping_enable(&svga->mapping); + svga->vga_enabled = 1; +} + +int vga_isenabled(void* p) +{ + vga_t* vga = (vga_t*)p; + svga_t* svga = &vga->svga; + + return svga->vga_enabled; +} + static void * vga_init(const device_t *info) { @@ -149,6 +182,7 @@ ps1vga_init(const device_t *info) vga->svga.bpp = 8; vga->svga.miscout = 1; + vga->svga.vga_enabled = 1; return vga; }