From b36c0cb6976988b29ecfa3001f9a8f3240dc4abd Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 12 Feb 2024 20:58:06 +0100 Subject: [PATCH] More updates for the NEC PC-98x1 series. Still preliminary, but I hope it's a good start to work with. --- src/include/86box/machine.h | 10 + src/include/86box/vid_pc98x1_disp.h | 149 +++ src/include/86box/vid_pc98x1_egc.h | 83 ++ src/include/86box/vid_upd7220.h | 108 +- src/machine/machine.c | 1 + src/pic.c | 18 +- src/pit.c | 12 +- src/video/vid_pc98x1_disp.c | 1670 ++++++++++++++++++++++++++- src/video/vid_pc98x1_egc.c | 160 ++- src/video/vid_upd7220.c | 43 +- 10 files changed, 2097 insertions(+), 157 deletions(-) create mode 100644 src/include/86box/vid_pc98x1_disp.h create mode 100644 src/include/86box/vid_pc98x1_egc.h diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 4fba180b2..22a8687e2 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -336,6 +336,15 @@ typedef struct _machine_ { #endif } machine_t; +/*ToDo: preliminary, to improve.*/ +typedef struct _machine_pc98_ { + char *font_rom; + char *hdd_rom; + char *pci_rom; + char *sound_rom; + int init; +} machine_pc98_t; + /* Global variables. */ extern const machine_filter_t machine_types[]; extern const machine_filter_t machine_chipsets[]; @@ -343,6 +352,7 @@ extern const machine_t machines[]; extern int bios_only; extern int machine; extern void * machine_snd; +extern machine_pc98_t machine_pc98; /* Core functions. */ extern int machine_count(void); diff --git a/src/include/86box/vid_pc98x1_disp.h b/src/include/86box/vid_pc98x1_disp.h new file mode 100644 index 000000000..c22573c13 --- /dev/null +++ b/src/include/86box/vid_pc98x1_disp.h @@ -0,0 +1,149 @@ +/* + * 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. + * + * Emulation of the EGC graphics processor used by + * the NEC PC-98x1 series of computers. + * + * + * + * Authors: TAKEDA toshiya, + * yui/Neko Project II + * + * Copyright 2009-2023 TAKEDA, toshiya. + * Copyright 2008-2023 yui/Neko Project II. + */ +#ifndef VIDEO_PC98X1_DISP_H +# define VIDEO_PC98X1_DISP_H + +#define TVRAM_SIZE 0x4000 +#define VRAM16_SIZE 0x40000 +#define VRAM256_SIZE 0x80000 +#define EMS_SIZE 0x10000 + +enum { + MODE1_ATRSEL = 0x00, + MODE1_GRAPHIC = 0x01, + MODE1_COLUMN = 0x02, + MODE1_FONTSEL = 0x03, + MODE1_200LINE = 0x04, + MODE1_KAC = 0x05, + MODE1_MEMSW = 0x06, + MODE1_DISP = 0x07, +}; + +enum { + MODE2_16COLOR = 0x00, + MODE2_EGC = 0x02, + MODE2_WRITE_MASK = 0x03, + MODE2_256COLOR = 0x10, + MODE2_480LINE = 0x34, +}; + +enum { + MODE3_WRITE_MASK = 0x01, + MODE3_LINE_COLOR = 0x09, + MODE3_NPC_COLOR = 0x0b, + MODE3_LINE_CONNECT = 0x0f, +}; + +enum { + GRCG_PLANE_0 = 0x01, + GRCG_PLANE_1 = 0x02, + GRCG_PLANE_2 = 0x04, + GRCG_PLANE_3 = 0x08, + GRCG_PLANE_SEL = 0x30, + GRCG_RW_MODE = 0x40, + GRCG_CG_MODE = 0x80, +}; + +typedef struct pc98x1_vid_t { + /* vga */ + uint8_t tvram_buffer[480 * 640]; + uint8_t vram0_buffer[480 * 640]; + uint8_t vram1_buffer[480 * 640]; + uint8_t null_buffer[480 * 640]; + int width; + int height; + int last_width; + int last_height; + uint8_t dirty; + uint8_t blink; + uint32_t palette_chr[8]; + uint32_t palette_gfx[256]; + + uint8_t font[0x84000]; + uint8_t tvram[TVRAM_SIZE]; + uint8_t vram16[VRAM16_SIZE]; + uint8_t vram256[VRAM256_SIZE]; + uint8_t ems[EMS_SIZE]; + uint8_t *vram16_disp_b; + uint8_t *vram16_disp_r; + uint8_t *vram16_disp_g; + uint8_t *vram16_disp_e; + uint8_t *vram16_draw_b; + uint8_t *vram16_draw_r; + uint8_t *vram16_draw_g; + uint8_t *vram16_draw_e; + uint8_t *vram256_disp; + uint8_t *vram256_draw_0; + uint8_t *vram256_draw_1; + + GDCState gdc_chr; + GDCState gdc_gfx; + EGCState egc; + + uint8_t grcg_mode; + uint8_t grcg_tile_cnt; + uint8_t grcg_tile_b[4]; + uint16_t grcg_tile_w[4]; + + uint8_t crtv; + uint8_t pl; + uint8_t bl; + uint8_t cl; + uint8_t ssl; + uint8_t sur; + uint8_t sdr; + + uint8_t mode1[8]; + uint8_t mode2[128]; + uint8_t mode3[128]; + uint8_t mode_select; + + uint8_t digipal[4]; + uint8_t anapal[3][256]; + uint8_t anapal_select; + + uint8_t bank_draw; + uint8_t bank_disp; + uint8_t bank256_draw_0; + uint8_t bank256_draw_1; + uint16_t vram256_bank_0; + uint16_t vram256_bank_1; + uint8_t ems_selected; + + uint16_t font_code; + uint8_t font_line; + uint32_t cgwindow_addr_low; + uint32_t cgwindow_addr_high; + + int htotal; + int hblank; + + uint64_t dispontime; + uint64_t dispofftime; + + pc_timer_t timer; + double clock; +} pc98x1_vid_t; + +# ifdef EMU_DEVICE_H +extern const device_t pc98x1_vid_device; +# endif // EMU_DEVICE_H + +#endif /*VIDEO_PC98X1_EGC_H*/ diff --git a/src/include/86box/vid_pc98x1_egc.h b/src/include/86box/vid_pc98x1_egc.h new file mode 100644 index 000000000..3d29a1290 --- /dev/null +++ b/src/include/86box/vid_pc98x1_egc.h @@ -0,0 +1,83 @@ +/* + * 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. + * + * Emulation of the EGC graphics processor used by + * the NEC PC-98x1 series of computers. + * + * + * + * Authors: TAKEDA toshiya, + * yui/Neko Project II + * + * Copyright 2009-2024 TAKEDA, toshiya. + * Copyright 2008-2024 yui/Neko Project II. + */ +#ifndef VIDEO_PC98X1_EGC_H +# define VIDEO_PC98X1_EGC_H + +typedef union { + uint8_t b[2]; + uint16_t w; +} egcword_t; + +typedef union { + uint8_t b[4][2]; + uint16_t w[4]; + uint32_t d[2]; + uint64_t q; +} egcquad_t; + +typedef struct egc_t { + void *priv; + + uint16_t access; + uint16_t fgbg; + uint16_t ope; + uint16_t fg; + egcword_t mask; + uint16_t bg; + uint16_t sft; + uint16_t leng; + egcquad_t lastvram; + egcquad_t patreg; + egcquad_t fgc; + egcquad_t bgc; + int func; + uint32_t remain; + uint32_t stack; + uint8_t *inptr; + int inptr_vmstate; + uint8_t *outptr; + int outptr_vmstate; + egcword_t mask2; + egcword_t srcmask; + uint8_t srcbit; + uint8_t dstbit; + uint8_t sft8bitl; + uint8_t sft8bitr; + uint8_t buf[528]; /* 4096/8 + 4*4 */ + + /* vram */ + uint8_t *vram_ptr; + uint8_t *vram_b; + uint8_t *vram_r; + uint8_t *vram_g; + uint8_t *vram_e; + egcquad_t vram_src; + egcquad_t vram_data; +} egc_t; + +extern void egc_mem_writeb(egc_t *dev, uint32_t addr1, uint8_t value); +extern void egc_mem_writew(egc_t *dev, uint32_t addr1, uint16_t value); +extern uint8_t egc_mem_readb(egc_t *dev, uint32_t addr1); +extern uint16_t egc_mem_readw(egc_t *dev, uint32_t addr1); +extern void egc_set_vram(egc_t *dev, uint8_t *vram_ptr); +extern void egc_reset(egc_t *dev); +extern void egc_init(egc_t *dev, void *priv); + +#endif /*VIDEO_PC98X1_EGC_H*/ diff --git a/src/include/86box/vid_upd7220.h b/src/include/86box/vid_upd7220.h index 16b73f599..6cca0a5b1 100644 --- a/src/include/86box/vid_upd7220.h +++ b/src/include/86box/vid_upd7220.h @@ -19,17 +19,63 @@ #ifndef VIDEO_UPD7220_H # define VIDEO_UPD7220_H -#define TVRAM_SIZE 0x4000 -#define VRAM16_SIZE 0x40000 -#define VRAM256_SIZE 0x80000 -#define EMS_SIZE 0x10000 - #define GDC_BUFFERS 1024 #define GDC_TABLEMAX 0x1000 +enum { + GDC_CMD_RESET = 0x00, + GDC_CMD_SYNC = 0x0e, + GDC_CMD_SLAVE = 0x6e, + GDC_CMD_MASTER = 0x6f, + GDC_CMD_START = 0x6b, + GDC_CMD_BCTRL = 0x0c, + GDC_CMD_ZOOM = 0x46, + GDC_CMD_SCROLL = 0x70, + GDC_CMD_CSRFORM = 0x4b, + GDC_CMD_PITCH = 0x47, + GDC_CMD_LPEN = 0xc0, + GDC_CMD_VECTW = 0x4c, + GDC_CMD_VECTE = 0x6c, + GDC_CMD_TEXTW = 0x78, + GDC_CMD_TEXTE = 0x68, + GDC_CMD_CSRW = 0x49, + GDC_CMD_CSRR = 0xe0, + GDC_CMD_MASK = 0x4a, + GDC_CMD_WRITE = 0x20, + GDC_CMD_READ = 0xa0, + GDC_CMD_DMAR = 0xa4, + GDC_CMD_DMAW = 0x24, + /* unknown command (3 params) */ + GDC_CMD_UNK_5A = 0x5a, +}; + +enum { + GDC_STAT_DRDY = 0x01, + GDC_STAT_FULL = 0x02, + GDC_STAT_EMPTY = 0x04, + GDC_STAT_DRAW = 0x08, + GDC_STAT_DMA = 0x10, + GDC_STAT_VSYNC = 0x20, + GDC_STAT_HBLANK = 0x40, + GDC_STAT_LPEN = 0x80, +}; + +enum { + GDC_DIRTY_VRAM = 0x01, + GDC_DIRTY_START = 0x02, + GDC_DIRTY_SCROLL = 0x04, + GDC_DIRTY_CURSOR = 0x08, + GDC_DIRTY_GFX = GDC_DIRTY_VRAM | GDC_DIRTY_SCROLL, + GDC_DIRTY_CHR = GDC_DIRTY_GFX | GDC_DIRTY_CURSOR, +}; + + #define GDC_VTICKS 18 #define GDC_VSTICKS 2 +#define GDC_MULBIT 15 +#define GDC_TABLEBIT 12 + typedef struct upd7220_t { void *priv; @@ -71,49 +117,15 @@ typedef struct upd7220_t { uint16_t pattern; } upd7220_t; -extern void upd7220_init(upd7220_t *dev, void *priv, - uint8_t (*vram_read)(uint32_t addr, void *priv), - void (*vram_write)(uint32_t addr, uint8_t val, void *priv)); +extern void upd7220_init(upd7220_t *dev, void *priv, + uint8_t (*vram_read)(uint32_t addr, void *priv), + void (*vram_write)(uint32_t addr, uint8_t val, void *priv)); -void upd7220_param_write(uint16_t addr, uint8_t value, void *priv); -uint8_t upd7220_statreg_read(uint16_t addr, void *priv); -void upd7220_cmdreg_write(uint16_t addr, uint8_t value, void *priv); -uint8_t upd7220_data_read(uint16_t addr, void *priv); -void upd7220_reset(upd7220_t *dev); - -# ifdef EMU_DEVICE_H -extern const device_t ati68860_ramdac_device; -extern const device_t ati68875_ramdac_device; -extern const device_t att490_ramdac_device; -extern const device_t att491_ramdac_device; -extern const device_t att492_ramdac_device; -extern const device_t att498_ramdac_device; -extern const device_t av9194_device; -extern const device_t bt484_ramdac_device; -extern const device_t att20c504_ramdac_device; -extern const device_t bt485_ramdac_device; -extern const device_t att20c505_ramdac_device; -extern const device_t bt485a_ramdac_device; -extern const device_t gendac_ramdac_device; -extern const device_t ibm_rgb528_ramdac_device; -extern const device_t ics2494an_305_device; -extern const device_t ati18810_device; -extern const device_t ati18811_0_device; -extern const device_t ati18811_1_device; -extern const device_t ics2595_device; -extern const device_t icd2061_device; -extern const device_t ics9161_device; -extern const device_t sc11483_ramdac_device; -extern const device_t sc11487_ramdac_device; -extern const device_t sc11486_ramdac_device; -extern const device_t sc11484_nors2_ramdac_device; -extern const device_t sc1502x_ramdac_device; -extern const device_t sdac_ramdac_device; -extern const device_t stg_ramdac_device; -extern const device_t tkd8001_ramdac_device; -extern const device_t tseng_ics5301_ramdac_device; -extern const device_t tseng_ics5341_ramdac_device; -extern const device_t tvp3026_ramdac_device; -# endif +extern void upd7220_recalctimings(upd7220_t *dev); +extern void upd7220_param_write(uint16_t addr, uint8_t value, void *priv); +extern uint8_t upd7220_statreg_read(uint16_t addr, void *priv); +extern void upd7220_cmdreg_write(uint16_t addr, uint8_t value, void *priv); +extern uint8_t upd7220_data_read(uint16_t addr, void *priv); +extern void upd7220_reset(upd7220_t *dev); #endif /*VIDEO_UPD7220_H*/ diff --git a/src/machine/machine.c b/src/machine/machine.c index 9e530eb3b..38a525b1b 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -80,6 +80,7 @@ machine_init_ex(int m) machine_snd = NULL; is_vpc = 0; + machine_pc98.init = 0; standalone_gameport_type = NULL; gameport_instance_id = 0; diff --git a/src/pic.c b/src/pic.c index 82905261a..033444b62 100644 --- a/src/pic.c +++ b/src/pic.c @@ -233,7 +233,7 @@ pic_update_pending_at(void) { if (!(pic.interrupt & 0x20)) { pic2.int_pending = (find_best_interrupt(&pic2) != -1); - + if (pic2.int_pending) pic.irr |= (1 << pic2.icw3); else @@ -643,7 +643,11 @@ pic_init(void) pic_reset_hard(); shadow = 0; - io_sethandler(0x0020, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); + if (machine_pc98.init) { + io_sethandler_interleaved(0x0000, 0x0001, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); + io_sethandler_interleaved(0x0002, 0x0001, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); + } else + io_sethandler(0x0020, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic); } void @@ -658,8 +662,14 @@ pic_init_pcjr(void) void pic2_init(void) { - io_sethandler(0x00a0, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); - pic.slaves[2] = &pic2; + if (machine_pc98.init) { + io_sethandler_interleaved(0x0008, 0x0001, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + io_sethandler_interleaved(0x000a, 0x0001, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + pic.slaves[7] = &pic2; + } else { + io_sethandler(0x00a0, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, &pic2); + pic.slaves[2] = &pic2; + } } void diff --git a/src/pit.c b/src/pit.c index 6045fd842..e5b6dab11 100644 --- a/src/pit.c +++ b/src/pit.c @@ -1048,7 +1048,11 @@ pit_set_clock(uint32_t clock) else cpuclock = (double) clock; - PITCONSTD = (cpuclock / 1193182.0); + if (machine_pc98.init) + PITCONSTD = (cpuclock / 2457600.0); + else + PITCONSTD = (cpuclock / 1193182.0); + PITCONST = (uint64_t) (PITCONSTD * (double) (1ULL << 32)); #ifdef IMPRECISE_CGACONST CGACONST = (uint64_t) ((cpuclock / (19687503.0 / 11.0)) * (double) (1ULL << 32)); @@ -1102,7 +1106,11 @@ pit_set_clock(uint32_t clock) PITCONST = (24ULL << 32LL); CGACONST = (16ULL << 32LL); } else if (cpuclock != 14318184.0) { - PITCONSTD = (cpuclock / 1193182.0); + if (machine_pc98.init) + PITCONSTD = (cpuclock / 2457600.0); + else + PITCONSTD = (cpuclock / 1193182.0); + PITCONST = (uint64_t) (PITCONSTD * (double) (1ULL << 32)); #ifdef IMPRECISE_CGACONST CGACONST = (uint64_t) ((cpuclock / (19687503.0 / 11.0)) * (double) (1ULL << 32)); diff --git a/src/video/vid_pc98x1_disp.c b/src/video/vid_pc98x1_disp.c index 763fc143d..22a5e8fa1 100644 --- a/src/video/vid_pc98x1_disp.c +++ b/src/video/vid_pc98x1_disp.c @@ -14,8 +14,8 @@ * Authors: TAKEDA toshiya, * yui/Neko Project II * - * Copyright 2009-2023 TAKEDA, toshiya. - * Copyright 2008-2023 yui/Neko Project II. + * Copyright 2009-2024 TAKEDA, toshiya. + * Copyright 2008-2024 yui/Neko Project II. */ #include #include @@ -30,7 +30,10 @@ #include <86box/pit.h> #include <86box/mem.h> #include <86box/device.h> +#include <86box/machine.h> #include <86box/video.h> +#include <86box/vid_upd7220.h> +#include <86box/vid_pc98x1_egc.h> #include <86box/vid_pc98x1_disp.h> #include <86box/plat_unused.h> @@ -60,6 +63,1387 @@ enum { ATTR_COL = 0xe0, }; +/* vsync */ +static void +pc98x1_vsync_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x64 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + dev->crtv = 1; +} + +/* crtc */ +static void +pc98x1_crtc_pl_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x70 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->pl != value) { + dev->pl = value; + dev->dirty |= DIRTY_TVRAM; + } +} + +static void +pc98x1_crtc_bl_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x72 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->bl != value) { + dev->bl = value; + dev->dirty |= DIRTY_TVRAM; + } +} + +static void +pc98x1_crtc_cl_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x74 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->cl != value) { + dev->cl = value; + dev->dirty |= DIRTY_TVRAM; + } +} + +static void +pc98x1_crtc_ssl_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x76 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->ssl != value) { + dev->ssl = value; + dev->dirty |= DIRTY_TVRAM; + } +} + +static void +pc98x1_crtc_sur_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x78 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->sur != value) { + dev->sur = value; + dev->dirty |= DIRTY_TVRAM; + } +} + +static void +pc98x1_crtc_sdr_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x7a */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->sdr != value) { + dev->sdr = value; + dev->dirty |= DIRTY_TVRAM; + } +} + +/* grcg */ +static void +pc98x1_grcg_mode_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x7c */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + dev->grcg_mode = value; + dev->grcg_tile_cnt = 0; +} + +static void +pc98x1_grcg_tile_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x7e */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + dev->grcg_tile_b[dev->grcg_tile_cnt] = value; + dev->grcg_tile_cnt = (dev->grcg_tile_cnt + 1) & 3; +} + +static void +pc98x1_grcg_tile_writew(uint16_t addr, uint16_t value, void *priv) +{ + /* ioport 0x7e */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + dev->grcg_tile_w[dev->grcg_tile_cnt] = (value & 0xff) | (value << 8); + dev->grcg_tile_cnt = (dev->grcg_tile_cnt + 1) & 3; +} + +static void +pc98x1_grcg_mem_writeb(pc98x1_vid_t *dev, uint32_t addr1, uint8_t value) +{ + uint32_t addr = addr1 & 0x7fff; + + if (dev->grcg_mode & GRCG_RW_MODE) { + /* RMW */ + if (!(dev->grcg_mode & GRCG_PLANE_0)) { + dev->vram16_draw_b[addr] &= ~value; + dev->vram16_draw_b[addr] |= dev->grcg_tile_b[0] & value; + } + if (!(dev->grcg_mode & GRCG_PLANE_1)) { + dev->vram16_draw_r[addr] &= ~value; + dev->vram16_draw_r[addr] |= dev->grcg_tile_b[1] & value; + } + if (!(dev->grcg_mode & GRCG_PLANE_2)) { + dev->vram16_draw_g[addr] &= ~value; + dev->vram16_draw_g[addr] |= dev->grcg_tile_b[2] & value; + } + if (!(dev->grcg_mode & GRCG_PLANE_3)) { + dev->vram16_draw_e[addr] &= ~value; + dev->vram16_draw_e[addr] |= dev->grcg_tile_b[3] & value; + } + } else { + /* TDW */ + if (!(dev->grcg_mode & GRCG_PLANE_0)) + dev->vram16_draw_b[addr] = dev->grcg_tile_b[0]; + + if (!(dev->grcg_mode & GRCG_PLANE_1)) + dev->vram16_draw_r[addr] = dev->grcg_tile_b[0]; + + if (!(dev->grcg_mode & GRCG_PLANE_2)) + dev->vram16_draw_g[addr] = dev->grcg_tile_b[0]; + + if (!(dev->grcg_mode & GRCG_PLANE_3)) + dev->vram16_draw_e[addr] = dev->grcg_tile_b[0]; + } +} + +static void +pc98x1_grcg_mem_writew(pc98x1_vid_t *dev, uint32_t addr1, uint16_t value) +{ + uint32_t addr = addr1 & 0x7fff; + + if (dev->grcg_mode & GRCG_RW_MODE) { + /* RMW */ + if (!(dev->grcg_mode & GRCG_PLANE_0)) { + *(uint16_t *)(dev->vram16_draw_b + addr) &= ~value; + *(uint16_t *)(dev->vram16_draw_b + addr) |= dev->grcg_tile_w[0] & value; + } + if (!(dev->grcg_mode & GRCG_PLANE_1)) { + *(uint16_t *)(dev->vram16_draw_r + addr) &= ~value; + *(uint16_t *)(dev->vram16_draw_r + addr) |= dev->grcg_tile_w[1] & value; + } + if (!(dev->grcg_mode & GRCG_PLANE_2)) { + *(uint16_t *)(dev->vram16_draw_g + addr) &= ~value; + *(uint16_t *)(dev->vram16_draw_g + addr) |= dev->grcg_tile_w[2] & value; + } + if (!(dev->grcg_mode & GRCG_PLANE_3)) { + *(uint16_t *)(dev->vram16_draw_e + addr) &= ~value; + *(uint16_t *)(dev->vram16_draw_e + addr) |= dev->grcg_tile_w[3] & value; + } + } else { + /* TDW */ + if (!(dev->grcg_mode & GRCG_PLANE_0)) + *(uint16_t *)(dev->vram16_draw_b + addr) = dev->grcg_tile_w[0]; + + if (!(dev->grcg_mode & GRCG_PLANE_1)) + *(uint16_t *)(dev->vram16_draw_r + addr) = dev->grcg_tile_w[1]; + + if (!(dev->grcg_mode & GRCG_PLANE_2)) + *(uint16_t *)(dev->vram16_draw_g + addr) = dev->grcg_tile_w[2]; + + if (!(dev->grcg_mode & GRCG_PLANE_3)) + *(uint16_t *)(dev->vram16_draw_e + addr) = dev->grcg_tile_w[3]; + } +} + +/* cg window */ +static void +pc98x1_cgwindow_set_addr(pc98x1_vid_t *dev) +{ + uint32_t low = 0x7fff0, high; + uint8_t code = dev->font_code & 0x7f; + uint16_t lr = ((~dev->font_line) & 0x20) << 6; + + if (!(dev->font_code & 0xff00)) { + high = 0x80000 + (dev->font_code << 4); + if (!dev->mode1[MODE1_FONTSEL]) + high += 0x2000; + } else { + high = (dev->font_code & 0x7f7f) << 4; + if ((code >= 0x56) && (code < 0x58)) { + high += lr; + } else if ((code >= 0x09) && (code < 0x0c)) { + if (lr) + high = low; + } else if (((code >= 0x0c) && (code < 0x10)) || ((code >= 0x58) && (code < 0x60))) + high += lr; + else { + low = high; + high += 0x800; + } + } + dev->cgwindow_addr_low = low; + dev->cgwindow_addr_high = high; +} + +static void +pc98x1_cgwindow_code2_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0xa1 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + dev->font_code = (value << 8) | (dev->font_code & 0xff); + pc98x1_cgwindow_set_addr(dev); +} + +static uint8_t +pc98x1_cgwindow_code2_read(uint16_t addr, void *priv) +{ + /* ioport 0xa1 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + return (dev->font_code >> 8) & 0xff; +} + +static void +pc98x1_cgwindow_code1_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0xa3 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + dev->font_code = (dev->font_code & 0xff00) | value; + pc98x1_cgwindow_set_addr(dev); +} + +static uint8_t +pc98x1_cgwindow_code1_read(uint16_t addr, void *priv) +{ + /* ioport 0xa3 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + return dev->font_code & 0xff; +} + +static void +pc98x1_cgwindow_line_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0xa5 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + dev->font_line = value; + pc98x1_cgwindow_set_addr(dev); +} + +static uint8_t +pc98x1_cgwindow_line_read(uint8_t addr, void *priv) +{ + /* ioport 0xa5 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + return dev->font_line; +} + +static void +pc98x1_cgwindow_pattern_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0xa9 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint16_t lr = ((~dev->font_line) & 0x20) << 6; + + if ((dev->font_code & 0x7e) == 0x56) { + dev->font[((dev->font_code & 0x7f7f) << 4) + lr + (dev->font_line & 0x0f)] = value; + } +} + +static uint8_t +pc98x1_cgwindow_pattern_read(uint16_t addr, void *priv) +{ + /* ioport 0xa9 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint8_t type = dev->font_code & 0xff; + uint16_t lr = ((~dev->font_line) & 0x20) << 6; + + if ((type >= 0x09) && (type < 0x0c)) { + if (!lr) + return dev->font[((dev->font_code & 0x7f7f) << 4) + (dev->font_line & 0x0f)]; + } else if (dev->font_code & 0xff00) + return dev->font[((dev->font_code & 0x7f7f) << 4) + lr + (dev->font_line & 0x0f)]; + else if (!(dev->font_line & 0x10)) + return dev->font[0x80000 + (dev->font_code << 4) + (dev->font_line & 0x1f)]; + + return 0; +} + +static void +pc98x1_cgwindow_writeb(pc98x1_vid_t *dev, uint32_t addr, uint8_t value) +{ + if ((addr < 0x1000) && (dev->font_code & 0x7e) == 0x56) { + if (addr & 1) + dev->font[dev->cgwindow_addr_high + ((addr >> 1) & 0x0f)] = value; + else + dev->font[dev->cgwindow_addr_low + ((addr >> 1) & 0x0f)] = value; + } +} + +static void +pc98x1_cgwindow_writew(pc98x1_vid_t *dev, uint32_t addr, uint16_t value) +{ + if (addr < 0x1000) { + pc98x1_cgwindow_writeb(dev, addr, value & 0xff); + pc98x1_cgwindow_writeb(dev, addr + 1, (value >> 8) & 0xff); + } +} + +static void +pc98x1_cgwindow_writel(pc98x1_vid_t *dev, uint32_t addr, uint32_t value) +{ + if (addr < 0x1000) { + pc98x1_cgwindow_writeb(dev, addr, value & 0xff); + pc98x1_cgwindow_writeb(dev, addr + 1, (value >> 8) & 0xff); + pc98x1_cgwindow_writeb(dev, addr + 2, (value >> 16) & 0xff); + pc98x1_cgwindow_writeb(dev, addr + 3, (value >> 24) & 0xff); + } +} + +static uint8_t +pc98x1_cgwindow_readb(pc98x1_vid_t *dev, uint32_t addr) +{ + if (addr < 0x1000) { + if (addr & 1) + return dev->font[dev->cgwindow_addr_high + ((addr >> 1) & 0x0f)]; + else + return dev->font[dev->cgwindow_addr_low + ((addr >> 1) & 0x0f)]; + } + return 0xff; +} + +static uint16_t +pc98x1_cgwindow_readw(pc98x1_vid_t *dev, uint32_t addr) +{ + uint16_t value = 0xffff; + + if (addr < 0x1000) { + value = pc98x1_cgwindow_readb(dev, addr); + value |= pc98x1_cgwindow_readb(dev, addr + 1) << 8; + } + return value; +} + +static uint32_t +pc98x1_cgwindow_readl(pc98x1_vid_t *dev, uint32_t addr) +{ + uint16_t value = 0xffffffff; + + if (addr < 0x1000) { + value = pc98x1_cgwindow_readb(dev, addr); + value |= pc98x1_cgwindow_readb(dev, addr + 1) << 8; + value |= pc98x1_cgwindow_readb(dev, addr + 2) << 16; + value |= pc98x1_cgwindow_readb(dev, addr + 3) << 24; + } + return value; +} + +/* mode flip-flop */ +static void +pc98x1_mode_flipflop1_write(uint16_t addr, uint8_t value, void *priv) +{ + // ioport 0x68 + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + int num = (value >> 1) & 7; + + if (dev->mode1[num] != (value & 1)) { + switch (num) { + case MODE1_ATRSEL: + case MODE1_COLUMN: + dev->dirty |= DIRTY_TVRAM; + break; + case MODE1_200LINE: + dev->dirty |= DIRTY_VRAM0 | DIRTY_VRAM1; + break; + case MODE1_DISP: + dev->dirty |= DIRTY_DISPLAY; + break; + } + dev->mode1[num] = value & 1; + } +} + +static uint8_t +pc98x1_mode_flipflop1_read(uint16_t addr, void *priv) +{ + /* ioport 0x68 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint8_t value = 0; + + if (dev->mode1[MODE1_ATRSEL]) + value |= 0x01; + + if (dev->mode1[MODE1_GRAPHIC]) + value |= 0x04; + + if (dev->mode1[MODE1_COLUMN]) + value |= 0x08; + + if (dev->mode1[MODE1_MEMSW]) + value |= 0x40; + + if (dev->mode1[MODE1_KAC]) + value |= 0x80; + + return value | 0x32; +} + +static void +pc98x1_mode_flipflop2_write(uint16_t addr, uint8_t value1, void *priv) +{ + /* ioport 0x6a */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint8_t value = value1 & 1; + int num = (value1 >> 1) & 0x7f; + + switch (num) { + case 0x00: + /* select 8/16 color */ + if (dev->mode2[num] != value) { + if (!dev->mode2[MODE2_256COLOR]) + dev->dirty |= DIRTY_PALETTE; + + dev->mode2[num] = value; + } + break; + case 0x02: + /* select grcg/egc mode */ + if (dev->mode2[MODE2_WRITE_MASK]) + dev->mode2[num] = value; + break; + case 0x10: + /* select 16/256 color */ + if (dev->mode2[MODE2_WRITE_MASK]) { + if (dev->mode2[num] != value) { + dev->dirty |= (DIRTY_PALETTE | DIRTY_VRAM0 | DIRTY_VRAM1); + dev->mode2[num] = value; + } + } + break; + case 0x34: + /* select 400/480 lines */ + if (dev->mode2[MODE2_WRITE_MASK]) { + if (dev->mode2[num] != value) { + dev->dirty |= (DIRTY_VRAM0 | DIRTY_VRAM1); + dev->mode2[num] = value; + } + } + break; + case 0x11: case 0x12: case 0x13: case 0x15: case 0x16: + case 0x30: case 0x31: case 0x33: case 0x65: + if (dev->mode2[MODE2_WRITE_MASK]) + dev->mode2[num] = value; + break; + default: + dev->mode2[num] = value; + break; + } +} + +static uint8_t +pc98x1_mode_flipflop2_read(uint16_t addr, void *priv) +{ + /* ioport 0x6a */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint8_t value = 0; + + if (dev->mode3[MODE3_LINE_CONNECT]) + value |= 0x01; + + if (dev->mode3[MODE3_WRITE_MASK]) + value |= 0x10; + + return value | 0xee; +} + +static void +pc98x1_mode_flipflop3_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x6e */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + switch (value & 0xfe) { + case 0x02: + dev->mode3[MODE3_WRITE_MASK] = value & 1; + break; + default: + if (dev->mode3[MODE3_WRITE_MASK]) + dev->mode3[(value >> 1) & 0x7f] = value & 1; + break; + } +} + +static uint8_t +pc98x1_mode_flipflop3_read(uint16_t addr, void *priv) +{ + /* ioport 0x6e */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint8_t value = 0; + + if (dev->mode3[MODE3_WRITE_MASK]) + value |= 0x01; + + if (dev->mode3[MODE3_LINE_COLOR]) + value |= 0x10; + + if (dev->mode3[MODE3_NPC_COLOR]) + value |= 0x80; + + return value | 0x6e; +} + +static void +pc98x1_mode_select_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x9a0 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + dev->mode_select = value; +} + +static uint8_t +pc98x1_mode_status_read(uint16_t addr, void *priv) +{ + /* ioport 0x9a0 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint8_t value = 0; + + if (dev->mode2[0x42]) + value |= 2; + + switch (dev->mode_select) { + case 0x01: if (dev->mode1[0x01]) { value |= 1; } break; + case 0x02: if (dev->mode1[0x04]) { value |= 1; } break; + case 0x03: if (dev->mode1[0x07]) { value |= 1; } break; + case 0x04: if (dev->mode2[0x00]) { value |= 1; } break; + case 0x05: if (dev->mode2[0x20]) { value |= 1; } break; + case 0x06: if (dev->mode2[0x22]) { value |= 1; } break; + case 0x07: if (dev->mode2[0x02]) { value |= 1; } break; + case 0x08: if (dev->mode2[0x03]) { value |= 1; } break; + case 0x09: if (dev->mode2[0x41]) { value |= 1; } break; + case 0x0a: if (dev->mode2[0x10]) { value |= 1; } break; + case 0x0b: if (dev->mode2[0x31]) { value |= 1; } break; + case 0x0d: if (dev->mode2[0x34]) { value |= 1; } break; + case 0x0e: if (dev->mode2[0x11]) { value |= 1; } break; + case 0x0f: if (dev->mode2[0x12]) { value |= 1; } break; + case 0x10: if (dev->mode2[0x35]) { value |= 1; } break; + case 0x11: if (dev->mode2[0x13]) { value |= 1; } break; + case 0x12: if (dev->mode2[0x16]) { value |= 1; } break; + case 0x13: if (dev->mode2[0x14]) { value |= 1; } break; + case 0x14: if (dev->mode2[0x33]) { value |= 1; } break; + case 0x15: if (dev->mode2[0x30]) { value |= 1; } break; + case 0x16: if (dev->mode2[0x61]) { value |= 1; } break; + case 0x17: if (dev->mode2[0x36]) { value |= 1; } break; + case 0x18: if (dev->mode2[0x15]) { value |= 1; } break; + case 0x19: if (dev->mode2[0x24]) { value |= 1; } break; + case 0x1a: if (dev->mode2[0x64]) { value |= 1; } break; + case 0x1b: if (dev->mode2[0x17]) { value |= 1; } break; + case 0x1c: if (dev->mode2[0x37]) { value |= 1; } break; + case 0x1d: if (dev->mode2[0x60]) { value |= 1; } break; + case 0x1e: if (dev->mode2[0x23]) { value |= 1; } break; + case 0x1f: if (dev->mode2[0x35]) { value |= 1; } break; + default: break; + } + return value; +} + +/* vram bank */ +static void +pc98x1_vram_disp_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0xa4 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (value & 1) { + if (dev->bank_disp != DIRTY_VRAM1) { + dev->vram16_disp_b = dev->vram16 + 0x20000; + dev->vram16_disp_r = dev->vram16 + 0x28000; + dev->vram16_disp_g = dev->vram16 + 0x30000; + dev->vram16_disp_e = dev->vram16 + 0x38000; + dev->vram256_disp = dev->vram256 + 0x40000; + dev->bank_disp = DIRTY_VRAM1; + dev->dirty |= DIRTY_DISPLAY; + } + } else { + if (dev->bank_disp != DIRTY_VRAM0) { + dev->vram16_disp_b = dev->vram16 + 0x00000; + dev->vram16_disp_r = dev->vram16 + 0x08000; + dev->vram16_disp_g = dev->vram16 + 0x10000; + dev->vram16_disp_e = dev->vram16 + 0x18000; + dev->vram256_disp = dev->vram256 + 0x00000; + dev->bank_disp = DIRTY_VRAM0; + dev->dirty |= DIRTY_DISPLAY; + } + } +} + +static uint8_t +pc98x1_vram_disp_read(uint16_t addr, void *priv) +{ + /* ioport 0xa4 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->bank_disp == DIRTY_VRAM0) { + /*return 0;*/ + return 0xfe; + } + /*return 1;*/ + return 0xff; +} + +static void +pc98x1_vram_draw_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0xa6 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (value & 1) { + dev->vram16_draw_b = dev->vram16 + 0x20000; + dev->vram16_draw_r = dev->vram16 + 0x28000; + dev->vram16_draw_g = dev->vram16 + 0x30000; + dev->vram16_draw_e = dev->vram16 + 0x38000; + dev->bank_draw = DIRTY_VRAM1; + } else { + dev->vram16_draw_b = dev->vram16 + 0x00000; + dev->vram16_draw_r = dev->vram16 + 0x08000; + dev->vram16_draw_g = dev->vram16 + 0x10000; + dev->vram16_draw_e = dev->vram16 + 0x18000; + dev->bank_draw = DIRTY_VRAM0; + } + egc_set_vram(&dev->egc, dev->vram16_draw_b); +} + +static uint8_t +pc98x1_vram_draw_read(uint16_t addr, void *priv) +{ + /* ioport 0xa6 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->bank_draw == DIRTY_VRAM0) { + /*return 0;*/ + return 0xfe; + } + /*return 1;*/ + return 0xff; +} + +/* palette */ +static void +pc98x1_palette_a8_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0xa8 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR] || dev->mode2[MODE2_16COLOR]) + dev->anapal_select = value; + else { + if (dev->digipal[0] != value) { + dev->digipal[0] = value; + dev->dirty |= DIRTY_PALETTE; + } + } +} + +static uint8_t +pc98x1_palette_a8_read(uint16_t addr, void *priv) +{ + /* ioport 0xa8 */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR] || dev->mode2[MODE2_16COLOR]) + return dev->anapal_select; + + return dev->digipal[0]; +} + +static void +pc98x1_palette_aa_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0xaa */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + if (dev->anapal[PALETTE_G][dev->anapal_select] != value) { + dev->anapal[PALETTE_G][dev->anapal_select] = value; + dev->dirty |= DIRTY_PALETTE; + } + } else if (dev->mode2[MODE2_16COLOR]) { + if (dev->anapal[PALETTE_G][dev->anapal_select & 0x0f] != (value & 0x0f)) { + dev->anapal[PALETTE_G][dev->anapal_select & 0x0f] = value & 0x0f; + dev->dirty |= DIRTY_PALETTE; + } + } else { + if (dev->digipal[1] != value) { + dev->digipal[1] = value; + dev->dirty |= DIRTY_PALETTE; + } + } +} + +static uint8_t +pc98x1_palette_aa_read(uint16_t addr, void *priv) +{ + /* ioport 0xaa */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) + return dev->anapal[PALETTE_G][dev->anapal_select]; + else if (dev->mode2[MODE2_16COLOR]) + return dev->anapal[PALETTE_G][dev->anapal_select & 0x0f]; + + return dev->digipal[1]; +} + +static void +pc98x1_palette_ac_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0xac */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + if (dev->anapal[PALETTE_R][dev->anapal_select] != value) { + dev->anapal[PALETTE_R][dev->anapal_select] = value; + dev->dirty |= DIRTY_PALETTE; + } + } else if (dev->mode2[MODE2_16COLOR]) { + if (dev->anapal[PALETTE_R][dev->anapal_select & 0x0f] != (value & 0x0f)) { + dev->anapal[PALETTE_R][dev->anapal_select & 0x0f] = value & 0x0f; + dev->dirty |= DIRTY_PALETTE; + } + } else { + if (dev->digipal[2] != value) { + dev->digipal[2] = value; + dev->dirty |= DIRTY_PALETTE; + } + } +} + +static uint8_t +pc98x1_palette_ac_read(uint16_t addr, void *priv) +{ + /* ioport 0xac */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) + return dev->anapal[PALETTE_R][dev->anapal_select]; + else if (dev->mode2[MODE2_16COLOR]) + return dev->anapal[PALETTE_R][dev->anapal_select & 0x0f]; + + return dev->digipal[2]; +} + +static void +pc98x1_palette_ae_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0xae */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + if (dev->anapal[PALETTE_B][dev->anapal_select] != value) { + dev->anapal[PALETTE_B][dev->anapal_select] = value; + dev->dirty |= DIRTY_PALETTE; + } + } else if (dev->mode2[MODE2_16COLOR]) { + if (dev->anapal[PALETTE_B][dev->anapal_select & 0x0f] != (value & 0x0f)) { + dev->anapal[PALETTE_B][dev->anapal_select & 0x0f] = value & 0x0f; + dev->dirty |= DIRTY_PALETTE; + } + } else { + if (dev->digipal[3] != value) { + dev->digipal[3] = value; + dev->dirty |= DIRTY_PALETTE; + } + } +} + +static uint8_t +pc98x1_palette_ae_read(uint16_t addr, void *priv) +{ + /* ioport 0xae */ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) + return dev->anapal[PALETTE_B][dev->anapal_select]; + else if (dev->mode2[MODE2_16COLOR]) + return dev->anapal[PALETTE_B][dev->anapal_select & 0x0f]; + + return dev->digipal[3]; +} + +/* horizontal frequency */ +static void +pc98x1_horiz_freq_write(uint16_t addr, uint8_t value, void *priv) +{ + /* ioport 0x9a8 */ +} + +static uint8_t +pc98x1_horiz_freq_read(uint16_t addr, void *priv) +{ + /* ioport 0x9a8 */ + return 0; +} + +/* memory */ +static void +pc98x1_tvram_writeb(uint32_t addr, uint8_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (addr < 0x3fe2) { + dev->tvram[addr] = value; + dev->dirty |= DIRTY_TVRAM; + } else if (addr < 0x4000) { + /* memory switch */ + if (dev->mode1[MODE1_MEMSW]) { + if (dev->tvram[addr] != value) { + dev->tvram[addr] = value; + /* save memory switch */ +// pc98x1_memsw_save(dev); + } + } + } else + pc98x1_cgwindow_writeb(dev, addr & 0x3fff, value); +} + +static void +pc98x1_tvram_writew(uint32_t addr, uint16_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (addr < 0x3fe2) { + *(uint16_t *)(dev->tvram + addr) = value; + dev->dirty |= DIRTY_TVRAM; + } else if (addr < 0x4000) { + /* memory switch */ + if (dev->mode1[MODE1_MEMSW]) { + if (*(uint16_t *)(dev->tvram + addr) != value) { + *(uint16_t *)(dev->tvram + addr) = value; + /* save memory switch */ +// pc98x1_memsw_save(dev); + } + } + } else + pc98x1_cgwindow_writew(dev, addr & 0x3fff, value); +} + +static void +pc98x1_tvram_writel(uint32_t addr, uint32_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (addr < 0x3fe2) { + *(uint32_t *)(dev->tvram + addr) = value; + dev->dirty |= DIRTY_TVRAM; + } else if (addr < 0x4000) { + /* memory switch */ + if (dev->mode1[MODE1_MEMSW]) { + if (*(uint32_t *)(dev->tvram + addr) != value) { + *(uint32_t *)(dev->tvram + addr) = value; + /* save memory switch */ +// pc98x1_memsw_save(dev); + } + } + } else + pc98x1_cgwindow_writel(dev, addr & 0x3fff, value); +} + +static uint8_t +pc98x1_tvram_readb(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (addr < 0x4000) + return dev->tvram[addr]; + + return pc98x1_cgwindow_readb(dev, addr & 0x3fff); +} + +static uint16_t +pc98x1_tvram_readw(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (addr < 0x4000) + return *(uint16_t *)(dev->tvram + addr); + + return pc98x1_cgwindow_readw(dev, addr & 0x3fff); +} + +static uint32_t +pc98x1_tvram_readl(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (addr < 0x4000) + return *(uint32_t *)(dev->tvram + addr); + + return pc98x1_cgwindow_readl(dev, addr & 0x3fff); +} + +static void +pc98x1_vram_writeb(uint32_t addr, uint8_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + if (addr < 0x8000) { + dev->vram256_draw_0[addr] = value; + dev->dirty |= dev->bank256_draw_0; + } else if (addr < 0x10000) { + dev->vram256_draw_1[addr & 0x7fff] = value; + dev->dirty |= dev->bank256_draw_1; + } + } else if (dev->grcg_mode & GRCG_CG_MODE) { + if (dev->mode2[MODE2_EGC]) + egc_mem_writeb(&dev->egc, addr, value); + else + pc98x1_grcg_mem_writeb(dev, addr, value); + + dev->dirty |= dev->bank_draw; + } else { + dev->vram16_draw_b[addr] = value; + dev->dirty |= dev->bank_draw; + } +} + +static void +pc98x1_vram_writew(uint32_t addr, uint16_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + if (addr < 0x8000) { + *(uint16_t *)(dev->vram256_draw_0 + addr) = value; + dev->dirty |= dev->bank256_draw_0; + } else if (addr < 0x10000) { + *(uint16_t *)(dev->vram256_draw_1 + (addr & 0x7fff)) = value; + dev->dirty |= dev->bank256_draw_1; + } + } else if (dev->grcg_mode & GRCG_CG_MODE) { + if (dev->mode2[MODE2_EGC]) + egc_mem_writew(&dev->egc, addr, value); + else + pc98x1_grcg_mem_writew(dev, addr, value); + + dev->dirty |= dev->bank_draw; + } else { + *(uint16_t *)(dev->vram16_draw_b + addr) = value; + dev->dirty |= dev->bank_draw; + } +} + +static void +pc98x1_vram_writel(uint32_t addr, uint32_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + if (addr < 0x8000) { + *(uint32_t *)(dev->vram256_draw_0 + addr) = value; + dev->dirty |= dev->bank256_draw_0; + } else if (addr < 0x10000) { + *(uint32_t *)(dev->vram256_draw_1 + (addr & 0x7fff)) = value; + dev->dirty |= dev->bank256_draw_1; + } + } else if (dev->grcg_mode & GRCG_CG_MODE) { + if (dev->mode2[MODE2_EGC]) { + egc_mem_writew(&dev->egc, addr, value & 0xffff); + egc_mem_writew(&dev->egc, addr + 2, value >> 16); + } else { + pc98x1_grcg_mem_writew(dev, addr, value & 0xffff); + pc98x1_grcg_mem_writew(dev, addr + 2, value >> 16); + } + dev->dirty |= dev->bank_draw; + } else { + *(uint32_t *)(dev->vram16_draw_b + addr) = value; + dev->dirty |= dev->bank_draw; + } +} + +static uint8_t +pc98x1_vram_readb(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + if (addr < 0x8000) + return dev->vram256_draw_0[addr]; + else if (addr < 0x10000) + return dev->vram256_draw_1[addr & 0x7fff]; + + return 0xff; + } else if (dev->grcg_mode & GRCG_CG_MODE) { + if (dev->mode2[MODE2_EGC]) + return egc_mem_readb(&dev->egc, addr); + else + return pc98x1_grcg_mem_readb(dev, addr); + } + + return dev->vram16_draw_b[addr]; +} + +static uint16_t +pc98x1_vram_readw(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + if (addr < 0x8000) + return *(uint16_t *)(dev->vram256_draw_0 + addr); + else if (addr < 0x10000) + return *(uint16_t *)(dev->vram256_draw_1 + (addr & 0x7fff)); + + return 0xffff; + } else if (dev->grcg_mode & GRCG_CG_MODE) { + if (dev->mode2[MODE2_EGC]) + return egc_mem_readw(&dev->egc, addr); + else + return pc98x1_grcg_mem_readw(dev, addr); + } + + return *(uint16_t *)(dev->vram16_draw_b + addr); +} + +static uint32_t +pc98x1_vram_readl(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint32_t value; + + if (dev->mode2[MODE2_256COLOR]) { + if (addr < 0x8000) + return *(uint32_t *)(dev->vram256_draw_0 + addr); + else if (addr < 0x10000) + return *(uint32_t *)(dev->vram256_draw_1 + (addr & 0x7fff)); + + return 0xffffffff; + } else if (dev->grcg_mode & GRCG_CG_MODE) { + if (dev->mode2[MODE2_EGC]) { + value = egc_mem_readw(&dev->egc, addr); + value |= egc_mem_readw(&dev->egc, addr + 2) << 16; + return value; + } else { + value = pc98x1_grcg_mem_readw(dev, addr); + value |= pc98x1_grcg_mem_readw(dev, addr + 2) << 16; + return value; + } + } + return *(uint32_t *)(dev->vram16_draw_b + addr); +} + +static void +pc98x1_vram_b0000_writeb(uint32_t addr, uint8_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->ems_selected) + dev->ems[addr] = value; + else + pc98x1_vram_writeb(addr + 0x8000, value, dev); +} + +static void +pc98x1_vram_b0000_writew(uint32_t addr, uint16_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->ems_selected) + *(uint16_t *)(dev->ems + addr) = value; + else + pc98x1_vram_writew(addr + 0x8000, value, dev); +} + +static void +pc98x1_vram_b0000_writel(uint32_t addr, uint32_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->ems_selected) + *(uint32_t *)(dev->ems + addr) = value; + else + pc98x1_vram_writel(addr + 0x8000, value, dev); +} + +static uint8_t +pc98x1_vram_b0000_readb(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->ems_selected) + return dev->ems[addr]; + + return pc98x1_vram_readb(addr + 0x8000, dev); +} + +static uint16_t +pc98x1_vram_b0000_readw(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->ems_selected) + return *(uint16_t *)(dev->ems + addr); + + return pc98x1_vram_readw(addr + 0x8000, dev); +} + +static uint32_t +pc98x1_vram_b0000_readl(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->ems_selected) + return *(uint32_t *)(dev->ems + addr); + + return pc98x1_vram_readl(addr + 0x8000, dev); +} + +static void +pc98x1_vram_e0000_writeb(uint32_t addr, uint8_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + static const uint32_t iomask8[4] = { 0xffffff00, 0xffff00ff, 0xff00ffff, 0x00ffffff }; + uint32_t src, prev, mask; + int offset; + bool rop_update = false; + + if (dev->mode2[MODE2_256COLOR]) { + switch (addr & 0x7fff) { + case 0x0004: + dev->vram256_bank_0 = value; + if (value & 0x08) + dev->bank256_draw_0 = DIRTY_VRAM1; + else + dev->bank256_draw_0 = DIRTY_VRAM0; + + dev->vram256_draw_0 = dev->vram256 dev (dev->vram256_bank_0 & 0x0f) * 0x8000; + break; + case 0x0006: + dev->vram256_bank_1 = value; + if (value & 0x08) + dev->bank256_draw_1 = DIRTY_VRAM1; + else + dev->bank256_draw_1 = DIRTY_VRAM0; + + dev->vram256_draw_1 = dev->vram256 + (dev->vram256_bank_1 & 0x0f) * 0x8000; + break; + case 0x0100: /*PEGC planar*/ + pclog("ToDo later."); + break; + default: + break; + } + } else + pc98x1_vram_writeb(addr + 0x18000, value, dev); +} + +static void +pc98x1_vram_e0000_writew(uint32_t addr, uint16_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) + pc98x1_vram_e0000_writeb(addr, valu, deve); + else + pc98x1_vram_writew(addr + 0x18000, value, dev); +} + +static void +pc98x1_vram_e0000_writel(uint32_t addr, uint32_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + pc98x1_vram_e0000_writew(addr, value & 0xffff, dev); + pc98x1_vram_e0000_writew(addr + 2, value >> 16, dev); + } else + pc98x1_vram_writel(addr + 0x18000, value, dev); +} + +static uint8_t +pc98x1_vram_e0000_readb(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + switch (addr & 0x7fff) { + case 0x0004: + return dev->vram256_bank_0 & 0xff; + case 0x0005: + return dev->vram256_bank_0 >> 8; + case 0x0006: + return dev->vram256_bank_1 & 0xff; + case 0x0007: + return dev->vram256_bank_1 >> 8; + case 0x0100: + return 0; /* support packed pixel only */ + default: + break; + } + return 0xff; + } + return pc98x1_vram_readb(addr + 0x18000, dev); +} + +static uint16_t +pc98x1_vram_e0000_readw(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + switch (addr & 0x7fff) { + case 0x0004: + return dev->vram256_bank_0; + case 0x0006: + return dev->vram256_bank_1; + case 0x0100: + return 0; /* support packed pixel only */ + default: + break; + } + return 0xffff; + } + return pc98x1_vram_readw(addr + 0x18000, dev); +} + +static uint32_t +pc98x1_vram_e0000_readl(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint32_t value = 0xffffffff; + + if (dev->mode2[MODE2_256COLOR]) { + value = pc98x1_vram_e0000_readw(addr, dev); + value |= (pc98x1_vram_e0000_readw(addr + 1, dev) << 16); + } else + value = pc98x1_vram_readl(opaque, addr + 0x18000); + + return value; +} + +static void +pc98x1_vram_f00000_writeb(uint32_t addr, uint8_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + dev->vram256[addr] = value; + if (addr & 0x40000) + dev->dirty |= DIRTY_VRAM1; + else if (addr < 0x10000) + dev->dirty |= DIRTY_VRAM0; + } +} + +static void +pc98x1_vram_f00000_writew(uint32_t addr, uint16_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + *(uint16_t *)(dev->vram256 + addr) = value; + if (addr & 0x40000) + dev->dirty |= DIRTY_VRAM1; + else if (addr < 0x10000) + dev->dirty |= DIRTY_VRAM0; + } +} + +static void +pc98x1_vram_f00000_writel(uint32_t addr, uint32_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) { + *(uint32_t *)(dev->vram256 + addr) = value; + if (addr & 0x40000) + dev->dirty |= DIRTY_VRAM1; + else if (addr < 0x10000) + dev->dirty |= DIRTY_VRAM0; + } +} + +static uint8_t +pc98x1_vram_f00000_readb(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) + return dev->vram256[addr]; + + return 0xff; +} + +static uint16_t +pc98x1_vram_f00000_readw(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) + return *(uint16_t *)(dev->vram256 + addr); + + return 0xffff; +} + +static uint32_t +pc98x1_vram_f00000_readl(uint32_t addr, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + + if (dev->mode2[MODE2_256COLOR]) + return *(uint32_t *)(dev->vram256 + addr); + + return 0xffffffff; +} + +/* gdc */ +static void +pc98x1_gdc_tvram_write(uint32_t addr1, uint8_t val, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint32_t addr = addr1 & 0x3fff; + + if (addr < 0x3fe2) + dev->tvram[addr] = value; +} + +static uint32_t +pc98x1_gdc_tvram_read(uint32_t addr1, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint32_t addr = addr1 & 0x3fff; + + return dev->tvram[addr]; +} + +static void +pc98x1_gdc_vram_write(uint32_t addr1, uint8_t value, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint32_t addr = addr1 & 0x1ffff; + + if (addr < 0x18000) + return pc98x1_vram_writeb(addr, value, dev); + + return pc98x1_vram_e0000_writeb(addr & 0x7fff, value, dev); +} + +static uint8_t +pc98x1_gdc_vram_read(uint32_t addr1, void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)priv; + uint32_t addr = addr1 & 0x1ffff; + + if (addr < 0x18000) + return pc98x1_vram_readb(addr, dev); + + return pc98x1_vram_e0000_readb(addr & 0x7fff, dev); +} + static void pc98x1_update_palette(pc98x1_vid_t *dev) { @@ -79,7 +1463,7 @@ pc98x1_update_palette(pc98x1_vid_t *dev) b = dev->anapal[PALETTE_B][i]; dev->palette_gfx[i] = makecol(r, g, b); } - } else if (s->mode2[MODE2_16COLOR]) { + } else if (dev->mode2[MODE2_16COLOR]) { for (i = 0; i < 16; i++) { r = dev->anapal[PALETTE_R][i] << 4; g = dev->anapal[PALETTE_G][i] << 4; @@ -134,7 +1518,7 @@ pc98x1_render_chr_screen(pc98x1_vid_t *dev) ysur = bl * sur; ysdr = bl * (sur + sdr); - if (s->mode1[MODE1_COLUMN]) { + if (dev->mode1[MODE1_COLUMN]) { xofs = 16; addrofs = 2; } else { @@ -196,7 +1580,7 @@ pc98x1_render_chr_screen(pc98x1_vid_t *dev) uint8_t pattern = dev->font[offset + l]; if (!(attr & ATTR_ST)) pattern = 0; - else if (((attr & ATTR_BL) && (s->blink & 0x20)) || + else if (((attr & ATTR_BL) && (dev->blink & 0x20)) || (attr & ATTR_RV)) pattern = ~pattern; @@ -235,7 +1619,7 @@ pc98x1_render_chr_screen(pc98x1_vid_t *dev) } static void -pc98x1_render_gfx_screen(pc98x1_t *dev) +pc98x1_render_gfx_screen(pc98x1_vid_t *dev) { uint8_t *dest; int x, y; @@ -271,9 +1655,9 @@ pc98x1_render_gfx_screen(pc98x1_t *dev) } else { uint32_t *addr = pc98x1_gdc_get_address(&dev->gdc_gfx, 1, 0x7fff); if (dev->bank_disp == DIRTY_VRAM0) - dest = s->vram0_buffer; + dest = dev->vram0_buffer; else - dest = s->vram1_buffer; + dest = dev->vram1_buffer; for (y = 0; y < 400; y++) { for (x = 0; x < 640; x += 8) { @@ -326,11 +1710,6 @@ pc98x1_vid_timer(void *priv) uint8_t *src_chr; uint8_t *src_gfx; - if (dev->mode2[MODE2_256COLOR] && dev->mode2[MODE2_480LINE]) - dev->height = 480; - else - dev->height = 400; - if (!dev->linepos) { timer_advance_u64(&dev->timer, dev->dispofftime); dev->linepos = 1; @@ -424,10 +1803,11 @@ pc98x1_vid_timer(void *priv) if (dev->crtv) { picint(1 << 2); dev->crtv = 0; - } + } else + picintc(1 << 2); } - if (dev->displine == dev->height + 32) { + if (dev->displine == (dev->height + 32)) { dev->vsync &= ~GDC_STAT_VSYNC; dev->dispon = 1; dev->displine = 0; @@ -451,9 +1831,6 @@ pc98x1_vid_timer(void *priv) video_blit_memtoscreen(0, 0, xsize, ysize); frames++; - video_res_x = dev->width; - video_res_y = dev->height; - video_bpp = 8; /* blink */ dev->blink++; if ((prev_blink & 0x20) != (dev->blink & 0x20)) { @@ -462,3 +1839,260 @@ pc98x1_vid_timer(void *priv) } } } + +/* font (based on Neko Project 2) */ +static void +pc98x1_kanji_copy(uint8_t *dst, uint8_t *src, int from, int to) +{ + int i, j, k; + uint8_t *p, *q; + + for (i = from; i < to; i++) { + p = src + 0x1800 + (0x60 * 32 * (i - 1)); + q = dst + 0x20000 + (i << 4); + for (j = 0x20; j < 0x80; j++) { + for (k = 0; k < 16; k++) { + *(q + 0x800) = *(p + 16); + *q++ = *p++; + } + p += 16; + q += 0x1000 - 16; + } + } +} + +static void +pc98x1_font_init(pc98x1_vid_t *dev) +{ + FILE *fp; + char *s; + uint8_t *buf = NULL; + uint8_t *p, *q; + int i, j; + + p = dev->font + 0x81000; + q = dev->font + 0x82000; + for (i = 0; i < 256; i++) { + q += 8; + for (j = 0; j < 4; j++) { + uint32_t bit = 0; + if (i & (1 << j)) + bit |= 0xf0f0f0f0; + if (i & (0x10 << j)) + bit |= 0x0f0f0f0f; + *(uint32_t *)p = bit; + p += 4; + *(uint16_t *)q = (uint16_t)bit; + q += 2; + } + } + for (i = 0; i < 0x80; i++) { + q = dev->font + (i << 12); + memset(q + 0x000, 0, 0x0560 - 0x000); + memset(q + 0x580, 0, 0x0d60 - 0x580); + memset(q + 0xd80, 0, 0x1000 - 0xd80); + } + s = machine_pc98.font_rom; //"roms/machines/pc98x1/font.rom"; + fp = rom_fopen(s, "rb"); + if (fp == NULL) + return; + + fseek(fp, 0, SEEK_SET); + buf = malloc(0x46800); + if (fread(s, 1, 0x46800, fp) == 0x46800) { + /* 8x8 font */ + uint8_t *dst = dev->font + 0x82000; + uint8_t *src = buf; + int cnt = 256; + while (cnt--) { + memcpy(dst, src, 8); + dst += 16; + src += 8; + } + /* 8x16 font */ + memcpy(dev->font + 0x80000, buf + 0x0800, 16 * 128); + memcpy(dev->font + 0x80800, buf + 0x1000, 16 * 128); + /* kanji font */ + pc98x1_kanji_copy(dev->font, buf, 0x01, 0x30); + pc98x1_kanji_copy(dev->font, buf, 0x30, 0x56); + pc98x1_kanji_copy(dev->font, buf, 0x58, 0x5d); + } + fclose(fp); + free(buf); +} + +static const uint8_t memsw_default[] = { + 0xe1, 0x48, 0xe1, 0x05, 0xe1, 0x0c, 0xe1, 0x00, + 0xe1, 0x01, 0xe1, 0x40, 0xe1, 0x00, 0xe1, 0x00, +}; + +static void +pc98x1_vid_reset(pc98x1_vid_t *dev) +{ + int i; + + dev->bank_disp = DIRTY_VRAM0; + dev->bank_draw = DIRTY_VRAM0; + dev->bank256_draw_0 = DIRTY_VRAM0; + dev->bank256_draw_1 = DIRTY_VRAM0; + + dev->vram16_disp_b = dev->vram16 + 0x00000; + dev->vram16_disp_r = dev->vram16 + 0x08000; + dev->vram16_disp_g = dev->vram16 + 0x10000; + dev->vram16_disp_e = dev->vram16 + 0x18000; + dev->vram16_draw_b = dev->vram16 + 0x00000; + dev->vram16_draw_r = dev->vram16 + 0x08000; + dev->vram16_draw_g = dev->vram16 + 0x10000; + dev->vram16_draw_e = dev->vram16 + 0x18000; + + dev->vram256_disp = dev->vram256; + dev->vram256_draw_0 = dev->vram256; + dev->vram256_draw_1 = dev->vram256; + + egc_set_vram(&dev->egc, dev->vram16_draw_b); + + gdc_reset(&dev->gdc_chr); + gdc_reset(&dev->gdc_gfx); + egc_reset(&dev->egc); + + dev->crtv = 1; + + dev->grcg_mode = 0; + dev->pl = 0; + dev->bl = 0x0f; + dev->cl = 0x10; + dev->ssl = 0; + dev->sur = 0; + dev->sdr = 24; + + dev->ems_selected = 0; + + memset(dev->mode1, 0, sizeof(dev->mode1)); + memset(dev->mode2, 0, sizeof(dev->mode2)); + memset(dev->mode3, 0, sizeof(dev->mode3)); + dev->mode_select = 0; + + dev->font_code = 0; + dev->font_line = 0; + pc98x1_cgwindow_set_addr(dev); + + /* reset palette */ + for (i = 0; i < 8; i++) { + dev->anapal[PALETTE_B][i] = (i & 1) ? 0x07 : 0; + dev->anapal[PALETTE_R][i] = (i & 2) ? 0x07 : 0; + dev->anapal[PALETTE_G][i] = (i & 4) ? 0x07 : 0; + } + for (i = 8; i < 16; i++) { + dev->anapal[PALETTE_B][i] = (i & 1) ? 0x0f : 0; + dev->anapal[PALETTE_R][i] = (i & 2) ? 0x0f : 0; + dev->anapal[PALETTE_G][i] = (i & 4) ? 0x0f : 0; + } + dev->anapal_select = 0; + + /* force redraw */ + dev->dirty = 0xff; + dev->blink = 0; + + dev->width = 640; + dev->height = 400; +} + +static void * +pc98x1_vid_init(UNUSED(const device_t *info)) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *)calloc(1, sizeof(pc98x1_vid_t)) + pc98x1_font_init(dev); /*To be improved further and its code to be moved onto loadfont()*/ + + for (int i = 0; i < 16; i++) + dev->tvram[0x3fe0 + (i << 1)] = memsw_default[i]; + + upd7220_init(&dev->gdc_chr, dev, pc98x1_gdc_tvram_read, pc98x1_gdc_tvram_write); + upd7220_init(&dev->gdc_gfx, dev, pc98x1_gdc_vram_read, pc98x1_gdc_vram_write); + egc_init(&dev->egc, dev); + + mem_mapping_add(&dev->tvram_mapping, 0xa0000, 0x08000, pc98x1_tvram_readb, pc98x1_tvram_readw, pc98x1_tvram_readl, pc98x1_tvram_writeb, pc98x1_tvram_writew, pc98x1_tvram_writel, NULL, MEM_MAPPING_EXTERNAL, dev); + mem_mapping_add(&dev->vram_a8000_mapping, 0xa8000, 0x08000, pc98x1_vram_readb, pc98x1_vram_readw, pc98x1_vram_readl, pc98x1_vram_writeb, pc98x1_vram_writew, pc98x1_vram_writel, NULL, MEM_MAPPING_EXTERNAL, dev); + mem_mapping_add(&dev->vram_b0000_mapping, 0xb0000, 0x10000, pc98x1_vram_b0000_readb, pc98x1_vram_b0000_readw, pc98x1_vram_b0000_readl, pc98x1_vram_b0000_writeb, pc98x1_vram_b0000_writew, pc98x1_vram_b0000_writel, NULL, MEM_MAPPING_EXTERNAL, dev); + + mem_mapping_add(&dev->vram_e0000_mapping, 0xe0000, 0x08000, pc98x1_vram_e0000_readb, pc98x1_vram_e0000_readw, pc98x1_vram_e0000_readl, pc98x1_vram_e0000_writeb, pc98x1_vram_e0000_writew, pc98x1_vram_e0000_writel, NULL, MEM_MAPPING_EXTERNAL, dev); + mem_mapping_add(&dev->vram_f00000_mapping, 0xf00000, 0xa0000, pc98x1_vram_f00000_readb, pc98x1_vram_f00000_readw, pc98x1_vram_f00000_readl, pc98x1_vram_f00000_writeb, pc98x1_vram_f00000_writew, pc98x1_vram_f00000_writel, NULL, MEM_MAPPING_EXTERNAL, dev); + + io_sethandler_interleaved(0x0060, 0x0001, upd7220_statreg_read, NULL, NULL, upd7220_param_write, NULL, NULL, &dev->gdc_chr); + io_sethandler_interleaved(0x0062, 0x0001, upd7220_data_read, NULL, NULL, upd7220_cmdreg_write, NULL, NULL, &dev->gdc_chr); + + io_sethandler_interleaved(0x0064, 0x0001, NULL, NULL, NULL, pc98x1_vsync_write, NULL, NULL, dev); + + io_sethandler_interleaved(0x0068, 0x0001, pc98x1_mode_flipflop1_read, NULL, NULL, pc98x1_mode_flipflop1_write, NULL, NULL, dev); + io_sethandler_interleaved(0x006a, 0x0001, pc98x1_mode_flipflop2_read, NULL, NULL, pc98x1_mode_flipflop2_write, NULL, NULL, dev); + io_sethandler_interleaved(0x006e, 0x0001, pc98x1_mode_flipflop3_read, NULL, NULL, pc98x1_mode_flipflop3_write, NULL, NULL, dev); + + io_sethandler_interleaved(0x0070, 0x0001, NULL, NULL, NULL, pc98x1_crtc_pl_write, NULL, NULL, dev); + io_sethandler_interleaved(0x0072, 0x0001, NULL, NULL, NULL, pc98x1_crtc_bl_write, NULL, NULL, dev); + io_sethandler_interleaved(0x0074, 0x0001, NULL, NULL, NULL, pc98x1_crtc_cl_write, NULL, NULL, dev); + io_sethandler_interleaved(0x0076, 0x0001, NULL, NULL, NULL, pc98x1_crtc_ssl_write, NULL, NULL, dev); + io_sethandler_interleaved(0x0078, 0x0001, NULL, NULL, NULL, pc98x1_crtc_sur_write, NULL, NULL, dev); + io_sethandler_interleaved(0x007a, 0x0001, NULL, NULL, NULL, pc98x1_crtc_sdr_write, NULL, NULL, dev); + + io_sethandler_interleaved(0x007c, 0x0001, NULL, NULL, NULL, pc98x1_grcg_mode_write, NULL, NULL, dev); + io_sethandler_interleaved(0x007e, 0x0001, NULL, NULL, NULL, pc98x1_grcg_tile_write, pc98x1_grcg_tile_writew, NULL, dev); + + io_sethandler_interleaved(0x00a0, 0x0001, upd7220_statreg_read, NULL, NULL, upd7220_param_write, NULL, NULL, &dev->gdc_gfx); + io_sethandler_interleaved(0x00a2, 0x0001, upd7220_data_read, NULL, NULL, upd7220_cmdreg_write, NULL, NULL, &dev->gdc_gfx); + + io_sethandler_interleaved(0x00a1, 0x0001, pc98x1_cgwindow_code2_read, NULL, NULL, pc98x1_cgwindow_code2_write, NULL, NULL, dev); + io_sethandler_interleaved(0x00a3, 0x0001, pc98x1_cgwindow_code1_read, NULL, NULL, pc98x1_cgwindow_code1_write, NULL, NULL, dev); + io_sethandler_interleaved(0x00a5, 0x0001, pc98x1_cgwindow_line_read, NULL, NULL, pc98x1_cgwindow_line_write, NULL, NULL, dev); + io_sethandler_interleaved(0x00a9, 0x0001, pc98x1_cgwindow_pattern_read, NULL, NULL, pc98x1_cgwindow_pattern_write, NULL, NULL, dev); + + io_sethandler_interleaved(0x00a4, 0x0001, pc98x1_vram_disp_read, NULL, NULL, pc98x1_vram_disp_write, NULL, NULL, dev); + io_sethandler_interleaved(0x00a6, 0x0001, pc98x1_vram_draw_read, NULL, NULL, pc98x1_vram_draw_write, NULL, NULL, dev); + + io_sethandler_interleaved(0x00a8, 0x0001, pc98x1_palette_a8_read, NULL, NULL, pc98x1_palette_a8_write, NULL, NULL, dev); + io_sethandler_interleaved(0x00aa, 0x0001, pc98x1_palette_aa_read, NULL, NULL, pc98x1_palette_aa_write, NULL, NULL, dev); + io_sethandler_interleaved(0x00ac, 0x0001, pc98x1_palette_ac_read, NULL, NULL, pc98x1_palette_ac_write, NULL, NULL, dev); + io_sethandler_interleaved(0x00ae, 0x0001, pc98x1_palette_ae_read, NULL, NULL, pc98x1_palette_ae_write, NULL, NULL, dev); + + io_sethandler_interleaved(0x04a0, 0x0010, NULL, NULL, NULL, egc_ioport_writeb, egc_ioport_writew, NULL, &dev->egc); + + io_sethandler_interleaved(0x09a0, 0x0001, pc98x1_mode_status_read, NULL, NULL, pc98x1_mode_select_write, NULL, NULL, dev); + + io_sethandler_interleaved(0x09a8, 0x0001, pc98x1_horiz_freq_read, NULL, NULL, pc98x1_horiz_freq_write, NULL, NULL, dev); + + pc98x1_vid_reset(dev); + + timer_add(&dev->timer, pc98x1_vid_timer, dev, 1); + return dev; +} + +static void +pc98x1_vid_close(void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *) priv; + + if (dev) + free(dev); +} + +static void +pc98x1_speed_changed(void *priv) +{ + pc98x1_vid_t *dev = (pc98x1_vid_t *) priv; + + upd7220_recalctimings(&dev->gdc_chr); + upd7220_recalctimings(&dev->gdc_gfx); +} + +// clang-format off +const device_t pc98x1_vid_device = { + .name = "NEC PC-98x1 Built-in Video", + .internal_name = "pc98x1_vid", + .flags = 0, + .local = 0, + .init = pc98x1_vid_init, + .close = pc98x1_vid_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = pc98x1_vid_speed_changed, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/video/vid_pc98x1_egc.c b/src/video/vid_pc98x1_egc.c index 63e78bdc4..f61795812 100644 --- a/src/video/vid_pc98x1_egc.c +++ b/src/video/vid_pc98x1_egc.c @@ -32,6 +32,7 @@ #include <86box/device.h> #include <86box/video.h> #include <86box/vid_pc98x1_egc.h> +#include <86box/vid_pc98x1_disp.h> #include <86box/plat_unused.h> /***********************************************************/ @@ -956,6 +957,82 @@ static const uint16_t egc_maskword[16][4] = { {0x0000, 0xffff, 0xffff, 0xffff}, {0xffff, 0xffff, 0xffff, 0xffff} }; + +void +egc_mem_writeb(egc_t *dev, uint32_t addr1, uint8_t value) +{ + uint32_t addr = addr1 & 0x7fff; + uint32_t ext = addr1 & 1; + egcquad_t data; + + if ((dev->ope & 0x0300) == 0x0200) { + dev->patreg.b[0][ext] = dev->vram_b[addr]; + dev->patreg.b[1][ext] = dev->vram_r[addr]; + dev->patreg.b[2][ext] = dev->vram_g[addr]; + dev->patreg.b[3][ext] = dev->vram_e[addr]; + } + data.q = egc_opeb(dev, addr, value); + if (dev->mask2.b[ext]) { + if (!(dev->access & 1)) { + dev->vram_b[addr] &= ~dev->mask2.b[ext]; + dev->vram_b[addr] |= data.b[0][ext] & dev->mask2.b[ext]; + } + if (!(dev->access & 2)) { + dev->vram_r[addr] &= ~dev->mask2.b[ext]; + dev->vram_r[addr] |= data.b[1][ext] & dev->mask2.b[ext]; + } + if (!(dev->access & 4)) { + dev->vram_g[addr] &= ~dev->mask2.b[ext]; + dev->vram_g[addr] |= data.b[2][ext] & dev->mask2.b[ext]; + } + if (!(dev->access & 8)) { + dev->vram_e[addr] &= ~dev->mask2.b[ext]; + dev->vram_e[addr] |= data.b[3][ext] & dev->mask2.b[ext]; + } + } +} + +void +egc_mem_writew(egc_t *dev, uint32_t addr1, uint16_t value) +{ + uint32_t addr = addr1 & 0x7fff; + egcquad_t data; + + if (!(addr & 1)) { + if ((dev->ope & 0x0300) == 0x0200) { + dev->patreg.w[0] = *(uint16_t *)(&dev->vram_b[addr]); + dev->patreg.w[1] = *(uint16_t *)(&dev->vram_r[addr]); + dev->patreg.w[2] = *(uint16_t *)(&dev->vram_g[addr]); + dev->patreg.w[3] = *(uint16_t *)(&dev->vram_e[addr]); + } + data.q = egc_opew(dev, addr, value); + if (dev->mask2.w) { + if (!(dev->access & 1)) { + *(uint16_t *)(&dev->vram_b[addr]) &= ~dev->mask2.w; + *(uint16_t *)(&dev->vram_b[addr]) |= data.w[0] & dev->mask2.w; + } + if (!(dev->access & 2)) { + *(uint16_t *)(&dev->vram_r[addr]) &= ~dev->mask2.w; + *(uint16_t *)(&dev->vram_r[addr]) |= data.w[1] & dev->mask2.w; + } + if (!(dev->access & 4)) { + *(uint16_t *)(&dev->vram_g[addr]) &= ~dev->mask2.w; + *(uint16_t *)(&dev->vram_g[addr]) |= data.w[2] & dev->mask2.w; + } + if (!(dev->access & 8)) { + *(uint16_t *)(&dev->vram_e[addr]) &= ~dev->mask2.w; + *(uint16_t *)(&dev->vram_e[addr]) |= data.w[3] & dev->mask2.w; + } + } + } else if (!(dev->sft & 0x1000)) { + egc_mem_writeb(s, addr1, value & 0xff); + egc_mem_writeb(s, addr1 + 1, (value >> 8) & 0xff); + } else { + egc_mem_writeb(s, addr1, (value >> 8) & 0xff); + egc_mem_writeb(s, addr1 + 1, value & 0xff); + } +} + uint8_t egc_mem_readb(egc_t *dev, uint32_t addr1) { @@ -1048,81 +1125,6 @@ egc_mem_readw(egc_t *dev, uint32_t addr1) } } -void -egc_mem_writeb(egc_t *dev, uint32_t addr1, uint8_t value) -{ - uint32_t addr = addr1 & 0x7fff; - uint32_t ext = addr1 & 1; - egcquad_t data; - - if ((dev->ope & 0x0300) == 0x0200) { - dev->patreg.b[0][ext] = dev->vram_b[addr]; - dev->patreg.b[1][ext] = dev->vram_r[addr]; - dev->patreg.b[2][ext] = dev->vram_g[addr]; - dev->patreg.b[3][ext] = dev->vram_e[addr]; - } - data.q = egc_opeb(dev, addr, value); - if (dev->mask2.b[ext]) { - if (!(dev->access & 1)) { - dev->vram_b[addr] &= ~dev->mask2.b[ext]; - dev->vram_b[addr] |= data.b[0][ext] & dev->mask2.b[ext]; - } - if (!(dev->access & 2)) { - dev->vram_r[addr] &= ~dev->mask2.b[ext]; - dev->vram_r[addr] |= data.b[1][ext] & dev->mask2.b[ext]; - } - if (!(dev->access & 4)) { - dev->vram_g[addr] &= ~dev->mask2.b[ext]; - dev->vram_g[addr] |= data.b[2][ext] & dev->mask2.b[ext]; - } - if (!(dev->access & 8)) { - dev->vram_e[addr] &= ~dev->mask2.b[ext]; - dev->vram_e[addr] |= data.b[3][ext] & dev->mask2.b[ext]; - } - } -} - -void -egc_mem_writew(egc_t *dev, uint32_t addr1, uint16_t value) -{ - uint32_t addr = addr1 & 0x7fff; - egcquad_t data; - - if (!(addr & 1)) { - if ((dev->ope & 0x0300) == 0x0200) { - dev->patreg.w[0] = *(uint16_t *)(&dev->vram_b[addr]); - dev->patreg.w[1] = *(uint16_t *)(&dev->vram_r[addr]); - dev->patreg.w[2] = *(uint16_t *)(&dev->vram_g[addr]); - dev->patreg.w[3] = *(uint16_t *)(&dev->vram_e[addr]); - } - data.q = egc_opew(dev, addr, value); - if (dev->mask2.w) { - if (!(dev->access & 1)) { - *(uint16_t *)(&dev->vram_b[addr]) &= ~dev->mask2.w; - *(uint16_t *)(&dev->vram_b[addr]) |= data.w[0] & dev->mask2.w; - } - if (!(dev->access & 2)) { - *(uint16_t *)(&dev->vram_r[addr]) &= ~dev->mask2.w; - *(uint16_t *)(&dev->vram_r[addr]) |= data.w[1] & dev->mask2.w; - } - if (!(dev->access & 4)) { - *(uint16_t *)(&dev->vram_g[addr]) &= ~dev->mask2.w; - *(uint16_t *)(&dev->vram_g[addr]) |= data.w[2] & dev->mask2.w; - } - if (!(dev->access & 8)) { - *(uint16_t *)(&dev->vram_e[addr]) &= ~dev->mask2.w; - *(uint16_t *)(&dev->vram_e[addr]) |= data.w[3] & dev->mask2.w; - } - } - } else if (!(dev->sft & 0x1000)) { - egc_mem_writeb(s, addr1, value & 0xff); - egc_mem_writeb(s, addr1 + 1, (value >> 8) & 0xff); - } else { - egc_mem_writeb(s, addr1, (value >> 8) & 0xff); - egc_mem_writeb(s, addr1 + 1, value & 0xff); - } -} - /* i/o */ void @@ -1130,7 +1132,7 @@ egc_ioport_writeb(uint16_t addr, uint8_t value, void *priv) { /* ioport 0x4a0 - 0x4af */ egc_t *dev = (egc_t *)priv; - pc98x1_vid_t *vid = (pc98x1_vid_t *)dev->vid; + pc98x1_vid_t *vid = (pc98x1_vid_t *)dev->priv; if (!((vid->grcg_mode & GRCG_CG_MODE) && vid->mode2[MODE2_EGC])) return; @@ -1220,7 +1222,7 @@ egc_ioport_writew(uint16_t addr, uint16_t value, void *priv) { /* ioport 0x4a0 - 0x4af */ egc_t *dev = (egc_t *)priv; - pc98x1_vid_t *vid = (pc98x1_vid_t *)dev->vid; + pc98x1_vid_t *vid = (pc98x1_vid_t *)dev->priv; if (!((vid->grcg_mode & GRCG_CG_MODE) && vid->mode2[MODE2_EGC])) return; @@ -1277,10 +1279,6 @@ egc_set_vram(egc_t *dev, uint8_t *vram_ptr) void egc_reset(egc_t *dev) { - pc98x1_vid_t *vid = (pc98x1_vid_t *)dev->vid; - memset(dev, 0, sizeof(egc_t)); - - dev->priv = vid; dev->access = 0xfff0; dev->fgbg = 0x00ff; dev->mask.w = 0xffff; diff --git a/src/video/vid_upd7220.c b/src/video/vid_upd7220.c index 989663239..94c94df68 100644 --- a/src/video/vid_upd7220.c +++ b/src/video/vid_upd7220.c @@ -31,10 +31,9 @@ #include <86box/device.h> #include <86box/video.h> #include <86box/vid_upd7220.h> +#include <86box/vid_pc98x1_disp.h> #include <86box/plat_unused.h> -static video_timings_t timing_upd7220 = { .type = 0, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; - /***********************************************************/ /* NEC uPD7220 GDC (based on Neko Project 2) */ @@ -54,11 +53,45 @@ static const int gdc_vectdir[16][4] = { { 0,-1,-1,-1}, {-1,-1,-1, 0}, {-1, 0,-1, 1}, {-1, 1, 0, 1} }; +void +upd7220_recalctimings(upd7220_t *dev) +{ + pc98x1_vid_t *vid = (pc98x1_vid_t *) dev->priv; + double crtcconst; + double _dispontime; + double _dispofftime; + + if (vid->mode2[MODE2_256COLOR] && vid->mode2[MODE2_480LINE]) + vid->clock = (uint64_t)(cpuclock / 25175000.0 * (double) (1ULL << 32)); + else + vid->clock = (uint64_t)(cpuclock / 21052600.0 * (double) (1ULL << 32)); + + vid->width = MIN(96, dev->sync[1] + 2); + vid->height = MIN(512, ((dev->sync[7] & 0x03) << 8) | (dev->sync[6])); + + vid->hblank = ((dev->sync[2] & 0x1f) + (dev->sync[4] & 0x3f) + 2) * 8; + vid->htotal = ((dev->sync[3] >> 2) + 1) * 8; + + crtcconst = vid->clock * 8.0; + _dispontime = vid->htotal - vid->hblank; + _dispofftime = vid->hblank; + + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + vid->dispontime = (uint64_t) (_dispontime); + vid->dispofftime = (uint64_t) (_dispofftime); + if (vid->dispontime < TIMER_USEC) + vid->dispontime = TIMER_USEC; + if (vid->dispofftime < TIMER_USEC) + vid->dispofftime = TIMER_USEC; +} + static void upd7220_draw_pset(upd7220_t *dev, int x, int y) { uint16_t dot = dev->pattern & 1; - uint32_t addr = y * 80 + (x >> 3) + 0x8000; + uint32_t addr = (y * 80) + (x >> 3) + 0x8000; uint8_t bit = 0x80 >> (x & 7); uint8_t cur = dev->vram_read(dev->priv, addr); @@ -444,6 +477,7 @@ upd7220_cmd_reset(upd7220_t *dev) dev->statreg = 0; dev->cmdreg = -1; dev->dirty = 0xff; + upd7220_recalctimings(dev); } static void @@ -455,6 +489,7 @@ upd7220_cmd_sync(upd7220_t *dev) dev->sync[i] = dev->params[i]; dev->cmdreg = -1; + upd7220_recalctimings(dev); } static void @@ -981,7 +1016,7 @@ upd7220_statreg_read(uint16_t addr, void *priv) { /* ioport 0x60(chr), 0xa0(gfx) */ upd7220_t *dev = (upd7220_t *) priv; - pc98x1_vid_t *vid = (pc98x1_vid_t *)dev->vid; + pc98x1_vid_t *vid = (pc98x1_vid_t *) dev->priv; uint8_t value = dev->statreg | vid->vsync; #if 0