diff --git a/src/include/86box/vid_ps55da2.h b/src/include/86box/vid_ps55da2.h index 70007be19..f029b5751 100644 --- a/src/include/86box/vid_ps55da2.h +++ b/src/include/86box/vid_ps55da2.h @@ -1,24 +1,24 @@ -/* - * 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. - */ - -#ifndef VIDEO_DA2_DEVICE_H -#define VIDEO_DA2_DEVICE_H - -#ifdef EMU_DEVICE_H -extern const device_t ps55da2_device; -#endif -#endif /*VIDEO_DA2_DEVICE_H*/ +/* + * 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. + */ + +#ifndef VIDEO_DA2_DEVICE_H +#define VIDEO_DA2_DEVICE_H + +#ifdef EMU_DEVICE_H +extern const device_t ps55da2_device; +#endif +#endif /*VIDEO_DA2_DEVICE_H*/ diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index a19965f6f..0ac136630 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -1,3222 +1,3222 @@ -/* - * 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_JPAN "roms/video/da2/94X1320.BIN" -#define DA2_FONTROM_PATH_HANT "roms/video/da2/23F2698.BIN" -#define DA2_FONTROM_SIZE 1536*1024 -#define DA2_FONTROM_BASESBCS 0x98000 -#define DA2_GAIJIRAM_SBCS 0x34000 -#define DA2_GAIJIRAM_SBEX 0x3c000 -#define DA2_INVALIDACCESS8 0xff -#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 0x100 -#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_DCONFIG_CHARSET_JPAN 0 /* for Code page 932 Japanese */ -//#define DA2_DCONFIG_CHARSET_HANG 1 /* for Code page 934 Hangul */ -//#define DA2_DCONFIG_CHARSET_HANS 2 /* for Code page 936 Simplified Chinese */ -#define DA2_DCONFIG_CHARSET_HANT 3 /* for Code page 938 Traditional Chinese */ -#define DA2_DCONFIG_MONTYPE_COLOR 0x0A -#define DA2_DCONFIG_MONTYPE_8515 0x0B -#define DA2_DCONFIG_MONTYPE_MONO 0x09 - -#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_CPUTCHAR 5 -#define DA2_BLT_CDONE 6 -#define DA2_BLT_CLOAD 7 -/* 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 /* 1 = DA-2, 0 = DA-3 */ -//#define Mon_ID3 0x10 -#define FontCard 0x08 /* ? */ -/* 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 */ - -/* IO 3E0/3E1:0Bh 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 //1 010b IBM 8514, 9518 color 1040x768 -//#define StarbuckM 0x09 //1 001b IBM 8507, 8604 grayscale -//#define Lark_B 0x02 //0 010b IBM 9517 color 1040x768 but 4bpp -//#define Dallas 0x0B //1 011b IBM 8515, 9515 color 1040x740 palette B - -/* 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 - -#ifndef RELEASE_BUILD -#define ENABLE_DA2_LOG 1 -#endif - -#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 attrc[0x40]; - int attraddr, attrff; - int attr_palette_enable; - //uint8_t seqregs[64]; - int outflipflop; - int inflipflop; - int iolatch; - - int ioctladdr; - int fctladdr; - int crtcaddr; - - uint32_t decode_mask; - uint32_t vram_max; - uint32_t vram_mask; - - uint32_t gdcla[8]; - 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; - - 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; - - 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 write_bank, read_bank; - - int fullchange; - - void (*render)(struct da2_t* da2); - - /*If set then another device is driving the monitor output and the SVGA - card should not attempt to display anything */ - int override; - - /* end VGA compatible regs*/ - struct - { - int enable; - mem_mapping_t mapping; - uint8_t ram[256 * 1024]; - uint8_t *font; - int charset; - } mmio; - - 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; - uint8_t monitorid; - - 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); -} -void DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) -{ - pixel32 srcpx; - if (srcaddr >= DA2_FONTROM_SIZE) { - da2_log("DA2 Putchar Addr Error %x\n", srcaddr); - return; - } - for (int i = 0; i < 8; i++) - srcpx.p8[i] = ((uint32_t)da2->mmio.font[srcaddr] << 24) - | ((uint32_t)da2->mmio.font[srcaddr + 1] << 16) - | ((uint32_t)da2->mmio.font[srcaddr + 2] << 8) - | ((uint32_t)da2->mmio.font[srcaddr + 3] << 0);//read in word - - DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); -} -#ifdef ENABLE_DA2_DEBUGBLT -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++) - { - pclog("%X", pixel1tohex(addr, i, da2)); - } -} -void print_bytetobin(uint8_t b) { - for (int i = 0; i < 8; i++) - { - if(b & 0x80) - pclog("1"); - else - pclog("0"); - b <<= 1; - } -} -//Convert internal char code to Shift JIS code -inline int isKanji1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } -inline int isKanji2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } -uint16_t IBMJtoSJIS(uint16_t knj) -{ - if (knj < 0x100) return 0xffff; - knj -= 0x100; - if (knj <= 0x1f7d) - ;/* do nothing */ - else if (knj >= 0xb700 && knj <= 0xb75f) { - knj -= 0x90ec; - } - else if (knj >= 0xb3f0 && knj <= 0xb67f) { - knj -= 0x906c; - } - else if (knj >= 0x8000 && knj <= 0x8183) - { - knj -= 0x5524; - } - else - return 0xffff; - uint32_t knj1 = knj / 0xBC; - uint32_t knj2 = knj - (knj1 * 0xBC); - knj1 += 0x81; - if (knj1 > 0x9F) knj1 += 0x40; - knj2 += 0x40; - if (knj2 > 0x7E) knj2++; - //if (!isKanji1(knj1)) return 0xffff; - //if (!isKanji2(knj2)) return 0xffff; - knj = knj1 << 8; - knj |= knj2; - return knj; -} -#endif -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[0x10] == 0xbc04) { /* Put char used by OS/2 (i'm not sure what the condition is) */ - da2->bitblt.exec = DA2_BLT_CPUTCHAR; - /* Todo: addressing */ - //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; - //} - uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; - uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; - da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + 2; - da2->bitblt.destaddr += 2; - da2->bitblt.srcpitch = 0; - da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ - da2->bitblt.bitshift_destr += 1; - da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); - } - else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { - da2->bitblt.exec = DA2_BLT_CPUTCHAR; - uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; - uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; - da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 64 + 2 + DA2_FONTROM_BASESBCS; - da2->bitblt.destaddr += 2; - da2->bitblt.srcpitch = 0; - da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ - da2->bitblt.bitshift_destr += 1; - da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); - } - 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]); - } - } -} -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.indata = 0; - da2_bitblt_load(da2); - 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_CPUTCHAR: - //da2->bitblt.y += 2; - da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x * 2 + da2->bitblt.y * 130 + 0 + 260; - pclog("scr %x dest %x :", da2->bitblt.srcaddr, da2->bitblt.destaddr); - //da2->bitblt.srcaddr += 2; - if(da2->bitblt.reg[0x12] < 0x100) - da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; - else - da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; - print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 2]); - print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 3]); - pclog("\n"); - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - //if (1) { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 3) - { - da2->bitblt.exec = DA2_BLT_CDONE; - } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr += 130; - //da2->bitblt.destaddr += da2->bitblt.destpitch + 2; - //da2->bitblt.srcaddr += -1; - } - else if (da2->bitblt.x == 0) { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); - da2->bitblt.x++; - //da2->bitblt.x++; - } - else { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); - da2->bitblt.x++; - //da2->bitblt.x++; - } - //da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x + da2->bitblt.y * 130 + 2; - ////da2->bitblt.srcaddr += 2; - //da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2 ) + (da2->bitblt.y * 3) + 2; - break; - case DA2_BLT_CDONE: - /* initialize regs 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_bitblt_dopayload(da2_t* da2) { - if (da2->bitblt.exec == DA2_BLT_CIDLE) - { - da2->bitblt.exec = DA2_BLT_CLOAD; - //timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - /* do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle */ - da2_log("da2 Do bitblt\n"); - while (da2->bitblt.exec != DA2_BLT_CIDLE) - { - da2_bitblt_exec(da2); - } - da2_log("da2 End bitblt %x\n", da2->bitblt.exec); - } -} - -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->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]; - da2->ioctl[da2->ioctladdr] = val; - if (oldval != val) { - if (da2->ioctladdr == LS_RESET && val & 0x01) /* Reset 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; - } - } - 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; - if (da2->fctl[da2->fctladdr & 0x1f] != val) - da2_log("fctl changed %x: %x -> %x %04X:%04X\n", da2->fctladdr & 0x1f, da2->fctl[da2->fctladdr & 0x1f], val, cs >> 4, cpu_state.pc); - 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->attrc[LV_PANNING] != val)) - da2->fullchange = changeframecount; - if (da2->attrc[da2->attraddr & 0x3f] != val) - da2_log("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrc[da2->attraddr & 0x3f], val); - da2->attrc[da2->attraddr & 0x3f] = val; - //da2_log("set attrc %x: %x\n", da2->attraddr & 31, val); - if (da2->attraddr < 16) - da2->fullchange = changeframecount; - if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr < 0x10) - { - for (int c = 0; c < 16; c++) - { - //if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = (da2->attrc[c] & 0xf) | ((da2->attrc[0x14] & 0xf) << 4); - //else da2->egapal[c] = (da2->attrc[c] & 0x3f) | ((da2->attrc[0x14] & 0xc) << 4); - if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = da2->attrc[c] & 0xf; - else da2->egapal[c] = da2->attrc[c] & 0x3f; - } - } - switch (da2->attraddr) - { - case LV_COLOR_PLANE_ENAB: - if ((val & 0xff) != da2->plane_mask) - da2->fullchange = changeframecount; - da2->plane_mask = val & 0xff; - break; - case 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; - } - break; - case LV_MODE_CONTROL: - case LV_ATTRIBUTE_CNTL: - case LV_COMPATIBILITY: - da2_recalctimings(da2); - break; - default: - break; - } - } - da2->attrff ^= 1; - break; - case 0x3E9: - /* VZ Editor's CURSOR.COM writes data via this port */ - da2->attrc[da2->attraddr & 0x3f] = val; - 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; - uint16_t temp; - - 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 DA2_INVALIDACCESS8; - temp = da2->ioctl[da2->ioctladdr]; - if (da2->ioctladdr == LS_STATUS) { /* Status register */ - if (da2->attrc[LV_COMPATIBILITY] & 0x08) { /* for detecting monitor type and cable wiring */ - if (da2->monitorid == DA2_DCONFIG_MONTYPE_MONO) { - /* grayscale monitor */ - if ((da2->vgapal[0].r >= 10) || (da2->vgapal[0].g >= 40) || (da2->vgapal[0].b >= 10)) - temp &= 0x7F; /* Inactive when the RGB output voltage is high (or the cable is not connected to a color monitor). */ - else - temp |= 0x80; /* Active when the RGB output voltage is low and the cable is connected to a color monitor. - If the cable or the monitor is wrong, it becomes inactive. */ - } else { - /* color monitor */ - if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 80) - temp &= 0x7F; - else - temp |= 0x80; - } - } else { - temp |= 0x80; - } - temp &= 0xf6;//clear busy bits - if (da2->bitblt.indata) /* for OS/2 J1.3 */ - da2_bitblt_dopayload(da2); - if (da2->bitblt.exec != DA2_BLT_CIDLE) - { - //da2_log("exec:%x\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 DA2_INVALIDACCESS8; - temp = da2->fctl[da2->fctladdr]; - break; - case LC_INDEX: - temp = da2->crtcaddr; - break; - case LC_DATA: - if (da2->crtcaddr > 0x1f) return DA2_INVALIDACCESS8; - 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->attrc[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, Japanese)] -The Font ROM can be accessed via 128 KB memory window located at A0000-BFFFFh. - - Bank 0 - 4800- * - Bank 1, 2, 3 - * - * - Bank 4 - * -0DB6Fh ( 4800-8DB6Fh) : JIS X 0208 DBCS (24 x 24) (IBMJ code: 100-1F7Dh) - 10000-16D1Fh (90000-96D1Fh) : IBM Extended Characters (IBMJ code: 2ADC-2C5Fh) - 18000-1BFCFh (98000-9BFCFh) : JIS X 0201 SBCS (13 x 30) - 1C000-1FFFFh (9C000-9FFFFh) : Codepage 437 characters (13 x 30) - Bank 5 - 00000-0C68Fh (A0000-AC68Fh) : Gaiji used by DOS Bunsho - 10000-13FFFh (B0000-B3FFFh) : Extended SBCS (13 x 30) - 14000-1477Fh (B4000-B477Fh) : Half-width box drawing characters used by DOS Bunsho - 16000-17FFFh (B6000-B7FFFh) : Codepage 850 characters (13 x 30) - 18000-1A3FFh (B8000-BA3FFh) : CAD control icons and box drawing characters (32 x 32) - - Some models have the signature 80h, 01h placed at Bank 0:1AFFEh. (it disables hardware text drawing in OS/2 J1.3) - -[Font ROM Map (DA3, Traditional Chinese)] - Bank 0 - 11 : Valid Font ROM data - Bank 12 : Alias of bank 11 (At least, DOS T5.0 uses this on purpose.) - Bank 13 : All addresses return 0xFF - -[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->attrc[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->attrc[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 - // 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 = DA2_GAIJIRAM_SBEX; - else - fontbase = DA2_GAIJIRAM_SBCS; - 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->attrc[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->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];//vertical line (white) - } - if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) {//HGrid - for (uint32_t n = 0; n < 13; n++) - p[n] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[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->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2;//Choose color 2 if mode 8 - fg = (da2->attrc[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 = DA2_GAIJIRAM_SBCS; - 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->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;//Choose color 2 if mode 8 - //fg = (da2->attrc[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]]; - } - 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->attrc[LV_MODE_CONTROL] & 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->attrc[0x1f] & 0x08)) - if (da2->attrc[LV_COMPATIBILITY] & 0x08) - { - if (!(da2->ioctl[LS_MODE] & 0x01)) {//16 color graphics mode - da2->hdisp *= 16; - da2->char_width = 13; - da2->hdisp_old = da2->hdisp; - if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) { - 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->attrc[LV_ATTRIBUTE_CNTL] & 1) { - 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); - - //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 - if (da2->mmio.charset == DA2_DCONFIG_CHARSET_HANT) { - if (addr >= 0x1a0000) return DA2_INVALIDACCESS8; - if (addr >= 0x180000) addr -= 0x40000; /* The bank 12 (180000h-19ffffh) is beyond the available ROM address range, - but the Chinese font sub card actually has this alias, and is used by DOS T5.0. */ - } - if (addr >= DA2_FONTROM_SIZE) return DA2_INVALIDACCESS8; - //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]); - return da2->mmio.font[addr]; - break; - default: - return DA2_INVALIDACCESS8;//invalid memory access - break; - } - } - else if (!(da2->ioctl[LS_MODE] & 1))//8 or 256 color mode - { - cycles -= video_timing_read_b; - for (int i = 0; i < 8; i++) - da2->gdcla[i] = da2->vram[(addr << 3) | i];//read in byte - //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 - -#ifdef ENABLE_DA2_DEBUGBLT - ////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; -#endif - - 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.indata = 1; - if(da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) - da2_log("da2_mmio_write payload overflow! mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); - 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); -#ifdef ENABLE_DA2_DEBUGBLT - //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; - //} -#endif - - cycles -= video_timing_write_b; - - da2->changedvram[addr >> 12] = changeframecount; - addr <<= 3; - - for (int i = 0; i < 8; i++) - da2->gdcsrc[i] = da2->gdcla[i];//use latch - - //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: - 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 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]; -#ifdef ENABLE_DA2_DEBUGBLT - //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; - //} -#endif - 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; - - for (int i = 0; i < 8; i++) - da2->gdcsrc[i] = da2->gdcla[i];//use latch - - 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) - { - case 2: - 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 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; - 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 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 DA2_INVALIDACCESS8; - 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(); - } - - 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_CURSOR_ROW_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->vc++; - da2->vc &= 2047; - - if (da2->vc == da2->dispend) - { - 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->attrc[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--; - } - } - 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); - - 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; - - // 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->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->attrc[LV_PANNING] & 7; - } - if (da2->sc == (da2->crtc[LC_CURSOR_ROW_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 | Page_Two; /* Configuration 1 : DA-II, 1024 KB */ - da2->ioctl[LS_CONFIG1] |= ((da2->monitorid & 0x8 ) << 1); /* Configuration 1 : Monitor ID 3 */ - da2->ioctl[LS_CONFIG2] = (da2->monitorid & 0x7); /* Configuration 2: Monitor ID 0-2 */ - da2->fctl[0] = 0x2b; /* 3E3h:0 */ - da2->fctl[LF_MMIO_MODE] = 0xb0; /* 3E3h:0bh */ - da2->attrc[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->interlace = 0; - da2->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ - da2->attr_palette_enable = 0; /* disable attribute generator */ - - /* Set default color palette (Windows 3.1 display driver 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->cram = malloc(0x1000); - da2->vram_display_mask = DA2_MASK_CRAM; - da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h - da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ - - da2->mmio.charset = device_get_config_int("charset"); - da2->mmio.font= malloc(DA2_FONTROM_SIZE); - switch(da2->mmio.charset) - { - case DA2_DCONFIG_CHARSET_HANT: - da2_loadfont(DA2_FONTROM_PATH_HANT, da2); - break; - case DA2_DCONFIG_CHARSET_JPAN: - da2_loadfont(DA2_FONTROM_PATH_JPAN, da2); - break; - } - - 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_HANT) || rom_present(DA2_FONTROM_PATH_JPAN)); -} - -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->attrc, 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->attrc[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); - } -#endif -#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 - free(da2->cram); - free(da2->vram); - free(da2->changedvram); - free(da2->mmio.font); - 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; -} - -static const device_config_t da2_configuration[] = { - // clang-format off - { - .name = "charset", - .description = "Charset", - .type = CONFIG_SELECTION, - .default_int = DA2_DCONFIG_CHARSET_JPAN, - .selection = { - { - .description = "932 (Japanese)", - .value = DA2_DCONFIG_CHARSET_JPAN - }, - { - .description = "938 (Traditional Chinese)", - .value = DA2_DCONFIG_CHARSET_HANT - }, - { .description = "" } - } - }, - { - .name = "montype", - .description = "Monitor type", - .type = CONFIG_SELECTION, - .default_int = DA2_DCONFIG_MONTYPE_COLOR, - .selection = { - { - .description = "Color", - .value = DA2_DCONFIG_MONTYPE_COLOR - }, - { - .description = "IBM 8515", - .value = DA2_DCONFIG_MONTYPE_8515 - }, - { - .description = "Grayscale", - .value = DA2_DCONFIG_MONTYPE_MONO - }, - { .description = "" } - } - }, - { .name = "", .description = "", .type = CONFIG_END } - // clang-format on -}; - -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 = da2_configuration -}; - -void -da2_device_add(void) -{ - if (!da2_standalone_enabled) - return; - - if (machine_has_bus(machine, MACHINE_BUS_MCA)) - device_add(&ps55da2_device); - else - return; -} +/* + * 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_JPAN "roms/video/da2/94X1320.BIN" +#define DA2_FONTROM_PATH_HANT "roms/video/da2/23F2698.BIN" +#define DA2_FONTROM_SIZE 1536*1024 +#define DA2_FONTROM_BASESBCS 0x98000 +#define DA2_GAIJIRAM_SBCS 0x34000 +#define DA2_GAIJIRAM_SBEX 0x3c000 +#define DA2_INVALIDACCESS8 0xff +#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 0x100 +#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_DCONFIG_CHARSET_JPAN 0 /* for Code page 932 Japanese */ +//#define DA2_DCONFIG_CHARSET_HANG 1 /* for Code page 934 Hangul */ +//#define DA2_DCONFIG_CHARSET_HANS 2 /* for Code page 936 Simplified Chinese */ +#define DA2_DCONFIG_CHARSET_HANT 3 /* for Code page 938 Traditional Chinese */ +#define DA2_DCONFIG_MONTYPE_COLOR 0x0A +#define DA2_DCONFIG_MONTYPE_8515 0x0B +#define DA2_DCONFIG_MONTYPE_MONO 0x09 + +#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_CPUTCHAR 5 +#define DA2_BLT_CDONE 6 +#define DA2_BLT_CLOAD 7 +/* 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 /* 1 = DA-2, 0 = DA-3 */ +//#define Mon_ID3 0x10 +#define FontCard 0x08 /* ? */ +/* 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 */ + +/* IO 3E0/3E1:0Bh 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 //1 010b IBM 8514, 9518 color 1040x768 +//#define StarbuckM 0x09 //1 001b IBM 8507, 8604 grayscale +//#define Lark_B 0x02 //0 010b IBM 9517 color 1040x768 but 4bpp +//#define Dallas 0x0B //1 011b IBM 8515, 9515 color 1040x740 palette B + +/* 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 + +#ifndef RELEASE_BUILD +#define ENABLE_DA2_LOG 1 +#endif + +#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 attrc[0x40]; + int attraddr, attrff; + int attr_palette_enable; + //uint8_t seqregs[64]; + int outflipflop; + int inflipflop; + int iolatch; + + int ioctladdr; + int fctladdr; + int crtcaddr; + + uint32_t decode_mask; + uint32_t vram_max; + uint32_t vram_mask; + + uint32_t gdcla[8]; + 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; + + 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; + + 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 write_bank, read_bank; + + int fullchange; + + void (*render)(struct da2_t* da2); + + /*If set then another device is driving the monitor output and the SVGA + card should not attempt to display anything */ + int override; + + /* end VGA compatible regs*/ + struct + { + int enable; + mem_mapping_t mapping; + uint8_t ram[256 * 1024]; + uint8_t *font; + int charset; + } mmio; + + 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; + uint8_t monitorid; + + 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); +} +void DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) +{ + pixel32 srcpx; + if (srcaddr >= DA2_FONTROM_SIZE) { + da2_log("DA2 Putchar Addr Error %x\n", srcaddr); + return; + } + for (int i = 0; i < 8; i++) + srcpx.p8[i] = ((uint32_t)da2->mmio.font[srcaddr] << 24) + | ((uint32_t)da2->mmio.font[srcaddr + 1] << 16) + | ((uint32_t)da2->mmio.font[srcaddr + 2] << 8) + | ((uint32_t)da2->mmio.font[srcaddr + 3] << 0);//read in word + + DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); +} +#ifdef ENABLE_DA2_DEBUGBLT +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++) + { + pclog("%X", pixel1tohex(addr, i, da2)); + } +} +void print_bytetobin(uint8_t b) { + for (int i = 0; i < 8; i++) + { + if(b & 0x80) + pclog("1"); + else + pclog("0"); + b <<= 1; + } +} +//Convert internal char code to Shift JIS code +inline int isKanji1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } +inline int isKanji2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } +uint16_t IBMJtoSJIS(uint16_t knj) +{ + if (knj < 0x100) return 0xffff; + knj -= 0x100; + if (knj <= 0x1f7d) + ;/* do nothing */ + else if (knj >= 0xb700 && knj <= 0xb75f) { + knj -= 0x90ec; + } + else if (knj >= 0xb3f0 && knj <= 0xb67f) { + knj -= 0x906c; + } + else if (knj >= 0x8000 && knj <= 0x8183) + { + knj -= 0x5524; + } + else + return 0xffff; + uint32_t knj1 = knj / 0xBC; + uint32_t knj2 = knj - (knj1 * 0xBC); + knj1 += 0x81; + if (knj1 > 0x9F) knj1 += 0x40; + knj2 += 0x40; + if (knj2 > 0x7E) knj2++; + //if (!isKanji1(knj1)) return 0xffff; + //if (!isKanji2(knj2)) return 0xffff; + knj = knj1 << 8; + knj |= knj2; + return knj; +} +#endif +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[0x10] == 0xbc04) { /* Put char used by OS/2 (i'm not sure what the condition is) */ + da2->bitblt.exec = DA2_BLT_CPUTCHAR; + /* Todo: addressing */ + //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; + //} + uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; + uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; + da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + 2; + da2->bitblt.destaddr += 2; + da2->bitblt.srcpitch = 0; + da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ + da2->bitblt.bitshift_destr += 1; + da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); + } + else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { + da2->bitblt.exec = DA2_BLT_CPUTCHAR; + uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; + uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; + da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 64 + 2 + DA2_FONTROM_BASESBCS; + da2->bitblt.destaddr += 2; + da2->bitblt.srcpitch = 0; + da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ + da2->bitblt.bitshift_destr += 1; + da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); + } + 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]); + } + } +} +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.indata = 0; + da2_bitblt_load(da2); + 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_CPUTCHAR: + //da2->bitblt.y += 2; + da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x * 2 + da2->bitblt.y * 130 + 0 + 260; + pclog("scr %x dest %x :", da2->bitblt.srcaddr, da2->bitblt.destaddr); + //da2->bitblt.srcaddr += 2; + if(da2->bitblt.reg[0x12] < 0x100) + da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; + else + da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; + print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 2]); + print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 3]); + pclog("\n"); + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + //if (1) { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 3) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += 130; + //da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + //da2->bitblt.srcaddr += -1; + } + else if (da2->bitblt.x == 0) { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + //da2->bitblt.x++; + } + else { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + //da2->bitblt.x++; + } + //da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x + da2->bitblt.y * 130 + 2; + ////da2->bitblt.srcaddr += 2; + //da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2 ) + (da2->bitblt.y * 3) + 2; + break; + case DA2_BLT_CDONE: + /* initialize regs 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_bitblt_dopayload(da2_t* da2) { + if (da2->bitblt.exec == DA2_BLT_CIDLE) + { + da2->bitblt.exec = DA2_BLT_CLOAD; + //timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + /* do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle */ + da2_log("da2 Do bitblt\n"); + while (da2->bitblt.exec != DA2_BLT_CIDLE) + { + da2_bitblt_exec(da2); + } + da2_log("da2 End bitblt %x\n", da2->bitblt.exec); + } +} + +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->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]; + da2->ioctl[da2->ioctladdr] = val; + if (oldval != val) { + if (da2->ioctladdr == LS_RESET && val & 0x01) /* Reset 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; + } + } + 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; + if (da2->fctl[da2->fctladdr & 0x1f] != val) + da2_log("fctl changed %x: %x -> %x %04X:%04X\n", da2->fctladdr & 0x1f, da2->fctl[da2->fctladdr & 0x1f], val, cs >> 4, cpu_state.pc); + 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->attrc[LV_PANNING] != val)) + da2->fullchange = changeframecount; + if (da2->attrc[da2->attraddr & 0x3f] != val) + da2_log("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrc[da2->attraddr & 0x3f], val); + da2->attrc[da2->attraddr & 0x3f] = val; + //da2_log("set attrc %x: %x\n", da2->attraddr & 31, val); + if (da2->attraddr < 16) + da2->fullchange = changeframecount; + if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr < 0x10) + { + for (int c = 0; c < 16; c++) + { + //if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = (da2->attrc[c] & 0xf) | ((da2->attrc[0x14] & 0xf) << 4); + //else da2->egapal[c] = (da2->attrc[c] & 0x3f) | ((da2->attrc[0x14] & 0xc) << 4); + if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = da2->attrc[c] & 0xf; + else da2->egapal[c] = da2->attrc[c] & 0x3f; + } + } + switch (da2->attraddr) + { + case LV_COLOR_PLANE_ENAB: + if ((val & 0xff) != da2->plane_mask) + da2->fullchange = changeframecount; + da2->plane_mask = val & 0xff; + break; + case 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; + } + break; + case LV_MODE_CONTROL: + case LV_ATTRIBUTE_CNTL: + case LV_COMPATIBILITY: + da2_recalctimings(da2); + break; + default: + break; + } + } + da2->attrff ^= 1; + break; + case 0x3E9: + /* VZ Editor's CURSOR.COM writes data via this port */ + da2->attrc[da2->attraddr & 0x3f] = val; + 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; + uint16_t temp; + + 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 DA2_INVALIDACCESS8; + temp = da2->ioctl[da2->ioctladdr]; + if (da2->ioctladdr == LS_STATUS) { /* Status register */ + if (da2->attrc[LV_COMPATIBILITY] & 0x08) { /* for detecting monitor type and cable wiring */ + if (da2->monitorid == DA2_DCONFIG_MONTYPE_MONO) { + /* grayscale monitor */ + if ((da2->vgapal[0].r >= 10) || (da2->vgapal[0].g >= 40) || (da2->vgapal[0].b >= 10)) + temp &= 0x7F; /* Inactive when the RGB output voltage is high (or the cable is not connected to a color monitor). */ + else + temp |= 0x80; /* Active when the RGB output voltage is low and the cable is connected to a color monitor. + If the cable or the monitor is wrong, it becomes inactive. */ + } else { + /* color monitor */ + if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 80) + temp &= 0x7F; + else + temp |= 0x80; + } + } else { + temp |= 0x80; + } + temp &= 0xf6;//clear busy bits + if (da2->bitblt.indata) /* for OS/2 J1.3 */ + da2_bitblt_dopayload(da2); + if (da2->bitblt.exec != DA2_BLT_CIDLE) + { + //da2_log("exec:%x\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 DA2_INVALIDACCESS8; + temp = da2->fctl[da2->fctladdr]; + break; + case LC_INDEX: + temp = da2->crtcaddr; + break; + case LC_DATA: + if (da2->crtcaddr > 0x1f) return DA2_INVALIDACCESS8; + 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->attrc[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, Japanese)] +The Font ROM can be accessed via 128 KB memory window located at A0000-BFFFFh. + + Bank 0 + 4800- * + Bank 1, 2, 3 + * - * + Bank 4 + * -0DB6Fh ( 4800-8DB6Fh) : JIS X 0208 DBCS (24 x 24) (IBMJ code: 100-1F7Dh) + 10000-16D1Fh (90000-96D1Fh) : IBM Extended Characters (IBMJ code: 2ADC-2C5Fh) + 18000-1BFCFh (98000-9BFCFh) : JIS X 0201 SBCS (13 x 30) + 1C000-1FFFFh (9C000-9FFFFh) : Codepage 437 characters (13 x 30) + Bank 5 + 00000-0C68Fh (A0000-AC68Fh) : Gaiji used by DOS Bunsho + 10000-13FFFh (B0000-B3FFFh) : Extended SBCS (13 x 30) + 14000-1477Fh (B4000-B477Fh) : Half-width box drawing characters used by DOS Bunsho + 16000-17FFFh (B6000-B7FFFh) : Codepage 850 characters (13 x 30) + 18000-1A3FFh (B8000-BA3FFh) : CAD control icons and box drawing characters (32 x 32) + + Some models have the signature 80h, 01h placed at Bank 0:1AFFEh. (it disables hardware text drawing in OS/2 J1.3) + +[Font ROM Map (DA3, Traditional Chinese)] + Bank 0 - 11 : Valid Font ROM data + Bank 12 : Alias of bank 11 (At least, DOS T5.0 uses this on purpose.) + Bank 13 : All addresses return 0xFF + +[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->attrc[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->attrc[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 + // 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 = DA2_GAIJIRAM_SBEX; + else + fontbase = DA2_GAIJIRAM_SBCS; + 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->attrc[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->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];//vertical line (white) + } + if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) {//HGrid + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[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->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2;//Choose color 2 if mode 8 + fg = (da2->attrc[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 = DA2_GAIJIRAM_SBCS; + 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->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;//Choose color 2 if mode 8 + //fg = (da2->attrc[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]]; + } + 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->attrc[LV_MODE_CONTROL] & 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->attrc[0x1f] & 0x08)) + if (da2->attrc[LV_COMPATIBILITY] & 0x08) + { + if (!(da2->ioctl[LS_MODE] & 0x01)) {//16 color graphics mode + da2->hdisp *= 16; + da2->char_width = 13; + da2->hdisp_old = da2->hdisp; + if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) { + 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->attrc[LV_ATTRIBUTE_CNTL] & 1) { + 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); + + //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 + if (da2->mmio.charset == DA2_DCONFIG_CHARSET_HANT) { + if (addr >= 0x1a0000) return DA2_INVALIDACCESS8; + if (addr >= 0x180000) addr -= 0x40000; /* The bank 12 (180000h-19ffffh) is beyond the available ROM address range, + but the Chinese font sub card actually has this alias, and is used by DOS T5.0. */ + } + if (addr >= DA2_FONTROM_SIZE) return DA2_INVALIDACCESS8; + //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]); + return da2->mmio.font[addr]; + break; + default: + return DA2_INVALIDACCESS8;//invalid memory access + break; + } + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 or 256 color mode + { + cycles -= video_timing_read_b; + for (int i = 0; i < 8; i++) + da2->gdcla[i] = da2->vram[(addr << 3) | i];//read in byte + //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 + +#ifdef ENABLE_DA2_DEBUGBLT + ////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; +#endif + + 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.indata = 1; + if(da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) + da2_log("da2_mmio_write payload overflow! mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + 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); +#ifdef ENABLE_DA2_DEBUGBLT + //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; + //} +#endif + + cycles -= video_timing_write_b; + + da2->changedvram[addr >> 12] = changeframecount; + addr <<= 3; + + for (int i = 0; i < 8; i++) + da2->gdcsrc[i] = da2->gdcla[i];//use latch + + //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: + 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 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]; +#ifdef ENABLE_DA2_DEBUGBLT + //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; + //} +#endif + 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; + + for (int i = 0; i < 8; i++) + da2->gdcsrc[i] = da2->gdcla[i];//use latch + + 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) + { + case 2: + 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 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; + 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 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 DA2_INVALIDACCESS8; + 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(); + } + + 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_CURSOR_ROW_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->vc++; + da2->vc &= 2047; + + if (da2->vc == da2->dispend) + { + 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->attrc[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--; + } + } + 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); + + 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; + + // 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->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->attrc[LV_PANNING] & 7; + } + if (da2->sc == (da2->crtc[LC_CURSOR_ROW_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 | Page_Two; /* Configuration 1 : DA-II, 1024 KB */ + da2->ioctl[LS_CONFIG1] |= ((da2->monitorid & 0x8 ) << 1); /* Configuration 1 : Monitor ID 3 */ + da2->ioctl[LS_CONFIG2] = (da2->monitorid & 0x7); /* Configuration 2: Monitor ID 0-2 */ + da2->fctl[0] = 0x2b; /* 3E3h:0 */ + da2->fctl[LF_MMIO_MODE] = 0xb0; /* 3E3h:0bh */ + da2->attrc[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->interlace = 0; + da2->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ + da2->attr_palette_enable = 0; /* disable attribute generator */ + + /* Set default color palette (Windows 3.1 display driver 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->cram = malloc(0x1000); + da2->vram_display_mask = DA2_MASK_CRAM; + da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h + da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ + + da2->mmio.charset = device_get_config_int("charset"); + da2->mmio.font= malloc(DA2_FONTROM_SIZE); + switch(da2->mmio.charset) + { + case DA2_DCONFIG_CHARSET_HANT: + da2_loadfont(DA2_FONTROM_PATH_HANT, da2); + break; + case DA2_DCONFIG_CHARSET_JPAN: + da2_loadfont(DA2_FONTROM_PATH_JPAN, da2); + break; + } + + 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_HANT) || rom_present(DA2_FONTROM_PATH_JPAN)); +} + +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->attrc, 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->attrc[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); + } +#endif +#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 + free(da2->cram); + free(da2->vram); + free(da2->changedvram); + free(da2->mmio.font); + 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; +} + +static const device_config_t da2_configuration[] = { + // clang-format off + { + .name = "charset", + .description = "Charset", + .type = CONFIG_SELECTION, + .default_int = DA2_DCONFIG_CHARSET_JPAN, + .selection = { + { + .description = "932 (Japanese)", + .value = DA2_DCONFIG_CHARSET_JPAN + }, + { + .description = "938 (Traditional Chinese)", + .value = DA2_DCONFIG_CHARSET_HANT + }, + { .description = "" } + } + }, + { + .name = "montype", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .default_int = DA2_DCONFIG_MONTYPE_COLOR, + .selection = { + { + .description = "Color", + .value = DA2_DCONFIG_MONTYPE_COLOR + }, + { + .description = "IBM 8515", + .value = DA2_DCONFIG_MONTYPE_8515 + }, + { + .description = "Grayscale", + .value = DA2_DCONFIG_MONTYPE_MONO + }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +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 = da2_configuration +}; + +void +da2_device_add(void) +{ + if (!da2_standalone_enabled) + return; + + if (machine_has_bus(machine, MACHINE_BUS_MCA)) + device_add(&ps55da2_device); + else + return; +}