From 8ec67527c61bec3ee30ec7d0872e1b8893724ca9 Mon Sep 17 00:00:00 2001 From: waltje Date: Thu, 23 May 2019 13:52:57 -0500 Subject: [PATCH] Small fixes here and there. Removed the crashdump code completely. Applied the first batch of upstream changes. Changed files to deal with new tmrval_t type (include timer.h at top.) Added the first "floppy controller card", part of the new framework. Hopefully fixed the Sigma Color 400 - works OK on DTK now. --- src/config.c | 51 +- src/config.h | 4 +- src/device.c | 2 +- src/devices/chipsets/intel4x0.c | 4 +- src/devices/disk/hdc_st506_xt.c | 65 ++- src/devices/disk/hdc_xtide.c | 2 +- src/devices/disk/hdd_image.c | 59 ++- src/devices/disk/zip.c | 26 +- src/devices/floppy/fdc.c | 37 +- src/devices/floppy/fdc.h | 18 +- src/devices/floppy/fdc_pii15xb.c | 202 ++++++++ src/devices/floppy/fdc_pii15xb.h | 59 +++ src/devices/floppy/fdd_86f.c | 2 +- src/devices/input/keyboard.h | 3 +- src/devices/input/keyboard_at.c | 5 +- src/devices/input/keyboard_xt.c | 29 +- src/devices/input/mouse.c | 9 +- src/devices/input/mouse.h | 4 +- src/devices/input/mouse_serial.c | 32 +- src/devices/scsi/scsi_cdrom.c | 32 +- src/devices/scsi/scsi_disk.c | 8 +- src/devices/scsi/scsi_ncr5380.c | 63 ++- src/devices/scsi/scsi_x54x.c | 1 + src/devices/sound/snd_sb_dsp.c | 10 +- src/devices/system/clk.c | 63 ++- src/devices/system/clk.h | 5 +- src/devices/system/dma.c | 65 ++- src/devices/system/dma.h | 18 +- src/devices/system/nvr_at.c | 114 +++-- src/devices/system/pic.c | 5 + src/devices/video/vid_ati28800.c | 29 +- src/devices/video/vid_ati_mach64.c | 3 +- src/devices/video/vid_cga_compaq.c | 81 +-- src/devices/video/vid_cl54xx.c | 5 +- src/devices/video/vid_et4000.c | 7 +- src/devices/video/vid_et4000w32.c | 3 +- src/devices/video/vid_genius.c | 765 ++++++++++++++++++----------- src/devices/video/vid_ht216.c | 7 +- src/devices/video/vid_im1024.c | 141 ++---- src/devices/video/vid_pgc.c | 313 ++++++++---- src/devices/video/vid_pgc.h | 8 +- src/devices/video/vid_s3.c | 13 +- src/devices/video/vid_s3_virge.c | 5 +- src/devices/video/vid_sigma.c | 544 +++++++++++--------- src/devices/video/vid_tgui9440.c | 31 +- src/devices/video/vid_tvga.c | 13 +- src/devices/video/vid_voodoo.c | 3 +- src/machines/m_compaq.c | 4 +- src/machines/m_olim24.c | 43 +- src/machines/m_tandy1000.c | 8 +- src/machines/m_tosh1x00.c | 2 +- src/machines/machine.h | 17 +- src/pc.c | 28 +- src/win/mingw/Makefile.MinGW | 19 +- src/win/msvc/Makefile.VC | 17 +- src/win/win.c | 7 +- src/win/win.h | 8 +- src/win/win_crashdump.c | 262 ---------- src/win/win_d3d.cpp | 13 +- src/win/win_devconf.c | 4 +- src/win/win_joystick.cpp | 244 ++++++--- src/win/win_mouse.cpp | 208 +++++++- src/win/win_ui.c | 5 +- 63 files changed, 2451 insertions(+), 1406 deletions(-) create mode 100644 src/devices/floppy/fdc_pii15xb.c create mode 100644 src/devices/floppy/fdc_pii15xb.h delete mode 100644 src/win/win_crashdump.c diff --git a/src/config.c b/src/config.c index 3df0274..3518679 100644 --- a/src/config.c +++ b/src/config.c @@ -12,7 +12,7 @@ * on Windows XP, possibly Vista and several UNIX systems. * Use the -DANSI_CFG for use on these systems. * - * Version: @(#)config.c 1.0.48 2019/05/17 + * Version: @(#)config.c 1.0.48 2019/05/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -818,6 +818,32 @@ load_other(config_t *cfg, const char *cat) char temp[128], *p; int c; + if (machine_get_flags_fixed() & MACHINE_FDC) { + config_delete_var(cat, "fdc"); + cfg->fdc_type = FDC_INTERNAL; + } else { + p = config_get_string(cat, "fdc", NULL); + if (p == NULL) { + if (machine_get_flags() & MACHINE_FDC) + p = "internal"; + else + p = "none"; + } +#if 0 /* not yet */ + cfg->fdc_type = fdc_get_from_internal_name(p); +#else + if (! strcmp(p, "none")) + cfg->fdc_type = 0; + if (! strcmp(p, "internal")) + cfg->fdc_type = 1; + + if (! strcmp(p, "dtk_pii151b")) + cfg->fdc_type = 10; + if (! strcmp(p, "dtk_pii158b")) + cfg->fdc_type = 11; +#endif + } + if (machine_get_flags_fixed() & MACHINE_HDC) { config_delete_var(cat, "hdc"); cfg->hdc_type = HDC_INTERNAL; @@ -874,6 +900,29 @@ save_other(const config_t *cfg, const char *cat) char temp[512]; int c; + if (cfg->fdc_type == FDC_NONE) + config_delete_var(cat, "fdc"); + else { +#if 0 /* not yet */ + config_set_string(cat, "fdc", + fdc_get_internal_name(cfg->fdc_type)); +#else + switch(cfg->fdc_type) { + case FDC_NONE: + strcpy(temp, "none"); break; + + case FDC_INTERNAL: + strcpy(temp, "internal"); break; + + case 10: + strcpy(temp, "dtk_pii151b"); break; + + case 11: + strcpy(temp, "dtk_pii158b"); break; + } +#endif + } + if (cfg->hdc_type == HDC_NONE) config_delete_var(cat, "hdc"); else diff --git a/src/config.h b/src/config.h index 19dfcbe..5e1ec13 100644 --- a/src/config.h +++ b/src/config.h @@ -8,7 +8,7 @@ * * Configuration file handler header. * - * Version: @(#)config.h 1.0.4 2019/05/04 + * Version: @(#)config.h 1.0.5 2019/05/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -116,6 +116,8 @@ typedef struct { // FIXME: ZIP + int fdc_type; /* FDC type (ISA) */ + int hdc_type, /* HDC type */ ide_ter_enabled, ide_qua_enabled; diff --git a/src/device.c b/src/device.c index bcb2979..7a2f3c0 100644 --- a/src/device.c +++ b/src/device.c @@ -100,7 +100,7 @@ device_flags(uint32_t flags) char *p = NULL; if (flags == DEVICE_ROOT) - return("[ROOT]"); + return("[ ROOT ]"); strcpy(sp, "[ "); sp += strlen(sp); diff --git a/src/devices/chipsets/intel4x0.c b/src/devices/chipsets/intel4x0.c index 8b5c696..2395042 100644 --- a/src/devices/chipsets/intel4x0.c +++ b/src/devices/chipsets/intel4x0.c @@ -8,7 +8,7 @@ * * Implementation of the Intel 430/440 PCISet chipsets. * - * Version: @(#)intel4x0.c 1.0.7 2019/05/13 + * Version: @(#)intel4x0.c 1.0.7 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -336,7 +336,7 @@ i4x0_init(const device_t *info, UNUSED(void *parent)) else dev->regs[0x57] = 0x31; dev->regs[0x60] = dev->regs[0x61] = dev->regs[0x62] = \ - dev->regs[0x63] = 0x02; + dev->regs[0x63] = 0x02; dev->regs[0x64] = 0x02; if (dev->chip >= INTEL_430FX) dev->regs[0x72] = 0x02; diff --git a/src/devices/disk/hdc_st506_xt.c b/src/devices/disk/hdc_st506_xt.c index 90e5c79..18b6332 100644 --- a/src/devices/disk/hdc_st506_xt.c +++ b/src/devices/disk/hdc_st506_xt.c @@ -41,12 +41,14 @@ * Since all controllers (including the ones made by DTC) use * (mostly) the same API, we keep them all in this module. * - * Version: @(#)hdc_st506_xt.c 1.0.22 2019/05/17 + * Version: @(#)hdc_st506_xt.c 1.0.23 2019/05/17 * * Authors: Fred N. van Kempen, + * Miran Grca, * Sarah Walker, * * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2019 Miran Grca. * Copyright 2008-2018 Sarah Walker. * * This program is free software; you can redistribute it and/or modify @@ -108,7 +110,7 @@ /* Status register. */ -#define STAT_REQ 0x01 /* controller ready */ +#define STAT_REQ 0x01 /* ready for new request */ #define STAT_IO 0x02 /* input, data to host */ #define STAT_CD 0x04 /* command mode (else data) */ #define STAT_BSY 0x08 /* controller is busy */ @@ -291,6 +293,9 @@ st506_complete(hdc_t *dev) dev->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY; dev->state = STATE_COMPLETION_BYTE; + if (dev->irq_dma & DMA_ENA) + dma_set_drq(dev->dma, 0); + if (dev->irq_dma & IRQ_ENA) { dev->status |= STAT_IRQ; picint(1 << dev->irq); @@ -395,7 +400,7 @@ st506_callback(priv_t priv) int val; /* Cancel the timer for now. */ - dev->callback = 0LL; + dev->callback = 0; /* Get the drive info. Note that the API supports up to 8 drives! */ dev->drive_sel = (dev->command[1] >> 5) & 0x07; @@ -409,7 +414,7 @@ st506_callback(priv_t priv) DEBUG("ST506: TEST_READY(%i) = %i\n", dev->drive_sel, drive->present); if (! drive->present) - st506_error(dev, ERR_NOT_READY); //AVAILABLE + st506_error(dev, ERR_NOT_READY); st506_complete(dev); break; @@ -420,7 +425,7 @@ st506_callback(priv_t priv) dev->drive_sel, drive->present); if (! drive->present) { st506_error(dev, ERR_NOT_READY); - st506_complete(dev); //AVAILABLE + st506_complete(dev); break; } @@ -600,13 +605,12 @@ st506_callback(priv_t priv) dev->status = STAT_BSY | STAT_IO | STAT_REQ; if (dev->irq_dma & DMA_ENA) { dev->callback = ST506_TIME; - dev->status |= STAT_DRQ; + dma_set_drq(dev->dma, 1); } dev->state = STATE_SEND_DATA; break; case STATE_SEND_DATA: - dev->status &= ~STAT_DRQ; for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { val = dma_channel_write(dev->dma, dev->buff[dev->buff_pos]); if (val == DMA_NODATA) { @@ -615,9 +619,10 @@ st506_callback(priv_t priv) st506_complete(dev); return; } - dev->callback = ST506_TIME; - dev->state = STATE_SENT_DATA; } + dma_set_drq(dev->dma, 0); + dev->callback = ST506_TIME; + dev->state = STATE_SENT_DATA; break; case STATE_SENT_DATA: @@ -645,7 +650,7 @@ st506_callback(priv_t priv) dev->status = STAT_BSY | STAT_IO | STAT_REQ; if (dev->irq_dma & DMA_ENA) { dev->callback = ST506_TIME; - dev->status |= STAT_DRQ; + dma_set_drq(dev->dma, 1); } dev->state = STATE_SEND_DATA; break; @@ -681,13 +686,12 @@ st506_callback(priv_t priv) dev->status = STAT_BSY | STAT_REQ; if (dev->irq_dma & DMA_ENA) { dev->callback = ST506_TIME; - dev->status |= STAT_DRQ; + dma_set_drq(dev->dma, 1); } dev->state = STATE_RECEIVE_DATA; break; case STATE_RECEIVE_DATA: - dev->status &= ~STAT_DRQ; for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { val = dma_channel_read(dev->dma); if (val == DMA_NODATA) { @@ -697,10 +701,11 @@ st506_callback(priv_t priv) return; } dev->buff[dev->buff_pos] = val & 0xff; - - dev->callback = ST506_TIME; - dev->state = STATE_RECEIVED_DATA; } + + dma_set_drq(dev->dma, 0); + dev->callback = ST506_TIME; + dev->state = STATE_RECEIVED_DATA; break; case STATE_RECEIVED_DATA: @@ -728,7 +733,7 @@ st506_callback(priv_t priv) dev->status = STAT_BSY | STAT_REQ; if (dev->irq_dma & DMA_ENA) { dev->callback = ST506_TIME; - dev->status |= STAT_DRQ; + dma_set_drq(dev->dma, 1); } dev->state = STATE_RECEIVE_DATA; break; @@ -794,13 +799,12 @@ st506_callback(priv_t priv) dev->status = STAT_BSY | STAT_IO | STAT_REQ; if (dev->irq_dma & DMA_ENA) { dev->callback = ST506_TIME; - dev->status |= STAT_DRQ; + dma_set_drq(dev->dma, 1); } dev->state = STATE_SEND_DATA; break; case STATE_SEND_DATA: - dev->status &= ~STAT_DRQ; for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { val = dma_channel_write(dev->dma, dev->buff[dev->buff_pos]); if (val == DMA_NODATA) { @@ -809,9 +813,11 @@ st506_callback(priv_t priv) st506_complete(dev); return; } - dev->callback = ST506_TIME; - dev->state = STATE_SENT_DATA; } + + dma_set_drq(dev->dma, 0); + dev->callback = ST506_TIME; + dev->state = STATE_SENT_DATA; break; case STATE_SENT_DATA: @@ -831,13 +837,12 @@ st506_callback(priv_t priv) dev->status = STAT_BSY | STAT_REQ; if (dev->irq_dma & DMA_ENA) { dev->callback = ST506_TIME; - dev->status |= STAT_DRQ; + dma_set_drq(dev->dma, 1); } dev->state = STATE_RECEIVE_DATA; break; case STATE_RECEIVE_DATA: - dev->status &= ~STAT_DRQ; for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { val = dma_channel_read(dev->dma); if (val == DMA_NODATA) { @@ -847,10 +852,11 @@ st506_callback(priv_t priv) return; } dev->buff[dev->buff_pos] = val & 0xff; - - dev->state = STATE_RECEIVED_DATA; - dev->callback = ST506_TIME; } + + dma_set_drq(dev->dma, 0); + dev->callback = ST506_TIME; + dev->state = STATE_RECEIVED_DATA; break; case STATE_RECEIVED_DATA: @@ -1188,6 +1194,8 @@ st506_read(uint16_t port, priv_t priv) case 1: /* read status */ ret = dev->status; + if ((dev->irq_dma & DMA_ENA) && dma_get_drq(dev->dma)) + ret |= STAT_DRQ; break; case 2: /* read option jumpers */ @@ -1248,6 +1256,13 @@ st506_write(uint16_t port, uint8_t val, priv_t priv) case 3: /* DMA/IRQ enable register */ dev->irq_dma = val; + if (! (dev->irq_dma & DMA_ENA)) + dma_set_drq(dev->dma, 0); + + if (! (dev->irq_dma & IRQ_ENA)) { + dev->status &= ~STAT_IRQ; + picintc(1 << dev->irq); + } break; } } diff --git a/src/devices/disk/hdc_xtide.c b/src/devices/disk/hdc_xtide.c index a835d29..eef5146 100644 --- a/src/devices/disk/hdc_xtide.c +++ b/src/devices/disk/hdc_xtide.c @@ -240,7 +240,7 @@ const device_t xtide_acculogic_device = { const device_t xtide_at_ps2_device = { "PS/2 AT XTIDE (1.1.5)", - DEVICE_ISA | DEVICE_PS2, + DEVICE_ISA, (HDD_BUS_IDE << 8) | 3, ROM_PATH_PS2_AT, xtide_init, xtide_close, NULL, diff --git a/src/devices/disk/hdd_image.c b/src/devices/disk/hdd_image.c index a8bdeeb..90f6d3a 100644 --- a/src/devices/disk/hdd_image.c +++ b/src/devices/disk/hdd_image.c @@ -14,13 +14,13 @@ * merged with hdd.c, since that is the scope of hdd.c. The * actual format handlers can then be in hdd_format.c etc. * - * Version: @(#)hdd_image.c 1.0.9 2018/10/24 + * Version: @(#)hdd_image.c 1.0.10 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -781,11 +781,23 @@ void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { hdd_image_t *img = &hdd_images[id]; + uint32_t i; - img->pos = sector; - + /* Move to the desired position in the image. */ fseeko64(img->file, ((uint64_t)sector << 9LL) + img->base, SEEK_SET); - fread(buffer, 1, count << 9, img->file); + + /* Now read all (consecutive) blocks from the image. */ + for (i = 0; i < count; i++) { + /* If past end of image, give up. */ + if (feof(img->file)) + break; + + /* Read a block. */ + fread(buffer + (i << 9), 1, 512, img->file); + + /* Update position. */ + img->pos = sector + i; + } } @@ -826,11 +838,23 @@ void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { hdd_image_t *img = &hdd_images[id]; + uint32_t i; - img->pos = sector; - + /* Move to the desired position in the image. */ fseeko64(img->file, ((uint64_t)sector << 9LL) + img->base, SEEK_SET); - fwrite(buffer, count << 9, 1, img->file); + + /* Now write all (consecutive) blocks to the image. */ + for (i = 0; i < count; i++) { + /* If past end of image, give up. */ + if (feof(img->file)) + break; + + /* Write a block. */ + fwrite(buffer + (i << 9), 512, 1, img->file); + + /* Update position. */ + img->pos = sector + i; + } } @@ -865,12 +889,21 @@ hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) memset(empty, 0x00, sizeof(empty)); - img->pos = sector; - + /* Move to the desired position in the image. */ fseeko64(img->file, ((uint64_t)sector << 9LL) + img->base, SEEK_SET); - for (i = 0; i < count; i++) - fwrite(empty, 512, 1, img->file); + /* Now write all (consecutive) blocks to the image. */ + for (i = 0; i < count; i++) { + /* If past end of image, give up. */ + if (feof(img->file)) + break; + + /* Write a block. */ + fwrite(empty, 512, 1, img->file); + + /* Update position. */ + img->pos = sector + i; + } } diff --git a/src/devices/disk/zip.c b/src/devices/disk/zip.c index 0ab5b62..3a7e6be 100644 --- a/src/devices/disk/zip.c +++ b/src/devices/disk/zip.c @@ -9,7 +9,7 @@ * Implementation of the Iomega ZIP drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)zip.c 1.0.26 2019/05/17 + * Version: @(#)zip.c 1.0.27 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -1096,6 +1096,8 @@ data_phase_error(zip_t *dev) static int zip_blocks(zip_t *dev, int32_t *len, int first_batch, int out) { + int i; + *len = 0; if (! dev->sector_len) { @@ -1114,10 +1116,16 @@ zip_blocks(zip_t *dev, int32_t *len, int first_batch, int out) *len = dev->requested_blocks << 9; fseek(dev->drv->f, dev->drv->base + (dev->sector_pos << 9), SEEK_SET); - if (out) - fwrite(dev->buffer, 1, *len, dev->drv->f); - else - fread(dev->buffer, 1, *len, dev->drv->f); + + for (i = 0; i < dev->requested_blocks; i++) { + if (feof(dev->drv->f)) + break; + + if (out) + fwrite(dev->buffer + (i << 9), 1, 512, dev->drv->f); + else + fread(dev->buffer + (i << 9), 1, 512, dev->drv->f); + } DEBUG("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); @@ -1590,8 +1598,12 @@ do_command(void *p, uint8_t *cdb) break; } +#if 0 if ((dev->sector_pos >= dev->drv->medium_size) || ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)) { +#else + if ((dev->sector_pos >= dev->drv->medium_size)) { +#endif lba_out_of_range(dev); return; } @@ -1648,8 +1660,12 @@ do_command(void *p, uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; +#if 0 if ((dev->sector_pos >= dev->drv->medium_size) || ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)) { +#else + if ((dev->sector_pos >= dev->drv->medium_size)) { +#endif lba_out_of_range(dev); return; } diff --git a/src/devices/floppy/fdc.c b/src/devices/floppy/fdc.c index 07c7976..a1822e0 100644 --- a/src/devices/floppy/fdc.c +++ b/src/devices/floppy/fdc.c @@ -9,7 +9,7 @@ * Implementation of the NEC uPD-765 and compatible floppy disk * controller. * - * Version: @(#)fdc.c 1.0.24 2019/05/17 + * Version: @(#)fdc.c 1.0.24 2019/05/20 * * Authors: Miran Grca, * Sarah Walker, @@ -105,17 +105,19 @@ static const int command_has_drivesel[256] = { #ifdef ENABLE_FDC_LOG int fdc_do_log = ENABLE_FDC_LOG; #endif -uint8_t current_drive = 0; -int lastbyte = 0; int floppymodified[FDD_NUM]; int floppyrate[FDD_NUM]; +static int lastbyte = 0; +static uint8_t current_drive = 0; + + static void fdc_callback(priv_t priv); #ifdef _LOGGING -static void +void fdc_log(int level, const char *fmt, ...) { # ifdef ENABLE_FDC_LOG @@ -2141,7 +2143,7 @@ fdc_set_base(fdc_t *fdc, int base) { int super_io = (fdc->flags & FDC_FLAG_SUPERIO); - if (fdc->flags & FDC_FLAG_AT) { + if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_sethandler(base + (super_io ? 2 : 0), super_io ? 4 : 6, fdc_read,NULL,NULL, fdc_write,NULL,NULL, fdc); io_sethandler(base+7, 1, @@ -2165,7 +2167,7 @@ fdc_remove(fdc_t *fdc) { int super_io = (fdc->flags & FDC_FLAG_SUPERIO); - if (fdc->flags & FDC_FLAG_AT) { + if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_removehandler(fdc->base_address + (super_io?2:0), super_io?4:6, fdc_read,NULL,NULL, fdc_write,NULL,NULL, fdc); io_removehandler(fdc->base_address+7, 1, @@ -2283,7 +2285,8 @@ fdc_init(const device_t *info, UNUSED(void *parent)) else fdc->dma_ch = 2; - DEBUG("FDC: %04X (flags: %08X)\n", fdc->base_address, fdc->flags); + DEBUG("FDC: %s (I/O=%04X, flags=%08x)\n", + info->name, fdc->base_address, fdc->flags); timer_add(fdc_callback, fdc, &fdc->time, &fdc->time); @@ -2318,6 +2321,16 @@ const device_t fdc_xt_device = { NULL }; +const device_t fdc_xt_amstrad_device = { + "PC/XT Floppy Drive Controller (Amstrad)", + 0, + FDC_FLAG_DISKCHG_ACTLOW | FDC_FLAG_AMSTRAD, + NULL, + fdc_init, fdc_close, fdc_reset, + NULL, NULL, NULL, NULL, + NULL +}; + const device_t fdc_pcjr_device = { "PCjr Floppy Drive Controller", 0, @@ -2397,3 +2410,13 @@ const device_t fdc_toshiba_device = { NULL, NULL, NULL, NULL, NULL }; + +const device_t fdc_dp8473_device = { + "NS DP8473 Floppy Drive Controller", + 0, + FDC_FLAG_NSDP, + NULL, + fdc_init, fdc_close, fdc_reset, + NULL, NULL, NULL, NULL, + NULL +}; diff --git a/src/devices/floppy/fdc.h b/src/devices/floppy/fdc.h index 745f40a..74b8e94 100644 --- a/src/devices/floppy/fdc.h +++ b/src/devices/floppy/fdc.h @@ -8,14 +8,14 @@ * * Definitions for the floppy disk controller driver. * - * Version: @(#)fdc.h 1.0.8 2019/05/13 + * Version: @(#)fdc.h 1.0.9 2019/05/20 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. * Copyright 2008-2018 Sarah Walker. * * This program is free software; you can redistribute it and/or modify @@ -40,6 +40,12 @@ # define EMU_FDC_H +/* Controller types. */ +#define FDC_NONE 0 +#define FDC_INTERNAL 1 + + +/* FDC internal flags. */ #define FDC_FLAG_PCJR 0x01 /* PCjr */ #define FDC_FLAG_DISKCHG_ACTLOW 0x02 /* Amstrad, PS/1, PS/2 ISA */ #define FDC_FLAG_AT 0x04 /* AT+, PS/x */ @@ -49,6 +55,8 @@ #define FDC_FLAG_MORE_TRACKS 0x40 /* W83877F, W83977F, PC87306, PC87309 */ #define FDC_FLAG_NSC 0x80 /* PC87306, PC87309 */ #define FDC_FLAG_TOSHIBA 0x100 /* Toshiba TC8565 (T1200) */ +#define FDC_FLAG_AMSTRAD 0x200 /* Non-AT Amstrad machines */ +#define FDC_FLAG_NSDP 0x400 /* DP8473N, DP8473V */ typedef struct { @@ -105,7 +113,9 @@ typedef struct { #ifdef EMU_DEVICE_H extern const device_t fdc_xt_device; +extern const device_t fdc_xt_amstrad_device; extern const device_t fdc_toshiba_device; +extern const device_t fdc_dp8473_device; extern const device_t fdc_pcjr_device; extern const device_t fdc_at_device; extern const device_t fdc_at_actlow_device; @@ -116,6 +126,8 @@ extern const device_t fdc_at_nsc_device; #endif +extern void fdc_log(int level, const char *fmt, ...); + extern void fdc_remove(fdc_t *fdc); extern void fdc_poll(fdc_t *fdc); extern void fdc_abort(fdc_t *fdc); diff --git a/src/devices/floppy/fdc_pii15xb.c b/src/devices/floppy/fdc_pii15xb.c new file mode 100644 index 0000000..f78982f --- /dev/null +++ b/src/devices/floppy/fdc_pii15xb.c @@ -0,0 +1,202 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the DTK PII-151B and PII-158B cards. + * + * These are DP8473-based floppy controller ISA cards for XT + * class systems, and allow usage of standard and high-density + * drives on them. They have their own BIOS which takes over + * from the standard system BIOS. + * + * Version: @(#)fdc_pii15xb.c 1.0.1 2019/05/20 + * + * Author: Fred N. van Kempen, + * + * Copyright 2019 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#define dbglog fdc_log +#include "../../emu.h" +//#include "../../timer.h" +//#include "../../io.h" +#include "../../mem.h" +#include "../../rom.h" +#include "../../device.h" +#include "../../plat.h" +#include "fdd.h" +#include "fdc.h" +#include "fdc_pii15xb.h" + + +typedef struct { + const char *name; + int type; + + uint32_t bios_addr, + bios_size; + rom_t bios_rom; + + fdc_t *fdc; +} pii_t; + + +/* Load and enable a BIOS ROM if we have one, and is enabled. */ +static void +set_bios(pii_t *dev, const wchar_t *fn) +{ + uint32_t temp; + FILE *fp; + + /* Only do this if needed. */ + if ((fn == NULL) || (dev->bios_addr == 0)) return; + + if ((fp = rom_fopen(fn, L"rb")) == NULL) return; + + (void)fseek(fp, 0L, SEEK_END); + temp = ftell(fp); + (void)fclose(fp); + + /* Assume 128K, then go down. */ + dev->bios_size = 0x020000; + while (temp < dev->bios_size) + dev->bios_size >>= 1; + + /* Create a memory mapping for the space. */ + rom_init(&dev->bios_rom, fn, dev->bios_addr, + dev->bios_size, dev->bios_size-1, 0, MEM_MAPPING_EXTERNAL); +} + + +static void +pii_close(priv_t priv) +{ + pii_t *dev = (pii_t *)priv; + + free(dev); +} + + +static priv_t +pii_init(const device_t *info, UNUSED(void *parent)) +{ + pii_t *dev; + + dev = (pii_t *)mem_alloc(sizeof(pii_t)); + memset(dev, 0x00, sizeof(pii_t)); + dev->type = info->local; + + dev->bios_addr = device_get_config_hex20("bios_addr"); + + if (info->path && dev->bios_addr != 0x000000) + set_bios(dev, info->path); + + /* Attach the DP8473 chip. */ + dev->fdc = (fdc_t *)device_add_parent(&fdc_dp8473_device, (priv_t)dev); + + INFO("FDC: %s (I/O=%04X, flags=%08x)\n", + info->name, dev->fdc->base_address, dev->fdc->flags); + + return((priv_t)dev); +} + + +static const device_config_t pii_config[] = { + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0x0ce000, + { + { + "Disabled", 0 + }, + { + "CA00H", 0x0ca000 + }, + { + "CC00H", 0x0cc000 + }, + { + "CE00H", 0x0ce000 + }, + { + NULL + } + } + }, + { + "speed", "Drive Speed", CONFIG_SELECTION, "", 0, + { + { + "Single", 0 + }, + { + "Dual", 1 + }, + { + NULL + } + } + }, + { + NULL, + } +}; + +const device_t fdc_pii151b_device = { + "DTK PII-151B (MiniMicro) Floppy Drive Controller", + DEVICE_ISA, + 151, + PII_151B_BIOS_PATH, + pii_init, pii_close, NULL, + NULL, NULL, NULL, NULL, + pii_config +}; + +const device_t fdc_pii158b_device = { + "DTK PII-158B (MiniMicro4) Floppy Drive Controller", + DEVICE_ISA, + 158, + PII_158B_BIOS_PATH, + pii_init, pii_close, NULL, + NULL, NULL, NULL, NULL, + pii_config +}; diff --git a/src/devices/floppy/fdc_pii15xb.h b/src/devices/floppy/fdc_pii15xb.h new file mode 100644 index 0000000..ac7584e --- /dev/null +++ b/src/devices/floppy/fdc_pii15xb.h @@ -0,0 +1,59 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the DTK PII-151B and PII-158B cards. + * + * Version: @(#)fdc_pii15xb.h 1.0.1 2019/05/20 + * + * Author: Fred N. van Kempen, + * + * Copyright 2019 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef FLOPPY_PII15XB_H +# define FLOPPY_PII15XB_H + + +#define PII_151B_BIOS_PATH L"floppy/dtk/pii-15x/pii-151b.rom" +#define PII_158B_BIOS_PATH L"floppy/dtk/pii-15x/pii-158b.rom" + + +extern const device_t fdc_pii151b_device; +extern const device_t fdc_pii158b_device; + + +#endif /*FLOPPY_PII15XB_H*/ diff --git a/src/devices/floppy/fdd_86f.c b/src/devices/floppy/fdd_86f.c index a70f161..e37c58b 100644 --- a/src/devices/floppy/fdd_86f.c +++ b/src/devices/floppy/fdd_86f.c @@ -3074,7 +3074,7 @@ d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) if (track_table) tbl = track_table; - if (!fdd_doublestep_40(drive)) { + if (! fdd_doublestep_40(drive)) { d86f_decompose_encoded_buffer(drive, 0); if (sides == 2) d86f_decompose_encoded_buffer(drive, 1); diff --git a/src/devices/input/keyboard.h b/src/devices/input/keyboard.h index 0644fc3..cce6aaf 100644 --- a/src/devices/input/keyboard.h +++ b/src/devices/input/keyboard.h @@ -8,7 +8,7 @@ * * Definitions for the keyboard interface. * - * Version: @(#)keyboard.h 1.0.15 2019/05/13 + * Version: @(#)keyboard.h 1.0.16 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -85,6 +85,7 @@ extern const device_t keyboard_pc_device; extern const device_t keyboard_pc82_device; extern const device_t keyboard_xt_device; extern const device_t keyboard_xt86_device; +extern const device_t keyboard_xt_compaq_device; extern const device_t keyboard_generic_device; extern const device_t keyboard_tandy_device; extern const device_t keyboard_laserxt3_device; diff --git a/src/devices/input/keyboard_at.c b/src/devices/input/keyboard_at.c index 2f853f8..4f0a12d 100644 --- a/src/devices/input/keyboard_at.c +++ b/src/devices/input/keyboard_at.c @@ -16,7 +16,7 @@ * it either will not process ctrl-alt-esc, or it will not do * ANY input. * - * Version: @(#)keyboard_at.c 1.0.28 2019/05/13 + * Version: @(#)keyboard_at.c 1.0.29 2019/05/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -2739,14 +2739,13 @@ kbd_write(uint16_t port, uint8_t val, priv_t priv) case 0xd4: /* write to mouse */ DEBUG("ATkbd: write to mouse (%02x)\n", val); + /* FIXME: What does this do? --FvK */ if (val == 0xbb) break; set_enable_mouse(dev, 1); if (mouse_write && (KBC_TYPE(dev) >= KBC_TYPE_PS2_NOREF)) mouse_write(val, mouse_p); - else if (!mouse_write && (KBC_TYPE(dev) >= KBC_TYPE_PS2_NOREF)) - keyboard_at_adddata_mouse(0xff); break; default: diff --git a/src/devices/input/keyboard_xt.c b/src/devices/input/keyboard_xt.c index 46a6273..17011af 100644 --- a/src/devices/input/keyboard_xt.c +++ b/src/devices/input/keyboard_xt.c @@ -10,7 +10,7 @@ * * **NOTE** The key_queue stuff should be in the device data. * - * Version: @(#)keyboard_xt.c 1.0.19 2019/05/13 + * Version: @(#)keyboard_xt.c 1.0.20 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -686,13 +686,6 @@ kbd_write(uint16_t port, uint8_t val, priv_t priv) speaker_gated = val & 1; speaker_enable = val & 2; -#ifdef USE_CASSETTE - if (dev->type <= KBC_PC82) { - if (cassette_enabled) - cassette_motor(! (val & 0x08)); - } -#endif - if (speaker_enable) speaker_was_enable = 1; pit_set_gate(&pit, 2, val & 1); @@ -702,6 +695,15 @@ kbd_write(uint16_t port, uint8_t val, priv_t priv) dev->blocked = 0; picintc(2); } + + if (dev->type <= KBC_PC82) { +#ifdef USE_CASSETTE + if (cassette_enabled) + cassette_motor(! (val & 0x08)); +#endif + DEBUG("PPI: cassette motor is %s\n", (val & 0x08) ? "OFF" : "ON"); + DEBUG("PPI: cassette IN is %i\n", !!(val & 0x10)); + } break; case 0x63: @@ -779,7 +781,6 @@ kbd_read(uint16_t port, priv_t priv) /* Make the IBM PC BIOS happy (Cassette Interface.) */ if (dev->type <= KBC_PC82) ret |= (ppispeakon ? 0x10 : 0); - break; case 0x63: @@ -997,6 +998,16 @@ const device_t keyboard_xt86_device = { NULL }; +const device_t keyboard_xt_compaq_device = { + "Compaq Portable Keyboard", + 0, + KBC_GENERIC, /* wrong */ + NULL, + kbd_init, kbd_close, kbd_reset, + NULL, NULL, NULL, NULL, + NULL +}; + const device_t keyboard_generic_device = { "Generic XT Keyboard", 0, diff --git a/src/devices/input/mouse.c b/src/devices/input/mouse.c index 580813b..58bbe16 100644 --- a/src/devices/input/mouse.c +++ b/src/devices/input/mouse.c @@ -8,7 +8,7 @@ * * Common driver module for MOUSE devices. * - * Version: @(#)mouse.c 1.0.21 2019/05/13 + * Version: @(#)mouse.c 1.0.22 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -156,7 +156,7 @@ mouse_set_buttons(int buttons) void -mouse_process(void) +mouse_poll(void) { static int poll_delay = 2; @@ -165,7 +165,10 @@ mouse_process(void) if (--poll_delay) return; - mouse_poll(); +#ifdef USE_DINPUT + /* Grab mouse data from platform. */ + mouse_process(); +#endif if (mouse_func != NULL) { if (! mouse_func(mouse_x,mouse_y,mouse_z,mouse_buttons, mouse_priv)) { diff --git a/src/devices/input/mouse.h b/src/devices/input/mouse.h index 83cfe15..87f94fe 100644 --- a/src/devices/input/mouse.h +++ b/src/devices/input/mouse.h @@ -8,7 +8,7 @@ * * Definitions for the mouse driver. * - * Version: @(#)mouse.h 1.0.13 2019/05/13 + * Version: @(#)mouse.h 1.0.14 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -89,9 +89,9 @@ extern void mouse_init(void); extern void mouse_close(void); extern void mouse_reset(void); extern void mouse_set_buttons(int buttons); +extern void mouse_poll(void); extern void mouse_process(void); extern void mouse_set_poll(int (*f)(int,int,int,int,priv_t), priv_t); -extern void mouse_poll(void); extern void mouse_bus_set_irq(priv_t priv, int irq); diff --git a/src/devices/input/mouse_serial.c b/src/devices/input/mouse_serial.c index 6bb61eb..8e76495 100644 --- a/src/devices/input/mouse_serial.c +++ b/src/devices/input/mouse_serial.c @@ -10,13 +10,13 @@ * * TODO: Add the Genius Serial Mouse. * - * Version: @(#)mouse_serial.c 1.0.15 2019/04/25 + * Version: @(#)mouse_serial.c 1.0.16 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, * * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2018 Miran Grca. + * Copyright 2018,2019 Miran Grca. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -112,8 +112,8 @@ data_msystems(mouse_t *dev, int x, int y, int b) { dev->data[0] = 0x80; dev->data[0] |= (b & 0x01) ? 0x00 : 0x04; /* left button */ - dev->data[0] |= (b & 0x02) ? 0x00 : 0x01; /* middle button */ - dev->data[0] |= (b & 0x04) ? 0x00 : 0x02; /* right button */ + dev->data[0] |= (b & 0x04) ? 0x00 : 0x01; /* middle button */ + dev->data[0] |= (b & 0x02) ? 0x00 : 0x02; /* right button */ dev->data[1] = x; dev->data[2] = -y; dev->data[3] = x; /* same as byte 1 */ @@ -127,8 +127,8 @@ static uint8_t data_3bp(mouse_t *dev, int x, int y, int b) { dev->data[0] |= (b & 0x01) ? 0x00 : 0x04; /* left button */ - dev->data[0] |= (b & 0x02) ? 0x00 : 0x02; /* middle button */ - dev->data[0] |= (b & 0x04) ? 0x00 : 0x01; /* right button */ + dev->data[0] |= (b & 0x04) ? 0x00 : 0x02; /* middle button */ + dev->data[0] |= (b & 0x02) ? 0x00 : 0x01; /* right button */ dev->data[1] = x; dev->data[2] = -y; @@ -150,8 +150,8 @@ data_mmseries(mouse_t *dev, int x, int y, int b) if (y < 0) dev->data[0] |= 0x08; dev->data[0] |= (b & 0x01) ? 0x04 : 0x00; /* left button */ - dev->data[0] |= (b & 0x02) ? 0x02 : 0x00; /* middle button */ - dev->data[0] |= (b & 0x04) ? 0x01 : 0x00; /* right button */ + dev->data[0] |= (b & 0x04) ? 0x02 : 0x00; /* middle button */ + dev->data[0] |= (b & 0x02) ? 0x01 : 0x00; /* right button */ dev->data[1] = abs(x); dev->data[2] = abs(y); @@ -164,8 +164,8 @@ data_bp1(mouse_t *dev, int x, int y, int b) { dev->data[0] = 0x80; dev->data[0] |= (b & 0x01) ? 0x10 : 0x00; /* left button */ - dev->data[0] |= (b & 0x02) ? 0x08 : 0x00; /* middle button */ - dev->data[0] |= (b & 0x04) ? 0x04 : 0x00; /* right button */ + dev->data[0] |= (b & 0x04) ? 0x08 : 0x00; /* middle button */ + dev->data[0] |= (b & 0x02) ? 0x04 : 0x00; /* right button */ dev->data[1] = (x & 0x3f); dev->data[2] = (x >> 6); dev->data[3] = (y & 0x3f); @@ -227,8 +227,8 @@ data_hex(mouse_t *dev, int x, int y, int b) but = 0x00; but |= (b & 0x01) ? 0x04 : 0x00; /* left button */ - but |= (b & 0x02) ? 0x02 : 0x00; /* middle button */ - but |= (b & 0x04) ? 0x01 : 0x00; /* right button */ + but |= (b & 0x04) ? 0x02 : 0x00; /* middle button */ + but |= (b & 0x02) ? 0x01 : 0x00; /* right button */ /* Encode the packet as HEX values. */ sprintf(temp, "%02X%02X%01X", (int8_t)y, (int8_t)x, but & 0x0f); @@ -248,6 +248,10 @@ ser_report(mouse_t *dev, int x, int y, int z, int b) memset(dev->data, 0x00, sizeof(dev->data)); + /* If the mouse is 2-button, ignore the middle button. */ + if (dev->but == 2) + b &= ~0x04; + switch(dev->type) { case MOUSE_MSYSTEMS: len = data_msystems(dev, x, y, b); @@ -304,7 +308,6 @@ ser_report(mouse_t *dev, int x, int y, int z, int b) if (! dev->delay) dev->delay = dev->period; -//pclog(0,"SerMouse%d: report(%d), len=%d\n", dev->port,dev->type,dev->data_len); } @@ -315,7 +318,6 @@ ser_timer(void *priv) mouse_t *dev = (mouse_t *)priv; uint8_t b = 0x00; -//pclog(0,"SerMouse%d: timer, phase=%d pos=%d\n",dev->port,dev->phase,dev->pos); switch (dev->phase) { case PHASE_ID: /* Grab next ID byte. */ @@ -381,7 +383,6 @@ ser_timer(void *priv) /* Send byte if we can. */ if (dev->serial != NULL) { serial_write(dev->serial, &b, 1); -//pclog(0,"SerMouse%d: writing %02x\n",dev->port, b); } } @@ -392,7 +393,6 @@ ser_callback(void *serial, void *priv) { mouse_t *dev = (mouse_t *)priv; -pclog(0,"Serial%d: callback @%08lx\n", dev->port, dev->serial); if (serial == NULL) return; serial_clear(serial); diff --git a/src/devices/scsi/scsi_cdrom.c b/src/devices/scsi/scsi_cdrom.c index 92eef72..948bf59 100644 --- a/src/devices/scsi/scsi_cdrom.c +++ b/src/devices/scsi/scsi_cdrom.c @@ -1110,15 +1110,22 @@ read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *len) cdsize = dev->drv->ops->size(dev->drv); else { not_ready(dev); - return 0; + return -1; } + /* FIXME: + * Temporarily disabled this because the Triones ATAPI DMA driver + * seems to always request a 4-sector read but sets the DMA bus + * master to transfer less data than that. + */ +#if 0 if (dev->sector_pos >= cdsize) { DEBUG("CD-ROM %i: Trying to read from beyond the end of disc (%i >= %i)\n", dev->id, dev->sector_pos, cdsize); lba_out_of_range(dev); - return 0; + return -1; } +#endif if ((dev->sector_pos + dev->sector_len - 1) >= cdsize) { DEBUG("CD-ROM %i: Trying to read to beyond the end of disc (%i >= %i)\n", dev->id, @@ -1189,6 +1196,9 @@ read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch) DEBUG("Read %i bytes of blocks...\n", *len); + if (ret == -1) + return 0; + if (!ret || ((dev->old_len != *len) && !first_batch)) { if ((dev->old_len != *len) && !first_batch) illegal_mode(dev); @@ -2163,17 +2173,17 @@ do_command(void *p, uint8_t *cdb) memset(dev->buffer, 0, 36); dev->buffer[0] = 0; dev->buffer[1] = 34; - dev->buffer[2] = 1; /* track number (LSB) */ - dev->buffer[3] = 1; /* session number (LSB) */ - dev->buffer[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ - dev->buffer[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ - dev->buffer[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ + dev->buffer[2] = 1; /* track number (LSB) */ + dev->buffer[3] = 1; /* session number (LSB) */ + dev->buffer[5] = (0 << 5) | (0 << 4) | (4 << 0);/* not damaged, primary copy, data track */ + dev->buffer[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ + dev->buffer[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ if (dev->drv->ops && dev->drv->ops->size) { - dev->buffer[24] = (dev->drv->ops->size(dev->drv) >> 24) & 0xff; /* track size */ - dev->buffer[25] = (dev->drv->ops->size(dev->drv) >> 16) & 0xff; /* track size */ - dev->buffer[26] = (dev->drv->ops->size(dev->drv) >> 8) & 0xff; /* track size */ - dev->buffer[27] = dev->drv->ops->size(dev->drv) & 0xff; /* track size */ + dev->buffer[24] = ((dev->drv->ops->size(dev->drv) - 1) >> 24) & 0xff; /* track size */ + dev->buffer[25] = ((dev->drv->ops->size(dev->drv) - 1) >> 16) & 0xff; /* track size */ + dev->buffer[26] = ((dev->drv->ops->size(dev->drv) - 1) >> 8) & 0xff; /* track size */ + dev->buffer[27] = (dev->drv->ops->size(dev->drv) - 1) & 0xff; /* track size */ } else { not_ready(dev); buf_free(dev); diff --git a/src/devices/scsi/scsi_disk.c b/src/devices/scsi/scsi_disk.c index b4fcac3..6628196 100644 --- a/src/devices/scsi/scsi_disk.c +++ b/src/devices/scsi/scsi_disk.c @@ -813,7 +813,7 @@ disk_command(void *p, uint8_t *cdb) break; } - if ((dev->sector_pos > last_sector) || ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + if (dev->sector_pos > last_sector) { lba_out_of_range(dev); return; } @@ -879,8 +879,7 @@ disk_command(void *p, uint8_t *cdb) break; } - if ((dev->sector_pos > last_sector) || - ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + if (dev->sector_pos > last_sector) { lba_out_of_range(dev); return; } @@ -918,8 +917,7 @@ disk_command(void *p, uint8_t *cdb) DEBUG("SCSI DISK %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); - if ((dev->sector_pos > last_sector) || - ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + if (dev->sector_pos > last_sector) { lba_out_of_range(dev); return; } diff --git a/src/devices/scsi/scsi_ncr5380.c b/src/devices/scsi/scsi_ncr5380.c index 5b497c8..7ffafb7 100644 --- a/src/devices/scsi/scsi_ncr5380.c +++ b/src/devices/scsi/scsi_ncr5380.c @@ -1411,7 +1411,7 @@ ncr_init(const device_t *info, UNUSED(void *parent)) break; case 10: /* Longshine LCS6821N */ - ncr_dev->rom_addr = 0xDC000; + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); rom_init(&ncr_dev->bios_rom, info->path, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); @@ -1424,7 +1424,7 @@ ncr_init(const device_t *info, UNUSED(void *parent)) break; case 11: /* Rancho RT1000B */ - ncr_dev->rom_addr = 0xDC000; + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); rom_init(&ncr_dev->bios_rom, info->path, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); @@ -1437,12 +1437,13 @@ ncr_init(const device_t *info, UNUSED(void *parent)) break; case 12: /* Trantor T130B */ - ncr_dev->rom_addr = 0xDC000; + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); ncr_dev->base = device_get_config_hex16("base"); ncr_dev->irq = device_get_config_int("irq"); rom_init(&ncr_dev->bios_rom, info->path, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + mem_map_disable(&ncr_dev->bios_rom.mapping); mem_map_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, t130b_read, NULL, NULL, @@ -1493,6 +1494,35 @@ ncr_init(const device_t *info, UNUSED(void *parent)) } +static const device_config_t ncr5380_mmio_config[] = { + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xd8000, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "CC00H", 0xcc000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + NULL + } + } + }, + { + NULL + } +}; + static const device_config_t t130b_config[] = { { "base", "Address", CONFIG_HEX16, "", 0x0350, @@ -1531,6 +1561,29 @@ static const device_config_t t130b_config[] = { } } }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xd8000, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "CC00H", 0xcc000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + NULL + } + } + }, { NULL } @@ -1650,7 +1703,7 @@ const device_t scsi_lcs6821n_device = { LCS6821N_ROM, ncr_init, ncr_close, NULL, NULL, NULL, NULL, NULL, - NULL + ncr5380_mmio_config }; const device_t scsi_rt1000b_device = { @@ -1660,7 +1713,7 @@ const device_t scsi_rt1000b_device = { RT1000B_ROM, ncr_init, ncr_close, NULL, NULL, NULL, NULL, NULL, - NULL + ncr5380_mmio_config }; const device_t scsi_t130b_device = { diff --git a/src/devices/scsi/scsi_x54x.c b/src/devices/scsi/scsi_x54x.c index 684db59..df3545e 100644 --- a/src/devices/scsi/scsi_x54x.c +++ b/src/devices/scsi/scsi_x54x.c @@ -49,6 +49,7 @@ #include "../../emu.h" #include "../../timer.h" #include "../../io.h" +#include "../../cpu/cpu.h" #include "../../mem.h" #include "../../rom.h" #include "../../device.h" diff --git a/src/devices/sound/snd_sb_dsp.c b/src/devices/sound/snd_sb_dsp.c index 26076d7..b0e3802 100644 --- a/src/devices/sound/snd_sb_dsp.c +++ b/src/devices/sound/snd_sb_dsp.c @@ -14,14 +14,14 @@ * 486-50 - 32kHz * Pentium - 45kHz * - * Version: @(#)snd_sb_dsp.c 1.0.10 2019/05/13 + * Version: @(#)snd_sb_dsp.c 1.0.11 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2019 Miran Grca. * Copyright 2008-2018 Sarah Walker. * * This program is free software; you can redistribute it and/or modify @@ -249,12 +249,12 @@ void sb_dsp_speed_changed(sb_dsp_t *dsp) if (dsp->sb_timeo < 256LL) dsp->sblatcho = TIMER_USEC * (256LL - dsp->sb_timeo); else - dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256LL))); + dsp->sblatcho = (tmrval_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256LL))); if (dsp->sb_timei < 256LL) dsp->sblatchi = TIMER_USEC * (256LL - dsp->sb_timei); else - dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256LL))); + dsp->sblatchi = (tmrval_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256LL))); } void sb_add_data(sb_dsp_t *dsp, uint8_t v) @@ -455,7 +455,7 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x41: /*Set output sampling rate*/ case 0x42: /*Set input sampling rate*/ if (dsp->sb_type < SB16) break; - dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); + dsp->sblatcho = (tmrval_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); DBGLOG(1, "Sample rate - %ihz (%i)\n",dsp->sb_data[1]+(dsp->sb_data[0]<<8), dsp->sblatcho); temp = dsp->sb_freq; dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8); diff --git a/src/devices/system/clk.c b/src/devices/system/clk.c index b67bf73..95f0098 100644 --- a/src/devices/system/clk.c +++ b/src/devices/system/clk.c @@ -8,6 +8,18 @@ * * Implement the Intel 8284 Clock Generator functionality. * + * The clock generator is responsible for providing clocks for + * all peripheral components on the board. Originally, it used + * a single crystal oscillator (the 14.3MHz one) from which all + * others were derived (the 1.8Mhz clock for the PIT, the 4.77M + * for the processor and bus, and a buffered 14.3M for the video + * cards) but later, a second oscillator was added, allowing for + * a 'turbo' mode for the processor, where the processor speed + * was higher than the bus and peripheral speeds. + * + * On more modern systems, this functionality of course has been + * integrated into the chipsets. + * * Version: @(#)clk.c 1.0.2 2019/05/17 * * Authors: Fred N. van Kempen, @@ -49,15 +61,16 @@ #include "clk.h" -float cpuclock; -float bus_timing; +float cpu_clock; /* clock for the processor */ +float bus_timing; /* clock divider for the bus clock */ -double PITCONST; -float CGACONST; -float MDACONST; -float VGACONST1, +double PITCONST; /* divider for the PIT (i8254) */ + +float CGACONST; /* divider for the CGA controller */ +float MDACONST; /* divider for the MDA controller */ +float VGACONST1, /* divider for the VGA controllers */ VGACONST2; -float RTCCONST; +float RTCCONST; /* divider for the RTC */ /* Set default CPU/crystal clock and xt_cpu_multi. */ @@ -68,13 +81,13 @@ clk_setup(uint32_t freq) if (cpu_get_type() >= CPU_286) { /* For 286 and up, this is easy. */ - cpuclock = (float)freq; - PITCONST = cpuclock / 1193182.0; - CGACONST = (float) (cpuclock / (19687503.0 / 11.0)); + cpu_clock = (float)freq; + PITCONST = cpu_clock / 1193182.0; + CGACONST = (float) (cpu_clock / (19687503.0 / 11.0)); xt_cpu_multi = 1; } else { /* Not so much for XT-class systems. */ - cpuclock = 14318184.0; + cpu_clock = 14318184.0; PITCONST = 12.0; CGACONST = 8.0; xt_cpu_multi = 3; @@ -85,7 +98,7 @@ clk_setup(uint32_t freq) switch (speed) { case 7159092: /* 7.16 MHz */ if (cpu_get_flags() & CPU_ALTERNATE_XTAL) { - cpuclock = 28636368.0; + cpu_clock = 28636368.0; xt_cpu_multi = 4; } else xt_cpu_multi = 2; @@ -96,39 +109,39 @@ clk_setup(uint32_t freq) case 10000000: /* 10 MHz */ case 12000000: /* 12 MHz */ case 16000000: /* 16 MHz */ - cpuclock = ((float)speed * xt_cpu_multi); + cpu_clock = ((float)speed * xt_cpu_multi); break; default: if (cpu_get_flags() & CPU_ALTERNATE_XTAL) { - cpuclock = 28636368.0; + cpu_clock = 28636368.0; xt_cpu_multi = 6; } break; } - if (cpuclock == 28636368.0) { + if (cpu_clock == 28636368.0) { PITCONST = 24.0; CGACONST = 16.0; - } else if (cpuclock != 14318184.0) { - PITCONST = cpuclock / 1193182.0; - CGACONST = (float) (cpuclock / (19687503.0 / 11.0)); + } else if (cpu_clock != 14318184.0) { + PITCONST = cpu_clock / 1193182.0; + CGACONST = (float) (cpu_clock / (19687503.0 / 11.0)); } } xt_cpu_multi <<= TIMER_SHIFT; - MDACONST = (float) (cpuclock / 2032125.0); - VGACONST1 = (float) (cpuclock / 25175000.0); - VGACONST2 = (float) (cpuclock / 28322000.0); - RTCCONST = (float) (cpuclock / 32768.0); + MDACONST = (float) (cpu_clock / 2032125.0); + VGACONST1 = (float) (cpu_clock / 25175000.0); + VGACONST2 = (float) (cpu_clock / 28322000.0); + RTCCONST = (float) (cpu_clock / 32768.0); - TIMER_USEC = (tmrval_t)((cpuclock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); + TIMER_USEC = (tmrval_t)((cpu_clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); - bus_timing = (float) (cpuclock / (double)cpu_busspeed); + bus_timing = (float) (cpu_clock / (double)cpu_busspeed); INFO("CLK: cpu=%.2f xt=%d PIT=%.2f RTC=%.2f CGA=%.2f MDA=%.2f TMR=%" PRIu64 "\n", - cpuclock, xt_cpu_multi, (float)PITCONST, RTCCONST, CGACONST, MDACONST, + cpu_clock, xt_cpu_multi, (float)PITCONST, RTCCONST, CGACONST, MDACONST, TIMER_USEC); device_speed_changed(); diff --git a/src/devices/system/clk.h b/src/devices/system/clk.h index c473350..d14d68a 100644 --- a/src/devices/system/clk.h +++ b/src/devices/system/clk.h @@ -8,7 +8,7 @@ * * Definitions for Intel 8284 driver. * - * Version: @(#)clk.h 1.0.1 2019/05/05 + * Version: @(#)clk.h 1.0.2 2019/05/17 * * Author: Fred N. van Kempen, * @@ -36,6 +36,9 @@ # define EMU_CLK_H +extern float cpu_clock; +extern float bus_timing; + extern double PITCONST; extern float CGACONST, diff --git a/src/devices/system/dma.c b/src/devices/system/dma.c index 5a0f6a1..c655a20 100644 --- a/src/devices/system/dma.c +++ b/src/devices/system/dma.c @@ -8,7 +8,7 @@ * * Implementation of the Intel DMA controllers. * - * Version: @(#)dma.c 1.0.11 2019/05/13 + * Version: @(#)dma.c 1.0.12 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -61,8 +61,10 @@ static int dma_wp, static uint8_t dma_m; static uint8_t dma_stat; static uint8_t dma_stat_rq; +static uint8_t dma_stat_rq_pc; static uint8_t dma_command, dma16_command; + static struct { int xfr_command, xfr_channel; @@ -374,7 +376,9 @@ dma_read(uint16_t addr, UNUSED(priv_t priv)) return(temp); case 8: /*Status register*/ - temp = dma_stat & 0xf; + temp = dma_stat_rq_pc & 0xf; + temp <<= 4; + temp |= dma_stat & 0xf; dma_stat &= ~0xf; return(temp); @@ -417,12 +421,22 @@ dma_write(uint16_t addr, uint8_t val, UNUSED(priv_t priv)) dma[channel].cc = dma[channel].cb; return; - case 8: /*Control register*/ + case 8: /*Control register*/ dma_command = val; + if (val & 0x01) + fatal("DMA: memory-to-memory enable!\n"); return; + case 9: /*Request register */ + channel = (val & 0x03); + if (val & 0x04) + dma_stat_rq_pc |= (1 << channel); + else + dma_stat_rq_pc &= ~(1 << channel); + break; + case 0xa: /*Mask*/ - if (val & 4) + if (val & 0x04) dma_m |= (1 << (val & 3)); else dma_m &= ~(1 << (val & 3)); @@ -449,6 +463,7 @@ dma_write(uint16_t addr, uint8_t val, UNUSED(priv_t priv)) case 0xd: /*Master clear*/ dma_wp = 0; dma_m |= 0xf; + dma_stat_rq_pc &= ~0x0f; return; case 0xf: /*Mask write*/ @@ -492,7 +507,8 @@ dma16_read(uint16_t addr, UNUSED(priv_t priv)) return(temp); case 8: /*Status register*/ - temp = dma_stat >> 4; + temp = (dma_stat_rq_pc & 0xf0); + temp |= dma_stat >> 4; dma_stat &= ~0xf0; return(temp); } @@ -543,6 +559,14 @@ dma16_write(uint16_t addr, uint8_t val, UNUSED(priv_t priv)) case 8: /*Control register*/ return; + case 9: /*Request register */ + channel = (val & 3) + 4; + if (val & 4) + dma_stat_rq_pc |= (1 << channel); + else + dma_stat_rq_pc &= ~(1 << channel); + break; + case 0xa: /*Mask*/ if (val & 4) dma_m |= (0x10 << (val & 3)); @@ -571,6 +595,7 @@ dma16_write(uint16_t addr, uint8_t val, UNUSED(priv_t priv)) case 0xd: /*Master clear*/ dma16_wp = 0; dma_m |= 0xf0; + dma_stat_rq_pc &= ~0xf0; return; case 0xf: /*Mask write*/ @@ -662,12 +687,18 @@ dma_reset(void) dma[c].cb = 0; dma[c].size = (c & 4) ? 1 : 0; } + + dma_stat = 0x00; + dma_stat_rq = 0x00; + dma_stat_rq_pc = 0x00; } void dma_init(void) { + dma_reset(); + io_sethandler(0x0000, 16, dma_read,NULL,NULL, dma_write,NULL,NULL, NULL); io_sethandler(0x0080, 8, @@ -679,7 +710,9 @@ dma_init(void) void dma16_init(void) { - io_sethandler(0x00C0, 32, + dma_reset(); + + io_sethandler(0x00c0, 32, dma16_read,NULL,NULL, dma16_write,NULL,NULL, NULL); io_sethandler(0x0088, 8, dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); @@ -711,7 +744,7 @@ dma_alias_remove_piix(void) dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); io_removehandler(0x0098, 1, dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); - io_removehandler(0x009C, 3, + io_removehandler(0x009c, 3, dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); } @@ -719,6 +752,8 @@ dma_alias_remove_piix(void) void ps2_dma_init(void) { + dma_reset(); + io_sethandler(0x0018, 1, dma_ps2_read,NULL,NULL, dma_ps2_write,NULL,NULL, NULL); io_sethandler(0x001a, 1, @@ -727,6 +762,22 @@ ps2_dma_init(void) } +int +dma_get_drq(int channel) +{ + return !!(dma_stat_rq_pc & (1 << channel)); +} + + +void +dma_set_drq(int channel, int set) +{ + dma_stat_rq_pc &= ~(1 << channel); + if (set) + dma_stat_rq_pc |= (1 << channel); +} + + int dma_channel_read(int channel) { diff --git a/src/devices/system/dma.h b/src/devices/system/dma.h index 9b3be3a..06a84b4 100644 --- a/src/devices/system/dma.h +++ b/src/devices/system/dma.h @@ -8,14 +8,14 @@ * * Definitions for the Intel DMA controller. * - * Version: @(#)dma.h 1.0.3 2018/06/25 + * Version: @(#)dma.h 1.0.4 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. * Copyright 2008-2018 Sarah Walker. * * This program is free software; you can redistribute it and/or modify @@ -71,6 +71,9 @@ extern void ps2_dma_init(void); extern void dma_reset(void); extern int dma_mode(int channel); +extern int dma_get_drq(int channel); +extern void dma_set_drq(int channel, int set); + extern int dma_channel_read(int channel); extern int dma_channel_write(int channel, uint16_t val); @@ -79,15 +82,6 @@ extern void DMAPageRead(uint32_t PhysAddress, uint8_t *DataRead, extern void DMAPageWrite(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize); -#if 0 -extern void readdma0(void); -extern int readdma1(void); -extern uint8_t readdma2(void); -extern int readdma3(void); - -extern void writedma2(uint8_t temp); -#endif - extern void dma_alias_set(void); extern void dma_alias_remove(void); extern void dma_alias_remove_piix(void); diff --git a/src/devices/system/nvr_at.c b/src/devices/system/nvr_at.c index 99cc7c3..01a6298 100644 --- a/src/devices/system/nvr_at.c +++ b/src/devices/system/nvr_at.c @@ -197,7 +197,7 @@ * Sarah Walker, * * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2019 Miran Grca. * Copyright 2008-2018 Sarah Walker. * * This program is free software; you can redistribute it and/or modify @@ -290,7 +290,7 @@ typedef struct { uint8_t addr; - tmrval_t ecount, + tmrval_t ecount, rtctime; } local_t; @@ -446,23 +446,73 @@ timer_update(priv_t priv) } -/* Re-calculate the timer values. */ -static void -timer_recalc(nvr_t *nvr, int add) +static double +nvr_period(nvr_t *nvr) { - local_t *local = (local_t *)nvr->data; - tmrval_t c, nt; + double dusec = (double)TIMER_USEC; + double ret = 0.0; - c = 1ULL << ((nvr->regs[RTC_REGA] & REGA_RS) - 1); - nt = (tmrval_t)(RTCCONST * c * (1LL << TIMER_SHIFT)); + switch (nvr->regs[RTC_REGA] & REGA_RS) { + case 0: + default: + break; - if (add == 2) { - local->rtctime = nt; - return; - } else if (add == 1) - local->rtctime += nt; - else if (local->rtctime > nt) - local->rtctime = nt; + case 1: + case 8: + ret = 3906.25; + break; + + case 2: + case 9: + ret = 7812.5; + break; + + case 3: + ret = 122.070; + break; + + case 4: + ret = 244.141; + break; + + case 5: + ret = 488.281; + break; + + case 6: + ret = 976.5625; + break; + + case 7: + ret = 1953.125; + break; + + case 10: + ret = 15625.0; + break; + + case 11: + ret = 31250.0; + break; + + case 12: + ret = 62500.0; + break; + + case 13: + ret = 125000.0; + break; + + case 14: + ret = 250000.0; + break; + + case 15: + ret = 500000.0; + break; + } + + return(ret * dusec); } @@ -472,14 +522,13 @@ timer_intr(priv_t priv) nvr_t *nvr = (nvr_t *)priv; local_t *local = (local_t *)nvr->data; - if (! (nvr->regs[RTC_REGA] & REGA_RS)) { - local->rtctime = 0x7fffffff; + if (nvr->regs[RTC_REGA] & REGA_RS) { + local->rtctime += (tmrval_t)nvr_period(nvr); + } else { + local->rtctime = 0; return; } - /* Update our timer interval. */ - timer_recalc(nvr, 1); - nvr->regs[RTC_REGC] |= REGC_PF; if (nvr->regs[RTC_REGB] & REGB_PIE) { nvr->regs[RTC_REGC] |= REGC_IRQF; @@ -525,10 +574,13 @@ nvr_write(uint16_t addr, uint8_t val, priv_t priv) switch(local->addr) { case RTC_REGA: nvr->regs[RTC_REGA] = val; - if (val & REGA_RS) - timer_recalc(nvr, 1); - else - local->rtctime = 0x7fffffff; + if (val & REGA_RS) { + if ((val & 0x70) == 0x20) + local->rtctime = TIMER_USEC * 500000; + else + local->rtctime = 0; + } else + local->rtctime = 0LL; break; case RTC_REGB: @@ -646,16 +698,16 @@ nvr_start(nvr_t *nvr) /* Start the RTC. */ nvr->regs[RTC_REGA] = (REGA_RS2|REGA_RS1); nvr->regs[RTC_REGB] = REGB_2412; - timer_recalc(nvr, 1); } static void -nvr_recalc(void *priv) +nvr_recalc(priv_t priv) { nvr_t *nvr = (nvr_t *)priv; + local_t *local = (local_t *)nvr->data; - timer_recalc(nvr, 0); + local->rtctime = TIMER_USEC * 500000; } @@ -723,12 +775,12 @@ nvr_at_init(const device_t *info, UNUSED(void *parent)) nvr_init(nvr); /* Start the timers. */ - timer_add(timer_update, nvr, &local->ecount, &local->ecount); - timer_add(timer_intr, nvr, &local->rtctime, TIMER_ALWAYS_ENABLED); + timer_add(timer_update, (priv_t)nvr, &local->ecount, &local->ecount); + timer_add(timer_intr, (priv_t)nvr, &local->rtctime, &local->rtctime); /* Set up the I/O handler for this device. */ io_sethandler(0x0070, 2, - nvr_read,NULL,NULL, nvr_write,NULL,NULL, nvr); + nvr_read,NULL,NULL, nvr_write,NULL,NULL, (priv_t)nvr); return((priv_t)nvr); } diff --git a/src/devices/system/pic.c b/src/devices/system/pic.c index dc7ee2c..d00f984 100644 --- a/src/devices/system/pic.c +++ b/src/devices/system/pic.c @@ -234,10 +234,14 @@ pic_read(uint16_t addr, priv_t priv) if (dev->read) { DBGLOG(1, "PIC1: read ins %02X\n", dev->ins); +#if 0 if (AT) return(dev->ins | (pic2.ins ? 4 : 0)); else return(dev->ins); +#else + return(dev->ins | (pic2.ins ? 4 : 0)); +#endif } return(dev->pend); @@ -320,6 +324,7 @@ pic2_write(uint16_t addr, uint8_t val, priv_t priv) dev->icw = 1; dev->icw1 = val; dev->ins = 0; + pic.pend &= ~4; update_pending(); return; diff --git a/src/devices/video/vid_ati28800.c b/src/devices/video/vid_ati28800.c index ec10209..002cfda 100644 --- a/src/devices/video/vid_ati28800.c +++ b/src/devices/video/vid_ati28800.c @@ -49,6 +49,7 @@ #include "../../rom.h" #include "../../device.h" #include "../../plat.h" +#include "../system/clk.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" @@ -372,26 +373,26 @@ ati28800_recalctimings(svga_t *svga) ati28800_t *dev = (ati28800_t *)svga->p; switch(((dev->regs[0xbe] & 0x10) >> 1) | ((dev->regs[0xb9] & 2) << 1) | ((svga->miscout & 0x0C) >> 2)) { - case 0x00: svga->clock = cpuclock / 42954000.0; break; - case 0x01: svga->clock = cpuclock / 48771000.0; break; + case 0x00: svga->clock = cpu_clock / 42954000.0; break; + case 0x01: svga->clock = cpu_clock / 48771000.0; break; #if 0 case 0x02: INFO("ATI: Clock 2\n", break; #endif - case 0x03: svga->clock = cpuclock / 36000000.0; break; - case 0x04: svga->clock = cpuclock / 50350000.0; break; - case 0x05: svga->clock = cpuclock / 56640000.0; break; + case 0x03: svga->clock = cpu_clock / 36000000.0; break; + case 0x04: svga->clock = cpu_clock / 50350000.0; break; + case 0x05: svga->clock = cpu_clock / 56640000.0; break; #if 0 case 0x06: INFO("ATI: Clock 2\n", break; #endif - case 0x07: svga->clock = cpuclock / 44900000.0; break; - case 0x08: svga->clock = cpuclock / 30240000.0; break; - case 0x09: svga->clock = cpuclock / 32000000.0; break; - case 0x0A: svga->clock = cpuclock / 37500000.0; break; - case 0x0B: svga->clock = cpuclock / 39000000.0; break; - case 0x0C: svga->clock = cpuclock / 40000000.0; break; - case 0x0D: svga->clock = cpuclock / 56644000.0; break; - case 0x0E: svga->clock = cpuclock / 75000000.0; break; - case 0x0F: svga->clock = cpuclock / 65000000.0; break; + case 0x07: svga->clock = cpu_clock / 44900000.0; break; + case 0x08: svga->clock = cpu_clock / 30240000.0; break; + case 0x09: svga->clock = cpu_clock / 32000000.0; break; + case 0x0A: svga->clock = cpu_clock / 37500000.0; break; + case 0x0B: svga->clock = cpu_clock / 39000000.0; break; + case 0x0C: svga->clock = cpu_clock / 40000000.0; break; + case 0x0D: svga->clock = cpu_clock / 56644000.0; break; + case 0x0E: svga->clock = cpu_clock / 75000000.0; break; + case 0x0F: svga->clock = cpu_clock / 65000000.0; break; default: break; } diff --git a/src/devices/video/vid_ati_mach64.c b/src/devices/video/vid_ati_mach64.c index b0c2b0b..34e8116 100644 --- a/src/devices/video/vid_ati_mach64.c +++ b/src/devices/video/vid_ati_mach64.c @@ -48,6 +48,7 @@ #include "../../mem.h" #include "../../rom.h" #include "../../plat.h" +#include "../system/clk.h" #include "../system/pci.h" #include "video.h" #include "vid_svga.h" @@ -468,7 +469,7 @@ void mach64_recalctimings(svga_t *svga) svga->hdisp_time = svga->hdisp = ((mach64->crtc_h_total_disp >> 16) & 255) + 1; svga->vsyncstart = (mach64->crtc_v_sync_strt_wid & 2047) + 1; svga->rowoffset = (mach64->crtc_off_pitch >> 22); - svga->clock = cpuclock / clock_gen->output_clock; + svga->clock = cpu_clock / clock_gen->output_clock; svga->ma_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; svga->linedbl = svga->rowcount = 0; svga->split = 0xffffff; diff --git a/src/devices/video/vid_cga_compaq.c b/src/devices/video/vid_cga_compaq.c index 01bd8a1..15e941b 100644 --- a/src/devices/video/vid_cga_compaq.c +++ b/src/devices/video/vid_cga_compaq.c @@ -8,7 +8,7 @@ * * Implementation of CGA used by Compaq PC's. * - * Version: @(#)vid_cga_compaq.c 1.0.12 2019/05/13 + * Version: @(#)vid_cga_compaq.c 1.0.13 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -42,11 +42,11 @@ #include #include #include "../../emu.h" +#include "../../timer.h" #include "../../cpu/cpu.h" #include "../../io.h" #include "../../mem.h" #include "../../rom.h" -#include "../../timer.h" #include "../../device.h" #include "../../plat.h" #include "../system/clk.h" @@ -55,8 +55,10 @@ #include "vid_cga_comp.h" -#define CGA_RGB 0 -#define CGA_COMPOSITE 1 +enum { + CGA_RGB = 0, + CGA_COMPOSITE +}; typedef struct { @@ -78,8 +80,8 @@ recalc_timings(compaq_cga_t *dev) _dispontime *= MDACONST; _dispofftime *= MDACONST; - dev->cga.dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - dev->cga.dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + dev->cga.dispontime = (tmrval_t)(_dispontime * (1 << TIMER_SHIFT)); + dev->cga.dispofftime = (tmrval_t)(_dispofftime * (1 << TIMER_SHIFT)); } @@ -123,7 +125,7 @@ compaq_poll(priv_t priv) } dev->cga.lastline = dev->cga.displine; - cols[0] = (dev->cga.cgacol & 15); + cols[0] = (dev->cga.cgacol & 15) + 16; for (c = 0; c < 8; c++) { screen->line[dev->cga.displine][c].val = cols[0]; @@ -360,6 +362,32 @@ compaq_poll(priv_t priv) } +static void +compaq_cga_close(priv_t priv) +{ + compaq_cga_t *dev = (compaq_cga_t *)priv; + + if (dev->cga.cpriv != NULL) + cga_comp_close(dev->cga.cpriv); + + free(dev->cga.vram); + + free(dev); +} + + +static void +speed_changed(priv_t priv) +{ + compaq_cga_t *dev = (compaq_cga_t *)priv; + + if (dev->cga.crtc[9] == 13) /* character height */ + recalc_timings(dev); + else + cga_recalctimings(&dev->cga); +} + + static priv_t compaq_cga_init(const device_t *info, UNUSED(void *parent)) { @@ -368,12 +396,14 @@ compaq_cga_init(const device_t *info, UNUSED(void *parent)) dev = (compaq_cga_t *)mem_alloc(sizeof(compaq_cga_t)); memset(dev, 0x00, sizeof(compaq_cga_t)); + dev->flags = info->local; display_type = device_get_config_int("display_type"); dev->cga.composite = (display_type != CGA_RGB); dev->cga.revision = device_get_config_int("composite_type"); dev->cga.snow_enabled = device_get_config_int("snow_enabled"); dev->cga.rgb_type = device_get_config_int("rgb_type"); + dev->cga.crtc[9] = 13; /* character height */ dev->cga.vram = (uint8_t *)mem_alloc(0x4000); @@ -381,14 +411,21 @@ compaq_cga_init(const device_t *info, UNUSED(void *parent)) timer_add(compaq_poll, (priv_t)dev, &dev->cga.vidtime, TIMER_ALWAYS_ENABLED); +#if 0 + /* FIXME: setting it to dev->cga.vram apparently causes problems. */ mem_map_add(&dev->cga.mapping, 0xb8000, 0x08000, cga_read,NULL,NULL, cga_write,NULL,NULL, dev->cga.vram, MEM_MAPPING_EXTERNAL, (priv_t)dev); +#else + mem_map_add(&dev->cga.mapping, 0xb8000, 0x08000, + cga_read,NULL,NULL, cga_write,NULL,NULL, + NULL, MEM_MAPPING_EXTERNAL, (priv_t)dev); +#endif io_sethandler(0x03d0, 16, cga_in,NULL,NULL, cga_out,NULL,NULL, (priv_t)dev); - if (info->local) { + if (dev->flags) { for (c = 0; c < 256; c++) { dev->attr[c][0][0] = dev->attr[c][1][0] = dev->attr[c][1][1] = 16; if (c & 8) @@ -410,8 +447,6 @@ compaq_cga_init(const device_t *info, UNUSED(void *parent)) dev->attr[0x88][0][1] = dev->attr[0x88][1][1] = 16; } - dev->flags = info->local; - overscan_x = overscan_y = 16; cga_palette = (dev->cga.rgb_type << 1); @@ -424,32 +459,6 @@ compaq_cga_init(const device_t *info, UNUSED(void *parent)) } -static void -compaq_cga_close(priv_t priv) -{ - compaq_cga_t *dev = (compaq_cga_t *)priv; - - if (dev->cga.cpriv != NULL) - cga_comp_close(dev->cga.cpriv); - - free(dev->cga.vram); - - free(dev); -} - - -static void -speed_changed(priv_t priv) -{ - compaq_cga_t *dev = (compaq_cga_t *)priv; - - if (dev->cga.crtc[9] == 13) /* Character height */ - recalc_timings(dev); - else - cga_recalctimings(&dev->cga); -} - - extern const device_config_t cga_config[]; static const video_timings_t cga_timings = { VID_ISA,8,16,32,8,16,32 }; diff --git a/src/devices/video/vid_cl54xx.c b/src/devices/video/vid_cl54xx.c index 6e4c1ef..2f81dbc 100644 --- a/src/devices/video/vid_cl54xx.c +++ b/src/devices/video/vid_cl54xx.c @@ -54,6 +54,7 @@ #include "../../rom.h" #include "../../device.h" #include "../../plat.h" +#include "../system/clk.h" #include "../system/pci.h" #include "video.h" #include "vid_svga.h" @@ -460,7 +461,7 @@ recalc_timings(svga_t *svga) clocksel = (svga->miscout >> 2) & 3; if (!dev->vclk_n[clocksel] || !dev->vclk_d[clocksel]) - svga->clock = cpuclock / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); + svga->clock = cpu_clock / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); else { int n = dev->vclk_n[clocksel] & 0x7f; int d = (dev->vclk_d[clocksel] & 0x3e) >> 1; @@ -479,7 +480,7 @@ recalc_timings(svga_t *svga) } } - svga->clock = cpuclock / freq; + svga->clock = cpu_clock / freq; } if (dev->vram_size == (1 << 19)) /* Note : why 512KB VRAM cards does not wrap */ diff --git a/src/devices/video/vid_et4000.c b/src/devices/video/vid_et4000.c index 5f3adfc..59b17f2 100644 --- a/src/devices/video/vid_et4000.c +++ b/src/devices/video/vid_et4000.c @@ -49,6 +49,7 @@ #include "../../rom.h" #include "../../device.h" #include "../../plat.h" +#include "../system/clk.h" #include "../system/mca.h" #include "video.h" #include "vid_svga.h" @@ -420,15 +421,15 @@ et4000_recalctimings(svga_t *svga) break; case 3: - svga->clock = cpuclock / 40000000.0; + svga->clock = cpu_clock / 40000000.0; break; case 5: - svga->clock = cpuclock / 65000000.0; + svga->clock = cpu_clock / 65000000.0; break; default: - svga->clock = cpuclock / 36000000.0; + svga->clock = cpu_clock / 36000000.0; break; } diff --git a/src/devices/video/vid_et4000w32.c b/src/devices/video/vid_et4000w32.c index ed6e04e..baf7442 100644 --- a/src/devices/video/vid_et4000w32.c +++ b/src/devices/video/vid_et4000w32.c @@ -53,6 +53,7 @@ #include "../../rom.h" #include "../../device.h" #include "../../plat.h" +#include "../system/clk.h" #include "../system/pci.h" #include "video.h" #include "vid_svga.h" @@ -254,7 +255,7 @@ et4000w32p_recalctimings(svga_t *svga) if (svga->crtc[0x3F] & 0x01) svga->htotal += 256; if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; - svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); + svga->clock = cpu_clock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); switch (svga->bpp) { diff --git a/src/devices/video/vid_genius.c b/src/devices/video/vid_genius.c index 9d1293c..2a13e6d 100644 --- a/src/devices/video/vid_genius.c +++ b/src/devices/video/vid_genius.c @@ -1,4 +1,5 @@ /* + dev->genius_control |= 0x10; * VARCem Virtual ARchaeological Computer EMulator. * An emulator of (mostly) x86-based PC systems and devices, * using the ISA,EISA,VLB,MCA and PCI system buses, roughly @@ -70,8 +71,8 @@ * John Elliott, * * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2016-2018 John Elliott. + * Copyright 2016-2019 Miran Grca. + * Copyright 2016-2019 John Elliott. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -99,6 +100,7 @@ #include "../../emu.h" #include "../../timer.h" #include "../../io.h" +#include "../../cpu/cpu.h" #include "../../mem.h" #include "../../rom.h" #include "../../device.h" @@ -121,6 +123,10 @@ typedef struct { uint8_t mda_crtc[32]; /* The 'CRTC' as the host PC sees it */ int mda_crtcreg; /* Current CRTC register */ + + uint8_t cga_crtc[32]; /* The 'CRTC' as the host PC sees it */ + int cga_crtcreg; /* Current CRTC register */ + uint8_t genius_control; /* Native control register * I think bit 0 enables the full * framebuffer. @@ -133,15 +139,16 @@ typedef struct { * 93h => chars are 24 pixels high [12 x 2] */ uint8_t genius_mode; /* Current mode (see list at top of file) */ - uint8_t cga_ctrl; /* Emulated CGA control register */ - uint8_t mda_ctrl; /* Emulated MDA control register */ - uint8_t cga_colour; /* Emulated CGA colour register (ignored) */ - uint8_t mda_stat; /* MDA status (IN 0x3BA) */ + uint8_t cga_ctrl; /* Emulated CGA control register */ + uint8_t cga_color; /* Emulated CGA color register (ignored) */ uint8_t cga_stat; /* CGA status (IN 0x3DA) */ - int font; /* Current font, 0 or 1 */ + uint8_t mda_ctrl; /* Emulated MDA control register */ + uint8_t mda_stat; /* MDA status (IN 0x3BA) */ + int enabled; /* Display enabled, 0 or 1 */ + int font; /* Current font, 0 or 1 */ int detach; /* Detach cursor, 0 or 1 */ tmrval_t dispontime, dispofftime; @@ -152,16 +159,21 @@ typedef struct { int vc; int dispon, blink; - uint32_t pal[4]; + uint8_t pal[4]; - uint32_t cols[256][2][2]; + uint8_t attr[256][2][2]; /* attr -> colors */ + uint8_t fontdatm[256][16]; uint8_t fontdat[256][16]; uint8_t *vram; } genius_t; +static const video_timings_t genius_timings = { VID_ISA,8,16,32,8,16,32 }; +static const int8_t wsarray[16] = {3,4,5,6,7,8,4,5,6,7,8,4,5,6,7,8}; + + static void recalc_timings(genius_t *dev) { @@ -180,92 +192,51 @@ recalc_timings(genius_t *dev) static void -genius_out(uint16_t port, uint8_t val, priv_t priv) +wait_states(void) { - genius_t *dev = (genius_t *)priv; + int8_t ws; - switch (port) { - case 0x3b0: /* Command / control register */ - dev->genius_control = val; - if (val & 1) - mem_map_set_addr(&dev->mapping, 0xa0000, 0x28000); - else - mem_map_set_addr(&dev->mapping, 0xb0000, 0x10000); - break; - - case 0x3b1: - dev->genius_charh = val; - break; - - /* Emulated CRTC, register select */ - case 0x3b2: case 0x3b4: case 0x3b6: - case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: - dev->mda_crtcreg = val & 31; - break; - - /* Emulated CRTC, value */ - case 0x3b3: case 0x3b5: case 0x3b7: - case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: - dev->mda_crtc[dev->mda_crtcreg] = val; - recalc_timings(dev); - return; - - /* Emulated MDA control register */ - case 0x3b8: - dev->mda_ctrl = val; - return; - - /* Emulated CGA control register */ - case 0x3d8: - dev->cga_ctrl = val; - return; - - /* Emulated CGA colour register */ - case 0x3d9: - dev->cga_colour = val; - return; - } + ws = wsarray[cycles & 0x0f]; + cycles -= ws; } -static uint8_t -genius_in(uint16_t port, priv_t priv) +static int +get_lines(genius_t *dev) { - genius_t *dev = (genius_t *)priv; - uint8_t ret = 0xff; + int ret = 350; - switch (port) { - case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: - case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: - ret = dev->mda_crtcreg; + switch (dev->genius_charh & 0x13) { + case 0x00: + ret = 990; /* 80x66 */ break; - case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: - case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: - ret = dev->mda_crtc[dev->mda_crtcreg]; + case 0x01: + ret = 980; /* 80x70 */ break; - case 0x3b8: - ret = dev->mda_ctrl; + case 0x02: + ret = 988; /* guess: 80x76 */ break; - case 0x3d9: - ret = dev->cga_colour; + case 0x03: + ret = 984; /* 80x82 */ break; - case 0x3ba: - ret = dev->mda_stat; + case 0x10: + ret = 375; /* logic says 80x33 but it appears to be 80x25 */ break; - case 0x3d8: - ret = dev->cga_ctrl; + case 0x11: + ret = 490; /* guess: 80x35, fits the logic as well, half of 80x70 */ break; - case 0x3da: - ret = dev->cga_stat; + case 0x12: + ret = 494; /* guess: 80x38 */ break; - default: + case 0x13: + ret = 492; /* 80x41 */ break; } @@ -273,202 +244,255 @@ genius_in(uint16_t port, priv_t priv) } -static void -genius_write(uint32_t addr, uint8_t val, priv_t priv) -{ - genius_t *dev = (genius_t *)priv; - - if (dev->genius_control & 1) { - addr = addr % 0x28000; - } else { - /* If hi-res memory is disabled, only visible in the B000 segment */ - addr = (addr & 0xffff) + 0x10000; - } - - dev->vram[addr] = val; -} - - -static uint8_t -genius_read(uint32_t addr, priv_t priv) -{ - genius_t *dev = (genius_t *)priv; - - if (dev->genius_control & 1) { - addr = addr % 0x28000; - } else { - /* If hi-res memory is disabled, only visible in the B000 segment */ - addr = (addr & 0xffff) + 0x10000; - } - - return dev->vram[addr]; -} - - /* Draw a single line of the screen in either text mode */ static void -text_line(genius_t *dev, uint8_t background) +text_line(genius_t *dev, uint8_t bg, int mda, int cols80) { - int x; int w = 80; /* 80 characters across */ - int cw = 9; /* Each character is 9 pixels wide */ - uint8_t chr, attr; - uint8_t bitmap[2]; - int blink, c, row; + int cw = 9; /* each character is 9 pixels wide */ + uint8_t chr, attr, sc, ctrl; + uint8_t *crtc, bitmap[2]; + int x, blink, c, row, charh; int drawcursor, cursorline; uint16_t addr; - uint8_t sc; - int charh; uint16_t ma = (dev->mda_crtc[13] | (dev->mda_crtc[12] << 8)) & 0x3fff; uint16_t ca = (dev->mda_crtc[15] | (dev->mda_crtc[14] << 8)) & 0x3fff; - uint8_t *framebuf = dev->vram + 0x10000; - uint32_t col; + uint8_t *framebuf = dev->vram + 0x010000; + uint32_t dl = dev->displine; + uint8_t col; - /* Character height is 12-15 */ - charh = 15 - (dev->genius_charh & 3); - if (dev->genius_charh & 0x10) { - row = ((dev->displine >> 1) / charh); - sc = ((dev->displine >> 1) % charh); + if (mda) { + /* Character height is 12-15. */ + if (dev->displine >= get_lines(dev)) + return; + + crtc = dev->mda_crtc; + ctrl = dev->mda_ctrl; + charh = 15 - (dev->genius_charh & 3); + +#if 0 + if (dev->genius_charh & 0x10) { + row = ((dl >> 1) / charh); + sc = ((dl >> 1) % charh); + } else { + row = (dl / charh); + sc = (dl % charh); + } +#else + row = (dl / charh); + sc = (dl % charh); +#endif } else { - row = (dev->displine / charh); - sc = (dev->displine % charh); + if ((dev->displine < 512) || (dev->displine >= 912)) + return; + + crtc = dev->cga_crtc; + ctrl = dev->cga_ctrl; + framebuf += 0x08000; + + dl -= 512; + w = crtc[1]; + cw = 8; + charh = crtc[9] + 1; + + row = ((dl >> 1) / charh); + sc = ((dl >> 1) % charh); } + + ma = (crtc[13] | (crtc[12] << 8)) & 0x3fff; + ca = (crtc[15] | (crtc[14] << 8)) & 0x3fff; + addr = ((ma & ~1) + row * w) * 2; + if (! mda) + dl += 512; + ma += (row * w); - - if ((dev->mda_crtc[10] & 0x60) == 0x20) { + + if ((crtc[10] & 0x60) == 0x20) cursorline = 0; - } else { - cursorline = ((dev->mda_crtc[10] & 0x1F) <= sc) && - ((dev->mda_crtc[11] & 0x1F) >= sc); - } + else + cursorline = ((crtc[10] & 0x1f) <= sc) && ((crtc[11] & 0x1f) >= sc); for (x = 0; x < w; x++) { - chr = framebuf[(addr + 2 * x) & 0x3FFF]; - attr = framebuf[(addr + 2 * x + 1) & 0x3FFF]; - drawcursor = ((ma == ca) && cursorline && dev->enabled && - (dev->mda_ctrl & 8)); +#if 0 + if ((dev->genius_charh & 0x10) && ((addr + 2 * x) > 0x0fff)) + chr = 0x00; + if ((dev->genius_charh & 0x10) && ((addr + 2 * x + 1) > 0x0fff)) + attr = 0x00; +#endif + chr = framebuf[(addr + 2 * x) & 0x3fff]; + attr = framebuf[(addr + 2 * x + 1) & 0x3fff]; - switch (dev->mda_crtc[10] & 0x60) { - case 0x00: drawcursor = drawcursor && (dev->blink & 16); break; - case 0x60: drawcursor = drawcursor && (dev->blink & 32); break; + drawcursor = ((ma == ca) && cursorline && dev->enabled && (ctrl & 8)); + + switch (crtc[10] & 0x60) { + case 0x00: + drawcursor = drawcursor && (dev->blink & 16); + break; + + case 0x60: + drawcursor = drawcursor && (dev->blink & 32); + break; } - blink = ((dev->blink & 16) && - (dev->mda_ctrl & 0x20) && - (attr & 0x80) && !drawcursor); - if (dev->mda_ctrl & 0x20) attr &= 0x7F; + blink = ((dev->blink & 16) && (ctrl & 0x20) && (attr & 0x80) && !drawcursor); - /* MDA underline */ - if (sc == charh && ((attr & 7) == 1)) { - col = dev->cols[attr][blink][1]; + if (ctrl & 0x20) + attr &= 0x7f; + + /* MDA underline. */ + if (mda && (sc == charh) && ((attr & 7) == 1)) { + col = dev->attr[attr][blink][1]; if (dev->genius_control & 0x20) - col ^= 0xffffff; + col ^= 15; for (c = 0; c < cw; c++) { - if (col != background) - screen->line[dev->displine][(x * cw) + c].val = col; + if (col != bg) { + if (cols80) + screen->line[dl][(x * cw) + c].pal = col; + else { + screen->line[dl][((x * cw) << 1) + (c << 1)].pal = + screen->line[dl][((x * cw) << 1) + (c << 1) + 1].pal = col; + } + } } - } else { - /* Draw 8 pixels of character */ - bitmap[0] = dev->fontdat[chr][sc]; + } else { + /* Draw 8 pixels of character. */ + if (mda) + bitmap[0] = dev->fontdatm[chr][sc]; + else + bitmap[0] = dev->fontdat[chr][sc]; + for (c = 0; c < 8; c++) { - col = dev->cols[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; - if (!(dev->enabled) || !(dev->mda_ctrl & 8)) - col = dev->cols[0][0][0]; + col = dev->attr[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; + if (!dev->enabled || !(ctrl & 8)) + col = dev->attr[0][0][0]; if (dev->genius_control & 0x20) - col ^= 0xffffff; + col ^= 15; - if (col != background) - screen->line[dev->displine][(x * cw) + c].val = col; + if (col != bg) { + if (cols80) + screen->line[dl][(x * cw) + c].pal = col; + else { + screen->line[dl][((x * cw) << 1) + (c << 1)].pal = + screen->line[dl][((x * cw) << 1) + (c << 1) + 1].pal = col; + } + } } - /* The ninth pixel column... */ - if ((chr & ~0x1f) == 0xc0) { - /* Echo column 8 for the graphics chars */ - col = screen->line[dev->displine][(x * cw) + 7].val; - if (col != background) - screen->line[dev->displine][(x * cw) + 8].val = col; - } else { - /* Otherwise fill with background */ - col = dev->cols[attr][blink][0]; - if (dev->genius_control & 0x20) - col ^= 0xffffff; - - if (col != background) - if (col != background) - screen->line[dev->displine][(x * cw) + 8].val = col; + if (cw == 9) { + /* The ninth pixel column... */ + if ((chr & ~0x1f) == 0xc0) { + /* Echo column 8 for the graphics chars. */ + if (cols80) { + col = screen->line[dl][(x * cw) + 7].pal; + if (col != bg) + screen->line[dl][(x * cw) + 8].pal = col; + } else { + col = screen->line[dl][((x * cw) << 1) + 14].pal; + if (col != bg) { + screen->line[dl][((x * cw) << 1) + 16].pal = + screen->line[dl][((x * cw) << 1) + 17].pal = col; + } + } + } else { + /* Otherwise fill with background. */ + col = dev->attr[attr][blink][0]; + if (dev->genius_control & 0x20) + col ^= 15; + if (col != bg) { + if (cols80) + screen->line[dl][(x * cw) + 8].pal = col; + else { + screen->line[dl][((x * cw) << 1) + 16].pal = + screen->line[dl][((x * cw) << 1) + 17].pal = col; + } + } + } } + if (drawcursor) { - for (c = 0; c < cw; c++) - screen->line[dev->displine][(x * cw) + c].val ^= dev->cols[attr][0][1]; + for (c = 0; c < cw; c++) { + if (cols80) + screen->line[dl][(x * cw) + c].pal ^= dev->attr[attr][0][1]; + else { + screen->line[dl][((x * cw) << 1) + (c << 1)].pal ^= dev->attr[attr][0][1]; + screen->line[dl][((x * cw) << 1) + (c << 1) + 1].pal ^= dev->attr[attr][0][1]; + } + } } - ++ma; + + ma++; } } } -/* Draw a line in the CGA 640x200 mode */ +/* Draw a line in the CGA 640x200 mode. */ static void cga_line(genius_t *dev) { - uint32_t dat; - uint32_t ink; + uint8_t ink_f, ink_b; uint32_t addr; + uint8_t dat; int x, c; - ink = (dev->genius_control & 0x20) ? dev->pal[0] : dev->pal[3]; + ink_f = (dev->genius_control & 0x20) ? dev->pal[0] : dev->pal[3]; + ink_b = (dev->genius_control & 0x20) ? dev->pal[3] : dev->pal[0]; - /* We draw the CGA at row 600 */ - if (dev->displine < 600) return; + /* We draw the CGA at row 512 */ + if ((dev->displine < 512) || (dev->displine >= 912)) + return; - addr = 0x18000 + 80 * ((dev->displine - 600) >> 2); - if ((dev->displine - 600) & 2) - addr += 0x2000; + addr = 0x018000 + 80 * ((dev->displine - 512) >> 2); + if ((dev->displine - 512) & 2) + addr += 0x002000; for (x = 0; x < 80; x++) { - dat = dev->vram[addr]; + dat = dev->vram[addr]; addr++; for (c = 0; c < 8; c++) { if (dat & 0x80) - screen->line[dev->displine][x*8 + c].val = ink; + screen->line[dev->displine][(x << 3) + c].pal = ink_f; + else + screen->line[dev->displine][(x << 3) + c].pal = ink_b; + dat = dat << 1; } } } -/* Draw a line in the native high-resolution mode */ +/* Draw a line in the native high-resolution mode. */ static void hires_line(genius_t *dev) { - uint32_t dat; - uint32_t ink; + uint8_t ink_f, ink_b; uint32_t addr; + uint8_t dat; int x, c; - ink = (dev->genius_control & 0x20) ? dev->pal[0] : dev->pal[3]; + ink_f = (dev->genius_control & 0x20) ? dev->pal[0] : dev->pal[3]; + ink_b = (dev->genius_control & 0x20) ? dev->pal[3] : dev->pal[0]; - /* The first 512 lines live at A0000 */ - if (dev->displine < 512) { + if (dev->displine < 512) /* first 512 lines live at A0000 */ addr = 128 * dev->displine; - } else { - /* The second 496 live at B8000 */ - addr = 0x18000 + 128 * (dev->displine - 512); - } + else /* second 496 live at B8000 */ + addr = 0x018000 + (128 * (dev->displine - 512)); for (x = 0; x < 91; x++) { - dat = dev->vram[addr]; - addr++; + dat = dev->vram[addr + x]; for (c = 0; c < 8; c++) { if (dat & 0x80) - screen->line[dev->displine][x*8 + c].val = ink; + screen->line[dev->displine][(x << 3) + c].pal = ink_f; + else + screen->line[dev->displine][(x << 3) + c].pal = ink_b; + dat = dat << 1; } } @@ -479,47 +503,59 @@ static void genius_poll(priv_t priv) { genius_t *dev = (genius_t *)priv; - uint8_t background; + uint8_t bg; int x; - if (!dev->linepos) { + if (! dev->linepos) { dev->vidtime += dev->dispofftime; dev->cga_stat |= 1; dev->mda_stat |= 1; dev->linepos = 1; + if (dev->dispon) { if (dev->genius_control & 0x20) - background = dev->pal[3]; + bg = dev->pal[3]; else - background = dev->pal[0]; + bg = dev->pal[0]; if (dev->displine == 0) video_blit_wait_buffer(); - /* Start off with a blank line */ + /* Start off with a blank line. */ for (x = 0; x < GENIUS_XSIZE; x++) - screen->line[dev->displine][x].val = background; + screen->line[dev->displine][x].pal = bg; /* If graphics display enabled, draw graphics on top * of the blanked line */ if (dev->cga_ctrl & 8) { - if (dev->genius_control & 8) + if (((dev->genius_control & 0x11) == 0x00) || (dev->genius_control & 0x08)) cga_line(dev); - else + else if ((dev->genius_control & 0x11) == 0x01) hires_line(dev); + else { + if (dev->cga_ctrl & 2) + cga_line(dev); + else { + if (dev->cga_ctrl & 1) + text_line(dev, bg, 0, 1); + else + text_line(dev, bg, 0, 0); + } + } } /* If MDA display is enabled, draw MDA text on top * of the lot */ if (dev->mda_ctrl & 8) - text_line(dev, background); + text_line(dev, bg, 1, 1); } dev->displine++; /* Hardcode a fixed refresh rate and VSYNC timing */ - if (dev->displine == 1008) { + if (dev->displine == GENIUS_YSIZE) { /* Start of VSYNC */ dev->cga_stat |= 8; + dev->mda_stat |= 8; dev->dispon = 0; } @@ -527,6 +563,7 @@ genius_poll(priv_t priv) /* End of VSYNC */ dev->displine = 0; dev->cga_stat &= ~8; + dev->mda_stat &= ~8; dev->dispon = 1; } } else { @@ -537,8 +574,8 @@ genius_poll(priv_t priv) dev->vidtime += dev->dispontime; dev->linepos = 0; - if (dev->displine == 1008) { -/* Hardcode GENIUS_XSIZE * GENIUS_YSIZE window size */ + if (dev->displine == GENIUS_YSIZE) { + /* Hardcode GENIUS_XSIZE * GENIUS_YSIZE window size */ if (GENIUS_XSIZE != xsize || GENIUS_YSIZE != ysize) { xsize = GENIUS_XSIZE; ysize = GENIUS_YSIZE; @@ -550,7 +587,7 @@ genius_poll(priv_t priv) video_force_resize_set(0); } - video_blit_start(0, 0, 0, 0, ysize, xsize, ysize); + video_blit_start(1, 0, 0, 0, ysize, xsize, ysize); frames++; /* Fixed 728x1008 resolution */ @@ -563,20 +600,186 @@ genius_poll(priv_t priv) } +static void +genius_out(uint16_t port, uint8_t val, priv_t priv) +{ + genius_t *dev = (genius_t *)priv; + + DEBUG("GENIUS: out(%04x, %02x)\n", port, val); + + switch (port) { + case 0x03b0: /* command / control register */ + dev->genius_control = val; + if (val & 1) + mem_map_set_addr(&dev->mapping, 0xa0000, 0x28000); + else + mem_map_set_addr(&dev->mapping, 0xb0000, 0x10000); + break; + + case 0x03b1: + dev->genius_charh = val; + break; + + case 0x03b2: /* emulated MDA CRTC, register select */ + case 0x03b4: + case 0x03b6: + dev->mda_crtcreg = val & 31; + break; + + case 0x03b3: /* emulated MDA CRTC, value */ + case 0x03b5: + case 0x03b7: + dev->mda_crtc[dev->mda_crtcreg] = val; + recalc_timings(dev); + break; + + case 0x03b8: /* emulated MDA control register */ + dev->mda_ctrl = val; + break; + + case 0x03d0: /* emulated CGA CRTC, register select */ + case 0x03d2: + case 0x03d4: + case 0x03d6: + dev->cga_crtcreg = val & 31; + break; + + case 0x03d1: /* emulated CGA CRTC, value */ + case 0x03d3: + case 0x03d5: + case 0x03d7: + dev->cga_crtc[dev->cga_crtcreg] = val; + recalc_timings(dev); + break; + + case 0x03d8: /* emulated CGA control register */ + dev->cga_ctrl = val; + break; + + case 0x03d9: /* emulated CGA color register */ + dev->cga_color = val; + break; + } +} + + +static uint8_t +genius_in(uint16_t port, priv_t priv) +{ + genius_t *dev = (genius_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x03b0: case 0x03b2: case 0x03b4: case 0x03b6: + ret = dev->mda_crtcreg; + break; + + case 0x03b1: case 0x03b3: case 0x03b5: case 0x03b7: + ret = dev->mda_crtc[dev->mda_crtcreg]; + break; + + case 0x03b8: + ret = dev->mda_ctrl; + break; + + case 0x03ba: + ret = dev->mda_stat; + break; + + case 0x03d0: case 0x03d2: case 0x03d4: case 0x03d6: + ret = dev->cga_crtcreg; + break; + + case 0x03d1: case 0x03d3: case 0x03d5: case 0x03d7: + ret = dev->cga_crtc[dev->cga_crtcreg]; + break; + + case 0x03d8: + ret = dev->cga_ctrl; + break; + + case 0x03d9: + ret = dev->cga_color; + break; + + case 0x03da: + ret = dev->cga_stat; + break; + + default: + break; + } + + return(ret); +} + + +static void +genius_write(uint32_t addr, uint8_t val, priv_t priv) +{ + genius_t *dev = (genius_t *)priv; + + wait_states(); + + if (dev->genius_control & 1) { + if ((addr >= 0x0a0000) && (addr < 0x0b0000)) + addr = (addr - 0x0a0000) & 0x00ffff; + else if ((addr >= 0x0b0000) && (addr < 0x0b8000)) + addr = ((addr - 0x0b0000) & 0x007fff) + 0x010000; + else + addr = ((addr - 0x0b8000) & 0x00ffff) + 0x018000; + } else { + /* If hi-res memory is disabled, only visible in the B000 segment */ + if (addr >= 0x0b8000) + addr = (addr & 0x003fff) + 0x018000; + else + addr = (addr & 0x007fff) + 0x010000; + } + + dev->vram[addr] = val; +} + + +static uint8_t +genius_read(uint32_t addr, priv_t priv) +{ + genius_t *dev = (genius_t *)priv; + + wait_states(); + + if (dev->genius_control & 1) { + if ((addr >= 0x0a0000) && (addr < 0x0b0000)) + addr = (addr - 0x0a0000) & 0x00ffff; + else if ((addr >= 0x0b0000) && (addr < 0x0b8000)) + addr = ((addr - 0x0b0000) & 0x007fff) + 0x010000; + else + addr = ((addr - 0x0b8000) & 0x00ffff) + 0x018000; + } else { + /* If hi-res memory is disabled, only visible in the B000 segment */ + if (addr >= 0x0b8000) + addr = (addr & 0x003fff) + 0x018000; + else + addr = (addr & 0x007fff) + 0x010000; + } + + return(dev->vram[addr]); +} + + static int -load_font(genius_t *dev, const wchar_t *s) +load_font(genius_t *dev, const wchar_t *fn) { FILE *fp; int c; - fp = rom_fopen(s, L"rb"); + fp = rom_fopen(fn, L"rb"); if (fp == NULL) { - ERRLOG("%s: cannot load font '%ls'\n", dev->name, s); + ERRLOG("%s: cannot load font '%ls'\n", dev->name, fn); return(0); } for (c = 0; c < 256; c++) - (void)fread(&dev->fontdat[c][0], 1, 16, fp); + (void)fread(&dev->fontdatm[c][0], 1, 16, fp); (void)fclose(fp); @@ -584,6 +787,26 @@ load_font(genius_t *dev, const wchar_t *s) } +static void +genius_close(priv_t priv) +{ + genius_t *dev = (genius_t *)priv; + + free(dev->vram); + + free(dev); +} + + +static void +speed_changed(priv_t priv) +{ + genius_t *dev = (genius_t *)priv; + + recalc_timings(dev); +} + + static priv_t genius_init(const device_t *info, UNUSED(void *parent)) { @@ -599,90 +822,74 @@ genius_init(const device_t *info, UNUSED(void *parent)) return(NULL); } - /* 160K video RAM */ - dev->vram = (uint8_t *)mem_alloc(0x28000); + /* Allocate 160K video RAM. */ + dev->vram = (uint8_t *)mem_alloc(0x028000); timer_add(genius_poll, (priv_t)dev, &dev->vidtime, TIMER_ALWAYS_ENABLED); - /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in - * high-resolution modes) */ - mem_map_add(&dev->mapping, 0xb0000, 0x10000, + /* + * Occupy memory between 0xB0000 and 0xBFFFF. + * (moves to 0xA0000 in high-resolution modes) + */ + mem_map_add(&dev->mapping, 0x0b0000, 0x010000, genius_read,NULL,NULL, genius_write,NULL,NULL, NULL, MEM_MAPPING_EXTERNAL, (priv_t)dev); - /* Respond to both MDA and CGA I/O ports */ - io_sethandler(0x03b0, 0x000C, + /* Respond to both MDA and CGA I/O ports. */ + io_sethandler(0x03b0, 12, genius_in,NULL,NULL, genius_out,NULL,NULL, (priv_t)dev); - io_sethandler(0x03d0, 0x0010, + io_sethandler(0x03d0, 16, genius_in,NULL,NULL, genius_out,NULL,NULL, (priv_t)dev); - dev->pal[0] = makecol(0x00, 0x00, 0x00); - dev->pal[1] = makecol(0x55, 0x55, 0x55); - dev->pal[2] = makecol(0xaa, 0xaa, 0xaa); - dev->pal[3] = makecol(0xff, 0xff, 0xff); + dev->pal[0] = 0 + 16; /* 0 */ + dev->pal[1] = 8 + 16; /* 8 */ + dev->pal[2] = 7 + 16; /* 7 */ + dev->pal[3] = 15 + 16; /* F */ - /* MDA attributes */ - /* I don't know if the Genius's MDA emulation actually does - * emulate bright / non-bright. For the time being pretend it does. */ + /* + * MDA attributes. + * I don't know if the Genius's MDA emulation actually does + * emulate bright / non-bright. For the time being pretend + * it does. + */ for (c = 0; c < 256; c++) { - dev->cols[c][0][0] = dev->cols[c][1][0] = - dev->cols[c][1][1] = dev->pal[0]; - if (c & 0x08) - dev->cols[c][0][1] = dev->pal[3]; - else - dev->cols[c][0][1] = dev->pal[2]; + dev->attr[c][0][0] = dev->attr[c][1][0] = + dev->attr[c][1][1] = dev->pal[0]; + if (c & 8) + dev->attr[c][0][1] = dev->pal[3]; + else + dev->attr[c][0][1] = dev->pal[2]; } - dev->cols[0x70][0][1] = dev->pal[0]; - dev->cols[0x70][0][0] = dev->cols[0x70][1][0] = - dev->cols[0x70][1][1] = dev->pal[3]; - dev->cols[0xF0][0][1] = dev->pal[0]; - dev->cols[0xF0][0][0] = dev->cols[0xF0][1][0] = - dev->cols[0xF0][1][1] = dev->pal[3]; - dev->cols[0x78][0][1] = dev->pal[2]; - dev->cols[0x78][0][0] = dev->cols[0x78][1][0] = - dev->cols[0x78][1][1] = dev->pal[3]; - dev->cols[0xF8][0][1] = dev->pal[2]; - dev->cols[0xF8][0][0] = dev->cols[0xF8][1][0] = - dev->cols[0xF8][1][1] = dev->pal[3]; - dev->cols[0x00][0][1] = dev->cols[0x00][1][1] = dev->pal[0]; - dev->cols[0x08][0][1] = dev->cols[0x08][1][1] = dev->pal[0]; - dev->cols[0x80][0][1] = dev->cols[0x80][1][1] = dev->pal[0]; - dev->cols[0x88][0][1] = dev->cols[0x88][1][1] = dev->pal[0]; + dev->attr[0x70][0][1] = dev->pal[0]; + dev->attr[0x70][0][0] = dev->attr[0x70][1][0] = + dev->attr[0x70][1][1] = dev->pal[3]; + dev->attr[0xf0][0][1] = dev->pal[0]; + dev->attr[0xf0][0][0] = dev->attr[0xf0][1][0] = + dev->attr[0xf0][1][1] = dev->pal[3]; + dev->attr[0x78][0][1] = dev->pal[2]; + dev->attr[0x78][0][0] = dev->attr[0x78][1][0] = + dev->attr[0x78][1][1] = dev->pal[3]; + dev->attr[0xf8][0][1] = dev->pal[2]; + dev->attr[0xf8][0][0] = dev->attr[0xf8][1][0] = + dev->attr[0xf8][1][1] = dev->pal[3]; + dev->attr[0x00][0][1] = dev->attr[0x00][1][1] = dev->pal[0]; + dev->attr[0x08][0][1] = dev->attr[0x08][1][1] = dev->pal[0]; + dev->attr[0x80][0][1] = dev->attr[0x80][1][1] = dev->pal[0]; + dev->attr[0x88][0][1] = dev->attr[0x88][1][1] = dev->pal[0]; - /* Start off in 80x25 text mode */ - dev->cga_stat = 0xF4; + /* Set up for 80x25 text mode. */ + dev->enabled = 1; + dev->cga_stat = 0xf4; dev->genius_mode = 2; - dev->enabled = 1; - dev->genius_charh = 0x90; /* Native character height register */ + dev->genius_control |= 0x10; + dev->genius_charh = 0x90; /* native character height register */ - video_inform(DEVICE_VIDEO_GET(info->flags), - (const video_timings_t *)info->vid_timing); + video_inform(DEVICE_VIDEO_GET(info->flags), &genius_timings); return((priv_t)dev); } -static void -genius_close(priv_t priv) -{ - genius_t *dev = (genius_t *)priv; - - free(dev->vram); - free(dev); -} - - -static void -speed_changed(priv_t priv) -{ - genius_t *dev = (genius_t *)priv; - - recalc_timings(dev); -} - - -static const video_timings_t genius_timings = { VID_ISA,8,16,32,8,16,32 }; - const device_t genius_device = { "Genius VHR", DEVICE_VIDEO(VID_TYPE_MDA) | DEVICE_ISA, @@ -692,6 +899,6 @@ const device_t genius_device = { NULL, speed_changed, NULL, - &genius_timings, + NULL, NULL }; diff --git a/src/devices/video/vid_ht216.c b/src/devices/video/vid_ht216.c index 6a97cf6..ede7176 100644 --- a/src/devices/video/vid_ht216.c +++ b/src/devices/video/vid_ht216.c @@ -50,6 +50,7 @@ #include "../../rom.h" #include "../../device.h" #include "../../plat.h" +#include "../system/clk.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" @@ -170,15 +171,15 @@ recalc_timings(svga_t *svga) switch (dev->clk_sel) { case 5: - svga->clock = (cpuclock * (double)(1ULL << 32)) / 65000000.0; + svga->clock = (cpu_clock * (double)(1ULL << 32)) / 65000000.0; break; case 6: - svga->clock = (cpuclock * (double)(1ULL << 32)) / 40000000.0; + svga->clock = (cpu_clock * (double)(1ULL << 32)) / 40000000.0; break; case 10: - svga->clock = (cpuclock * (double)(1ULL << 32)) / 80000000.0; + svga->clock = (cpu_clock * (double)(1ULL << 32)) / 80000000.0; break; } diff --git a/src/devices/video/vid_im1024.c b/src/devices/video/vid_im1024.c index 1b0de90..d4d0782 100644 --- a/src/devices/video/vid_im1024.c +++ b/src/devices/video/vid_im1024.c @@ -82,17 +82,20 @@ #include "vid_pgc.h" +#define FONT_ROM_PATH L"video/im1024/im1024font.bin" +#define FONT_WIDTH 12 +#define FONT_HEIGHT 18 + + typedef struct { pgc_t pgc; - uint8_t fontx[256]; - uint8_t fonty[256]; - uint8_t font[256][128]; - uint8_t *fifo; unsigned fifo_len, fifo_wrptr, fifo_rdptr; + + uint8_t fontdat[256][36]; /* IM1024 12x18 font */ } im1024_t; @@ -167,7 +170,8 @@ input_byte(pgc_t *pgc, uint8_t *result) pgc_sleep(pgc); } - if (pgc->stopped) return(0); + if (pgc->stopped) + return(0); if (pgc->mapram[0x3ff]) { /* Reset triggered. */ @@ -638,40 +642,9 @@ hndl_rect(pgc_t *pgc) /* - * FIXME: - * Define a font character. - * - * Text drawing should probably be implemented in - * vid_pgc.c rather than here.. + * Override the PGC TSIZE command to parse its + * parameters as words rather than coordinates. */ -static void -hndl_tdefin(pgc_t *pgc) -{ - im1024_t *dev = (im1024_t *)pgc; - uint8_t ch, bt; - uint8_t rows, cols; - unsigned len, n; - - if (! pgc_param_byte(pgc, &ch)) return; - if (! pgc_param_byte(pgc, &cols)) return; - if (! pgc_param_byte(pgc, &rows)) return; - - DEBUG("IM1024: TDEFIN (%i,%i,%i) 0x%02x 0x%02x\n", - ch, rows, cols, pgc->mapram[0x300], pgc->mapram[0x301]); - - len = ((cols + 7) / 8) * rows; - for (n = 0; n < len; n++) { - if (! pgc_param_byte(pgc, &bt)) return; - - if (n < sizeof(dev->font[ch])) - dev->font[ch][n] = bt; - } - - dev->fontx[ch] = cols; - dev->fonty[ch] = rows; -} - - static void hndl_tsize(pgc_t *pgc) { @@ -684,50 +657,7 @@ hndl_tsize(pgc_t *pgc) } -static void -hndl_twrite(pgc_t *pgc) -{ - uint8_t buf[256]; - im1024_t *dev = (im1024_t *)pgc; - uint8_t count, mask, *row; - int x, y, wb, n; - int16_t x0 = pgc->x >> 16; - int16_t y0 = pgc->y >> 16; - - if (! pgc_param_byte(pgc, &count)) return; - - for (n = 0; n < count; n++) - if (! pgc_param_byte(pgc, &buf[n])) return; - buf[count] = 0; - - pgc_sto_raster(pgc, &x0, &y0); - - DEBUG("IM1024: TWRITE (%i) x0=%i y0=%i\n", count, x0, y0); - - for (n = 0; n < count; n++) { - wb = (dev->fontx[buf[n]] + 7) / 8; - DEBUG("IM1024: ch=0x%02x w=%i h=%i wb=%i\n", - buf[n], dev->fontx[buf[n]], dev->fonty[buf[n]], wb); - - for (y = 0; y < dev->fonty[buf[n]]; y++) { - mask = 0x80; - row = &dev->font[buf[n]][y * wb]; - for (x = 0; x < dev->fontx[buf[n]]; x++) { - if (row[0] & mask) - pgc_plot(pgc, x + x0, y0 - y); - mask = mask >> 1; - if (mask == 0) { - mask = 0x80; - row++; - } - } - } - - x0 += dev->fontx[buf[n]]; - } -} - - +/* Write text, using the builtin ROM font. */ static void hndl_txt88(pgc_t *pgc) { @@ -737,7 +667,7 @@ hndl_txt88(pgc_t *pgc) int16_t x0 = pgc->x >> 16; int16_t y0 = pgc->y >> 16; unsigned n; - int x, y, wb; + int x, y; if (! pgc_param_byte(pgc, &count)) return; @@ -747,17 +677,15 @@ hndl_txt88(pgc_t *pgc) pgc_sto_raster(pgc, &x0, &y0); - DEBUG("IM204: TWRITE (%i) x0=%i y0=%i\n", count, x0, y0); + DEBUG("IM204: TXT88 (%i) x0=%i y0=%i\n", count, x0, y0); for (n = 0; n < count; n++) { - wb = (dev->fontx[buf[n]] + 7) / 8; - DEBUG("IM1024: ch=0x%02x w=%i h=%i wb=%i\n", - buf[n], dev->fontx[buf[n]], dev->fonty[buf[n]], wb); + DEBUG("IM1024: ch=0x%02x w=%i h=%i\n", buf[n], FONT_WIDTH, FONT_HEIGHT); - for (y = 0; y < dev->fonty[buf[n]]; y++) { + for (y = 0; y < FONT_HEIGHT; y++) { mask = 0x80; - row = &dev->font[buf[n]][y * wb]; - for (x = 0; x < dev->fontx[buf[n]]; x++) { + row = &dev->fontdat[buf[n]][y * 2]; + for (x = 0; x < FONT_WIDTH; x++) { if (row[0] & mask) pgc_plot(pgc, x + x0, y0 - y); mask = mask >> 1; if (mask == 0) { @@ -767,7 +695,7 @@ hndl_txt88(pgc_t *pgc) } } - x0 += dev->fontx[buf[n]]; + x0 += FONT_WIDTH; } } @@ -917,11 +845,8 @@ static const pgc_cmd_t im1024_commands[] = { { "LUT8", 0xe6, pgc_hndl_lut8, NULL, 0 }, { "LUT8RD", 0x53, pgc_hndl_lut8rd,NULL, 0 }, { "L8RD", 0x53, pgc_hndl_lut8rd,NULL, 0 }, - { "TDEFIN", 0x84, hndl_tdefin, NULL, 0 }, - { "TD", 0x84, hndl_tdefin, NULL, 0 }, { "TSIZE", 0x81, hndl_tsize, NULL, 0 }, { "TS", 0x81, hndl_tsize, NULL, 0 }, - { "TWRITE", 0x8b, hndl_twrite, NULL, 0 }, { "TXT88", 0x88, hndl_txt88, NULL, 0 }, { "PAN", 0xb7, hndl_pan, NULL, 0 }, { "POLY", 0x30, hndl_poly, parse_poly, 0 }, @@ -936,6 +861,27 @@ static const pgc_cmd_t im1024_commands[] = { }; +static int +load_font(im1024_t *dev, const wchar_t *fn) +{ + FILE *fp; + int c; + + fp = rom_fopen(fn, L"rb"); + if (fp == NULL) { + ERRLOG("IM1024: cannot load font '%ls'\n", fn); + return(0); + } + + for (c = 0; c < 256; c++) + fread(&dev->fontdat[c][0], 1, 36, fp); + + (void)fclose(fp); + + return(1); +} + + static void im1024_close(priv_t priv) { @@ -964,6 +910,11 @@ im1024_init(const device_t *info, UNUSED(void *parent)) dev = (im1024_t *)mem_alloc(sizeof(im1024_t)); memset(dev, 0x00, sizeof(im1024_t)); + if (! load_font(dev, FONT_ROM_PATH)) { + free(dev); + return(NULL); + } + dev->fifo_len = 4096; dev->fifo = (uint8_t *)mem_alloc(dev->fifo_len); dev->fifo_wrptr = 0; @@ -994,7 +945,7 @@ const device_t im1024_device = { "ImageManager 1024", DEVICE_VIDEO(VID_TYPE_CGA) | DEVICE_ISA, 0, - NULL, + FONT_ROM_PATH, im1024_init, im1024_close, NULL, NULL, speed_changed, diff --git a/src/devices/video/vid_pgc.c b/src/devices/video/vid_pgc.c index 12c6c4c..710d0dd 100644 --- a/src/devices/video/vid_pgc.c +++ b/src/devices/video/vid_pgc.c @@ -139,24 +139,25 @@ static int output_byte(pgc_t *dev, uint8_t val) { /* If output buffer full, wait for it to empty. */ - while (!dev->stopped && dev->mapram[0x302] == (uint8_t)(dev->mapram[0x303] - 1)) { + while (!dev->stopped && + (dev->mapram[0x0302] == (uint8_t)(dev->mapram[0x0303] - 1))) { DEBUG("PGC: output buffer state: %02x %02x Sleeping\n", - dev->mapram[0x302], dev->mapram[0x303]); + dev->mapram[0x0302], dev->mapram[0x0303]); dev->waiting_output_fifo = 1; pgc_sleep(dev); } - if (dev->mapram[0x3ff]) { + if (dev->mapram[0x03ff]) { /* Reset triggered. */ pgc_reset(dev); return 0; } - dev->mapram[0x100 + dev->mapram[0x302]] = val; - dev->mapram[0x302]++; + dev->mapram[0x0100 + dev->mapram[0x0302]] = val; + dev->mapram[0x0302]++; DBGLOG(1, "PGC: output %02x: new state: %02x %02x\n", val, - dev->mapram[0x302], dev->mapram[0x303]); + dev->mapram[0x0302], dev->mapram[0x0303]); return 1; } @@ -180,19 +181,20 @@ static int error_byte(pgc_t *dev, uint8_t val) { /* If error buffer full, wait for it to empty. */ - while (!dev->stopped && dev->mapram[0x304] == dev->mapram[0x305] - 1) { + while (!dev->stopped && + (dev->mapram[0x0304] == dev->mapram[0x0305] - 1)) { dev->waiting_error_fifo = 1; pgc_sleep(dev); } - if (dev->mapram[0x3ff]) { + if (dev->mapram[0x03ff]) { /* Reset triggered. */ pgc_reset(dev); return 0; } - dev->mapram[0x200 + dev->mapram[0x304]] = val; - dev->mapram[0x304]++; + dev->mapram[0x0200 + dev->mapram[0x0304]] = val; + dev->mapram[0x0304]++; return 1; } @@ -221,21 +223,23 @@ static int input_byte(pgc_t *dev, uint8_t *result) { /* If input buffer empty, wait for it to fill. */ - while (!dev->stopped && dev->mapram[0x300] == dev->mapram[0x301]) { + while (!dev->stopped && + (dev->mapram[0x0300] == dev->mapram[0x0301])) { dev->waiting_input_fifo = 1; pgc_sleep(dev); } - if (dev->stopped) return 0; + if (dev->stopped) + return 0; - if (dev->mapram[0x3ff]) { + if (dev->mapram[0x03ff]) { /* Reset triggered. */ pgc_reset(dev); return 0; } - *result = dev->mapram[dev->mapram[0x301]]; - dev->mapram[0x301]++; + *result = dev->mapram[dev->mapram[0x0301]]; + dev->mapram[0x0301]++; return 1; } @@ -271,16 +275,22 @@ input_char(pgc_t *dev, char *result) static int read_command(pgc_t *dev) { + int count = 0; + char ch; + if (dev->clcur) return pgc_clist_byte(dev, &dev->hex_command); - if (dev->ascii_mode) { - char ch; - int count = 0; + if (dev->stopped) + return 0; + if (dev->ascii_mode) { while (count < 7) { if (! input_char(dev, &ch)) return 0; + if (dev->stopped) + return 0; + if (is_whitespace(ch)) { /* Pad to 6 characters */ while (count < 6) @@ -320,9 +330,9 @@ parse_command(pgc_t *dev, const pgc_cmd_t **pcmd) * Scan the list of valid commands. * * dev->commands may be a subclass list (terminated with '*') - * or the core list (terminated with '@') + * or the core list (terminated with NULL) */ - for (cmd = dev->commands; cmd->ascii[0] != '@'; cmd++) { + for (cmd = dev->commands; cmd->ascii != NULL; cmd++) { /* End of subclass command list, chain to core. */ if (cmd->ascii[0] == '*') cmd = dev->master; @@ -372,6 +382,7 @@ hndl_clbeg(pgc_t *dev) /* PGC has been reset. */ return; } + if (!cmd) { pgc_error(dev, PGC_ERROR_OPCODE); return; @@ -379,16 +390,16 @@ hndl_clbeg(pgc_t *dev) /* CLEND */ dev->clist[param] = cl; return; - } else { - if (! pgc_cl_append(&cl, dev->hex_command)) { - pgc_error(dev, PGC_ERROR_OVERFLOW); - return; - } + } - if (cmd->parser) { - if (! (*cmd->parser)(dev, &cl, cmd->p)) - return; - } + if (! pgc_cl_append(&cl, dev->hex_command)) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + return; + } + + if (cmd->parser) { + if (! (*cmd->parser)(dev, &cl, cmd->p)) + return; } } } @@ -1240,6 +1251,34 @@ hndl_resetf(pgc_t *dev) } +/* Define a font character. */ +static void +hndl_tdefin(pgc_t *dev) +{ + uint8_t ch, bt; + uint8_t rows, cols; + unsigned len, n; + + if (! pgc_param_byte(dev, &ch)) return; + if (! pgc_param_byte(dev, &cols)) return; + if (! pgc_param_byte(dev, &rows)) return; + + DEBUG("PGC: TDEFIN (%i,%i,%i) 0x%02x 0x%02x\n", + ch, rows, cols, dev->mapram[0x0300], dev->mapram[0x0301]); + + len = ((cols + 7) / 8) * rows; + for (n = 0; n < len; n++) { + if (! pgc_param_byte(dev, &bt)) return; + + if (n < sizeof(dev->font[ch])) + dev->font[ch][n] = bt; + } + + dev->fontx[ch] = cols; + dev->fonty[ch] = rows; +} + + /* TJUST sets text justify settings. */ static void hndl_tjust(pgc_t *dev) @@ -1259,14 +1298,58 @@ hndl_tjust(pgc_t *dev) /* TSIZE controls text horizontal spacing. */ static void -hndl_tsize(pgc_t *pgc) +hndl_tsize(pgc_t *dev) { int32_t param = 0; - if (! pgc_param_coord(pgc, ¶m)) return; + if (! pgc_param_coord(dev, ¶m)) return; DEBUG("PGC: TSIZE %i\n", param); - pgc->tsize = param; + dev->tsize = param; +} + + +/* Write text, using the user-uploaded RAM font. */ +static void +hndl_twrite(pgc_t *dev) +{ + uint8_t buf[256]; + uint8_t count, mask, *row; + int x, y, wb, n; + int16_t x0 = dev->x >> 16; + int16_t y0 = dev->y >> 16; + + if (! pgc_param_byte(dev, &count)) return; + + for (n = 0; n < count; n++) + if (! pgc_param_byte(dev, &buf[n])) return; + buf[count] = 0; + + pgc_sto_raster(dev, &x0, &y0); + + DEBUG("PGC: TWRITE (%i) x0=%i y0=%i\n", count, x0, y0); + + for (n = 0; n < count; n++) { + wb = (dev->fontx[buf[n]] + 7) / 8; + DEBUG("PGC: ch=0x%02x w=%i h=%i wb=%i\n", + buf[n], dev->fontx[buf[n]], dev->fonty[buf[n]], wb); + + for (y = 0; y < dev->fonty[buf[n]]; y++) { + mask = 0x80; + row = &dev->font[buf[n]][y * wb]; + for (x = 0; x < dev->fontx[buf[n]]; x++) { + if (row[0] & mask) + pgc_plot(dev, x + x0, y0 - y); + mask = mask >> 1; + if (mask == 0) { + mask = 0x80; + row++; + } + } + } + + x0 += dev->fontx[buf[n]]; + } } @@ -1331,7 +1414,7 @@ hndl_window(pgc_t *dev) * The following ASCII entries have special meaning: * ~~~~~~ command is valid only in hex mode * ****** end of subclass command list, now process core command list - * @@@@@@ end of core command list + * end of core command list * */ static const pgc_cmd_t pgc_commands[] = { @@ -1384,16 +1467,19 @@ static const pgc_cmd_t pgc_commands[] = { { "P", 0x30, hndl_poly, parse_poly, 0 }, { "RESETF", 0x04, hndl_resetf, NULL, 0 }, { "RF", 0x04, hndl_resetf, NULL, 0 }, + { "TDEFIN", 0x84, hndl_tdefin, NULL, 0 }, + { "TD", 0x84, hndl_tdefin, NULL, 0 }, { "TJUST", 0x85, hndl_tjust, pgc_parse_bytes, 2 }, { "TJ", 0x85, hndl_tjust, pgc_parse_bytes, 2 }, { "TSIZE", 0x81, hndl_tsize, pgc_parse_coords, 1 }, { "TS", 0x81, hndl_tsize, pgc_parse_coords, 1 }, + { "TWRITE", 0x8b, hndl_twrite, NULL, 0 }, { "VWPORT", 0xb2, hndl_vwport, pgc_parse_words, 4 }, { "VWP", 0xb2, hndl_vwport, pgc_parse_words, 4 }, { "WINDOW", 0xb3, hndl_window, pgc_parse_words, 4 }, { "WI", 0xb3, hndl_window, pgc_parse_words, 4 }, - { "@@@@@@", 0x00, NULL, NULL, 0 } + { NULL } }; @@ -1427,7 +1513,6 @@ pgc_thread(void *priv) if (! parse_command(dev, &cmd)) { /* Are we shutting down? */ if (dev->stopped) { -INFO("PGC: thread stopping..\n"); dev->stopped = 0; break; } @@ -1493,7 +1578,7 @@ pgc_result_word(pgc_t *dev, int16_t val) char buf[20]; if (! dev->ascii_mode) { - if (! output_byte(dev, val & 0xFF)) return 0; + if (! output_byte(dev, val & 0xff)) return 0; return output_byte(dev, val >> 8); } @@ -1511,7 +1596,7 @@ pgc_result_word(pgc_t *dev, int16_t val) int pgc_error(pgc_t *dev, int err) { - if (dev->mapram[0x307]) { + if (dev->mapram[0x0307]) { /* Errors enabled? */ if (dev->ascii_mode) { if (err >= PGC_ERROR_RANGE && err <= PGC_ERROR_MISSING) @@ -1535,16 +1620,16 @@ pgc_reset(pgc_t *dev) memset(dev->mapram, 0x00, sizeof(dev->mapram)); /* The 'CGA disable' jumper is not currently implemented. */ - dev->mapram[0x30b] = dev->cga_enabled = 1; - dev->mapram[0x30c] = dev->cga_enabled; - dev->mapram[0x30d] = dev->cga_enabled; + dev->mapram[0x030b] = dev->cga_enabled = 1; + dev->mapram[0x030c] = dev->cga_enabled; + dev->mapram[0x030d] = dev->cga_enabled; - dev->mapram[0x3f8] = 0x03; /* minor version */ - dev->mapram[0x3f9] = 0x01; /* minor version */ - dev->mapram[0x3fb] = 0xa5; /* } */ - dev->mapram[0x3fc] = 0x5a; /* PGC self-test passed */ - dev->mapram[0x3fd] = 0x55; /* } */ - dev->mapram[0x3fe] = 0x5a; /* } */ + dev->mapram[0x03f8] = 0x03; /* minor version */ + dev->mapram[0x03f9] = 0x01; /* minor version */ + dev->mapram[0x03fb] = 0xa5; /* } */ + dev->mapram[0x03fc] = 0x5a; /* PGC self-test passed */ + dev->mapram[0x03fd] = 0x55; /* } */ + dev->mapram[0x03fe] = 0x5a; /* } */ dev->ascii_mode = 1; /* start off in ASCII mode */ dev->line_pattern = 0xffff; @@ -1631,25 +1716,33 @@ pgc_wake(pgc_t *dev) void pgc_sleep(pgc_t *dev) { + uint8_t *n = NULL; + DEBUG("PGC: sleeping on %i %i %i %i 0x%02x 0x%02x\n", dev->stopped, dev->waiting_input_fifo, dev->waiting_output_fifo, - dev->waiting_error_fifo, dev->mapram[0x300], dev->mapram[0x301]); + dev->waiting_error_fifo, dev->mapram[0x0300], dev->mapram[0x0301]); /* Avoid entering waiting state. */ - if (dev->stopped) return; + if (dev->stopped) { + dev->waiting_input_fifo = 0; + dev->waiting_output_fifo = 0; + if (n != NULL) + *n = 0; + return; + } /* Race condition: If host wrote to the PGC during the that * won't be noticed */ if (dev->waiting_input_fifo && - dev->mapram[0x300] != dev->mapram[0x301]) { + dev->mapram[0x0300] != dev->mapram[0x0301]) { dev->waiting_input_fifo = 0; return; } /* Same if they read. */ if (dev->waiting_output_fifo && - dev->mapram[0x302] != (uint8_t)(dev->mapram[0x303] - 1)) { + dev->mapram[0x0302] != (uint8_t)(dev->mapram[0x0303] - 1)) { dev->waiting_output_fifo = 0; return; } @@ -2074,14 +2167,16 @@ pgc_ito_raster(pgc_t *dev, int32_t *x, int32_t *y) void pgc_recalctimings(pgc_t *dev) { - double disptime, _dispontime, _dispofftime; + double _dispontime, _dispofftime; + double disptime; /* Use a fixed 640x400 display. */ disptime = dev->screenw + 11; _dispontime = dev->screenw; _dispofftime = disptime - _dispontime; - dev->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - dev->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + + dev->dispontime = (tmrval_t)(_dispontime * (1 << TIMER_SHIFT)); + dev->dispofftime = (tmrval_t)(_dispofftime * (1 << TIMER_SHIFT)); } @@ -2092,10 +2187,10 @@ pgc_cga_text(pgc_t *dev, int w) uint8_t chr, attr; int drawcursor = 0; uint32_t cols[2]; - int pitch = (dev->mapram[0x3e9] + 1) * 2; + int pitch = (dev->mapram[0x03e9] + 1) * 2; uint16_t sc = (dev->displine & 0x0f) % pitch; - uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; - uint16_t ca = (dev->mapram[0x3ef] | (dev->mapram[0x3ee] << 8)) & 0x3fff; + uint16_t ma = (dev->mapram[0x03ed] | (dev->mapram[0x03ec] << 8)) & 0x3fff; + uint16_t ca = (dev->mapram[0x03ef] | (dev->mapram[0x03ee] << 8)) & 0x3fff; uint8_t *addr; uint32_t val; int x, c; @@ -2110,13 +2205,13 @@ pgc_cga_text(pgc_t *dev, int w) /* Cursor enabled? */ if (ma == ca && (dev->cgablink & 8) && - (dev->mapram[0x3ea] & 0x60) != 0x20) { - drawcursor = ((dev->mapram[0x3ea] & 0x1f) <= (sc >> 1)) && - ((dev->mapram[0x3eb] & 0x1f) >= (sc >> 1)); + (dev->mapram[0x03ea] & 0x60) != 0x20) { + drawcursor = ((dev->mapram[0x03ea] & 0x1f) <= (sc >> 1)) && + ((dev->mapram[0x03eb] & 0x1f) >= (sc >> 1)); } else drawcursor = 0; - if (dev->mapram[0x3d8] & 0x20) { + if (dev->mapram[0x03d8] & 0x20) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; if ((dev->cgablink & 8) && (attr & 0x80) && !drawcursor) @@ -2143,24 +2238,30 @@ pgc_cga_text(pgc_t *dev, int w) void pgc_cga_gfx40(pgc_t *dev) { - int x, c; + uint16_t ma = (dev->mapram[0x03ed] | (dev->mapram[0x03ec] << 8)) & 0x3fff; uint8_t cols[4]; - int col; - uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; uint8_t *addr; uint16_t dat; + int c, col, x; - cols[0] = (dev->mapram[0x3d9] & 15) + 16; - col = ((dev->mapram[0x3d9] & 16) ? 8 : 0) + 16; + cols[0] = (dev->mapram[0x03d9] & 15) + 16; + col = ((dev->mapram[0x03d9] & 16) ? 8 : 0) + 16; - if (dev->mapram[0x3d8] & 4) { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; - } else if (dev->mapram[0x3d9] & 32) { + /* + * On a real CGA, if bit 2 of port 03D8h and bit 5 of port 03D9h are + * both set, the palette used in graphics modes is red/cyan/white. On + * a PGC, it's magenta/cyan/white. You still get red/cyan/white if + * bit 5 of port 03D9h is not set. This is a firmware issue rather + * than hardware. + */ + if (dev->mapram[0x03d9] & 32) { cols[1] = col | 3; cols[2] = col | 5; cols[3] = col | 7; + } else if (dev->mapram[0x03d8] & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; } else { cols[1] = col | 2; cols[2] = col | 4; @@ -2183,14 +2284,14 @@ pgc_cga_gfx40(pgc_t *dev) void pgc_cga_gfx80(pgc_t *dev) { - int x, c; + uint16_t ma = (dev->mapram[0x03ed] | (dev->mapram[0x03ec] << 8)) & 0x3fff; uint8_t cols[2]; - uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; uint8_t *addr; uint16_t dat; + int c, x; cols[0] = 16; - cols[1] = (dev->mapram[0x3d9] & 15) + 16; + cols[1] = (dev->mapram[0x03d9] & 15) + 16; for (x = 0; x < 40; x++) { addr = &dev->cga_vram[(ma + 2 * x + 80 * (dev->displine >> 2) + 0x2000 * ((dev->displine >> 1) & 1)) & 0x3fff]; @@ -2233,17 +2334,17 @@ pgc_cga_poll(pgc_t *dev) } if (++dev->displine == PGC_CGA_HEIGHT) { - dev->mapram[0x3da] |= 8; + dev->mapram[0x03da] |= 8; dev->cgadispon = 0; } if (dev->displine == PGC_CGA_HEIGHT + 32) { - dev->mapram[0x3da] &= ~8; + dev->mapram[0x03da] &= ~8; dev->cgadispon = 1; dev->displine = 0; } } else { if (dev->cgadispon) - dev->mapram[0x3da] &= ~1; + dev->mapram[0x03da] &= ~1; dev->vidtime += dev->dispontime; dev->linepos = 0; @@ -2262,7 +2363,7 @@ pgc_cga_poll(pgc_t *dev) /* We have a fixed 640x400 screen for CGA modes. */ video_res_x = PGC_CGA_WIDTH; video_res_y = PGC_CGA_HEIGHT; - switch (dev->mapram[0x3d8] & 0x12) { + switch (dev->mapram[0x03d8] & 0x12) { case 0x12: video_bpp = 1; break; @@ -2296,7 +2397,7 @@ pgc_poll(priv_t priv) /* Not CGA, so must be native mode. */ if (! dev->linepos) { dev->vidtime += dev->dispofftime; - dev->mapram[0x3da] |= 1; + dev->mapram[0x03da] |= 1; dev->linepos = 1; if (dev->cgadispon && (uint32_t)dev->displine < dev->maxh) { if (dev->displine == 0) @@ -2318,18 +2419,18 @@ pgc_poll(priv_t priv) } if (++dev->displine == dev->screenh) { - dev->mapram[0x3da] |= 8; + dev->mapram[0x03da] |= 8; dev->cgadispon = 0; } if (dev->displine == dev->screenh + 32) { - dev->mapram[0x3da] &= ~8; + dev->mapram[0x03da] &= ~8; dev->cgadispon = 1; dev->displine = 0; } } else { if (dev->cgadispon) - dev->mapram[0x3da] &= ~1; + dev->mapram[0x03da] &= ~1; dev->vidtime += dev->dispontime; dev->linepos = 0; @@ -2444,7 +2545,7 @@ pgc_write(uint32_t addr, uint8_t val, priv_t priv) * * Map 2K here in case a clone requires it. */ - if (addr >= 0xc6000 && addr < 0xc6800) { + if (addr >= 0x0c6000 && addr < 0x0c6800) { addr &= 0x7ff; /* If one of the FIFOs has been updated, this may cause @@ -2454,48 +2555,48 @@ pgc_write(uint32_t addr, uint8_t val, priv_t priv) dev->mapram[addr] = val; switch (addr) { - case 0x300: /* input write pointer */ + case 0x0300: /* input write pointer */ if (dev->waiting_input_fifo && - dev->mapram[0x300] != dev->mapram[0x301]) { + dev->mapram[0x0300] != dev->mapram[0x0301]) { dev->waiting_input_fifo = 0; pgc_wake(dev); } break; - case 0x303: /* output read pointer */ + case 0x0303: /* output read pointer */ if (dev->waiting_output_fifo && - dev->mapram[0x302] != (uint8_t)(dev->mapram[0x303] - 1)) { + dev->mapram[0x0302] != (uint8_t)(dev->mapram[0x0303] - 1)) { dev->waiting_output_fifo = 0; pgc_wake(dev); } break; - case 0x305: /* error read pointer */ + case 0x0305: /* error read pointer */ if (dev->waiting_error_fifo && - dev->mapram[0x304] != (uint8_t)(dev->mapram[0x305] - 1)) { + dev->mapram[0x0304] != (uint8_t)(dev->mapram[0x0305] - 1)) { dev->waiting_error_fifo = 0; pgc_wake(dev); } break; - case 0x306: /* cold start flag */ + case 0x0306: /* cold start flag */ /* XXX This should be in IM-1024 specific code */ - dev->mapram[0x306] = 0; + dev->mapram[0x0306] = 0; break; - case 0x30c: /* display type */ - pgc_setdisplay(priv, dev->mapram[0x30c]); - dev->mapram[0x30d] = dev->mapram[0x30c]; + case 0x030c: /* display type */ + pgc_setdisplay(priv, dev->mapram[0x030c]); + dev->mapram[0x030d] = dev->mapram[0x030c]; break; - case 0x3ff: /* reboot the PGC */ + case 0x03ff: /* reboot the PGC */ pgc_wake(dev); break; } } } - if (addr >= 0xb8000 && addr < 0xc0000 && dev->cga_selected) { + if (addr >= 0x0b8000 && addr < 0x0c0000 && dev->cga_selected) { addr &= 0x3fff; dev->cga_vram[addr] = val; } @@ -2508,10 +2609,10 @@ pgc_read(uint32_t addr, priv_t priv) pgc_t *dev = (pgc_t *)priv; uint8_t ret = 0xff; - if (addr >= 0xc6000 && addr < 0xc6800) { + if (addr >= 0x0c6000 && addr < 0x0c6800) { addr &= 0x7ff; ret = dev->mapram[addr]; - } else if (addr >= 0xb8000 && addr < 0xc0000 && dev->cga_selected) { + } else if (addr >= 0x0b8000 && addr < 0x0c0000 && dev->cga_selected) { addr &= 0x3fff; ret = dev->cga_vram[addr]; } @@ -2541,14 +2642,14 @@ pgc_close(priv_t priv) * stops reading data. */ dev->stopped = 1; - dev->mapram[0x3ff] = 1; + dev->mapram[0x03ff] = 1; if (dev->waiting_input_fifo || dev->waiting_output_fifo) { /* Do an immediate wake-up. */ wake_timer(priv); } /* Wait for thread to stop. */ - while (dev->stopped); + thread_wait(dev->pgc_thread, -1); if (dev->cga_vram) free(dev->cga_vram); @@ -2572,10 +2673,20 @@ pgc_init(pgc_t *dev, int maxw, int maxh, int visw, int vish, { int i; - mem_map_add(&dev->mapping, 0xc6000, 2048, + /* + * Make it a 16k mapping at C4000 (will be C4000-C7FFF), + * because of the emulator's granularity - the original + * mapping will conflict with hard disk controller BIOS'es. + */ +#if 0 + mem_map_add(&dev->mapping, 0x0c6000, 2048, +#else + mem_map_add(&dev->mapping, 0x0c4000, 16384, +#endif pgc_read,NULL,NULL, pgc_write,NULL,NULL, NULL, MEM_MAPPING_EXTERNAL, (priv_t)dev); - mem_map_add(&dev->cga_mapping, 0xb8000, 32768, + + mem_map_add(&dev->cga_mapping, 0x0b8000, 32768, pgc_read,NULL,NULL, pgc_write,NULL,NULL, NULL, MEM_MAPPING_EXTERNAL, (priv_t)dev); diff --git a/src/devices/video/vid_pgc.h b/src/devices/video/vid_pgc.h index 8f30737..1db1d9c 100644 --- a/src/devices/video/vid_pgc.h +++ b/src/devices/video/vid_pgc.h @@ -8,7 +8,7 @@ * * Definitions for the PGC driver. * - * Version: @(#)vid_pgc.h 1.0.5 2019/05/73 + * Version: @(#)vid_pgc.h 1.0.6 2019/05/17 * * Authors: Fred N. van Kempen, * John Elliott, @@ -63,7 +63,7 @@ typedef struct pgc_cl { } pgc_cl_t; typedef struct pgc_cmd { - char ascii[6]; + const char *ascii; uint8_t hex; void (*handler)(struct pgc *); int (*parser) (struct pgc *, pgc_cl_t *, int); @@ -106,6 +106,10 @@ typedef struct pgc { uint8_t tjust_v; /* vert alignment 1=bottom 2=ctr 3=top*/ int32_t tsize; /* horizontal spacing */ + uint8_t fontx[256]; + uint8_t fonty[256]; + uint8_t font[256][128]; + int32_t x, y, z; /* drawing position */ thread_t *pgc_thread; diff --git a/src/devices/video/vid_s3.c b/src/devices/video/vid_s3.c index 5713171..8f1e4f4 100644 --- a/src/devices/video/vid_s3.c +++ b/src/devices/video/vid_s3.c @@ -50,6 +50,7 @@ #include "../../rom.h" #include "../../device.h" #include "../../plat.h" +#include "../system/clk.h" #include "../system/pci.h" #include "video.h" #include "vid_svga.h" @@ -1342,18 +1343,18 @@ void s3_recalctimings(svga_t *svga) if (ramdac->cr3 & 0x08) svga->hdisp *= 2; /* x2 clock multiplier */ if (((svga->miscout >> 2) & 3) == 3) - svga->clock = cpuclock / svga->getclock(svga->crtc[0x42] & 0x0f, svga->clock_gen); + svga->clock = cpu_clock / svga->getclock(svga->crtc[0x42] & 0x0f, svga->clock_gen); else - svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); + svga->clock = cpu_clock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805) { svga->interlace = svga->crtc[0x42] & 0x20; if (((svga->miscout >> 2) & 3) == 3) - svga->clock = cpuclock / svga->getclock(svga->crtc[0x42] & 0x0f, svga->clock_gen); + svga->clock = cpu_clock / svga->getclock(svga->crtc[0x42] & 0x0f, svga->clock_gen); else - svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); + svga->clock = cpu_clock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); } else { svga->interlace = svga->crtc[0x42] & 0x20; - svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); + svga->clock = cpu_clock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); } switch (svga->crtc[0x67] >> 4) @@ -3442,7 +3443,7 @@ const device_t s3_phoenix_vision864_pci_device = { const device_t s3_diamond_stealth64_vlb_device = { "S3 Trio64 (Diamond Stealth64 DRAM)", - DEVICE_VIDEO(VID_TYPE_SPEC) | DEVICE_PCI, + DEVICE_VIDEO(VID_TYPE_SPEC) | DEVICE_VLB, S3_DIAMOND_STEALTH64_764, ROM_DIAMOND_STEALTH64_764, s3_init, s3_close, NULL, diff --git a/src/devices/video/vid_s3_virge.c b/src/devices/video/vid_s3_virge.c index 13d2b94..2e1c3e5 100644 --- a/src/devices/video/vid_s3_virge.c +++ b/src/devices/video/vid_s3_virge.c @@ -8,7 +8,7 @@ * * S3 ViRGE emulation. * - * Version: @(#)vid_s3_virge.c 1.0.20 2019/05/73 + * Version: @(#)vid_s3_virge.c 1.0.20 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -48,6 +48,7 @@ #include "../../rom.h" #include "../../device.h" #include "../../plat.h" +#include "../system/clk.h" #include "../system/pci.h" #include "video.h" #include "vid_svga.h" @@ -707,7 +708,7 @@ static void s3_virge_recalctimings(svga_t *svga) int m = svga->seqregs[0x13] & 0x7f; double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0; - svga->clock = cpuclock / freq; + svga->clock = cpu_clock / freq; } } diff --git a/src/devices/video/vid_sigma.c b/src/devices/video/vid_sigma.c index e2f0324..fc7ecc7 100644 --- a/src/devices/video/vid_sigma.c +++ b/src/devices/video/vid_sigma.c @@ -54,7 +54,7 @@ * is well, but some strange mishaps with cursor positioning * occur. * - * Version: @(#)vid_sigma.c 1.0.12 2019/05/17 + * Version: @(#)vid_sigma.c 1.0.12 2019/05/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -101,8 +101,7 @@ #include "vid_cga.h" -#define ENABLE_CGA 1 /* set to 1 to enable CGA mode */ -#define SHORT_CARD 0 /* set to 1 to use the new ROMs */ +#define SHORT_CARD 1 /* set to 1 to use the new ROMs */ #if SHORT_CARD @@ -183,9 +182,10 @@ * plane 0-3 */ - -#define COMPOSITE_OLD 0 -#define COMPOSITE_NEW 1 +enum { + COMPOSITE_OLD = 0, + COMPOSITE_NEW +}; typedef struct { @@ -195,6 +195,7 @@ typedef struct { bios_ram; rom_t bios_rom; + uint32_t bios_addr; uint8_t crtc[32]; /* CRTC: real values */ int crtcreg; /* CRTC: Real selected register */ @@ -213,7 +214,8 @@ typedef struct { */ uint8_t crtc_value; /* value to return from a CRTC register read */ - uint8_t sigma_stat; /* status register [0x02da] */ + uint8_t sigma_stat, /* status register [0x02da] */ + fake_stat; /* see sigma_in() for comment */ uint8_t sigma_mode; /* mode control register [0x02d8] */ @@ -275,223 +277,19 @@ recalc_timings(sigma_t *dev) } -static void -sigma_out(uint16_t port, uint8_t val, priv_t priv) -{ - sigma_t *dev = (sigma_t *)priv; - uint8_t old; - - DBGLOG(1, "SIGMA: out(%04x, %02x)\n", port, val); - - if (port >= 0x03d0 && port < 0x03e0) { - dev->lastport = port & 0x0f; - dev->lastwrite = val; - - /* If set to NMI on video I/O... */ - if (dev->enable_nmi && (dev->sigma_ctl & CTL_NMI)) { - dev->lastport |= 0x80; /* card raised NMI */ - nmi = 1; - } - - /* - * For CRTC emulation, the card BIOS sets the - * value to be read from port 0x03d1 like this. - */ - if (port == 0x03d1) - dev->crtc_value = val; - - return; - } - - switch (port) { - case 0x02d0: - case 0x02d2: - case 0x02d4: - case 0x02d6: - dev->crtcreg = val & 0x1f; - break; - - case 0x02d1: - case 0x02d3: - case 0x02d5: - case 0x02d7: - old = dev->crtc[dev->crtcreg]; - dev->crtc[dev->crtcreg] = val & crtcmask[dev->crtcreg]; - if (old != val) { - if (dev->crtcreg < 0x0e || dev->crtcreg > 0x10) { - fullchange = changeframecount; - recalc_timings(dev); - } - } - break; - - case 0x02d8: - dev->sigma_mode = val; - break; - - case 0x02d9: - dev->sigma_ctl = val; - break; - - case 0x02db: - dev->lastport &= 0x7f; - break; - - case 0x02dc: /* reset NMI */ - nmi = 0; - dev->lastport &= 0x7f; - break; - - case 0x02dd: /* page in RAM at 0x0c1800 */ - if (dev->rom_paged) - mmu_invalidate(0x0c0000); - dev->rom_paged = 0; - break; - - case 0x02de: - if (dev->sigma_ctl & CTL_PALETTE) - dev->palette[val >> 4] = (val & 0x0f) ^ 0x0f; - else - dev->plane = val & 3; - break; - } -} - - -static uint8_t -sigma_in(uint16_t port, priv_t priv) -{ - sigma_t *dev = (sigma_t *)priv; - uint8_t ret = 0xff; - - switch (port) { - case 0x02d0: - case 0x02d2: - case 0x02d4: - case 0x02d6: - ret = dev->crtcreg; - break; - - case 0x02d1: - case 0x02d3: - case 0x02d5: - case 0x02d7: - ret = dev->crtc[dev->crtcreg & 0x1f]; - break; - - case 0x2da: - ret = (dev->sigma_ctl & 0xe0) | (dev->sigma_stat & 0x1f); - break; - - case 0x2db: /* return value that triggered NMI */ - ret = dev->lastwrite; - break; - - case 0x2dc: /* port that triggered NMI */ - ret = dev->lastport; - break; - - case 0x2dd: /* page in ROM at 0x0c1800 */ - ret = (dev->rom_paged ? 0x80 : 0); - if (dev->rom_paged) - mmu_invalidate(0x0c0000); - dev->rom_paged = 1; - break; - - case 0x03d1: - case 0x03d3: - case 0x03d5: - case 0x03d7: - ret = dev->crtc_value; - break; - - /* - * For CGA compatibility we have to return something palatable - * on this port. On a real card this functionality can be turned - * on or off with SW1/6. - */ - case 0x03da: - ret = dev->sigma_stat & 0x07; - if (dev->sigma_stat & STATUS_RETR_V) - ret |= 0x08; - break; - } - - DBGLOG(1, "SIGMA: in(%04x) = %02x\n", port, ret); - - return(ret); -} - - -static void -sigma_write(uint32_t addr, uint8_t val, priv_t priv) -{ - sigma_t *dev = (sigma_t *)priv; - - cycles -= 4; - - dev->vram[dev->plane * 0x8000 + (addr & 0x7fff)] = val; -} - - -static uint8_t -sigma_read(uint32_t addr, priv_t priv) -{ - sigma_t *dev = (sigma_t *)priv; - - cycles -= 4; - - return(dev->vram[dev->plane * 0x8000 + (addr & 0x7fff)]); -} - - -/* Write to the RAM part of the 8K ROM/RAM area. */ -static void -sigma_bwrite(uint32_t addr, uint8_t val, priv_t priv) -{ - sigma_t *dev = (sigma_t *)priv; - - addr &= 0x3fff; - if ((addr >= 0x1800) && (addr < 0x2000) && !dev->rom_paged) - dev->bram[addr & 0x07ff] = val; -} - - -/* Read from the 8K ROM/RAM area. */ -static uint8_t -sigma_bread(uint32_t addr, priv_t priv) -{ - sigma_t *dev = (sigma_t *)priv; - uint8_t ret = 0xff; - - /* If address higher than 8K, no go. */ - addr &= 0x3fff; - if (addr < 0x2000) { - if (addr < 0x1800 || dev->rom_paged) { - /* Read from the ROM. */ - ret = dev->bios_rom.rom[addr]; - } else { - /* Read from the RAM. */ - ret = dev->bram[addr & 0x07ff]; - } - } - - return(ret); -} - - /* Render a line in 80-column text mode. */ static void sigma_text80(sigma_t *dev) { uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)); - uint16_t ma = ((dev->ma & 0x3fff) << 1); + uint16_t ma = ((dev->ma << 1) & 0x3fff); uint8_t *vram = dev->vram + (ma << 1); int drawcursor, x, c; uint8_t chr, attr; uint8_t cols[4]; - ca = ca << 1; + /* Update cursor address (in words) to reflect bytes. */ + ca <<= 1; if (dev->sigma_ctl & CTL_CURSOR) ca++; ca &= 0x3fff; @@ -800,7 +598,7 @@ sigma_poll(priv_t priv) dev->vadj--; if (! dev->vadj) { dev->cgadispon = 1; - dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x1fff; dev->sc = 0; } } else if (dev->sc == dev->crtc[9]) { @@ -819,7 +617,7 @@ sigma_poll(priv_t priv) if (! dev->vadj) dev->cgadispon = 1; if (! dev->vadj) - dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x1fff; if ((dev->crtc[10] & 0x60) == 0x20) dev->cursoron = 0; @@ -901,6 +699,232 @@ sigma_poll(priv_t priv) } +static uint8_t +sigma_in(uint16_t port, priv_t priv) +{ + sigma_t *dev = (sigma_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x02d0: + case 0x02d2: + case 0x02d4: + case 0x02d6: + ret = dev->crtcreg; + break; + + case 0x02d1: + case 0x02d3: + case 0x02d5: + case 0x02d7: + ret = dev->crtc[dev->crtcreg & 0x1f]; + break; + + case 0x2da: + ret = (dev->sigma_ctl & 0xe0) | (dev->sigma_stat & 0x1f); + break; + + case 0x2db: /* return value that triggered NMI */ + ret = dev->lastwrite; + break; + + case 0x2dc: /* port that triggered NMI */ + ret = dev->lastport; + break; + + case 0x2dd: /* page in ROM at 0x0c1800 */ + ret = (dev->rom_paged ? 0x80 : 0); + if (dev->rom_paged) + mmu_invalidate(0x0c0000); + dev->rom_paged = 1; + break; + + case 0x03d1: + case 0x03d3: + case 0x03d5: + case 0x03d7: + ret = dev->crtc_value; + break; + + /* + * For CGA compatibility we have to return something palatable + * on this port. On a real card this functionality can be turned + * on or off with SW1/6. + */ + case 0x03da: + if (dev->sigma_mode & MODE_ENABLE) { + ret = dev->sigma_stat & 0x07; + if (dev->sigma_stat & STATUS_RETR_V) + ret |= 0x08; + } else { + /* + * The card is not running yet, and someone + * (probably the system BIOS) is trying to + * read our status in CGA mode. + * + * One of the systems that do this, is the + * DTK XT (PIM-10TB-Z board) with ERSO 2.42 + * BIOS. If this test fails (i.e. it doesnt + * see valid HS and VS bits alternate) it + * will generate lots of annoying beeps.. + * + * So, the trick here is to just send it + * some alternating bits, making it think + * the CGA circuitry is operational. + */ + dev->fake_stat ^= (0x08 | 0x01); + ret = dev->fake_stat; + } + break; + } + + DBGLOG(1, "SIGMA: in(%04x) = %02x\n", port, ret); + + return(ret); +} + + +static void +sigma_out(uint16_t port, uint8_t val, priv_t priv) +{ + sigma_t *dev = (sigma_t *)priv; + uint8_t old; + + DBGLOG(1, "SIGMA: out(%04x, %02x)\n", port, val); + + if (port >= 0x03d0 && port < 0x03e0) { + dev->lastport = port & 0x0f; + dev->lastwrite = val; + + /* If set to NMI on video I/O... */ + if (dev->enable_nmi && (dev->sigma_ctl & CTL_NMI)) { + dev->lastport |= 0x80; /* card raised NMI */ + nmi = 1; + } + + /* + * For CRTC emulation, the card BIOS sets the + * value to be read from port 0x03d1 like this. + */ + if ((port == 0x03d1) || (port == 0x03d3) || + (port == 0x03d5) || (port == 0x03d7)) + dev->crtc_value = val; + + return; + } + + switch (port) { + case 0x02d0: + case 0x02d2: + case 0x02d4: + case 0x02d6: + dev->crtcreg = val & 0x1f; + break; + + case 0x02d1: + case 0x02d3: + case 0x02d5: + case 0x02d7: + old = dev->crtc[dev->crtcreg]; + dev->crtc[dev->crtcreg] = val & crtcmask[dev->crtcreg]; + if (old != val) { + if (dev->crtcreg < 0x0e || dev->crtcreg > 0x10) { + fullchange = changeframecount; + recalc_timings(dev); + } + } + break; + + case 0x02d8: + dev->sigma_mode = val; + break; + + case 0x02d9: + dev->sigma_ctl = val; + break; + + case 0x02db: + dev->lastport &= 0x7f; + break; + + case 0x02dc: /* reset NMI */ + nmi = 0; + dev->lastport &= 0x7f; + break; + + case 0x02dd: /* page in RAM at 0x0c1800 */ + if (dev->rom_paged) + mmu_invalidate(0x0c0000); + dev->rom_paged = 0; + break; + + case 0x02de: + if (dev->sigma_ctl & CTL_PALETTE) + dev->palette[val >> 4] = (val & 0x0f) ^ 0x0f; + else + dev->plane = val & 3; + break; + } +} + + +static uint8_t +sigma_read(uint32_t addr, priv_t priv) +{ + sigma_t *dev = (sigma_t *)priv; + + cycles -= 4; + + return(dev->vram[dev->plane * 0x8000 + (addr & 0x7fff)]); +} + + +static void +sigma_write(uint32_t addr, uint8_t val, priv_t priv) +{ + sigma_t *dev = (sigma_t *)priv; + + cycles -= 4; + + dev->vram[dev->plane * 0x8000 + (addr & 0x7fff)] = val; +} + + +/* Read from the 8K ROM/RAM area. */ +static uint8_t +sigma_bread(uint32_t addr, priv_t priv) +{ + sigma_t *dev = (sigma_t *)priv; + uint8_t ret = 0xff; + + /* If address higher than 8K, no go. */ + addr &= 0x3fff; + if (addr < 0x2000) { + if (addr < 0x1800 || dev->rom_paged) { + /* Read from the ROM. */ + ret = dev->bios_rom.rom[addr]; + } else { + /* Read from the RAM. */ + ret = dev->bram[addr & 0x07ff]; + } + } + + return(ret); +} + + +/* Write to the RAM part of the 8K ROM/RAM area. */ +static void +sigma_bwrite(uint32_t addr, uint8_t val, priv_t priv) +{ + sigma_t *dev = (sigma_t *)priv; + + addr &= 0x3fff; + if ((addr >= 0x1800) && (addr < 0x2000) && !dev->rom_paged) + dev->bram[addr & 0x07ff] = val; +} + + static int load_font(sigma_t *dev, const wchar_t *fn) { @@ -953,6 +977,7 @@ static priv_t sigma_init(const device_t *info, UNUSED(void *parent)) { sigma_t *dev; + int spec; dev = (sigma_t *)mem_alloc(sizeof(sigma_t)); memset(dev, 0x00, sizeof(sigma_t)); @@ -963,8 +988,12 @@ sigma_init(const device_t *info, UNUSED(void *parent)) return(NULL); } + spec = device_get_config_int("enable_spec"); + dev->enable_nmi = device_get_config_int("enable_nmi"); + dev->bios_addr = device_get_config_hex20("bios_addr"); + cga_palette = device_get_config_int("rgb_type") << 1; if (cga_palette > 6) cga_palette = 0; @@ -978,7 +1007,7 @@ sigma_init(const device_t *info, UNUSED(void *parent)) NULL, MEM_MAPPING_EXTERNAL, (priv_t)dev); rom_init(&dev->bios_rom, info->path, - 0xc0000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + dev->bios_addr, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); /* * The BIOS ROM is overlaid by RAM, so remove its default @@ -987,15 +1016,16 @@ sigma_init(const device_t *info, UNUSED(void *parent)) mem_map_disable(&dev->bios_rom.mapping); memcpy(dev->bram, &dev->bios_rom.rom[0x1800], 0x0800); - mem_map_add(&dev->bios_ram, 0xc0000, 0x2000, + mem_map_add(&dev->bios_ram, dev->bios_addr, 0x2000, sigma_bread,NULL,NULL, sigma_bwrite,NULL,NULL, dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, (priv_t)dev); - io_sethandler(0x03d0, 16, - sigma_in,NULL,NULL, sigma_out,NULL,NULL, (priv_t)dev); io_sethandler(0x02d0, 16, sigma_in,NULL,NULL, sigma_out,NULL,NULL, (priv_t)dev); + io_sethandler(0x03d0, 16, + sigma_in,NULL,NULL, sigma_out,NULL,NULL, (priv_t)dev); + timer_add(sigma_poll, (priv_t)dev, &dev->vidtime, TIMER_ALWAYS_ENABLED); /* Start with ROM paged in, BIOS RAM paged out */ @@ -1004,7 +1034,31 @@ sigma_init(const device_t *info, UNUSED(void *parent)) if (dev->enable_nmi) dev->sigma_stat = STATUS_LPEN_T; - video_inform(DEVICE_VIDEO_GET(info->flags), &sigma_timing); + /* + * We can report ourselves as either a CGA card, or as + * an EGA/VGA ("Special") card. The latter is what my + * real Color400 does on my real DTK-1000, but that has + * two drawbacks: + * + * - on some BIOSes (such as the DTK's ERSO) this can + * confuse it into thinking it is an EGA. Some really + * weird behavior has been observed because of this. + * + * - the real Color 400 has its BIOS at CC00:0 (maybe + * because the system BIOS assumes EGA if at C000:0) + * and this means it will not initialize until other + * ROMs have been initialized. System BIOS usually + * does a quick check to see if a video ROM exists, + * and, if so, initializes that before any others. + * + * So, if you have a system that does not like it on + * C000:0, select another location for it, depending + * on your machine's configuration. + */ + if (spec) + video_inform(VID_TYPE_SPEC, &sigma_timing); + else + video_inform(DEVICE_VIDEO_GET(info->flags), &sigma_timing); return((priv_t)dev); } @@ -1041,6 +1095,50 @@ static const device_config_t sigma_config[] = { } } }, + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0x0c0000, + { + { + "C000H (default)", 0x0c0000 + }, + { + "C800H", 0x0c8000 + }, + { + "CC00H", 0x0cc000 + }, + { + "D000H", 0x0d0000 + }, + { + "D400H", 0x0d4000 + }, + { + "D800H", 0x0d8000 + }, + { + "DC00H", 0x0dc000 + }, + { + "E000H", 0x0e0000 + }, + { + "E400H", 0x0e4000 + }, + { + "E800H", 0x0e8000 + }, + { + "EC00H", 0x0ec000 + }, + { + NULL + } + } + }, + { + "enable_spec", "Enable Standalone Mode", CONFIG_BINARY, "", 0 + }, { "enable_nmi", "Enable NMI for CGA emulation", CONFIG_BINARY, "", 1 }, @@ -1052,11 +1150,7 @@ static const device_config_t sigma_config[] = { const device_t sigma_device = { "Sigma Color 400", -#if ENABLE_CGA DEVICE_VIDEO(VID_TYPE_CGA) | DEVICE_ISA, -#else - DEVICE_VIDEO(VID_TYPE_SPEC) | DEVICE_ISA, -#endif 0, BIOS_ROM_PATH, sigma_init, sigma_close, NULL, diff --git a/src/devices/video/vid_tgui9440.c b/src/devices/video/vid_tgui9440.c index 7837af3..b5be217 100644 --- a/src/devices/video/vid_tgui9440.c +++ b/src/devices/video/vid_tgui9440.c @@ -88,6 +88,7 @@ #include "../../rom.h" #include "../../device.h" #include "../../plat.h" +#include "../system/clk.h" #include "../system/pci.h" #include "video.h" #include "vid_svga.h" @@ -545,7 +546,7 @@ void tgui_recalctimings(svga_t *svga) if (tgui->type >= TGUI_9440) { if (svga->miscout & 8) - svga->clock = cpuclock / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); + svga->clock = cpu_clock / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); if (svga->gdcreg[0xf] & 0x08) svga->clock *= 2; @@ -556,20 +557,20 @@ void tgui_recalctimings(svga_t *svga) { switch (((svga->miscout >> 2) & 3) | ((tgui->newctrl2 << 2) & 4) | ((tgui->newctrl2 >> 3) & 8)) { - case 0x02: svga->clock = cpuclock/ 44900000.0; break; - case 0x03: svga->clock = cpuclock/ 36000000.0; break; - case 0x04: svga->clock = cpuclock/ 57272000.0; break; - case 0x05: svga->clock = cpuclock/ 65000000.0; break; - case 0x06: svga->clock = cpuclock/ 50350000.0; break; - case 0x07: svga->clock = cpuclock/ 40000000.0; break; - case 0x08: svga->clock = cpuclock/ 88000000.0; break; - case 0x09: svga->clock = cpuclock/ 98000000.0; break; - case 0x0a: svga->clock = cpuclock/118800000.0; break; - case 0x0b: svga->clock = cpuclock/108000000.0; break; - case 0x0c: svga->clock = cpuclock/ 72000000.0; break; - case 0x0d: svga->clock = cpuclock/ 77000000.0; break; - case 0x0e: svga->clock = cpuclock/ 80000000.0; break; - case 0x0f: svga->clock = cpuclock/ 75000000.0; break; + case 0x02: svga->clock = cpu_clock/ 44900000.0; break; + case 0x03: svga->clock = cpu_clock/ 36000000.0; break; + case 0x04: svga->clock = cpu_clock/ 57272000.0; break; + case 0x05: svga->clock = cpu_clock/ 65000000.0; break; + case 0x06: svga->clock = cpu_clock/ 50350000.0; break; + case 0x07: svga->clock = cpu_clock/ 40000000.0; break; + case 0x08: svga->clock = cpu_clock/ 88000000.0; break; + case 0x09: svga->clock = cpu_clock/ 98000000.0; break; + case 0x0a: svga->clock = cpu_clock/118800000.0; break; + case 0x0b: svga->clock = cpu_clock/108000000.0; break; + case 0x0c: svga->clock = cpu_clock/ 72000000.0; break; + case 0x0d: svga->clock = cpu_clock/ 77000000.0; break; + case 0x0e: svga->clock = cpu_clock/ 80000000.0; break; + case 0x0f: svga->clock = cpu_clock/ 75000000.0; break; } if (svga->gdcreg[0xf] & 0x08) { diff --git a/src/devices/video/vid_tvga.c b/src/devices/video/vid_tvga.c index 3bf1695..077c210 100644 --- a/src/devices/video/vid_tvga.c +++ b/src/devices/video/vid_tvga.c @@ -48,6 +48,7 @@ #include "../../rom.h" #include "../../device.h" #include "../../plat.h" +#include "../system/clk.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" @@ -148,12 +149,12 @@ recalc_timings(svga_t *svga) svga->rowoffset >>= 1; switch (((svga->miscout >> 2) & 3) | ((dev->newctrl2 << 2) & 4)) { - case 2: svga->clock = cpuclock/44900000.0; break; - case 3: svga->clock = cpuclock/36000000.0; break; - case 4: svga->clock = cpuclock/57272000.0; break; - case 5: svga->clock = cpuclock/65000000.0; break; - case 6: svga->clock = cpuclock/50350000.0; break; - case 7: svga->clock = cpuclock/40000000.0; break; + case 2: svga->clock = cpu_clock/44900000.0; break; + case 3: svga->clock = cpu_clock/36000000.0; break; + case 4: svga->clock = cpu_clock/57272000.0; break; + case 5: svga->clock = cpu_clock/65000000.0; break; + case 6: svga->clock = cpu_clock/50350000.0; break; + case 7: svga->clock = cpu_clock/40000000.0; break; } if (dev->oldctrl2 & 0x10) { diff --git a/src/devices/video/vid_voodoo.c b/src/devices/video/vid_voodoo.c index f35c61a..4d04b9e 100644 --- a/src/devices/video/vid_voodoo.c +++ b/src/devices/video/vid_voodoo.c @@ -52,6 +52,7 @@ #include "../../device.h" #include "../../nvr.h" #include "../../plat.h" +#include "../system/clk.h" #include "../system/pci.h" #include "video.h" #include "vid_svga.h" @@ -6262,7 +6263,7 @@ static void voodoo_pixelclock_update(voodoo_t *voodoo) voodoo->pixel_clock = t; - clock_const = cpuclock / t; + clock_const = cpu_clock / t; voodoo->line_time = (int)((double)line_length * clock_const * (double)(1 << TIMER_SHIFT)); } diff --git a/src/machines/m_compaq.c b/src/machines/m_compaq.c index e2eae9b..3e34aa2 100644 --- a/src/machines/m_compaq.c +++ b/src/machines/m_compaq.c @@ -22,7 +22,7 @@ * TheCollector1995, * * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2019 Miran Grca. * Copyright 2008-2018 Sarah Walker. * * This program is free software; you can redistribute it and/or modify @@ -177,7 +177,7 @@ cpq_init(const device_t *info, void *arg) /* Set up our DRAM refresh timer. */ pit_set_out_func(&pit, 1, m_xt_refresh_timer); - device_add(&keyboard_xt_device); + device_add(&keyboard_xt_compaq_device); parallel_setup(0, 0x03bc); if (config.video_card == VID_INTERNAL) diff --git a/src/machines/m_olim24.c b/src/machines/m_olim24.c index 088aeb9..278a54b 100644 --- a/src/machines/m_olim24.c +++ b/src/machines/m_olim24.c @@ -298,6 +298,25 @@ kbd_read(uint16_t port, priv_t priv) } +static void +kbd_reset(olim24_t *dev) +{ + dev->status = STAT_LOCK | STAT_CD; + dev->wantirq = 0; + dev->param = dev->param_total = 0; + dev->mouse_mode = 0; + dev->scan[0] = 0x1c; + dev->scan[1] = 0x53; + dev->scan[2] = 0x01; + dev->scan[3] = 0x4b; + dev->scan[4] = 0x4d; + dev->scan[5] = 0x48; + dev->scan[6] = 0x50; + + keyboard_scan = 1; +} + + static int mse_poll(int x, int y, int z, int b, priv_t priv) { @@ -675,35 +694,27 @@ olim24_init(const device_t *info, void *arg) dev->nvr.tick = rtc_ticker; nvr_init(&dev->nvr); io_sethandler(0x0070, 16, - rtc_read,NULL,NULL, rtc_write,NULL,NULL, &dev->nvr); + rtc_read,NULL,NULL, rtc_write,NULL,NULL, (priv_t)&dev->nvr); io_sethandler(0x0066, 2, - m24_read,NULL,NULL, NULL,NULL,NULL, dev); + m24_read,NULL,NULL, NULL,NULL,NULL, (priv_t)dev); /* Initialize the video adapter. */ m_olim24_vid_init(0); /* Initialize the keyboard. */ - dev->status = STAT_LOCK | STAT_CD; - dev->scan[0] = 0x1c; - dev->scan[1] = 0x53; - dev->scan[2] = 0x01; - dev->scan[3] = 0x4b; - dev->scan[4] = 0x4d; - dev->scan[5] = 0x48; - dev->scan[6] = 0x50; io_sethandler(0x0060, 2, - kbd_read,NULL,NULL, kbd_write,NULL,NULL, dev); + kbd_read,NULL,NULL, kbd_write,NULL,NULL, (priv_t)dev); io_sethandler(0x0064, 1, - kbd_read,NULL,NULL, kbd_write,NULL,NULL, dev); - keyboard_set_table(scancode_xt); + kbd_read,NULL,NULL, kbd_write,NULL,NULL, (priv_t)dev); + kbd_reset(dev); keyboard_send = kbd_adddata_ex; - keyboard_scan = 1; - timer_add(kbd_poll, dev, &keyboard_delay, TIMER_ALWAYS_ENABLED); + keyboard_set_table(scancode_xt); + timer_add(kbd_poll, (priv_t)dev, &keyboard_delay, TIMER_ALWAYS_ENABLED); /* Tell mouse driver about our internal mouse. */ mouse_reset(); - mouse_set_poll(mse_poll, dev); + mouse_set_poll(mse_poll, (priv_t)dev); device_add(&fdc_xt_device); diff --git a/src/machines/m_tandy1000.c b/src/machines/m_tandy1000.c index e05af7f..519d5d7 100644 --- a/src/machines/m_tandy1000.c +++ b/src/machines/m_tandy1000.c @@ -15,7 +15,7 @@ * Sarah Walker, * * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2019 Miran Grca. * Copyright 2008-2018 Sarah Walker. * * This program is free software; you can redistribute it and/or modify @@ -66,9 +66,11 @@ #define TANDY_EEP_SIZE 64 -#define TANDY_RGB 0 -#define TANDY_COMPOSITE 1 +enum { + TANDY_RGB = 0, + TANDY_COMPOSITE +}; enum { EEPROM_IDLE = 0, diff --git a/src/machines/m_tosh1x00.c b/src/machines/m_tosh1x00.c index 695ac83..e62eb4a 100644 --- a/src/machines/m_tosh1x00.c +++ b/src/machines/m_tosh1x00.c @@ -750,7 +750,7 @@ ctl_read(uint16_t addr, priv_t priv) case 0x0f: /* Detect EMS board */ switch (dev->sys_ctl[0x0e]) { case 0x50: - if (mem_size > 512) break; + if (mem_size > 512) ret = (0x90 | dev->ems_port_index); break; diff --git a/src/machines/machine.h b/src/machines/machine.h index 174b207..3a6be8d 100644 --- a/src/machines/machine.h +++ b/src/machines/machine.h @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.h 1.0.33 2019/05/02 + * Version: @(#)machine.h 1.0.34 2019/05/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -52,13 +52,14 @@ #define MACHINE_MCA 0x000100 /* sys has MCA bus */ #define MACHINE_PCI 0x000200 /* sys has PCI bus */ #define MACHINE_AGP 0x000400 /* sys has AGP bus */ -#define MACHINE_HDC 0x010000 /* sys has int HDC */ -#define MACHINE_HDC_PS2 0x020000 /* sys has int PS/2 HDC */ -#define MACHINE_MOUSE 0x040000 /* sys has int mouse */ -#define MACHINE_SOUND 0x080000 /* sys has int sound */ -#define MACHINE_VIDEO 0x100000 /* sys has int video */ -#define MACHINE_SCSI 0x200000 /* sys has int SCSI */ -#define MACHINE_NETWORK 0x400000 /* sys has int network */ +#define MACHINE_FDC 0x010000 /* sys has int FDC */ +#define MACHINE_HDC 0x020000 /* sys has int HDC */ +#define MACHINE_HDC_PS2 0x040000 /* sys has int PS/2 HDC */ +#define MACHINE_MOUSE 0x080000 /* sys has int mouse */ +#define MACHINE_SOUND 0x100000 /* sys has int sound */ +#define MACHINE_VIDEO 0x200000 /* sys has int video */ +#define MACHINE_SCSI 0x400000 /* sys has int SCSI */ +#define MACHINE_NETWORK 0x800000 /* sys has int network */ #define IS_ARCH(a) (machine->flags & (a)) ? 1 : 0; diff --git a/src/pc.c b/src/pc.c index 152c247..df157e6 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,7 +8,7 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.77 2019/05/17 + * Version: @(#)pc.c 1.0.77 2019/05/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -71,6 +71,8 @@ #include "devices/input/mouse.h" #include "devices/floppy/fdd.h" #include "devices/floppy/fdd_common.h" +#include "devices/floppy/fdc.h" +#include "devices/floppy/fdc_pii15xb.h" #include "devices/disk/hdd.h" #include "devices/disk/hdc.h" #include "devices/scsi/scsi.h" @@ -922,11 +924,29 @@ pc_reset_hard_init(void) /* Reset sound system. This MAY add a game port, so before joystick! */ sound_reset(); - /* Reset the Floppy and Hard Disk modules. */ + /* Reset the Floppy module. */ +//FIXME: move to floppy_reset() + switch(config.fdc_type) { + case FDC_NONE: + case FDC_INTERNAL: + break; + + case 10: + device_add(&fdc_pii151b_device); + break; + + case 11: + device_add(&fdc_pii158b_device); + break; + } fdd_reset(); + + /* Reset the Hard Disk module. */ +//FIXME: move to disk_reset() hdc_reset(); /* Reset and reconfigure the SCSI layer. */ +//FIXME: move to scsi_reset() scsi_card_init(); cdrom_hard_reset(); @@ -1086,7 +1106,9 @@ pc_thread(void *param) execx86(clockrate/100); } - mouse_process(); +#ifdef USE_DINPUT + mouse_poll(); +#endif joystick_process(); diff --git a/src/win/mingw/Makefile.MinGW b/src/win/mingw/Makefile.MinGW index 3db9cf9..3ee40ac 100644 --- a/src/win/mingw/Makefile.MinGW +++ b/src/win/mingw/Makefile.MinGW @@ -8,7 +8,7 @@ # # Makefile for Windows systems using the MinGW32 environment. # -# Version: @(#)Makefile.mingw 1.0.89 2019/05/17 +# Version: @(#)Makefile.mingw 1.0.89 2019/05/20 # # Author: Fred N. van Kempen, # @@ -63,7 +63,6 @@ endif # Which modules to include a development build. ifeq ($(DEV_BUILD), y) - CRASHDUMP := y DEV_BRANCH := y AMD_K := y SIS471 := y @@ -231,6 +230,7 @@ OPTS := $(EXTRAS) $(STUFF) \ -D__USE_MINGW_ANSI_STDIO_X RFLAGS := --input-format=rc -O coff LDFLAGS := +O := .o # Options fow Windows, X86. AFLAGS := -msse2 -mfpmath=sse @@ -306,9 +306,6 @@ ifeq ($(LOGGING), y) OPTS += -D_LOGGING RFLAGS += -D_LOGGING endif -ifeq ($(CRASHDUMP), y) - OPTS += -DUSE_CRASHDUMP -endif ifeq ($(RELEASE), y) OPTS += -DRELEASE_BUILD RFLAGS += -DRELEASE_BUILD @@ -767,6 +764,7 @@ DEVOBJ := bugger.o \ js_sw_pad.o js_tm_fcs.o \ FDDOBJ := fdc.o \ + fdc_pii15xb.o \ fdd.o \ fdd_common.o fdd_86f.o \ fdd_fdi.o fdi2raw.o lzf_c.o lzf_d.o \ @@ -856,15 +854,8 @@ VIDOBJ := video.o \ PLATOBJ := win.o \ win_lang.o win_dynld.o win_opendir.o win_thread.o \ - win_cdrom.o win_keyboard.o win_serial.o win_midi.o -ifeq ($(DINPUT), y) - PLATOBJ += win_mouse.o win_joystick.o -else - PLATOBJ += win_mouse_ri.o win_joystick_xi.o -endif -ifeq ($(CRASHDUMP), y) -PLATOBJ += win_crashdump.o -endif + win_cdrom.o win_keyboard.o win_serial.o win_midi.o \ + win_mouse.o win_joystick.o OBJ := $(MAINOBJ) $(CPUOBJ) $(MCHOBJ) $(SYSOBJ) $(CHIPOBJ) \ diff --git a/src/win/msvc/Makefile.VC b/src/win/msvc/Makefile.VC index 3ca3176..9028e5b 100644 --- a/src/win/msvc/Makefile.VC +++ b/src/win/msvc/Makefile.VC @@ -8,7 +8,7 @@ # # Makefile for Windows using Visual Studio 2015. # -# Version: @(#)Makefile.VC 1.0.73 2019/05/17 +# Version: @(#)Makefile.VC 1.0.73 2019/05/20 # # Author: Fred N. van Kempen, # @@ -63,7 +63,6 @@ endif # Which modules to include a development build. ifeq ($(DEV_BUILD), y) - CRASHDUMP := y DEV_BRANCH := y AMD_K := y SIS471 := y @@ -207,6 +206,7 @@ else LOPTS_C := -SUBSYSTEM:CONSOLE,5.01 LOPTS_W := -SUBSYSTEM:WINDOWS,5.01 endif +O := .obj # Add general build options from the environment. @@ -248,9 +248,6 @@ ifeq ($(LOGGING), y) OPTS += -D_LOGGING RFLAGS += -D_LOGGING endif -ifeq ($(CRASHDUMP), y) - OPTS += -DUSE_CRASHDUMP -endif ifeq ($(RELEASE), y) OPTS += -DRELEASE_BUILD RFLAGS += -DRELEASE_BUILD @@ -585,17 +582,17 @@ ifeq ($(DEV_BRANCH), y) ifeq ($(EL1), y) OPTS += -DUSE_EL1 - DEVBROBJ += net_3c501.o + DEVBROBJ += net_3c501.obj endif ifeq ($(PCNET), y) OPTS += -DUSE_IBMPCNET - DEVBROBJ += net_ibmpcnet.o + DEVBROBJ += net_ibmpcnet.obj endif ifeq ($(ARTI), y) OPTS += -DUSE_ARTISOFT - DEVBROBJ += net_arti2m.o + DEVBROBJ += net_arti2m.obj endif endif @@ -677,6 +674,7 @@ DEVOBJ := bugger.obj \ js_sw_pad.obj js_tm_fcs.obj FDDOBJ := fdc.obj \ + fdc_pii15xb.obj \ fdd.obj \ fdd_common.obj fdd_86f.obj \ fdd_fdi.obj fdi2raw.obj lzf_c.obj lzf_d.obj \ @@ -770,9 +768,6 @@ PLATOBJ := win.obj \ win_lang.obj win_opendir.obj win_dynld.obj win_thread.obj \ win_cdrom.obj win_keyboard.obj win_mouse.obj \ win_joystick.obj win_midi.obj -ifeq ($(CRASHDUMP), y) -PLATOBJ += win_crashdump.obj -endif OBJ := $(MAINOBJ) $(CPUOBJ) $(MCHOBJ) $(SYSOBJ) $(CHIPOBJ) \ diff --git a/src/win/win.c b/src/win/win.c index dbe02f2..5942a10 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -8,7 +8,7 @@ * * Platform main support module for Windows. * - * Version: @(#)win.c 1.0.30 2019/05/03 + * Version: @(#)win.c 1.0.31 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -231,11 +231,6 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) (void)ui_lang_set(lang); } -#ifdef USE_CRASHDUMP - /* Enable crash dump services. */ - InitCrashDump(); -#endif - /* Create console window. */ if (force_debug) plat_console(1); diff --git a/src/win/win.h b/src/win/win.h index 3b7e49b..50d99f4 100644 --- a/src/win/win.h +++ b/src/win/win.h @@ -10,13 +10,13 @@ * only things used globally within the Windows platform; the * generic platform defintions are in the plat.h file. * - * Version: @(#)win.h 1.0.24 2019/03/21 + * Version: @(#)win.h 1.0.25 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, * * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2019 Miran Grca. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -103,14 +103,12 @@ extern const vidapi_t d3d_vidapi; /* Internal platform support functions. */ -#ifdef USE_CRASHDUMP -extern void InitCrashDump(void); -#endif extern HICON LoadIconEx(PCTSTR name); extern void keyboard_getkeymap(void); extern void keyboard_handle(LPARAM lParam, int focus); extern void win_mouse_init(void); extern void win_mouse_close(void); +extern void mouse_handle(LPARAM lParam, int focus); /* Internal dialog functions. */ extern void dialog_center(HWND hdlg); diff --git a/src/win/win_crashdump.c b/src/win/win_crashdump.c deleted file mode 100644 index b0f1052..0000000 --- a/src/win/win_crashdump.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. - * - * This file is part of the VARCem Project. - * - * Handle generation of crash-dump reports. - * - * Version: @(#)win_crashdump.c 1.0.9 2018/10/24 - * - * Authors: Fred N. van Kempen, - * Riley (Rai-chan), - * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2017 Riley (Rai-chan). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. - */ -#define _WIN32_WINNT 0x0501 -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include -#include "../emu.h" -#include "../version.h" -#include "../plat.h" - - -#define ExceptionHandlerBufferSize (10240) - - -static PVOID hExceptionHandler; -static char *ExceptionHandlerBuffer, - *CurrentBufferPointer; -static char ExceptionHandlerFileName[1024]; - - -static LONG CALLBACK -MakeCrashDump(PEXCEPTION_POINTERS ExceptionInfo) -{ - SYSTEMTIME SystemTime; - HANDLE hDumpFile; - char *BufPtr; - DWORD i; - - /* Get current system date and time. */ - GetSystemTime(&SystemTime); - - /* - * Win32-specific functions will be used wherever possible, - * just in case the C stdlib-equivalents try to allocate - * memory. - * (The Win32-specific functions are generally just wrappers - * over NT system calls anyway.) - */ - if ((ExceptionInfo->ExceptionRecord->ExceptionCode >> 28) != 0xC) { - /* - * ExceptionCode is not a fatal exception (high 4b of - * ntstatus = 0xC) Not going to crash, let's not make - * a crash dump. - */ - return(EXCEPTION_CONTINUE_SEARCH); - } - - /* - * So, the program is about to crash. Oh no what do? - * Let's create a crash dump file as a debugging-aid. - * - * First, get the path to the executable. - */ - GetModuleFileName(NULL,ExceptionHandlerBuffer,ExceptionHandlerBufferSize); - if (GetLastError() != ERROR_SUCCESS) { - /* Could not get full path, create in current directory. */ - BufPtr = ExceptionHandlerBuffer; - } else { - /* - * Walk through the string backwards looking for the - * last backslash, so as to remove the "VARCem.exe" - * filename from the string. - */ - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; - for (; BufPtr > ExceptionHandlerBuffer; BufPtr--) { - if (BufPtr[0] == '\\') { - /* Found backslash, terminate the string after it. */ - BufPtr[1] = 0; - break; - } - } - - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; - } - - /* - * What would a good filename be? - * - * It should contain the current date and time so as - * to be (hopefully!) unique. - */ - plat_tempfile((wchar_t *)ExceptionHandlerBuffer, NULL, DUMP_FILE_EXT); - wcstombs(ExceptionHandlerFileName, (wchar_t *)ExceptionHandlerBuffer, - sizeof(ExceptionHandlerFileName)); - - - /* Now the filename is in the buffer, the file can be created. */ - hDumpFile = CreateFile( - ExceptionHandlerFileName, // The filename of the file to open. - GENERIC_WRITE, // The permissions to request. - 0, // Make sure other processes can't - // touch the crash dump at all - // while it's open. - NULL, // Leave the security descriptor - // undefined, it doesn't matter. - OPEN_ALWAYS, // Opens the file if it exists, - // creates a new file if it doesn't. - FILE_ATTRIBUTE_NORMAL, // File attributes / etc don't matter. - NULL); // A template file is not being used. - - /* Check to make sure the file was actually created. */ - if (hDumpFile == INVALID_HANDLE_VALUE) { - /* CreateFile() failed, so just do nothing more. */ - return(EXCEPTION_CONTINUE_SEARCH); - } - - /* - * Write the data we were passed out in a human-readable format. - * - * Get the name of the module where the exception occurred. - */ - HMODULE hMods[1024]; - MODULEINFO modInfo; - HMODULE ipModule = 0; - DWORD cbNeeded, w; - - /* Try to get a list of all loaded modules. */ - if (EnumProcessModules(GetCurrentProcess(), - hMods, sizeof(hMods), &cbNeeded)) { - /* Got it, now walk through all modules.. */ - for (w=0; w<(cbNeeded / sizeof(HMODULE)); w++) { - /* For each module, get the module information. */ - GetModuleInformation(GetCurrentProcess(), - hMods[w], &modInfo, sizeof(MODULEINFO)); - /* If the exception address is in the range of this module.. */ - if ( ((char *)ExceptionInfo->ExceptionRecord->ExceptionAddress >= (char *)modInfo.lpBaseOfDll) && - ((char *)ExceptionInfo->ExceptionRecord->ExceptionAddress < ((char *)modInfo.lpBaseOfDll + modInfo.SizeOfImage))) { - /* ...this is the module we're looking for! */ - ipModule = hMods[w]; - break; - } - } - } - - /* Start to put the crash-dump string into the buffer. */ - sprintf(ExceptionHandlerBuffer, - "#\r\n# %s %s\r\n#\r\n" - "# Crash on %d-%02d-%02d at %02d:%02d:%02d.%03d\r\n#\r\n" - "\r\n" - "Exception details:\r\n" - " NTSTATUS code: 0x%08lx\r\n Address: 0x%p", - emu_title, emu_fullversion, - SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, - SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, - SystemTime.wMilliseconds, - ExceptionInfo->ExceptionRecord->ExceptionCode, - (void *)ExceptionInfo->ExceptionRecord->ExceptionAddress); - - /* - * If we found the correct module, get the full path to - * the module the exception occured at and include it. - */ - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; - if (ipModule != 0) { - sprintf(BufPtr," ["); - GetModuleFileName(ipModule, &BufPtr[2], - ExceptionHandlerBufferSize - (int)strlen(ExceptionHandlerBuffer)); - if (GetLastError() == ERROR_SUCCESS) { - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; - sprintf(BufPtr,"]"); - BufPtr += 1; - } - } - - sprintf(BufPtr, - "\r\nNumber of parameters: %lu\r\nException parameters: ", - ExceptionInfo->ExceptionRecord->NumberParameters); - - for (i=0; iExceptionRecord->NumberParameters; i++) { - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; - sprintf(BufPtr,"0x%p ", - (void *)ExceptionInfo->ExceptionRecord->ExceptionInformation[i]); - } - BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer) - 1]; - -#if defined(__i386__) && !defined(__x86_64) - PCONTEXT Registers = ExceptionInfo->ContextRecord; - - /* This binary is being compiled for x86, include a register dump. */ - sprintf(BufPtr, - "\r\n\r\nRegister dump:\r\n\r\n" - "EIP:0x%08lx\r\n" - "EAX:0x%08lx EBX:0x%08lx ECX:0x%08lx EDX:0x%08lx\r\n" - "EBP:0x%08lx ESP:0x%08lx ESI:0x%08lx EDI:0x%08lx\r\n\r\n", - Registers->Eip, - Registers->Eax, Registers->Ebx, Registers->Ecx, Registers->Edx, - Registers->Ebp, Registers->Esp, Registers->Esi, Registers->Edi); -#else - /* Register dump not supported by this architecture. */ - /* (MinGW headers seem to lack the x64 CONTEXT structure definition) */ - sprintf(BufPtr, "\r\n"); -#endif - - /* Write the string to disk. */ - WriteFile(hDumpFile, ExceptionHandlerBuffer, - (int)strlen(ExceptionHandlerBuffer), NULL, NULL); - - /* Close the file. */ - CloseHandle(hDumpFile); - - /* Return, therefore causing the crash. */ - return(EXCEPTION_CONTINUE_SEARCH); -} - - -void -InitCrashDump(void) -{ - /* - * An exception handler should not allocate memory, - * so allocate 10kb for it to use if it gets called, - * an amount which should be more than enough. - */ - ExceptionHandlerBuffer = (char *)mem_alloc(ExceptionHandlerBufferSize); - CurrentBufferPointer = ExceptionHandlerBuffer; - - /* - * Register the exception handler. - * Zero first argument means this exception handler gets - * called last, therefore, crash dump is only made, when - * a crash is going to happen. - */ - hExceptionHandler = AddVectoredExceptionHandler(0, MakeCrashDump); -} diff --git a/src/win/win_d3d.cpp b/src/win/win_d3d.cpp index f3c21ca..4375892 100644 --- a/src/win/win_d3d.cpp +++ b/src/win/win_d3d.cpp @@ -8,7 +8,7 @@ * * Rendering module for Microsoft Direct3D 9. * - * Version: @(#)win_d3d.cpp 1.0.19 2019/05/17 + * Version: @(#)win_d3d.cpp 1.0.20 2019/05/19 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -622,16 +622,20 @@ d3d_screenshot(const wchar_t *fn) D3DLOCKED_RECT d3dlr; uint8_t *bits, *pixels, *ptr; HRESULT hr; - int i; + int i, old; #if USE_LIBPNG wchar_t temp[512]; #endif if (! d3dTexture) return; + old = is_enabled; + is_enabled = 0; + hr = d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); if (FAILED(hr)) { ERRLOG("D3D: GetBackBuffer failed, result = %08lx\n", hr); + is_enabled = old; return; } @@ -644,6 +648,7 @@ d3d_screenshot(const wchar_t *fn) ERRLOG("D3D: CreateOffscreenPlainSurface failed, result = %08lx\n", hr); copy->Release(); d3dSurface->Release(); + is_enabled = old; return; } @@ -652,6 +657,7 @@ d3d_screenshot(const wchar_t *fn) ERRLOG("D3D: GetTargetData failed, result = %08lx\n", hr); copy->Release(); d3dSurface->Release(); + is_enabled = old; return; } @@ -660,6 +666,7 @@ d3d_screenshot(const wchar_t *fn) ERRLOG("D3D: LockRect failed, result = %08lx\n", hr); copy->Release(); d3dSurface->Release(); + is_enabled = old; return; } bits = (uint8_t *)d3dlr.pBits; @@ -685,6 +692,8 @@ d3d_screenshot(const wchar_t *fn) d3dSurface->UnlockRect(); d3dSurface->Release(); + is_enabled = old; + #if USE_LIBPNG i = png_write_rgb(fn, 0, pixels, (int16_t)desc.Width, (int16_t)desc.Height); diff --git a/src/win/win_devconf.c b/src/win/win_devconf.c index 889da0d..d1afd59 100644 --- a/src/win/win_devconf.c +++ b/src/win/win_devconf.c @@ -12,7 +12,7 @@ * and builds a complete Win32 DIALOG resource block in a * buffer in memory, and then passes that to the API handler. * - * Version: @(#)win_devconf.c 1.0.24 2019/05/13 + * Version: @(#)win_devconf.c 1.0.25 2019/05/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -517,7 +517,7 @@ dlg_devconf(HWND hwnd, const device_t *device) itm->style = WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX; itm->x = 10; itm->y = y; - itm->cx = 80; + itm->cx = 180; itm->cy = 15; itm->id = id++; diff --git a/src/win/win_joystick.cpp b/src/win/win_joystick.cpp index db54e97..9b77255 100644 --- a/src/win/win_joystick.cpp +++ b/src/win/win_joystick.cpp @@ -13,13 +13,15 @@ * NOTE: Hacks currently needed to compile with MSVC; DX needs to * be updated to 11 or 12 or so. --FvK * - * Version: @(#)win_joystick.cpp 1.0.21 2019/05/03 + * Version: @(#)win_joystick.cpp 1.0.22 2019/05/17 * * Authors: Fred N. van Kempen, + * GH Cao, * Miran Grca, * Sarah Walker, * * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2019 GH Cao. * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. * @@ -43,13 +45,17 @@ */ #define WIN32_LEAN_AND_MEAN #include -#define DIRECTINPUT_VERSION 0x0800 -#include -#ifndef DIDEVTYPE_JOYSTICK +#ifdef USE_DINPUT +# define DIRECTINPUT_VERSION 0x0800 +# include +# ifndef DIDEVTYPE_JOYSTICK /* TODO: This is a crude hack to fix compilation on MSVC ... * it needs a rework at some point */ -# define DIDEVTYPE_JOYSTICK 4 +# define DIDEVTYPE_JOYSTICK 4 +# endif +#else +# include #endif #include #include @@ -71,6 +77,29 @@ #define MAX_PLAT_JOYSTICKS 8 #define STR_FONTNAME "Segoe UI" +#ifndef USE_DINPUT +# define XINPUT_MAX_JOYSTICKS 4 +# define XINPUT_NAME "Xinput compatible controller" +# define XINPUT_NAME_LX "Left Stick X" +# define XINPUT_NAME_LY "Left Stick Y" +# define XINPUT_NAME_RX "Right Stick X" +# define XINPUT_NAME_RY "Right Stick Y" +# define XINPUT_NAME_DPAD_X "D-pad X" +# define XINPUT_NAME_DPAD_Y "D-pad Y" +# define XINPUT_NAME_LB "LB" +# define XINPUT_NAME_RB "RB" +# define XINPUT_NAME_LT "LT" +# define XINPUT_NAME_RT "RT" +# define XINPUT_NAME_A "A" +# define XINPUT_NAME_B "B" +# define XINPUT_NAME_X "X" +# define XINPUT_NAME_Y "Y" +# define XINPUT_NAME_BACK "Back/View" +# define XINPUT_NAME_START "Start/Menu" +# define XINPUT_NAME_LS "Left Stick" +# define XINPUT_NAME_RS "Right Stick" +#endif + typedef struct { char name[64]; @@ -96,12 +125,17 @@ typedef struct { } plat_joystick_t; -static plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +static plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +#ifdef USE_DINPUT static LPDIRECTINPUTDEVICE8 lpdi_joystick[2] = {NULL, NULL}; -static GUID joystick_guids[MAX_JOYSTICKS]; -static LPDIRECTINPUT8 lpdi; +static GUID joystick_guids[MAX_JOYSTICKS]; +static LPDIRECTINPUT8 lpdi; +#else +static XINPUT_STATE controllers[XINPUT_MAX_JOYSTICKS]; +#endif +#ifdef USE_DINPUT /* Callback for DirectInput. */ static BOOL CALLBACK enum_callback(LPCDIDEVICEINSTANCE lpddi, UNUSED(LPVOID data)) @@ -171,11 +205,21 @@ obj_callback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) return(DIENUM_CONTINUE); } +#endif void joystick_init(void) { + plat_joystick_t *js; +#ifdef USE_DINPUT + LPDIRECTINPUTDEVICE8 temp; + DIPROPRANGE joy_axis_range; + DIDEVICEINSTANCE instance; + DIDEVCAPS devcaps; +#else + int val; +#endif int c; /* Only initialize if the game port is enabled. */ @@ -184,44 +228,39 @@ joystick_init(void) INFO("JOYSTICK: initializing (type=%i)\n", config.joystick_type); atexit(joystick_close); - + joysticks_present = 0; - + +#ifdef USE_DINPUT if (FAILED(DirectInput8Create(hInstance, - DIRECTINPUT_VERSION, IID_IDirectInput8A, - (void **) &lpdi, NULL))) + DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **)&lpdi, NULL))) fatal("joystick_init : DirectInputCreate failed\n"); if (FAILED(lpdi->EnumDevices(DIDEVTYPE_JOYSTICK, enum_callback, NULL, DIEDFL_ATTACHEDONLY))) fatal("joystick_init : EnumDevices failed\n"); - INFO("JOYSTICK: %i game device(s) found.\n", joysticks_present); - for (c = 0; c < joysticks_present; c++) { - LPDIRECTINPUTDEVICE8 lpdi_joystick_temp = NULL; - DIPROPRANGE joy_axis_range; - DIDEVICEINSTANCE device_instance; - DIDEVCAPS devcaps; + js = &plat_joystick_state[c]; - if (FAILED(lpdi->CreateDevice(joystick_guids[c], - &lpdi_joystick_temp, NULL))) + temp = NULL; + + if (FAILED(lpdi->CreateDevice(joystick_guids[c], &temp, NULL))) fatal("joystick_init : CreateDevice failed\n"); - if (FAILED(lpdi_joystick_temp->QueryInterface(IID_IDirectInputDevice8, + if (FAILED(temp->QueryInterface(IID_IDirectInputDevice8, (void **)&lpdi_joystick[c]))) fatal("joystick_init : CreateDevice failed\n"); - lpdi_joystick_temp->Release(); + temp->Release(); - memset(&device_instance, 0, sizeof(device_instance)); - device_instance.dwSize = sizeof(device_instance); - if (FAILED(lpdi_joystick[c]->GetDeviceInfo(&device_instance))) + memset(&instance, 0x00, sizeof(instance)); + instance.dwSize = sizeof(instance); + if (FAILED(lpdi_joystick[c]->GetDeviceInfo(&instance))) fatal("joystick_init : GetDeviceInfo failed\n"); DEBUG("Joystick%i:\n", c); - DEBUG(" Name = %s\n", device_instance.tszInstanceName); - DEBUG(" ProductName = %s\n", device_instance.tszProductName); - strncpy(plat_joystick_state[c].name, - device_instance.tszInstanceName, 64); + DEBUG(" Name = %s\n", instance.tszInstanceName); + DEBUG(" ProductName = %s\n", instance.tszProductName); + strncpy(js->name, instance.tszInstanceName, 64); memset(&devcaps, 0, sizeof(devcaps)); devcaps.dwSize = sizeof(devcaps); @@ -231,8 +270,7 @@ joystick_init(void) DEBUG(" Buttons = %i\n", devcaps.dwButtons); DEBUG(" POVs = %i\n", devcaps.dwPOVs); - lpdi_joystick[c]->EnumObjects(obj_callback, - &plat_joystick_state[c], DIDFT_ALL); + lpdi_joystick[c]->EnumObjects(obj_callback, js, DIDFT_ALL); if (FAILED(lpdi_joystick[c]->SetCooperativeLevel(hwndMain, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) fatal("joystick_init : SetCooperativeLevel failed\n"); @@ -260,12 +298,68 @@ joystick_init(void) if (FAILED(lpdi_joystick[c]->Acquire())) fatal("joystick_init : Acquire failed\n"); } +#else + memset(controllers, 0x00, sizeof(controllers)); + + for (c = 0; c < XINPUT_MAX_JOYSTICKS; c++) { + js = &plat_joystick_state[c]; + + val = XInputGetState(c, &controllers[c]); + if (val != ERROR_SUCCESS) continue; + + strcpy(js->name, XINPUT_NAME); + js->nr_axes = 8; + + /* analog stick */ + strcpy(js->axis[0].name, XINPUT_NAME_LX); + js->axis[0].id = 0; /* X axis */ + strcpy(js->axis[1].name, XINPUT_NAME_LY); + js->axis[1].id = 1; /* Y axis */ + strcpy(js->axis[2].name, XINPUT_NAME_RX); + js->axis[2].id = 3; /* RX axis */ + strcpy(js->axis[3].name, XINPUT_NAME_RY); + js->axis[3].id = 4; /* RY axis */ + + /* d-pad, assigned to Z and RZ */ + strcpy(js->axis[4].name, XINPUT_NAME_DPAD_X); + js->axis[4].id = 2; + strcpy(js->name, XINPUT_NAME_DPAD_Y); + js->axis[5].id = 5; + + /* Analog trigger */ + strcpy(js->axis[6].name, XINPUT_NAME_LT); + js->axis[6].id = 6; + strcpy(js->axis[7].name, XINPUT_NAME_RT); + js->axis[7].id = 7; + + js->nr_buttons = 12; + strcpy(js->button[0].name, XINPUT_NAME_A); + strcpy(js->button[1].name, XINPUT_NAME_B); + strcpy(js->button[2].name, XINPUT_NAME_X); + strcpy(js->button[3].name, XINPUT_NAME_Y); + strcpy(js->button[4].name, XINPUT_NAME_LB); + strcpy(js->button[5].name, XINPUT_NAME_RB); + strcpy(js->button[6].name, XINPUT_NAME_LT); + strcpy(js->button[7].name, XINPUT_NAME_RT); + strcpy(js->button[8].name, XINPUT_NAME_BACK); + strcpy(js->button[9].name, XINPUT_NAME_START); + strcpy(js->button[10].name, XINPUT_NAME_LS); + strcpy(js->button[11].name, XINPUT_NAME_RS); + + js->nr_povs = 0; + + joysticks_present++; + } +#endif + + INFO("JOYSTICK: %i game device(s) found.\n", joysticks_present); } void joystick_close(void) { +#ifdef USE_DINPUT if (lpdi_joystick[1]) { lpdi_joystick[1]->Release(); lpdi_joystick[1] = NULL; @@ -275,42 +369,43 @@ joystick_close(void) lpdi_joystick[0]->Release(); lpdi_joystick[0] = NULL; } +#endif } static int get_axis(int joystick_nr, int mapping) { + int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; + + if (LOWORD(pov) == 0xFFFF) + return 0; + if (mapping & POV_X) { - int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; - - if (LOWORD(pov) == 0xFFFF) - return 0; - else - return (int)sin((2*M_PI * (double)pov) / 36000.0) * 32767; + return (int)sin((2*M_PI * (double)pov) / 36000.0) * 32767; } else if (mapping & POV_Y) { - int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; + return (int)-cos((2*M_PI * (double)pov) / 36000.0) * 32767; + } - if (LOWORD(pov) == 0xFFFF) - return 0; - else - return (int)-cos((2*M_PI * (double)pov) / 36000.0) * 32767; - } else - return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id]; + return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id]; } void joystick_process(void) { + plat_joystick_t *js; +#ifdef USE_DINPUT + DIJOYSTATE joystate; +#endif int c, d; if (config.joystick_type == JOYSTICK_NONE) return; for (c = 0; c < joysticks_present; c++) { - DIJOYSTATE joystate; - int b; + js = &plat_joystick_state[c]; +#ifdef USE_DINPUT if (FAILED(lpdi_joystick[c]->Poll())) { lpdi_joystick[c]->Acquire(); lpdi_joystick[c]->Poll(); @@ -320,18 +415,55 @@ joystick_process(void) lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate); } - plat_joystick_state[c].a[0] = joystate.lX; - plat_joystick_state[c].a[1] = joystate.lY; - plat_joystick_state[c].a[2] = joystate.lZ; - plat_joystick_state[c].a[3] = joystate.lRx; - plat_joystick_state[c].a[4] = joystate.lRy; - plat_joystick_state[c].a[5] = joystate.lRz; + js->a[0] = joystate.lX; + js->a[1] = joystate.lY; + js->a[2] = joystate.lZ; + js->a[3] = joystate.lRx; + js->a[4] = joystate.lRy; + js->a[5] = joystate.lRz; - for (b = 0; b < 16; b++) - plat_joystick_state[c].b[b] = joystate.rgbButtons[b] & 0x80; + for (d = 0; d < 16; d++) + js->b[d] = joystate.rgbButtons[d] & 0x80; - for (b = 0; b < 4; b++) - plat_joystick_state[c].p[b] = joystate.rgdwPOV[b]; + for (d = 0; d < 4; d++) + js->p[d] = joystate.rgdwPOV[d]; +#else + d = XInputGetState(c, &controllers[c]); + if (d != ERROR_SUCCESS) continue; + + js->a[0] = controllers[c].Gamepad.sThumbLX; + js->a[1] = controllers[c].Gamepad.sThumbLY; + js->a[3] = controllers[c].Gamepad.sThumbRX; + js->a[4] = controllers[c].Gamepad.sThumbRY; + js->a[6] = controllers[c].Gamepad.bLeftTrigger << 7; + js->a[7] = controllers[c].Gamepad.bLeftTrigger << 7; + + js->b[0] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_A) ? 128 : 0; + js->b[1] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_B) ? 128 : 0; + js->b[2] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_X) ? 128 : 0; + js->b[3] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_Y) ? 128 : 0; + js->b[4] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? 128 : 0; + js->b[5] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) ? 128 : 0; + js->b[6] = (controllers[c].Gamepad.bLeftTrigger > 127) ? 128 : 0; + js->b[7] = (controllers[c].Gamepad.bRightTrigger > 127) ? 128 : 0; + js->b[8] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_BACK) ? 128 : 0; + js->b[9] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_START) ? 128 : 0; + js->b[10] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) ? 128 : 0; + js->b[11] = (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) ? 128 : 0; + + int dpad_x = 0, dpad_y = 0; + if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) + dpad_y += 32767; + if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) + dpad_y -= 32767; + if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) + dpad_x += 32767; + if (controllers[c].Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) + dpad_x -= 32767; + + js->a[2] = dpad_x; + js->a[5] = dpad_y; +#endif } for (c = 0; c < gamedev_get_max_joysticks(config.joystick_type); c++) { diff --git a/src/win/win_mouse.cpp b/src/win/win_mouse.cpp index 82b9500..00457bb 100644 --- a/src/win/win_mouse.cpp +++ b/src/win/win_mouse.cpp @@ -6,16 +6,18 @@ * * This file is part of the VARCem Project. * - * Mouse interface to host device. + * Mouse interface to host using DirectInput or RawInput. * - * Version: @(#)win_mouse.cpp 1.0.8 2019/05/03 + * Version: @(#)win_mouse.cpp 1.0.9 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, + * GH Cao, * Sarah Walker, * * Copyright 2017-2019 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2019 Miran Grca. + * Copyright 2019 GH Cao. * Copyright 2008-2018 Sarah Walker. * * This program is free software; you can redistribute it and/or modify @@ -37,8 +39,19 @@ * USA. */ #include -#define DIRECTINPUT_VERSION 0x0800 -#include +#ifdef USE_DINPUT +# define DIRECTINPUT_VERSION 0x0800 +# include +# define MOUSESTATE DIMOUSESTATE +#else +# include + typedef struct { + int rgbButtons[3]; + int lX, + lY; + int lZ; + } MOUSESTATE; +#endif #include #include #include "../emu.h" @@ -48,28 +61,47 @@ #include "win.h" -static LPDIRECTINPUT8 lpdi; +#ifdef USE_DINPUT static LPDIRECTINPUTDEVICE8 lpdi_mouse = NULL; -static DIMOUSESTATE mousestate; +#endif +static MOUSESTATE mousestate; void win_mouse_close(void) { +#ifdef USE_DINPUT if (lpdi_mouse != NULL) { lpdi_mouse->Release(); lpdi_mouse = NULL; } +#else + RAWINPUTDEVICE ridev; + + ridev.dwFlags = RIDEV_REMOVE; + ridev.hwndTarget = NULL; + ridev.usUsagePage = 0x01; + ridev.usUsage = 0x02; + + RegisterRawInputDevices(&ridev, 1, sizeof(ridev)); +#endif } void win_mouse_init(void) { +#ifdef USE_DINPUT + LPDIRECTINPUT8 lpdi; +#else + RAWINPUTDEVICE ridev; +#endif + atexit(win_mouse_close); mouse_capture = 0; +#ifdef USE_DINPUT if (FAILED(DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **) &lpdi, NULL))) fatal("plat_mouse_init: DirectInputCreate failed\n"); @@ -83,15 +115,27 @@ win_mouse_init(void) if (FAILED(lpdi_mouse->SetDataFormat(&c_dfDIMouse))) fatal("plat_mouse_init: SetDataFormat failed\n"); +#else + /* Initialize the RawInput (mouse) module. */ + ridev.dwFlags = 0; + ridev.hwndTarget = NULL; + ridev.usUsagePage = 0x01; + ridev.usUsage = 0x02; + if (! RegisterRawInputDevices(&ridev, 1, sizeof(ridev))) + fatal("plat_mouse_init: RegisterRawInputDevices failed\n"); +#endif + + memset(&mousestate, 0x00, sizeof(MOUSESTATE)); } +#ifdef USE_DINPUT void -mouse_poll(void) +mouse_process(void) { static int buttons = 0; static int x = 0, y = 0, z = 0; - int b; + int b, changed; if (FAILED(lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate))) { @@ -99,24 +143,136 @@ mouse_poll(void) lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate); } - if (mouse_capture || config.vid_fullscreen) { - if (x != mousestate.lX || y != mousestate.lY || z != mousestate.lZ) { - mouse_x += mousestate.lX; - mouse_y += mousestate.lY; - mouse_z += mousestate.lZ/120; + if (!mouse_capture && !config.vid_fullscreen) return; - x = mousestate.lX; - y = mousestate.lY; - z = mousestate.lZ/120; - } + changed = 0; + if (x != mousestate.lX || y != mousestate.lY || z != mousestate.lZ) { + mouse_x = mousestate.lX; + mouse_y = mousestate.lY; + mouse_z = mousestate.lZ / 120; - b = 0; - if (mousestate.rgbButtons[0] & 0x80) b |= 1; - if (mousestate.rgbButtons[1] & 0x80) b |= 2; - if (mousestate.rgbButtons[2] & 0x80) b |= 4; - if (buttons != b) { - mouse_buttons = b; - buttons = b; - } + x = mousestate.lX; + y = mousestate.lY; + z = mousestate.lZ / 120; + + changed++; + } + + b = 0; + if (mousestate.rgbButtons[0] & 0x80) b |= 1; + if (mousestate.rgbButtons[1] & 0x80) b |= 2; + if (mousestate.rgbButtons[2] & 0x80) b |= 4; + if (buttons != b) { + mouse_buttons = b; + buttons = b; + + changed++; } } + +#else + +void +mouse_handle(LPARAM lParam, int focus) +{ + static int buttons = 0; + static int x = 0, y = 0, z = 0; + uint32_t ri_size; + UINT size = 0; + RAWINPUT *raw; + RAWMOUSE *st; + int b, changed; + + if (! focus) + return; + + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, + &size, sizeof(RAWINPUTHEADER)); + raw = (RAWINPUT *)mem_alloc(size); + + /* Read the raw input data for the mouse. */ + ri_size = GetRawInputData((HRAWINPUT)lParam, RID_INPUT, + raw, &size, sizeof(RAWINPUTHEADER)); + + /* If wrong size, or input is not a mouse, ignore it. */ + if ((ri_size != size) || (raw->header.dwType != RIM_TYPEMOUSE)) { + ERRLOG("MOUSE: bad event buffer %i/%i\n", size, ri_size); + free(raw); + return; + } + + /* Read mouse buttons and wheel. */ + st = &raw->data.mouse; + if (st->usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) + mousestate.rgbButtons[0] |= 0x80; + else if (st->usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) + mousestate.rgbButtons[0] &= ~0x80; + if (st->usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) + mousestate.rgbButtons[1] |= 0x80; + else if (st->usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) + mousestate.rgbButtons[1] &= ~0x80; + if (st->usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) + mousestate.rgbButtons[2] |= 0x80; + else if (st->usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) + mousestate.rgbButtons[2] &= ~0x80; + + if (st->usButtonFlags & RI_MOUSE_WHEEL) + mousestate.lZ += (SHORT)st->usButtonData; + + if (st->usFlags & MOUSE_MOVE_ABSOLUTE) { + /* absolute mouse, i.e. RDP or VNC + * seems to work fine for RDP on Windows 10 + * Not sure about other environments. + */ + static int old_x = st->lLastX, old_y = st->lLastY; + + mousestate.lX += (st->lLastX - old_x) / 100; + mousestate.lY += (st->lLastY - old_y) / 100; + old_x = st->lLastX; + old_y = st->lLastY; +INFO("MOUSE: abs, %i/%i\n", mousestate.lX, mousestate.lY); + } else { + /* Relative mouse, i.e. regular mouse. */ + mousestate.lX += st->lLastX / 100; + mousestate.lY += st->lLastY / 100; +INFO("MOUSE: rel, %i/%i\n", mousestate.lX, mousestate.lY); + } + + /* No longer needed. */ + free(raw); + + if (!mouse_capture && !config.vid_fullscreen) return; + + changed = 0; +INFO("MOUSE: handle(focus=%i) dX=%i dY=%i dZ=%i B=(%i,%i,%i)\n", focus, + mousestate.lX, mousestate.lY, mousestate.lZ, !!mousestate.rgbButtons[0], + !!mousestate.rgbButtons[1], !!mousestate.rgbButtons[2]); + if (x != mousestate.lX || y != mousestate.lY || z != mousestate.lZ) { + mouse_x = mousestate.lX; + mouse_y = mousestate.lY; + mouse_z = mousestate.lZ / 120; + + x = mousestate.lX; + y = mousestate.lY; + z = mousestate.lZ / 120; + + changed++; + } + + b = 0; + if (mousestate.rgbButtons[0] & 0x80) b |= 1; + if (mousestate.rgbButtons[1] & 0x80) b |= 2; + if (mousestate.rgbButtons[2] & 0x80) b |= 4; + if (buttons != b) { + mouse_buttons = b; + buttons = b; + + changed++; + } + + /* Handle the machine end of things. */ + if (changed) + mouse_poll(); +} + +#endif diff --git a/src/win/win_ui.c b/src/win/win_ui.c index fae2e04..172f2fb 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -8,7 +8,7 @@ * * Implement the user Interface module. * - * Version: @(#)win_ui.c 1.0.38 2019/05/03 + * Version: @(#)win_ui.c 1.0.39 2019/05/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -589,6 +589,9 @@ input_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INPUT: keyboard_handle(lParam, infocus); +#ifndef USE_DINPUT + mouse_handle(lParam, infocus); +#endif break; case WM_SETFOCUS: