/* * 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 (and its successors) emulation. * * Notes: There are some known issues that should be corrected. * - Incorrect foreground text color appears on an active window in OS/2 J1.3. * - BitBlt's text drawing function does not work correctly. * - The screen resolution and blanking interval time maybe not correct. * * The code should be tested with following cases. * - Execute MODE 0, 1, 3 and 4 commands in DOS K3.3 to test various video modes. * - Run SAMPLE program with the BASIC interpreter in DOS K3.3. * - Run DOS J4.0 install program to test video mode 03. * - Run Win 3.1 (IBM-J OEM) and OS/2 J1.3 with 16 and 256 color driver to test BilBlt operations. * * Authors: Akamaki. * * Copyright 2024-2025 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_VM03_BASECHR 0x18000 #define DA2_VM03_BASEEXATTR 0x10000 #define DA2_INVALIDACCESS8 0xff #define DA2_MASK_MMIO 0x1ffff #define DA2_SIZE_VRAM 1024 * 1024 /* 0x100000 */ #define DA2_SIZE_CRAM 4 * 1024 /* 0x1000 */ #define DA2_SIZE_GAIJIRAM 256 * 1024 /* 0x40000 */ #define DA2_MASK_A000 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 */ /* These ROMs are currently not found. At least, IBM-J released a Korean and PRC version of PS/55 for each market. */ #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_CLINE 6 #define DA2_BLT_CDONE 7 #define DA2_BLT_CLOAD 8 /* 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 | J4.08 | 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 /* ? */ #define Page_One 0x06 /* 80000h 110b */ #define Page_Two 0x05 /* 100000h 101b */ #define Page_Four 0x03 /* 200000h 011b */ /* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode unsupported). */ /* 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 another palette */ /* 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 # define ENABLE_DA2_DEBUGBLT 1 // # define ENABLE_DA2_DEBUGVRAM 1 // # define ENABLE_DA2_DEBUGFULLSCREEN 1 // # define ENABLE_DA2_DEBUGMONWAIT 1 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 #ifdef ENABLE_DA2_DEBUGBLT # define da2_bltlog da2_log #else # define da2_bltlog(fmt, ...) #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[DA2_SIZE_GAIJIRAM]; uint8_t *font; int charset; } mmio; struct { int bitshift_destr; int raster_op; uint8_t payload[DA2_BLT_MEMSIZE]; int payload_addr; int32_t reg[DA2_BLT_REGSIZE]; // must be signed int #ifdef ENABLE_DA2_DEBUGBLT int32_t *debug_reg; // for debug int debug_reg_ip; // for debug int debug_exesteps; #endif 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; int32_t dest_x; int32_t dest_y; int16_t destpitch; int16_t srcpitch; int32_t fcolor; int32_t maskl, maskr; int32_t count; int32_t d; int octdir; int x, y; } bitblt; #ifdef ENABLE_DA2_DEBUGVRAM FILE *mmdbg_fp; FILE *mmrdbg_fp; uint32_t mmdbg_vidaddr; uint32_t mmrdbg_vidaddr; #endif 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_vram_r(uint32_t addr, da2_t *da2) { if (addr & ~da2->vram_mask) return -1; return da2->vram[addr]; } /* safety write for internal functions */ void DA2_vram_w(uint32_t addr, uint8_t val, da2_t *da2) { da2->vram[addr & da2->vram_mask] = val; return; } /* write pixel data with rop (Note: bitmask must be in big endian) */ 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_vram_r((destaddr + 24) | i, da2) | (DA2_vram_r((destaddr + 16) | i, da2) << 8) | (DA2_vram_r((destaddr + 8) | i, da2) << 16) | (DA2_vram_r((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; if (da2->bitblt.raster_op & 0x2010) /* NOT Src or NOT Pattern */ srcpx->p8[i] = ~srcpx->p8[i] & mask32.d; if (da2->bitblt.raster_op & 0x20) /* Dest NOT */ writepx[i] = (~writepx[i] & mask32.d) | (writepx[i] & ~mask32.d); switch (da2->bitblt.raster_op & 0x03) { 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_w(destaddr | i, (writepx[i] >> 24) & 0xff, da2); DA2_vram_w((destaddr + 8) | i, (writepx[i] >> 16) & 0xff, da2); } } 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(1000h or 1100h) + Command?(40 or 48) 08 Mask Left 09 Mask Right 0A Plane Mask? 0B ROP 2000 NOT Source 200 Source / Pattern 20 NOT Dest 10 NOT Pattern 8 ? 0-3 Bit op (0 None, 1 AND, 2 OR, 3 XOR) 0D 20 Exec (1) or Exec without reset regs? (21h) 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_vram_r((srcaddr + 24) | i, da2) | (DA2_vram_r((srcaddr + 16) | i, da2) << 8) | (DA2_vram_r((srcaddr + 8) | i, da2) << 16) | (DA2_vram_r((srcaddr + 0) | i, da2) << 24); 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); 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_r(((addr << 3) | j) & (1 << (7 - index)), da2)) 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; #ifdef ENABLE_DA2_DEBUGBLT da2_log("bltload: 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]); } #endif int i = 0; while (i < da2->bitblt.payload_addr) { 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_bltlog("[%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_bltlog("[%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_bltlog("[%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]); da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; i += 7; break; case 0x00: break; default: da2_log("bltload: 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++) { 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_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip) >= DA2_DEBUG_BLTLOG_MAX) da2->bitblt.debug_reg_ip = 0; da2->bitblt.debug_exesteps = 0; #endif da2_log("bltload_exec: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f); /* set bit shift */ da2->bitblt.raster_op = da2->bitblt.reg[0x0b]; 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; /* Put DBCS char used by OS/2 (i'm not sure what the condition is) */ if (da2->bitblt.reg[0x10] == 0xbc04) { 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; // } da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + 2; da2->bitblt.destaddr += 2; da2->bitblt.srcpitch = 0; da2->bitblt.bitshift_destr += 1; #ifdef ENABLE_DA2_DEBUGBLT uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; 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); #endif } /* Put SBCS char used by OS/2 */ else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { da2->bitblt.exec = DA2_BLT_CPUTCHAR; da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 64 + 2 + DA2_FONTROM_BASESBCS; da2->bitblt.destaddr += 2; da2->bitblt.srcpitch = 0; da2->bitblt.bitshift_destr += 1; #ifdef ENABLE_DA2_DEBUGBLT uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; 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); #endif } /* Draw a line */ else if (da2->bitblt.reg[0x5] == 0x43) { da2->bitblt.exec = DA2_BLT_CLINE; da2->bitblt.dest_x = (da2->bitblt.reg[0x32] & 0x7ff); da2->bitblt.dest_y = (da2->bitblt.reg[0x34] & 0x7ff); da2->bitblt.size_x = abs((da2->bitblt.reg[0x33] & 0x7ff) - (da2->bitblt.reg[0x32] & 0x7ff)); da2->bitblt.size_y = abs((da2->bitblt.reg[0x35] & 0x7ff) - (da2->bitblt.reg[0x34] & 0x7ff)); da2->bitblt.count = 0; da2->bitblt.octdir = da2->bitblt.reg[0x2D]; da2->bitblt.bitshift_destr = 0; if (da2->bitblt.octdir & 0x04) /* dX > dY */ da2->bitblt.d = 2 * da2->bitblt.size_y - da2->bitblt.size_x; else da2->bitblt.d = 2 * da2->bitblt.size_x - da2->bitblt.size_y; da2_log("drawline x=%d, y=%d, dx=%d, dy=%d, oct=%d\n", da2->bitblt.dest_x, da2->bitblt.dest_y, da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.octdir); } /* Fill a rectangle (or draw a horizontal / vertical line) */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) { 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; } /* Tiling a rectangle ??(transfer tile data multiple times) os/2 only */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x0040 && da2->bitblt.reg[0x3D] == 0x40) { 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); } /* Tiling a rectangle (transfer tile data multiple times) */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) { 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); } /* Block copy */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) { 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); } /* Block copy but reversed direction */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) { 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); #ifdef ENABLE_DA2_DEBUGBLT if(!(da2->bitblt.debug_exesteps & 0xf)) da2_log("bitblt_exec: %d %d\n", da2->bitblt.exec, da2->bitblt.debug_exesteps); da2->bitblt.debug_exesteps++; #endif switch (da2->bitblt.exec) { case DA2_BLT_CIDLE: // timer_disable(&da2->bitblt.timer); break; case DA2_BLT_CLOAD: da2_bitblt_load(da2); da2->bitblt.indata = 0; break; case DA2_BLT_CLINE: int pos_x = da2->bitblt.dest_x + da2->bitblt.x; int pos_y = da2->bitblt.dest_y + da2->bitblt.y; /* Draw a dot */ // outb(0x680, da2->bitblt.octdir); da2_bltlog("point: %d %d %d %d %d\n", pos_x, pos_y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); int destaddr = pos_y * (da2->rowoffset * 2) + pos_x / 8; int pixelmask = pos_x % 16; if (pixelmask >= 8) pixelmask = (0x8000 >> (pixelmask - 8)); else pixelmask = (0x80 >> pixelmask); DA2_DrawColorWithBitmask(destaddr, da2->bitblt.fcolor, pixelmask, da2); // da2_log("draw: %x %x %x\n", destaddr, da2->bitblt.fcolor, pixelmask); da2->bitblt.count++; /* Bresenham's line */ if (da2->bitblt.octdir & 0x04) { /* dX > dY */ if (da2->bitblt.octdir & 0x02) { da2->bitblt.x++; } else { da2->bitblt.x--; } if (da2->bitblt.d >= 0) { da2->bitblt.d -= (2 * da2->bitblt.size_x); if (da2->bitblt.octdir & 0x01) { da2->bitblt.y++; } else { da2->bitblt.y--; } } da2->bitblt.d += (2 * da2->bitblt.size_y); if (da2->bitblt.count >= da2->bitblt.size_x) da2->bitblt.exec = DA2_BLT_CDONE; } else { if (da2->bitblt.octdir & 0x01) { da2->bitblt.y++; } else { da2->bitblt.y--; } if (da2->bitblt.d >= 0) { da2->bitblt.d -= (2 * da2->bitblt.size_y); if (da2->bitblt.octdir & 0x02) { da2->bitblt.x++; } else { da2->bitblt.x--; } } da2->bitblt.d += (2 * da2->bitblt.size_x); if (da2->bitblt.count >= da2->bitblt.size_y) da2->bitblt.exec = DA2_BLT_CDONE; } 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: /* used in OS/2 J1.3 wo ROM patch. TODO: still not work */ // 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: if (!(da2->bitblt.reg[0x20] & 0x20)) { /* initialize regs and set magic value 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; } } else /* without init regs */ da2->bitblt.reg[0x20] = 0; /* need to stop execution */ if (da2->bitblt.indata) da2->bitblt.exec = DA2_BLT_CLOAD; else da2->bitblt.exec = DA2_BLT_CIDLE; break; } } void da2_bitblt_dopayload(void *priv) { da2_t *da2 = (da2_t *) priv; timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); if (da2->bitblt.exec != DA2_BLT_CIDLE) da2_bitblt_exec(da2); else if (da2->bitblt.indata && !(da2->ioctl[LS_MMIO] & 0x10) && (da2->bitblt.exec == DA2_BLT_CIDLE)) { da2->bitblt.exec = DA2_BLT_CLOAD; da2_bitblt_exec(da2); } else { // timer_disable(&da2->bitblt.timer); } } 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); } } 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)) /* 16 or 256 color graphics mode */ 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 */ #ifdef ENABLE_DA2_DEBUGFULLSCREEN val = 0x400; /* for debugging bitblt in Win 3.x */ #endif 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 & 0x0f] = 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 = 0xff; 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 bit */ // 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 |= 0x01; /* wait (bit 3 + bit 0) ? need verify */ // 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 |= 0x08; #ifdef ENABLE_DA2_DEBUGMONWAIT da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr, temp, cs >> 4, cpu_state.pc); #endif } 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 maybe equivalent to 3ba / 3da ISR1 */ { if (da2->cgastat & 0x01) da2->cgastat &= ~0x30; else da2->cgastat ^= 0x30; /* toggle */ 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 AC_REG: /* no register is revealed */ da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); da2->reg3ee[val & 0x0f] = 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 used by 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 Bitblt 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 to obtain the SBCS font.) Bank 13 : Filled by 0xFFh [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_MASK_CRAM]; attr = da2->cram[((da2->ma) + 1) & DA2_MASK_CRAM]; // 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_r(DA2_VM03_BASECHR + (da2->ma), da2); attr = DA2_vram_r(DA2_VM03_BASECHR + (da2->ma) + 1, da2); extattr = DA2_vram_r(DA2_VM03_BASEEXATTR + (da2->ma) + 1, da2); // if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (DA2_VM03_BASECHR + 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 */ /* BCS 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_r(DA2_VM03_BASECHR + (da2->ma) + 2, da2); 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) */ uint16_t font = da2->mmio.ram[DA2_GAIJIRAM_SBCS + chr * 0x40 + da2->sc * 2]; /* w13xh29 font */ font <<= 8; font |= da2->mmio.ram[DA2_GAIJIRAM_SBCS+ 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; } 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 (da2->ioctl[LS_MODE] & 0x02) { /* VGA passthrough mode */ da2->override = 1; svga_set_override(da2->mb_vga, 0); da2_log("DA2 selector: VGA\n"); } else { svga_set_override(da2->mb_vga, 1); da2->override = 0; da2_log("DA2 selector: DA2\n"); } } void da2_recalctimings(da2_t *da2) { double crtcconst; double _dispontime, _dispofftime, disptime; /* if output disabled or VGA passthrough */ if (!(da2->attrc[LV_COMPATIBILITY] & 0x08) || da2->ioctl[LS_MODE] & 0x02) return; da2->vtotal = da2->crtc[LC_VERTICAL_TOTALJ] & 0xfff; da2->dispend = da2->crtc[LC_V_DISPLAY_ENABLE_END] & 0xfff; da2->vsyncstart = da2->crtc[LC_VERTICAL_SYNC_START] & 0xfff; da2->split = da2->crtc[LC_LINE_COMPAREJ] & 0xfff; da2->split = 0xfff; da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff; 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)) /* 16 color graphics mode */ if (!(da2->ioctl[LS_MODE] & 0x01)) { 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_A000; } else { /* PS/55 8-color */ da2_log("Set videomode to PS/55 4 bpp graphics.\n"); da2->vram_display_mask = DA2_MASK_A000; 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; } // 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); } static void da2_mapping_update(da2_t *da2) { /* Has the CardEnable bit been changed? */ 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); timer_enable(&da2->bitblt.timer); } else { da2_log("DA2 disable registers\n"); timer_disable(&da2->bitblt.timer); 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); } } uint8_t da2_mca_read(int port, void *p) { da2_t *da2 = (da2_t *) p; return da2->pos_regs[port & 7]; } 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_log("da2_mca_reset called.\n"); da2_reset(da2); da2_mca_write(0x102, 0, da2); } static void da2_gdcropB(uint32_t addr,uint8_t bitmask, 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, bitmask); switch (da2->gdcreg[LG_COMMAND] & 0x03) { case 0: /*Set*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | (da2->gdcsrc[i] & ~bitmask); // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | (da2->vram[addr | i] & ~bitmask); DA2_vram_w(addr | i, (da2->gdcinput[i] & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); break; case 1: /*AND*/ // da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask) & da2->gdcsrc[i]; DA2_vram_w(addr | i, ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); break; case 2: /*OR*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | da2->gdcsrc[i]; DA2_vram_w(addr | i, ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); break; case 3: /*XOR*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) ^ da2->gdcsrc[i]; DA2_vram_w(addr | i, ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); 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_w(addr | i, (da2->gdcinput[i] & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); DA2_vram_w((addr + 8) | i, ((da2->gdcinput[i] >> 8) & bitmask_h) | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); 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_w(addr | i, ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); DA2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) & (da2->gdcsrc[i] >> 8)) & bitmask_h) | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); 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_w(addr | i, ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); DA2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) | (da2->gdcsrc[i] >> 8)) & bitmask_h) | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); 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_w(addr | i, ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); DA2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) ^ (da2->gdcsrc[i] >> 8)) & bitmask_h) | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); 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)) { /* 16 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)) {/* 16 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_DEBUGVRAM ////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 */ da2->mmio.ram[addr & DA2_MASK_GAIJIRAM] = 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); else { 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)) { /* 16 color or 256 color mode */ uint8_t bitmask; /* align bitmask to even address */ if (addr & 1) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; else bitmask = da2->gdcreg[LG_BIT_MASK_LOW]; #ifdef ENABLE_DA2_DEBUGVRAM da2_log("da2_wB %x %02x\n", addr, val); // 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 %02x ", addr, val); 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, bitmask, da2); return; } switch (da2->writemode) { case 2: /* equiv to vga write mode 1 */ for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) DA2_vram_w(addr | i, da2->gdcsrc[i], da2); break; case 0:/* equiv to vga write mode 0 */ if (da2->gdcreg[LG_DATA_ROTATION] & 7) val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; if (bitmask == 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_w(addr | i, val, da2); } 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, bitmask, 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], bitmask, 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:/* equiv to vga write mode 2 */ 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_w(addr | i, (((val & (1 << i)) ? 0xff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask), da2); //fprintf(da2->mmdbg_fp, "m1-1"); } else { for (int i = 0; i < 8; i++) da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0); da2_gdcropB(addr, bitmask, da2); //fprintf(da2->mmdbg_fp, "m1-2"); } break; case 3:/* equiv to vga write mode 3 */ if (da2->gdcreg[LG_DATA_ROTATION] & 7) val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; bitmask &= val; for (int i = 0; i < 8; i++) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; da2_gdcropB(addr, bitmask, da2); 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_w(addr, val, da2); 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; uint16_t bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; addr &= DA2_MASK_MMIO; bitmask <<= 8; bitmask |= (uint16_t) da2->gdcreg[LG_BIT_MASK_LOW]; #ifdef ENABLE_DA2_DEBUGVRAM // 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; // 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_w(addr | i, da2->gdcsrc[i] & 0xff, da2); DA2_vram_w((addr + 8) | i, da2->gdcsrc[i] >> 8, da2); } 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_w(addr | i, val & 0xff, da2); DA2_vram_w((addr + 8) | i, val >> 8, da2); } } 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_w(addr | i, wdata & 0xff, da2); DA2_vram_w((addr + 8) | i, wdata >> 8, da2); } } 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 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); 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)) { /* 16 color or 256 color mode */ // 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); } 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; 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) */ for (int i = 0; i < 256; i++) { da2->vgapal[i].r = ps55_palette_color[i & 0x3F][0]; da2->vgapal[i].g = ps55_palette_color[i & 0x3F][1]; da2->vgapal[i].b = ps55_palette_color[i & 0x3F][2]; da2->pallook[i] = makecol32((da2->vgapal[i].r & 0x3f) * 4, (da2->vgapal[i].g & 0x3f) * 4, (da2->vgapal[i].b & 0x3f) * 4); } da2_log("da2_reset done.\n"); } static void * da2_init(UNUSED(const device_t *info)) { if (svga_get_pri() == NULL) return NULL; svga_t *mb_vga = svga_get_pri(); mb_vga->cable_connected = 0; da2_t *da2 = calloc(1, sizeof(da2_t)); da2->mb_vga = mb_vga; da2->dispontime = 1000ull << 32; da2->dispofftime = 1000ull << 32; da2->vram = calloc(1, DA2_SIZE_VRAM); da2->vram_mask = DA2_SIZE_VRAM - 1; da2->cram = calloc(1, DA2_SIZE_CRAM); da2->vram_display_mask = DA2_MASK_CRAM; da2->changedvram = calloc(1, /*(memsize >> 12) << 1*/ DA2_SIZE_VRAM >> 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); /* Add magic code for OS/2 J1.3. This disables BitBlt's text drawing function. */ da2->mmio.font[0x1AFFE] = 0x80; da2->mmio.font[0x1AFFF] = 0x01; 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->bitblt.debug_reg_ip = 0; #endif #ifdef ENABLE_DA2_DEBUGVRAM da2->mmdbg_fp = fopen("da2_mmiowdat.txt", "w"); da2->mmrdbg_fp = fopen("da2_mmiordat.txt", "w"); #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 = 10 * TIMER_USEC; timer_add(&da2->bitblt.timer, da2_bitblt_dopayload, da2, 0); return da2; } static int da2_available(void) { 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 */ #ifdef ENABLE_DA2_LOG FILE *f; f = fopen("da2_cram.dmp", "wb"); if (f != NULL) { fwrite(da2->cram, DA2_SIZE_CRAM, 1, f); fclose(f); } f = fopen("da2_vram.dmp", "wb"); if (f != NULL) { fwrite(da2->vram, DA2_SIZE_VRAM, 1, f); fclose(f); } f = fopen("da2_gram.dmp", "wb"); if (f != NULL) { fwrite(da2->mmio.ram, DA2_SIZE_GAIJIRAM, 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); } free(da2->bitblt.debug_reg); #endif #ifdef ENABLE_DA2_DEBUGVRAM if (da2->mmdbg_fp != NULL) fclose(da2->mmdbg_fp); if (da2->mmrdbg_fp != NULL) fclose(da2->mmrdbg_fp); #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; }