diff --git a/src/config.c b/src/config.c index 23c5aa8..cdd3af3 100644 --- a/src/config.c +++ b/src/config.c @@ -12,15 +12,15 @@ * it on Windows XP, and possibly also Vista. Use the * -DANSI_CFG for use on these systems. * - * Version: @(#)config.c 1.0.40 2018/11/20 + * Version: @(#)config.c 1.0.41 2019/02/10 * * Authors: Fred N. van Kempen, * Miran Grca, * David Simunic, * 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 @@ -203,7 +203,7 @@ create_section(const char *name) section_t *ns = (section_t *)mem_alloc(sizeof(section_t)); memset(ns, 0x00, sizeof(section_t)); - strncpy(ns->name, name, sizeof(ns->name)); + strncpy(ns->name, name, strlen(ns->name)); list_add(&ns->list, &config_head); return(ns); @@ -216,7 +216,7 @@ create_entry(section_t *section, const char *name) entry_t *ne = (entry_t *)mem_alloc(sizeof(entry_t)); memset(ne, 0x00, sizeof(entry_t)); - strncpy(ne->name, name, sizeof(ne->name)); + strncpy(ne->name, name, strlen(ne->name)); list_add(&ne->list, §ion->entry_head); return(ne); @@ -1947,7 +1947,7 @@ config_set_string(const char *cat, const char *name, const char *val) if (ent == NULL) ent = create_entry(section, name); - strncpy(ent->data, val, sizeof(ent->data)); + strncpy(ent->data, val, strlen(ent->data)); mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); } diff --git a/src/cpu/386.c b/src/cpu/386.c index d375b22..d688483 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -8,13 +8,15 @@ * * Implementation of 80286+ CPU interpreter. * - * Version: @(#)386.c 1.0.5 2018/09/19 + * Version: @(#)386.c 1.0.6 2019/02/10 * - * Authors: Sarah Walker, + * Authors: Fred N. van Kempen, + * Sarah Walker, * Miran Grca, * + * Copyright 2018,2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 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 @@ -80,8 +82,7 @@ int timetolive = 0; /* Also in 386_dynarec.c: */ cpu_state_t cpu_state; int inscounts[256]; -uint32_t oldpc2; -uint32_t oldcs2; +//uint32_t oldcs2, oldpc2; uint32_t oxpc; int trap; int inttype; diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 49e3972..e1d4b13 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -8,13 +8,15 @@ * * Implementation of the CPU's dynamic recompiler. * - * Version: @(#)386_dynarec.c 1.0.5 2018/10/05 + * Version: @(#)386_dynarec.c 1.0.6 2019/02/10 * - * Authors: Sarah Walker, + * Authors: Fred N. van Kempen, * Miran Grca, + * Sarah Walker, * + * Copyright 2018,2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 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 @@ -64,8 +66,6 @@ /* Also in 386.c: */ cpu_state_t cpu_state; int inscounts[256]; -uint32_t oldpc2; -uint32_t oldcs2; uint32_t oxpc; int trap; int inttype; diff --git a/src/device.h b/src/device.h index 916f239..f10ef19 100644 --- a/src/device.h +++ b/src/device.h @@ -8,14 +8,14 @@ * * Definitions for the device handler. * - * Version: @(#)device.h 1.0.8 2018/09/19 + * Version: @(#)device.h 1.0.9 2019/02/10 * * 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 @@ -55,15 +55,16 @@ enum { DEVICE_ALL = 0x0000, /* any/all device */ DEVICE_UNSTABLE = 0x0001, /* unstable device, be cautious */ - DEVICE_AT = 0x0002, /* requires an AT-compatible system */ - DEVICE_PS2 = 0x0004, /* requires a PS/1 or PS/2 system */ + DEVICE_PCJR = 0x0002, /* requires an IBM PCjr */ + DEVICE_AT = 0x0004, /* requires an AT-compatible system */ + DEVICE_PS2 = 0x0008, /* requires a PS/1 or PS/2 system */ DEVICE_ISA = 0x0100, /* requires the ISA bus */ - DEVICE_CBUS = 0x0200, /* requires the C-BUS bus */ - DEVICE_MCA = 0x0400, /* requires the MCA bus */ - DEVICE_EISA = 0x0800, /* requires the EISA bus */ - DEVICE_VLB = 0x1000, /* requires the PCI bus */ - DEVICE_PCI = 0x2000, /* requires the VLB bus */ - DEVICE_AGP = 0x4000 /* requires the AGP bus */ + DEVICE_EISA = 0x0200, /* requires the EISA bus */ + DEVICE_VLB = 0x0400, /* requires the VLB bus */ + DEVICE_PCI = 0x0800, /* requires the PCI bus */ + DEVICE_AGP = 0x1000, /* requires the AGP bus */ + DEVICE_MCA = 0x2000, /* requires the MCA bus */ + DEVICE_CBUS = 0x4000 /* requires the C-BUS bus (PC98) */ }; #define DEVICE_SYS_MASK 0x0006 #define DEVICE_BUS_MASK 0xff00 diff --git a/src/devices/floppy/fdc.c b/src/devices/floppy/fdc.c index b633b2b..fe206e1 100644 --- a/src/devices/floppy/fdc.c +++ b/src/devices/floppy/fdc.c @@ -9,12 +9,12 @@ * Implementation of the NEC uPD-765 and compatible floppy disk * controller. * - * Version: @(#)fdc.c 1.0.17 2018/10/20 + * Version: @(#)fdc.c 1.0.18 2019/02/10 * * Authors: Miran Grca, * Sarah Walker, * - * 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 @@ -164,7 +164,7 @@ fdc_ctrl_reset(void *priv) fdc->head = 0; fdc->abort = 0; fdc->step = 0; - if (! (fdc->flags & FDC_FLAG_AT)) + if (!(fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_PS1)) fdc->rate = 2; } @@ -398,23 +398,6 @@ fdc_update_rates(fdc_t *fdc) } -void -fdc_update_is_nsc(fdc_t *fdc, int is_nsc) -{ - int old_is_nsc = fdc->flags & FDC_FLAG_NSC; - - if (is_nsc) - fdc->flags |= FDC_FLAG_NSC; - else - fdc->flags &= ~FDC_FLAG_NSC; - - if ((old_is_nsc ^ fdc->flags) & FDC_FLAG_NSC) - fdc->densel_force = fdc->densel_force ^ 3; - - fdc_update_rates(fdc); -} - - void fdc_update_max_track(fdc_t *fdc, int max_track) { @@ -661,7 +644,7 @@ fdc_seek(fdc_t *fdc, int drive, int params) { fdd_seek(real_drive(fdc, drive), params); - fdc->time = 5000LL * (1LL << TIMER_SHIFT); + fdc->time = 2048LL * (1LL << TIMER_SHIFT); fdc->stat |= (1 << fdc->drive); } @@ -684,7 +667,7 @@ fdc_bad_command(fdc_t *fdc) { fdc->stat = 0x10; fdc->interrupt = 0xfc; - timer_clock(); + timer_process(); fdc->time = 200LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); } @@ -775,7 +758,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) picintc(1 << fdc->irq); } if ((val & 0x80) && !(fdc->dor & 0x80)) { - timer_clock(); + timer_process(); fdc->time = 128LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->interrupt = -1; @@ -807,7 +790,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->pnum = fdc->ptot = 0; } if ((val & 4) && !(fdc->dor & 4)) { - timer_clock(); + timer_process(); fdc->time = 128LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->interrupt = -1; @@ -819,7 +802,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_ctrl_reset(fdc); } - timer_clock(); + timer_process(); timer_update_outstanding(); /* We simplify this since each motor now spins separately. */ for (i = 0; i < FDD_NUM; i++) { @@ -847,17 +830,13 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) case 4: if (val & 0x80) { - timer_clock(); + timer_process(); fdc->time = 128LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->interrupt = -1; fdc->perp &= 0xfc; fdc_ctrl_reset(fdc); } -#if 0 - if (fdc->flags & FDC_FLAG_PS1) - fdc->rate = val & 0x03; -#endif return; case 5: /*Command register*/ @@ -1051,7 +1030,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) if (fdc->pnum == fdc->ptot) { DEBUG("FDC: got all params %02X\n", fdc->command); fdc->interrupt = fdc->command & 0x1F; - timer_clock(); + timer_process(); fdc->time = 1024LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->reset_stat = 0; @@ -1149,7 +1128,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->st0 = 0x20 | (fdc->params[0] & 3); fdc->pcn[fdc->params[0] & 3] = 0; fdc->interrupt = -3; - timer_clock(); + timer_process(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; @@ -1157,8 +1136,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) fdc_seek(fdc, fdc->drive, -fdc->max_track); DEBUG("FDC: recalibrating...\n"); - fdc->time = 5000LL * (1LL << TIMER_SHIFT); - fdc->step = fdc->seek_dir = 1; + fdc->time = 2048LL * (1LL << TIMER_SHIFT); + fdc->seek_dir = fdc->step = 1; break; case 0x0d: /*Format*/ @@ -1195,7 +1174,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } else fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; fdc->interrupt = -3; - timer_clock(); + timer_process(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; @@ -1214,12 +1193,12 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_seek(fdc, fdc->drive, -fdc->params[1]); fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; } - fdc->time = 5000LL * (1LL << TIMER_SHIFT); + fdc->time = 2048LL * (1LL << TIMER_SHIFT); fdc->step = 1; } else { fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; - timer_clock(); + timer_process(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; @@ -1230,7 +1209,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) DEBUG("FDC: failed seek\n"); fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; - timer_clock(); + timer_process(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); break; @@ -1241,7 +1220,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->seek_dir = 1; fdc_seek(fdc, fdc->drive, fdc->params[1] - fdc->pcn[fdc->params[0] & 3]); fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; - fdc->time = 5000LL * (1LL << TIMER_SHIFT); + fdc->time = 2048LL * (1LL << TIMER_SHIFT); fdc->step = 1; } break; @@ -1287,7 +1266,7 @@ fdc_read(uint16_t addr, void *priv) cycles -= ISA_CYCLES(8); - switch (addr&7) { + switch (addr & 7) { case 0: /* STA */ if (fdc->flags & FDC_FLAG_PS1) { drive = real_drive(fdc, fdc->dor & 3); @@ -1296,9 +1275,9 @@ fdc_read(uint16_t addr, void *priv) Bit 2: INDEX (best return always 0 as it goes by very fast) Bit 6: DRQ */ - if (writeprot[drive]) /* WRITEPROT */ - ret |= 0x01; if (fdc->seek_dir) /* nDIRECTION */ + ret |= 0x01; + if (writeprot[drive]) /* WRITEPROT */ ret |= 0x02; if (!fdd_get_head(drive)) /* nHDSEL */ ret |= 0x08; @@ -1320,10 +1299,20 @@ fdc_read(uint16_t addr, void *priv) if (!fdd_get_type(1)) ret |= 80; /* -Drive Select 1,0 */ - if (drive) - ret |= 0x20; - else - ret |= 0x40; + switch (drive) { + case 0: + ret |= 0x43; + break; + case 1: + ret |= 0x23; + break; + case 2: + ret |= 0x62; + break; + case 3: + ret |= 0x61; + break; + } } else { if (is486) return 0xff; @@ -1349,10 +1338,12 @@ fdc_read(uint16_t addr, void *priv) case 3: drive = real_drive(fdc, fdc->dor & 3); if (fdc->flags & FDC_FLAG_PS1) { + fdc->step = 0; + /* PS/1 Model 2121 seems to return drive type in port - * 0x3f3, despite the 82077AA fdc_t not implementing + * 0x3f3, despite the 82077AA FDC not implementing * this. This is presumably implemented outside the - * fdc_t on one of the motherboard's support chips. + * FDC on one of the motherboard's support chips. * * Confirmed: 00=1.44M 3.5 * 10=2.88M 3.5 @@ -1716,7 +1707,7 @@ fdc_callback(void *priv) if (!fdd_track0(drive_num)) fdc->st0 |= 0x50; fdc->interrupt = -3; - timer_clock(); + timer_process(); fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); fdc->stat = 0x80 | (1 << fdc->drive); @@ -1725,7 +1716,7 @@ fdc_callback(void *priv) case 0x0d: /*Format track*/ if (fdc->format_state == 1) { fdc->format_state = 2; - timer_clock(); + timer_process(); fdc->time = 128LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); } else if (fdc->format_state == 2) { @@ -1771,10 +1762,10 @@ fdc_callback(void *priv) fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; #if 0 - timer_clock(); + timer_process(); +#endif fdc->time = 2048LL * (1LL << TIMER_SHIFT); timer_update_outstanding(); -#endif fdc->stat = 0x80 | (1 << fdc->drive); fdc_callback(fdc); return; @@ -2220,13 +2211,15 @@ fdc_reset(void *priv) fdc->enable_3f1 = 1; - fdc_update_is_nsc(fdc, 0); fdc_update_enh_mode(fdc, 0); if (fdc->flags & FDC_FLAG_PS1) fdc_update_densel_polarity(fdc, 0); else fdc_update_densel_polarity(fdc, 1); - fdc_update_densel_force(fdc, 0); + if (fdc->flags & FDC_FLAG_NSC) + fdc_update_densel_force(fdc, 3); + else + fdc_update_densel_force(fdc, 0); fdc_update_rwc(fdc, 0, default_rwc); fdc_update_rwc(fdc, 1, default_rwc); fdc_update_rwc(fdc, 2, default_rwc); @@ -2236,6 +2229,7 @@ fdc_reset(void *priv) fdc_update_drvrate(fdc, 2, 0); fdc_update_drvrate(fdc, 3, 0); fdc_update_drv2en(fdc, 1); + fdc_update_rates(fdc); fdc->fifo = 0; fdc->tfifo = 1; @@ -2311,6 +2305,7 @@ fdc_init(const device_t *info) fdd_set_fdc(fdc); imd_set_fdc(fdc); img_set_fdc(fdc); + mfm_set_fdc(fdc); fdc_reset(fdc); diff --git a/src/devices/floppy/fdd.c b/src/devices/floppy/fdd.c index 39a9c7c..7dc1dd6 100644 --- a/src/devices/floppy/fdd.c +++ b/src/devices/floppy/fdd.c @@ -8,14 +8,14 @@ * * Implementation of the floppy drive emulation. * - * Version: @(#)fdd.c 1.0.17 2018/10/20 + * Version: @(#)fdd.c 1.0.18 2019/02/10 * * 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 @@ -53,6 +53,7 @@ #include "fdd_imd.h" #include "fdd_img.h" #include "fdd_json.h" +#include "fdd_mfm.h" #include "fdd_td0.h" #include "fdc.h" @@ -73,12 +74,15 @@ int defaultwriteprot = 0; int curdrive = 0; int motorspin; int fdc_indexcount = 52; +int fdd_notfound = 0; +int oldtrack[FDD_NUM] = {0, 0, 0, 0}; #ifdef ENABLE_FDD_LOG int fdd_do_log = ENABLE_FDD_LOG; #endif static fdc_t *fdd_fdc; +static int fdd_period = 32; static const struct { @@ -115,6 +119,7 @@ static const struct { { L"IMD", imd_load, imd_close, -1 }, { L"IMG", img_load, img_close, -1 }, { L"JSON", json_load, json_close, -1 }, + { L"MFM", mfm_load, mfm_close, -1 }, { L"TD0", td0_load, td0_close, -1 }, { L"VFD", img_load, img_close, -1 }, { L"XDF", img_load, img_close, -1 }, @@ -163,14 +168,13 @@ int ui_writeprot[FDD_NUM] = {0, 0, 0, 0}; #define FLAG_IGNORE_DENSEL 512 #define FLAG_PS2 1024 -static const struct -{ - int max_track; - int flags; - const char *name; - const char *internal_name; -} drive_types[] = -{ + +static const struct { + int max_track; + int flags; + const char *name; + const char *internal_name; +} drive_types[] = { { /*None*/ 0, 0, "None", "none" }, @@ -224,526 +228,581 @@ void fdd_log(int level, const char *fmt, ...) { # ifdef ENABLE_FDD_LOG - va_list ap; + va_list ap; - if (fdd_do_log >= level) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } + if (fdd_do_log >= level) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } # endif } #endif -const char *fdd_getname(int type) +const char * +fdd_getname(int type) { - return drive_types[type].name; + return drive_types[type].name; } -const char *fdd_get_internal_name(int type) + +const char * +fdd_get_internal_name(int type) { - return drive_types[type].internal_name; + return drive_types[type].internal_name; } -int fdd_get_from_internal_name(const char *s) + +int +fdd_get_from_internal_name(const char *s) { - int c = 0; + int c = 0; - while (drive_types[c].internal_name != NULL) - { - if (! strcmp(drive_types[c].internal_name, s)) - return c; - c++; - } + while (drive_types[c].internal_name != NULL) { + if (! strcmp(drive_types[c].internal_name, s)) + return c; + c++; + } - /* Not found. */ - return 0; + /* Not found. */ + return 0; } /* This is needed for the dump as 86F feature. */ -void fdd_do_seek(int drive, int track) +void +fdd_do_seek(int drive, int track) { - if (drives[drive].seek) { - drives[drive].seek(drive, track); - } + if (drives[drive].seek) + drives[drive].seek(drive, track); } -void fdd_forced_seek(int drive, int track_diff) + +void +fdd_forced_seek(int drive, int track_diff) { - fdd[drive].track += track_diff; + fdd[drive].track += track_diff; - if (fdd[drive].track < 0) - fdd[drive].track = 0; + if (fdd[drive].track < 0) + fdd[drive].track = 0; - if (fdd[drive].track > drive_types[fdd[drive].type].max_track) - fdd[drive].track = drive_types[fdd[drive].type].max_track; + if (fdd[drive].track > drive_types[fdd[drive].type].max_track) + fdd[drive].track = drive_types[fdd[drive].type].max_track; - fdd_do_seek(drive, fdd[drive].track); + fdd_do_seek(drive, fdd[drive].track); } -void fdd_seek(int drive, int track_diff) + +void +fdd_seek(int drive, int track_diff) { - if (!track_diff) - return; + if (! track_diff) + return; - fdd[drive].track += track_diff; + fdd[drive].track += track_diff; - if (fdd[drive].track < 0) - fdd[drive].track = 0; + if (fdd[drive].track < 0) + fdd[drive].track = 0; - if (fdd[drive].track > drive_types[fdd[drive].type].max_track) - fdd[drive].track = drive_types[fdd[drive].type].max_track; + if (fdd[drive].track > drive_types[fdd[drive].type].max_track) + fdd[drive].track = drive_types[fdd[drive].type].max_track; - fdd_changed[drive] = 0; + fdd_changed[drive] = 0; - fdd_do_seek(drive, fdd[drive].track); + fdd_do_seek(drive, fdd[drive].track); } -int fdd_track0(int drive) + +int +fdd_track0(int drive) { - /* If drive is disabled, TRK0 never gets set. */ - if (!drive_types[fdd[drive].type].max_track) return 0; - - return !fdd[drive].track; -} - -int fdd_current_track(int drive) -{ - return fdd[drive].track; -} - -void fdd_set_densel(int densel) -{ - int i = 0; - - for (i = 0; i < 4; i++) - { - if (drive_types[fdd[i].type].flags & FLAG_INVERT_DENSEL) - { - fdd[i].densel = densel ^ 1; - } - else - { - fdd[i].densel = densel; - } - } -} - -int fdd_getrpm(int drive) -{ - int hole = fdd_hole(drive); - - int densel = 0; - - densel = fdd[drive].densel; - - if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL) - { - densel ^= 1; - } - - if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_360)) return 300; - if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_300)) return 360; - - if (drive_types[fdd[drive].type].flags & FLAG_525) - { - return densel ? 360 : 300; - } - else - { - /* fdd_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */ - if (hole == 1) - { - return densel ? 300 : 360; - } - else - { - return 300; - } - } -} - -int fdd_can_read_medium(int drive) -{ - int hole = fdd_hole(drive); - - hole = 1 << (hole + 4); - - return (drive_types[fdd[drive].type].flags & hole) ? 1 : 0; -} - -int fdd_doublestep_40(int drive) -{ - return (drive_types[fdd[drive].type].flags & FLAG_DOUBLE_STEP) ? 1 : 0; -} - -void fdd_set_type(int drive, int type) -{ - int old_type = fdd[drive].type; - fdd[drive].type = type; - if ((drive_types[old_type].flags ^ drive_types[type].flags) & FLAG_INVERT_DENSEL) - { - fdd[drive].densel ^= 1; - } -} - -int fdd_get_type(int drive) -{ - return fdd[drive].type; -} - -int fdd_get_flags(int drive) -{ - return drive_types[fdd[drive].type].flags; -} - -int fdd_is_525(int drive) -{ - return drive_types[fdd[drive].type].flags & FLAG_525; -} - -int fdd_is_dd(int drive) -{ - return (drive_types[fdd[drive].type].flags & 0x70) == 0x10; -} - -int fdd_is_ed(int drive) -{ - return drive_types[fdd[drive].type].flags & FLAG_HOLE2; -} - -int fdd_is_double_sided(int drive) -{ - return drive_types[fdd[drive].type].flags & FLAG_DS; -} - -void fdd_set_head(int drive, int head) -{ - if (head && !fdd_is_double_sided(drive)) - fdd[drive].head = 0; - else - fdd[drive].head = head; -} - -int fdd_get_head(int drive) -{ - if (!fdd_is_double_sided(drive)) - return 0; - return fdd[drive].head; -} - -void fdd_set_turbo(int drive, int turbo) -{ - fdd[drive].turbo = turbo; -} - -int fdd_get_turbo(int drive) -{ - return fdd[drive].turbo; -} - -void fdd_set_check_bpb(int drive, int check_bpb) -{ - fdd[drive].check_bpb = check_bpb; -} - -int fdd_get_check_bpb(int drive) -{ - return fdd[drive].check_bpb; -} - -int fdd_get_densel(int drive) -{ - if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL) - { - return fdd[drive].densel ^ 1; - } - else - { - return fdd[drive].densel; - } -} - -int fdd_load(int drive, const wchar_t *fn) -{ - int c = 0, size; - int ok; - wchar_t *p; - FILE *f; - - DEBUG("FDD: loading drive %d with '%ls'\n", drive, fn); - - if (!fn) return(0); - p = plat_get_extension(fn); - if (!p) return(0); - f = plat_fopen(fn, L"rb"); - if (!f) return(0); - fseek(f, -1, SEEK_END); - size = ftell(f) + 1; - fclose(f); - while (loaders[c].ext) - { - if (!wcscasecmp(p, loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) - { - driveloaders[drive] = c; - wcsncpy(floppyfns[drive], fn, sizeof_w(floppyfns[drive])); - d86f_setup(drive); - ok = loaders[c].load(drive, floppyfns[drive]); - if (! ok) - goto no_load; - - drive_empty[drive] = 0; - fdd_forced_seek(drive, 0); - fdd_changed[drive] = 1; - return(1); - } - c++; - } -no_load: - DEBUG("FDD: could not load '%ls' %s\n",fn,p); - drive_empty[drive] = 1; - fdd_set_head(drive, 0); - memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); - ui_sb_icon_state(drive, 1); - + /* If drive is disabled, TRK0 never gets set. */ + if (! drive_types[fdd[drive].type].max_track) return 0; + + return !fdd[drive].track; } -void fdd_close(int drive) + +int +fdd_current_track(int drive) { - DEBUG("FDD: closing drive %d\n", drive); -pclog(0,"FDD: close(%d)\n",drive); - - /* Make sure the 86F poll is back to idle state. */ - d86f_stop(drive); - -pclog(0,"FDD: close(%d) 1\n",drive); - if (loaders[driveloaders[drive]].close) - loaders[driveloaders[drive]].close(drive); - -pclog(0,"FDD: close(%d) 2\n",drive); - drive_empty[drive] = 1; - - fdd_set_head(drive, 0); - - floppyfns[drive][0] = 0; - - drives[drive].hole = NULL; - drives[drive].poll = NULL; - drives[drive].seek = NULL; - drives[drive].readsector = NULL; - drives[drive].writesector = NULL; - drives[drive].comparesector = NULL; - drives[drive].readaddress = NULL; - drives[drive].format = NULL; - drives[drive].byteperiod = NULL; - drives[drive].stop = NULL; - -pclog(0,"FDD: close(%d) 3\n",drive); - d86f_destroy(drive); - -pclog(0,"FDD: close(%d) 4\n",drive); - ui_sb_icon_state(drive, 1); -pclog(0,"FDD: close(%d) 5\n",drive); + return fdd[drive].track; } -int fdd_notfound = 0; -static int fdd_period = 32; -int fdd_hole(int drive) +void +fdd_set_densel(int densel) { - if (drives[drive].hole) - { - return drives[drive].hole(drive); - } + int i; + + for (i = 0; i < 4; i++) { + if (drive_types[fdd[i].type].flags & FLAG_INVERT_DENSEL) + fdd[i].densel = densel ^ 1; else - { - return 0; - } + fdd[i].densel = densel; + } } -double fdd_byteperiod(int drive) + +int +fdd_getrpm(int drive) { - if (drives[drive].byteperiod) - { - return drives[drive].byteperiod(drive); - } + int hole = fdd_hole(drive); + int densel = 0; + + densel = fdd[drive].densel; + + if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL) + densel ^= 1; + + if (! (drive_types[fdd[drive].type].flags & FLAG_RPM_360)) + return 300; + if (! (drive_types[fdd[drive].type].flags & FLAG_RPM_300)) + return 360; + + if (drive_types[fdd[drive].type].flags & FLAG_525) { + return densel ? 360 : 300; + } else { + /* fdd_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */ + if (hole == 1) + return densel ? 300 : 360; else - { - return 32.0; - } + return 300; + } } -double fdd_real_period(int drive) + +int +fdd_can_read_medium(int drive) { - double ddbp; - double dusec; + int hole = fdd_hole(drive); - ddbp = fdd_byteperiod(drive); + hole = 1 << (hole + 4); - dusec = (double) TIMER_USEC; + return (drive_types[fdd[drive].type].flags & hole) ? 1 : 0; +} - /* This is a giant hack but until the timings become even more correct, this is needed to make floppies work right on that BIOS. */ - if (fdd_get_turbo(drive)) - { - return (32.0 * dusec); + +int +fdd_doublestep_40(int drive) +{ + return (drive_types[fdd[drive].type].flags & FLAG_DOUBLE_STEP) ? 1 : 0; +} + + +void +fdd_set_type(int drive, int type) +{ + int old_type = fdd[drive].type; + + fdd[drive].type = type; + if ((drive_types[old_type].flags ^ drive_types[type].flags) & FLAG_INVERT_DENSEL) + fdd[drive].densel ^= 1; +} + + +int +fdd_get_type(int drive) +{ + return fdd[drive].type; +} + + +int +fdd_get_flags(int drive) +{ + return drive_types[fdd[drive].type].flags; +} + + +int +fdd_is_525(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_525; +} + + +int +fdd_is_dd(int drive) +{ + return (drive_types[fdd[drive].type].flags & 0x70) == 0x10; +} + + +int +fdd_is_ed(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_HOLE2; +} + + +int +fdd_is_double_sided(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_DS; +} + + +void +fdd_set_head(int drive, int head) +{ + if (head && !fdd_is_double_sided(drive)) + fdd[drive].head = 0; + else + fdd[drive].head = head; +} + + +int +fdd_get_head(int drive) +{ + if (! fdd_is_double_sided(drive)) + return 0; + + return fdd[drive].head; +} + + +void +fdd_set_turbo(int drive, int turbo) +{ + fdd[drive].turbo = turbo; +} + + +int +fdd_get_turbo(int drive) +{ + return fdd[drive].turbo; +} + + +void +fdd_set_check_bpb(int drive, int check_bpb) +{ + fdd[drive].check_bpb = check_bpb; +} + + +int +fdd_get_check_bpb(int drive) +{ + return fdd[drive].check_bpb; +} + + +int +fdd_get_densel(int drive) +{ + return fdd[drive].densel; +} + + +int +fdd_load(int drive, const wchar_t *fn) +{ + int c = 0, size; + int ok; + wchar_t *p; + FILE *f; + + DEBUG("FDD: loading drive %d with '%ls'\n", drive, fn); + + if (!fn) return(0); + p = plat_get_extension(fn); + if (!p) return(0); + f = plat_fopen(fn, L"rb"); + if (!f) return(0); + fseek(f, -1, SEEK_END); + size = ftell(f) + 1; + fclose(f); + + while (loaders[c].ext) { + if (!wcscasecmp(p, loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) { + driveloaders[drive] = c; + wcsncpy(floppyfns[drive], fn, sizeof_w(floppyfns[drive])); + d86f_setup(drive); + ok = loaders[c].load(drive, floppyfns[drive]); + if (! ok) + goto no_load; + + drive_empty[drive] = 0; + fdd_forced_seek(drive, 0); + fdd_changed[drive] = 1; + return(1); } - return (ddbp * dusec); -} + c++; + } -void fdd_poll(int drive) -{ - if (drive >= FDD_NUM) - { - fatal("Attempting to poll floppy drive %i that is not supposed to be there\n", drive); - } +no_load: + DEBUG("FDD: could not load '%ls' %s\n",fn,p); + drive_empty[drive] = 1; + fdd_set_head(drive, 0); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + ui_sb_icon_state(drive, 1); - fdd_poll_time[drive] += (int64_t) fdd_real_period(drive); - - if (drives[drive].poll) - drives[drive].poll(drive); - - if (fdd_notfound) - { - fdd_notfound--; - if (!fdd_notfound) - fdc_noidam(fdd_fdc); - } -} - -void fdd_poll_0(void *priv) -{ - fdd_poll(0); -} - -void fdd_poll_1(void *priv) -{ - fdd_poll(1); -} - -void fdd_poll_2(void *priv) -{ - fdd_poll(2); -} - -void fdd_poll_3(void *priv) -{ - fdd_poll(3); -} - -int fdd_get_bitcell_period(int rate) -{ - int bit_rate = 250; - - switch (rate) - { - case 0: /*High density*/ - bit_rate = 500; - break; - case 1: /*Double density (360 rpm)*/ - bit_rate = 300; - break; - case 2: /*Double density*/ - bit_rate = 250; - break; - case 3: /*Extended density*/ - bit_rate = 1000; - break; - } - - return 1000000 / bit_rate*2; /*Bitcell period in ns*/ + return 0; } -void fdd_set_rate(int drive, int drvden, int rate) +void +fdd_close(int drive) { - switch (rate) - { - case 0: /*High density*/ - fdd_period = 16; - break; - case 1: - switch(drvden) - { + DEBUG("FDD: closing drive %d\n", drive); + + /* Make sure the 86F poll is back to idle state. */ + d86f_stop(drive); + + if (loaders[driveloaders[drive]].close) + loaders[driveloaders[drive]].close(drive); + + drive_empty[drive] = 1; + + fdd_set_head(drive, 0); + + floppyfns[drive][0] = 0; + + drives[drive].hole = NULL; + drives[drive].poll = NULL; + drives[drive].seek = NULL; + drives[drive].readsector = NULL; + drives[drive].writesector = NULL; + drives[drive].comparesector = NULL; + drives[drive].readaddress = NULL; + drives[drive].format = NULL; + drives[drive].byteperiod = NULL; + drives[drive].stop = NULL; + + d86f_destroy(drive); + + ui_sb_icon_state(drive, 1); +} + + +int +fdd_hole(int drive) +{ + if (drives[drive].hole) + return drives[drive].hole(drive); + + return 0; +} + + +double +fdd_byteperiod(int drive) +{ + if (drives[drive].byteperiod) + return drives[drive].byteperiod(drive); + + return 32.0; +} + + +double +fdd_real_period(int drive) +{ + double ddbp; + double dusec; + + ddbp = fdd_byteperiod(drive); + dusec = (double)TIMER_USEC; + + /* + * This is a giant hack but until the timings become even more + * correct, this is needed to make floppies work right on thati + * BIOS. + */ + if (fdd_get_turbo(drive)) + return (32.0 * dusec); + + return (ddbp * dusec); +} + + +void +fdd_poll(int drive) +{ + if (drive >= FDD_NUM) + fatal("Attempting to poll floppy drive %i that is not supposed to be there\n", drive); + + fdd_poll_time[drive] += (int64_t) fdd_real_period(drive); + + if (drives[drive].poll) + drives[drive].poll(drive); + + if (fdd_notfound) { + fdd_notfound--; + if (! fdd_notfound) + fdc_noidam(fdd_fdc); + } +} + + +void +fdd_poll_0(void *priv) +{ + fdd_poll(0); +} + + +void +fdd_poll_1(void *priv) +{ + fdd_poll(1); +} + + +void +fdd_poll_2(void *priv) +{ + fdd_poll(2); +} + + +void +fdd_poll_3(void *priv) +{ + fdd_poll(3); +} + + +int +fdd_get_bitcell_period(int rate) +{ + int bit_rate = 250; + + switch (rate) { + case 0: /*High density*/ + bit_rate = 500; + break; + + case 1: /*Double density (360 rpm)*/ + bit_rate = 300; + break; + + case 2: /*Double density*/ + bit_rate = 250; + break; + + case 3: /*Extended density*/ + bit_rate = 1000; + break; + } + + return 1000000 / bit_rate*2; /*Bitcell period in ns*/ +} + + +void +fdd_set_rate(int drive, int drvden, int rate) +{ + switch (rate) { + case 0: /*High density*/ + fdd_period = 16; + break; + + case 1: + switch(drvden) { case 0: /*Double density (360 rpm)*/ - fdd_period = 26; - break; + fdd_period = 26; + break; + case 1: /*High density (360 rpm)*/ - fdd_period = 16; - break; + fdd_period = 16; + break; + case 2: - fdd_period = 4; - break; + fdd_period = 4; + break; } - case 2: /*Double density*/ - fdd_period = 32; - break; - case 3: /*Extended density*/ - fdd_period = 8; - break; - } + break; + + case 2: /*Double density*/ + fdd_period = 32; + break; + + case 3: /*Extended density*/ + fdd_period = 8; + break; + } } -void fdd_reset() + +void +fdd_reset(void) { - curdrive = 0; - fdd_period = 32; - timer_add(fdd_poll_0, &(fdd_poll_time[0]), &(motoron[0]), NULL); - timer_add(fdd_poll_1, &(fdd_poll_time[1]), &(motoron[1]), NULL); - timer_add(fdd_poll_2, &(fdd_poll_time[2]), &(motoron[2]), NULL); - timer_add(fdd_poll_3, &(fdd_poll_time[3]), &(motoron[3]), NULL); + curdrive = 0; + fdd_period = 32; + + timer_add(fdd_poll_0, &(fdd_poll_time[0]), &(motoron[0]), NULL); + timer_add(fdd_poll_1, &(fdd_poll_time[1]), &(motoron[1]), NULL); + timer_add(fdd_poll_2, &(fdd_poll_time[2]), &(motoron[2]), NULL); + timer_add(fdd_poll_3, &(fdd_poll_time[3]), &(motoron[3]), NULL); } -int oldtrack[FDD_NUM] = {0, 0, 0, 0}; -void fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size) +void +fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size) { - if (drives[drive].readsector) - drives[drive].readsector(drive, sector, track, side, density, sector_size); - else - fdd_notfound = 1000; + if (drives[drive].readsector) + drives[drive].readsector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; } -void fdd_writesector(int drive, int sector, int track, int side, int density, int sector_size) + +void +fdd_writesector(int drive, int sector, int track, int side, int density, int sector_size) { - if (drives[drive].writesector) - drives[drive].writesector(drive, sector, track, side, density, sector_size); - else - fdd_notfound = 1000; + if (drives[drive].writesector) + drives[drive].writesector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; } -void fdd_comparesector(int drive, int sector, int track, int side, int density, int sector_size) + +void +fdd_comparesector(int drive, int sector, int track, int side, int density, int sector_size) { - if (drives[drive].comparesector) - drives[drive].comparesector(drive, sector, track, side, density, sector_size); - else - fdd_notfound = 1000; + if (drives[drive].comparesector) + drives[drive].comparesector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; } -void fdd_readaddress(int drive, int side, int density) + +void +fdd_readaddress(int drive, int side, int density) { - if (drives[drive].readaddress) - drives[drive].readaddress(drive, side, density); + if (drives[drive].readaddress) + drives[drive].readaddress(drive, side, density); } -void fdd_format(int drive, int side, int density, uint8_t fill) + +void +fdd_format(int drive, int side, int density, uint8_t fill) { - if (drives[drive].format) - drives[drive].format(drive, side, density, fill); - else - fdd_notfound = 1000; + if (drives[drive].format) + drives[drive].format(drive, side, density, fill); + else + fdd_notfound = 1000; } -void fdd_stop(int drive) + +void +fdd_stop(int drive) { - if (drives[drive].stop) - drives[drive].stop(drive); + if (drives[drive].stop) + drives[drive].stop(drive); } -void fdd_set_fdc(void *fdc) + +void +fdd_set_fdc(void *fdc) { - fdd_fdc = (fdc_t *) fdc; + fdd_fdc = (fdc_t *) fdc; } diff --git a/src/devices/floppy/fdd.h b/src/devices/floppy/fdd.h index c15fe1e..26de4df 100644 --- a/src/devices/floppy/fdd.h +++ b/src/devices/floppy/fdd.h @@ -8,14 +8,14 @@ * * Definitions for the floppy drive emulation. * - * Version: @(#)fdd.h 1.0.9 2018/10/19 + * Version: @(#)fdd.h 1.0.10 2019/02/10 * * 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 @@ -248,11 +248,12 @@ typedef union { } sector_id_t; -void d86f_set_fdc(void *fdc); -void fdi_set_fdc(void *fdc); -void fdd_set_fdc(void *fdc); -void imd_set_fdc(void *fdc); -void img_set_fdc(void *fdc); +extern void d86f_set_fdc(void *fdc); +extern void fdi_set_fdc(void *fdc); +extern void fdd_set_fdc(void *fdc); +extern void imd_set_fdc(void *fdc); +extern void img_set_fdc(void *fdc); +extern void mfm_set_fdc(void *fdc); #ifdef __cplusplus diff --git a/src/devices/floppy/fdd_86f.c b/src/devices/floppy/fdd_86f.c index c1b9798..a843f85 100644 --- a/src/devices/floppy/fdd_86f.c +++ b/src/devices/floppy/fdd_86f.c @@ -10,13 +10,13 @@ * data in the form of FM/MFM-encoded transitions) which also * forms the core of the emulator's floppy disk emulation. * - * Version: @(#)fdd_86f.c 1.0.15 2018/10/20 + * Version: @(#)fdd_86f.c 1.0.16 2019/02/10 * * Authors: Fred N. van Kempen, * Miran Grca, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2018,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 @@ -190,6 +190,10 @@ typedef struct _sector_ { * Bits 10, 9 Zone type (3 = Commodore 64 zoned, 2 = Apple zoned, * 1 = Pre-Apple zoned #2, 0 = Pre-Apple zoned #1) * Bit 11 Data and surface bits are stored in reverse byte endianness + * Bit 12 If bits 6, 5 are not 0, they specify % of speedup instead + * of slowdown; + * If bits 6, 5 are 0, and bit 7 is 1, the extra bitcell count + * specifies the entire bitcell count */ typedef struct { FILE *f; @@ -362,6 +366,14 @@ d86f_get_rpm_mode(int drive) return (d86f_handler[drive].disk_flags(drive) & 0x60) >> 5; } + +int +d86f_get_speed_shift_dir(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) & 0x1000) >> 12; +} + + int d86f_reverse_bytes(int drive) { @@ -523,12 +535,15 @@ common_get_raw_size(int drive, int side) double rpm, rpm_diff; double size = 100000.0; int mfm; + int rm, ssd; mfm = d86f_is_mfm(drive); rpm = ((d86f_track_flags(drive) & 0xE0) == 0x20) ? 360.0 : 300.0; rpm_diff = 1.0; + rm = d86f_get_rpm_mode(drive); + ssd = d86f_get_speed_shift_dir(drive); - switch (d86f_get_rpm_mode(drive)) { + switch (rm) { case 1: rpm_diff = 1.01; break; @@ -546,6 +561,9 @@ common_get_raw_size(int drive, int side) break; } + if (ssd) + rpm_diff = 1.0 / rpm_diff; + switch (d86f_track_flags(drive) & 7) { case 0: rate = 500.0; @@ -574,9 +592,13 @@ common_get_raw_size(int drive, int side) if (! mfm) rate /= 2.0; - size = (size / 250.0) * rate; - size = (size * 300.0) / rpm; - size *= rpm_diff; + if (!rm && ssd) + size = 0.0; + else { + size = (size / 250.0) * rate; + size = (size * 300.0) / rpm; + size *= rpm_diff; + } /* * Round down to a multiple of 16 and add the extra bit cells, @@ -642,26 +664,30 @@ d86f_get_array_size(int drive, int side) { int array_size; int hole, rm; + int ssd; rm = d86f_get_rpm_mode(drive); - + ssd = d86f_get_speed_shift_dir(drive); hole = (d86f_handler[drive].disk_flags(drive) & 6) >> 1; - switch (hole) { + + if (!rm && ssd) /* Special case - extra bit cells size specifies entire array size. */ + array_size = 0; + else switch (hole) { case 0: case 1: default: array_size = 12500; switch (rm) { case 1: - array_size = 12625; + array_size = ssd ? 12376 : 12625; break; case 2: - array_size = 12687; + array_size = ssd ? 12315 : 12687; break; case 3: - array_size = 12750; + array_size = ssd ? 12254 : 12750; break; default: @@ -673,15 +699,15 @@ d86f_get_array_size(int drive, int side) array_size = 25000; switch (rm) { case 1: - array_size = 25250; + array_size = ssd ? 24752 : 25250; break; case 2: - array_size = 25375; + array_size = ssd ? 24630 : 25375; break; case 3: - array_size = 25500; + array_size = ssd ? 24509 : 25500; break; default: @@ -693,15 +719,15 @@ d86f_get_array_size(int drive, int side) array_size = 50000; switch (rm) { case 1: - array_size = 50500; + array_size = ssd ? 49504 : 50500; break; case 2: - array_size = 50750; + array_size = ssd ? 49261 : 50750; break; case 3: - array_size = 51000; + array_size = ssd ? 49019 : 51000; break; default: @@ -1106,23 +1132,16 @@ d86f_get_bit(int drive, int side) if (d86f_has_surface_desc(drive) && dev->track_surface_data && dev->track_surface_data[side]) { surface_bit = (surface_data >> track_bit) & 1; - if (! surface_bit) { - if (! current_bit) { - /* Bit is 0 and is not set to fuzzy, we add it as read. */ - dev->last_word[side] |= 1; - } else { - /* Bit is 1 and is not set to fuzzy, we add it as read. */ - dev->last_word[side] |= 1; - } - } else { + if (! surface_bit) + dev->last_word[side] |= current_bit; + else { if (current_bit) { /* Bit is 1 and is set to fuzzy, we randomly generate it. */ dev->last_word[side] |= (random_generate() & 1); } } - } else { + } else dev->last_word[side] |= current_bit; - } } @@ -1274,7 +1293,7 @@ d86f_word_is_aligned(int drive, int side, uint32_t base_pos) /* State 1: Find sector ID */ void -d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t ignore_other_am) +d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t wrong_am, uint16_t ignore_other_am) { d86f_t *dev = d86f[drive]; @@ -1290,6 +1309,15 @@ d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, ui return; } + if ((wrong_am) && (dev->last_word[side] == wrong_am)) { + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_nodataam(d86f_fdc); + return; + } + if ((ignore_other_am & 2) && (dev->last_word[side] == other_am)) { dev->calc_crc.word = 0xFFFF; fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); @@ -1336,7 +1364,7 @@ d86f_write_find_address_mark_fm(int drive, int side, find_t *find) void -d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t ignore_other_am) +d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t wrong_am, uint16_t ignore_other_am) { d86f_t *dev = d86f[drive]; @@ -1348,6 +1376,15 @@ d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, u return; } + if ((wrong_am) && (dev->last_word[side] == wrong_am) && (find->sync_marks >= 3)) { + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_nodataam(d86f_fdc); + return; + } + if ((dev->last_word[side] == req_am) && (find->sync_marks >= 3)) { if (d86f_word_is_aligned(drive, side, find->sync_pos)) { dev->calc_crc.word = 0xCDB4; @@ -1437,7 +1474,7 @@ d86f_read_sector_id(int drive, int side, int match) if (dev->id_find.bytes_obtained == 6) { /* We've got the ID. */ - if (dev->calc_crc.word != dev->track_crc.word) { + if ((dev->calc_crc.word != dev->track_crc.word) && (dev->last_sector.dword == dev->req_sector.dword)) { dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; DEBUG("86F: ID CRC error: %04X != %04X (%08X)\n", dev->track_crc.word, dev->calc_crc.word, dev->last_sector.dword); if ((dev->state != STATE_02_READ_ID) && (dev->state != STATE_0A_READ_ID)) { @@ -2413,9 +2450,9 @@ d86f_poll(int drive) case STATE_11_FIND_ID: case STATE_16_FIND_ID: if (mfm) - d86f_find_address_mark_mfm(drive, side, &(dev->id_find), 0x5554, 0, 0); + d86f_find_address_mark_mfm(drive, side, &(dev->id_find), 0x5554, 0, 0, 0); else - d86f_find_address_mark_fm(drive, side, &(dev->id_find), 0xF57E, 0, 0); + d86f_find_address_mark_fm(drive, side, &(dev->id_find), 0xF57E, 0, 0, 0); break; case STATE_0A_READ_ID: @@ -2434,18 +2471,18 @@ d86f_poll(int drive) case STATE_02_FIND_DATA: if (mfm) - d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 2); + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 0x5554, 2); else - d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 2); + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 0xF57E, 2); break; case STATE_06_FIND_DATA: case STATE_11_FIND_DATA: case STATE_16_FIND_DATA: if (mfm) - d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, fdc_is_sk(d86f_fdc) | 2); + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 0x5554, fdc_is_sk(d86f_fdc) | 2); else - d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, fdc_is_sk(d86f_fdc) | 2); + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 0xF57E, fdc_is_sk(d86f_fdc) | 2); break; case STATE_05_FIND_DATA: @@ -2458,9 +2495,9 @@ d86f_poll(int drive) case STATE_0C_FIND_DATA: if (mfm) - d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x554A, 0x5545, fdc_is_sk(d86f_fdc) | 2); + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x554A, 0x5545, 0x5554, fdc_is_sk(d86f_fdc) | 2); else - d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56A, 0xF56F, fdc_is_sk(d86f_fdc) | 2); + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56A, 0xF56F, 0xF57E, fdc_is_sk(d86f_fdc) | 2); break; case STATE_02_READ_DATA: @@ -2820,6 +2857,8 @@ d86f_decompose_encoded_buffer(int drive, int side) uint16_t *src1_s = dev->thin_track_surface_data[0][side]; uint16_t *src2 = dev->thin_track_encoded_data[1][side]; uint16_t *src2_s = dev->thin_track_surface_data[1][side]; + + dst = d86f_handler[drive].encoded_data(drive, side); len = d86f_get_array_size(drive, side); for (i = 0; i < len; i++) { @@ -2869,17 +2908,19 @@ d86f_read_track(int drive, int track, int thin_track, int side, uint16_t *da, ui fread(&(dev->side_flags[side]), 2, 1, dev->f); if (d86f_has_extra_bit_cells(drive)) { fread(&(dev->extra_bit_cells[side]), 4, 1, dev->f); - if (dev->extra_bit_cells[side] < -32768) - dev->extra_bit_cells[side] = -32768; - if (dev->extra_bit_cells[side] > 32768) - dev->extra_bit_cells[side] = 32768; - } else { + /* If RPM shift is 0% and direction is 1, do not adjust extra bit cells, + as that is the whole track length. */ + if (d86f_get_rpm_mode(drive) || !d86f_get_speed_shift_dir(drive)) { + if (dev->extra_bit_cells[side] < -32768) + dev->extra_bit_cells[side] = -32768; + if (dev->extra_bit_cells[side] > 32768) + dev->extra_bit_cells[side] = 32768; + } + } else dev->extra_bit_cells[side] = 0; - } fread(&(dev->index_hole_pos[side]), 4, 1, dev->f); - } else { + } else fseek(dev->f, dev->track_offset[logical_track] + d86f_track_header_size(drive), SEEK_SET); - } array_size = d86f_get_array_size(drive, side) << 1; if (d86f_has_surface_desc(drive)) fread(sa, 1, array_size, dev->f); @@ -3020,11 +3061,14 @@ d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) tbl = track_table; if (! fdd_doublestep_40(drive)) { - for (side = 0; side < sides; side++) { - fdd_set_head(drive, side); - d86f_decompose_encoded_buffer(drive, side); + d86f_decompose_encoded_buffer(drive, 0); + if (sides == 2) + d86f_decompose_encoded_buffer(drive, 1); + + for (thin_track = 0; thin_track < 2; thin_track++) { + for (side = 0; side < sides; side++) { + fdd_set_head(drive, side); - for (thin_track = 0; thin_track < 2; thin_track++) { if (sides == 2) logical_track = ((dev->cur_track + thin_track) << 1) + side; else @@ -3032,11 +3076,12 @@ d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) if (track_table && !tbl[logical_track]) { fseek(*f, 0, SEEK_END); - track_table[logical_track] = ftell(*f); + tbl[logical_track] = ftell(*f); } + if (tbl[logical_track]) { fseek(*f, tbl[logical_track], SEEK_SET); - d86f_write_track(drive, f, side, dev->thin_track_encoded_data[thin_track][side], dev->thin_track_surface_data[thin_track][side]); + d86f_write_track(drive, f, side, d86f_handler[drive].encoded_data(drive, side), dev->track_surface_data[side]); } } } @@ -3388,7 +3433,7 @@ d86f_export(int drive, const wchar_t *fn) int i; int inc = 1; uint32_t magic = 0x46423638; - uint16_t version = 0x020B; + uint16_t version = 0x020C; uint16_t disk_flags = d86f_handler[drive].disk_flags(drive); memset(tt, 0, 512 * sizeof(uint32_t)); diff --git a/src/devices/floppy/fdd_86f.h b/src/devices/floppy/fdd_86f.h index 9505810..c239405 100644 --- a/src/devices/floppy/fdd_86f.h +++ b/src/devices/floppy/fdd_86f.h @@ -8,13 +8,13 @@ * * Definitions for the 86F floppy image format. * - * Version: @(#)floppy_86f.h 1.0.5 2018/04/10 + * Version: @(#)floppy_86f.h 1.0.6 2019/02/10 * * Authors: Fred N. van Kempen, * Miran Grca, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2018,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 @@ -38,7 +38,7 @@ # define EMU_FLOPPY_86F_H -#define D86FVER 0x020B +#define D86FVER 0x020C extern void d86f_init(void); diff --git a/src/devices/floppy/fdd_common.c b/src/devices/floppy/fdd_common.c index dfab57d..61d103e 100644 --- a/src/devices/floppy/fdd_common.c +++ b/src/devices/floppy/fdd_common.c @@ -8,11 +8,11 @@ * * Shared code for all the floppy modules. * - * Version: @(#)fdd_common.c 1.0.5 2018/09/13 + * Version: @(#)fdd_common.c 1.0.6 2019/02/10 * * Author: Fred N. van Kempen, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * * 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 @@ -48,6 +48,7 @@ #include "fdd_imd.h" #include "fdd_img.h" #include "fdd_json.h" +#include "fdd_mfm.h" #include "fdd_td0.h" @@ -478,6 +479,7 @@ floppy_init(void) td0_init(); imd_init(); json_init(); + mfm_init(); /* Reset all drives. */ for (i = 0; i < FDD_NUM; i++) { diff --git a/src/devices/floppy/fdd_mfm.c b/src/devices/floppy/fdd_mfm.c new file mode 100644 index 0000000..20302f9 --- /dev/null +++ b/src/devices/floppy/fdd_mfm.c @@ -0,0 +1,475 @@ +/* + * 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 HxC MFM image format. + * + * Version: @(#)fdd_mfm.c 1.0.1 2018/11/12 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2018,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 + * 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. + */ +#include +#include +#include +#include +#include +#include +#define dbglog fdd_log +#include "../../emu.h" +#include "../../plat.h" +#include "fdd.h" +#include "fdd_86f.h" +#include "fdd_img.h" +#include "fdd_mfm.h" +#include "fdc.h" + + +#pragma pack(push,1) +typedef struct { + uint8_t hdr_name[7]; + + uint16_t tracks_no; + uint8_t sides_no; + + uint16_t rpm; + uint16_t bit_rate; + uint8_t if_type; + + uint32_t track_list_offset; +} mfm_header_t; + +typedef struct { + uint16_t track_no; + uint8_t side_no; + uint32_t track_size; + uint32_t track_offset; +} mfm_track_t; + +typedef struct { + uint16_t track_no; + uint8_t side_no; + uint16_t rpm; + uint16_t bit_rate; + uint32_t track_size; + uint32_t track_offset; +} mfm_adv_track_t; +#pragma pack(pop) + +typedef struct { + FILE *f; + + mfm_header_t hdr; + mfm_track_t *tracks; + mfm_adv_track_t *adv_tracks; + + int br_rounded, rpm_rounded, + total_tracks, cur_track; + + uint8_t track_data[2][256*1024]; +} mfm_t; + + +static mfm_t *mfm[FDD_NUM]; +static fdc_t *mfm_fdc; + + +static uint16_t +disk_flags(int drive) +{ + mfm_t *dev = mfm[drive]; + uint16_t temp_disk_flags = 0x1080; /* We ALWAYS claim to have extra bit cells, even if the actual amount is 0; + Bit 12 = 1, bits 6, 5 = 0 - extra bit cells field specifies the entire + amount of bit cells per track. */ + + switch (dev->br_rounded) { + case 500: + temp_disk_flags |= 2; + break; + + case 300: + case 250: + default: + temp_disk_flags |= 0; + break; + + case 1000: + temp_disk_flags |= 4; + break; + } + + if (dev->hdr.sides_no == 2) + temp_disk_flags |= 8; + + return(temp_disk_flags); +} + + +static int +get_track_index(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + int i, ret = -1; + + for (i = 0; i < dev->total_tracks; i++) { + if ((dev->tracks[i].track_no == dev->cur_track) && + (dev->tracks[i].side_no == side)) { + ret = i; + break; + } + } + + return ret; +} + + +static int +get_adv_track_index(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + int i, ret = -1; + + for (i = 0; i < dev->total_tracks; i++) { + if ((dev->adv_tracks[i].track_no == dev->cur_track) && + (dev->adv_tracks[i].side_no == side)) { + ret = i; + break; + } + } + + return ret; +} + + +static void +get_adv_track_bitrate(int drive, int side, int *br, int *rpm) +{ + mfm_t *dev = mfm[drive]; + int track_index; + double dbr; + + track_index = get_adv_track_index(drive, side); + + if (track_index == -1) { + *br = 250; + *rpm = 300; + } else { + dbr = round(((double) dev->adv_tracks[track_index].bit_rate) / 50.0) * 50.0; + *br = ((int) dbr); + dbr = round(((double) dev->adv_tracks[track_index].rpm) / 60.0) * 60.0; + *rpm = ((int) dbr); + } +} + + +static uint16_t +side_flags(int drive) +{ + mfm_t *dev = mfm[drive]; + uint16_t temp_side_flags = 0; + int side, br = 250, rpm = 300; + + if (dev->hdr.if_type & 0x80) { + side = fdd_get_head(drive); + get_adv_track_bitrate(drive, side, &br, &rpm); + } else { + br = dev->br_rounded; + rpm = dev->rpm_rounded; + } + + /* 300 kbps @ 360 rpm = 250 kbps @ 200 rpm */ + if ((rpm >= 352) && (rpm <= 367) && (br == 300)) { + br = 250; + rpm = 300; + } + + switch (br) { + case 500: + temp_side_flags = 0; + break; + + case 300: + temp_side_flags = 1; + break; + + case 250: + default: + temp_side_flags = 2; + break; + + case 1000: + temp_side_flags = 3; + break; + } + + if ((rpm >= 352) && (rpm <= 367)) + temp_side_flags |= 0x20; + + /* + * Set the encoding value to match that provided by the FDC. + * Then if it's wrong, it will sector not found anyway. + */ + temp_side_flags |= 0x08; + + return(temp_side_flags); +} + + +static uint32_t +get_raw_size(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + int track_index, is_300_rpm; + + if (dev->hdr.if_type & 0x80) + track_index = get_adv_track_index(drive, side); + else + track_index = get_track_index(drive, side); + + is_300_rpm = (dev->hdr.rpm < 352); + + if (track_index == -1) { + ERRLOG("MFM: Unable to find track (%i, %i)\n", dev->cur_track, side); + return is_300_rpm ? 100000 : 83333; + } + + /* Bit 7 on - my extension of the HxC MFM format to output exact bitcell counts + for each track instead of rounded byte counts. */ + if (dev->hdr.if_type & 0x80) + return dev->adv_tracks[track_index].track_size; + else + return dev->tracks[track_index].track_size * 8; +} + + +static int32_t +extra_bit_cells(int drive, int side) +{ + return (int32_t) get_raw_size(drive, side); +} + + +static uint16_t * +encoded_data(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + + return((uint16_t *)dev->track_data[side]); +} + + +void +mfm_read_side(int drive, int side) +{ + mfm_t *dev = mfm[drive]; + int track_index, track_size; + int track_bytes; + + if (dev->hdr.if_type & 0x80) + track_index = get_adv_track_index(drive, side); + else + track_index = get_track_index(drive, side); + + track_size = get_raw_size(drive, side); + track_bytes = track_size >> 3; + if (track_size & 0x07) + track_bytes++; + + if (track_index == -1) + memset(dev->track_data[side], 0x00, track_bytes); + else { + if (dev->hdr.if_type & 0x80) + fseek(dev->f, dev->adv_tracks[track_index].track_offset, SEEK_SET); + else + fseek(dev->f, dev->tracks[track_index].track_offset, SEEK_SET); + fread(dev->track_data[side], 1, track_size, dev->f); + } + + DEBUG("drive = %i, side = %i, dev->cur_track = %i, track_index = %i, track_size = %i\n", + drive, side, dev->cur_track, track_index, track_size); +} + + +static void +mfm_seek(int drive, int track) +{ + mfm_t *dev = mfm[drive]; + + DEBUG("mfm_seek(%i, %i)\n", drive, track); + + if (fdd_doublestep_40(drive)) { + if (dev->hdr.tracks_no <= 43) + track /= 2; + } + + dev->cur_track = track; + d86f_set_cur_track(drive, track); + + if (dev->f == NULL) + return; + + if (track < 0) + track = 0; + + mfm_read_side(drive, 0); + mfm_read_side(drive, 1); +} + + +void +mfm_init(void) +{ + memset(mfm, 0x00, sizeof(mfm)); +} + + +int +mfm_load(int drive, const wchar_t *fn) +{ + mfm_t *dev; + double dbr; + int i; + + writeprot[drive] = fwriteprot[drive] = 1; + + /* Allocate a drive block. */ + dev = (mfm_t *)malloc(sizeof(mfm_t)); + memset(dev, 0x00, sizeof(mfm_t)); + + dev->f = plat_fopen(fn, L"rb"); + if (dev->f == NULL) { + free(dev); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return(0); + } + + d86f_unregister(drive); + + /* Read the header. */ + fread(&dev->hdr, 1, sizeof(mfm_header_t), dev->f); + + /* Calculate tracks * sides, allocate the tracks array, and read it. */ + dev->total_tracks = dev->hdr.tracks_no * dev->hdr.sides_no; + if (dev->hdr.if_type & 0x80) { + dev->adv_tracks = (mfm_adv_track_t *) malloc(dev->total_tracks * sizeof(mfm_adv_track_t)); + fread(dev->adv_tracks, 1, dev->total_tracks * sizeof(mfm_adv_track_t), dev->f); + } else { + dev->tracks = (mfm_track_t *) malloc(dev->total_tracks * sizeof(mfm_track_t)); + fread(dev->tracks, 1, dev->total_tracks * sizeof(mfm_track_t), dev->f); + } + + /* The chances of finding a HxC MFM image of a single-sided thin track + disk are much smaller than the chances of finding a HxC MFM image + incorrectly converted from a SCP image, erroneously indicating 1 + side and 80+ tracks instead of 2 sides and <= 43 tracks, so if we + have detected such an image, convert the track numbers. */ + if ((dev->hdr.tracks_no > 43) && (dev->hdr.sides_no == 1)) { + dev->hdr.tracks_no >>= 1; + dev->hdr.sides_no <<= 1; + + for (i = 0; i < dev->total_tracks; i++) { + if (dev->hdr.if_type & 0x80) { + dev->adv_tracks[i].side_no <<= 1; + dev->adv_tracks[i].side_no |= (dev->adv_tracks[i].track_no & 1); + dev->adv_tracks[i].track_no >>= 1; + } else { + dev->tracks[i].side_no <<= 1; + dev->tracks[i].side_no |= (dev->tracks[i].track_no & 1); + dev->tracks[i].track_no >>= 1; + } + } + } + + if (!(dev->hdr.if_type & 0x80)) { + dbr = round(((double) dev->hdr.bit_rate) / 50.0) * 50.0; + dev->br_rounded = (int) dbr; + DEBUG("Round bit rate: %i kbps\n", dev->br_rounded); + + dbr = round(((double) dev->hdr.rpm) / 60.0) * 60.0; + dev->rpm_rounded = (int) dbr; + DEBUG("Round RPM: %i kbps\n", dev->rpm_rounded); + } + + /* Set up the drive unit. */ + mfm[drive] = dev; + + /* Attach this format to the D86F engine. */ + d86f_handler[drive].disk_flags = disk_flags; + d86f_handler[drive].side_flags = side_flags; + d86f_handler[drive].writeback = null_writeback; + d86f_handler[drive].set_sector = null_set_sector; + d86f_handler[drive].write_data = null_write_data; + d86f_handler[drive].format_conditions = null_format_conditions; + d86f_handler[drive].extra_bit_cells = extra_bit_cells; + d86f_handler[drive].encoded_data = encoded_data; + d86f_handler[drive].read_revolution = common_read_revolution; + d86f_handler[drive].index_hole_pos = null_index_hole_pos; + d86f_handler[drive].get_raw_size = get_raw_size; + d86f_handler[drive].check_crc = 1; + d86f_set_version(drive, D86FVER); + + d86f_common_handlers(drive); + + drives[drive].seek = mfm_seek; + + DEBUG("Loaded as MFM\n"); + + return(1); +} + + +void +mfm_close(int drive) +{ + mfm_t *dev = mfm[drive]; + + if (dev == NULL) return; + + d86f_unregister(drive); + + drives[drive].seek = NULL; + + if (dev->tracks) + free(dev->tracks); + + if (dev->adv_tracks) + free(dev->adv_tracks); + + if (dev->f) + fclose(dev->f); + + /* Release the memory. */ + free(dev); + mfm[drive] = NULL; +} + + +void +mfm_set_fdc(void *fdc) +{ + mfm_fdc = (fdc_t *)fdc; +} diff --git a/src/devices/floppy/fdd_mfm.h b/src/devices/floppy/fdd_mfm.h new file mode 100644 index 0000000..dbd356f --- /dev/null +++ b/src/devices/floppy/fdd_mfm.h @@ -0,0 +1,45 @@ +/* + * 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 MFM floppy image format. + * + * Version: @(#)floppy_mfm.h 1.0.1 2018/11/12 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2018,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 + * 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. + */ +#ifndef EMU_FLOPPY_MFM_H +# define EMU_FLOPPY_MFM_H + + +extern void mfm_init(void); +extern int mfm_load(int drive, const wchar_t *fn); +extern void mfm_close(int drive); + + +#endif /*EMU_FLOPPY_MFM_H*/ diff --git a/src/devices/input/keyboard_xt.c b/src/devices/input/keyboard_xt.c index 1213900..a686ea9 100644 --- a/src/devices/input/keyboard_xt.c +++ b/src/devices/input/keyboard_xt.c @@ -8,14 +8,14 @@ * * Implementation of the XT-style keyboard. * - * Version: @(#)keyboard_xt.c 1.0.9 2018/11/02 + * Version: @(#)keyboard_xt.c 1.0.10 2019/02/10 * * 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 @@ -67,11 +67,15 @@ typedef struct { - int8_t blocked; uint8_t type; + int8_t tandy; uint8_t pa; uint8_t pb; + + int8_t want_irq; + int8_t blocked; + uint8_t key_waiting; } xtkbd_t; @@ -348,13 +352,22 @@ kbd_poll(void *priv) keyboard_delay += (1000LL * TIMER_USEC); - if (key_queue_start != key_queue_end && !kbd->blocked) { - kbd->pa = key_queue[key_queue_start]; + if (!(kbd->pb & 0x40) && (! kbd->tandy)) + return; + + if (kbd->want_irq) { + kbd->want_irq = 0; + kbd->pa = kbd->key_waiting; + kbd->blocked = 1; picint(2); + } + + if (key_queue_start != key_queue_end && !kbd->blocked) { + kbd->key_waiting = key_queue[key_queue_start]; DBGLOG(1, "XTkbd: reading %02X from the key queue at %i\n", kbd->pa, key_queue_start); key_queue_start = (key_queue_start + 1) & 0x0f; - kbd->blocked = 1; + kbd->want_irq = 1; } } @@ -436,31 +449,34 @@ kbd_write(uint16_t port, uint8_t val, void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; - if (port != 0x61) return; + switch (port) { + case 0x61: + if (!(kbd->pb & 0x40) && (val & 0x40)) { + key_queue_start = key_queue_end = 0; + kbd->want_irq = 0; + kbd->blocked = 0; + kbd_adddata(0xaa); + } + kbd->pb = val; + ppi.pb = val; - if (!(kbd->pb & 0x40) && (val & 0x40)) { /*Reset keyboard*/ - DEBUG("XTkbd: reset keyboard\n"); - key_queue_end = key_queue_start; - kbd_adddata(0xaa); + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(&pit, 2, val & 1); + + if (val & 0x80) { + kbd->pa = 0; + kbd->blocked = 0; + picintc(2); + } + break; } - - if ((kbd->pb & 0x80)==0 && (val & 0x80)!=0) { - kbd->pa = 0; - kbd->blocked = 0; - picintc(2); - } - kbd->pb = val; - ppi.pb = val; - - timer_process(); - timer_update_outstanding(); - - speaker_update(); - speaker_gated = val & 1; - speaker_enable = val & 2; - if (speaker_enable) - was_speaker_enable = 1; - pit_set_gate(&pit, 2, val & 1); } @@ -473,14 +489,23 @@ kbd_read(uint16_t port, void *priv) switch (port) { case 0x60: - if ((kbd->type == 0) && (kbd->pb & 0x80)) { - vid = video_type(); - if (vid == VID_TYPE_SPEC) - ret = 0x4d; /* EGA/VGA */ - else if (vid == VID_TYPE_MDA) - ret = 0x7d; /* MDA/Hercules */ - else - ret = 0x6d; /* CGA */ + if (kbd->pb & 0x80) switch(kbd->type) { + case 0: + vid = video_type(); + if (vid == VID_TYPE_SPEC) + ret = 0x4d; /* EGA/VGA */ + else if (vid == VID_TYPE_MDA) + ret = 0x7d; /* MDA/Herc */ + else + ret = 0x6d; /* CGA */ + break; + + case 1: + /* + * According to Ruud on the PCem forum, this + * is supposed to return 0xFF on the XT. + */ + ret = 0xff; } else ret = kbd->pa; break; @@ -534,10 +559,13 @@ kbd_reset(void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; + kbd->want_irq = 0; kbd->blocked = 0; kbd->pa = 0x00; kbd->pb = 0x00; + keyboard_scan = 1; + key_queue_start = 0, key_queue_end = 0; } @@ -550,19 +578,18 @@ kbd_init(const device_t *info) kbd = (xtkbd_t *)mem_alloc(sizeof(xtkbd_t)); memset(kbd, 0x00, sizeof(xtkbd_t)); - kbd->type = info->local; - - keyboard_set_table(scancode_xt); - - keyboard_scan = 1; io_sethandler(0x0060, 4, kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); keyboard_send = kbd_adddata_ex; + kbd_reset(kbd); + kbd->type = info->local; timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, kbd); + keyboard_set_table(scancode_xt); + return(kbd); } diff --git a/src/devices/scsi/scsi_buslogic.c b/src/devices/scsi/scsi_buslogic.c index 47bfa95..c792d26 100644 --- a/src/devices/scsi/scsi_buslogic.c +++ b/src/devices/scsi/scsi_buslogic.c @@ -13,14 +13,14 @@ * 1 - BT-545S ISA; * 2 - BT-958D PCI * - * Version: @(#)scsi_buslogic.c 1.0.13 2018/10/16 + * Version: @(#)scsi_buslogic.c 1.0.14 2019/02/10 * * Authors: Fred N. van Kempen, * Miran Grca, * TheCollector1995, * - * 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 @@ -70,6 +70,7 @@ #define BT640A_BIOS_PATH L"scsi/buslogic/bt-640a_bios.rom" #define BT445S_BIOS_PATH L"scsi/buslogic/bt-445s_bios.rom" #define BT445S_AUTO_BIOS_PATH L"scsi/buslogic/bt-445s_autoscsi.rom" +#define BT445S_SCAM_BIOS_PATH L"scsi/buslogic/bt-445s_scam.rom" #define BT958D_BIOS_PATH L"scsi/buslogic/bt-958d_bios.rom" #define BT958D_AUTO_BIOS_PATH L"scsi/buslogic/bt-958d_autoscsi.rom" #define BT958D_SCAM_BIOS_PATH L"scsi/buslogic/bt-958d_scam.rom" @@ -1690,6 +1691,7 @@ buslogic_init(const device_t *info) has_scam_rom = 0; dev->fw_rev = "AA335"; dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_ISA: @@ -1704,6 +1706,7 @@ buslogic_init(const device_t *info) has_scam_rom = 0; dev->fw_rev = "AA421E"; dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_MCA: @@ -1719,6 +1722,7 @@ buslogic_init(const device_t *info) dev->pos_regs[1] = 0x07; mca_add(buslogic_mca_read, buslogic_mca_write, dev); dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_VLB: @@ -1729,10 +1733,13 @@ buslogic_init(const device_t *info) has_autoscsi_rom = 1; autoscsi_rom_name = BT445S_AUTO_BIOS_PATH; autoscsi_rom_size = 0x4000; - has_scam_rom = 0; - dev->fw_rev = "AA421E"; + has_scam_rom = 1; + scam_rom_name = BT445S_SCAM_BIOS_PATH; + scam_rom_size = 0x0200; + dev->fw_rev = "AA507B"; dev->bit32 = 1; dev->ha_bps = 10000000.0; /* fast SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_PCI: diff --git a/src/devices/scsi/scsi_cdrom.c b/src/devices/scsi/scsi_cdrom.c index ff2faa2..f713b83 100644 --- a/src/devices/scsi/scsi_cdrom.c +++ b/src/devices/scsi/scsi_cdrom.c @@ -8,13 +8,13 @@ * * Emulation of SCSI (and ATAPI) CD-ROM drives. * - * Version: @(#)scsi_cdrom.c 1.0.11 2018/11/02 + * Version: @(#)scsi_cdrom.c 1.0.12 2019/02/10 * * 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 @@ -2195,6 +2195,12 @@ do_command(void *p, uint8_t *cdb) case GPCMD_PLAY_AUDIO_12: case GPCMD_PLAY_AUDIO_MSF: case GPCMD_PLAY_AUDIO_TRACK_INDEX: +#if 0 + case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: + case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12: +#endif + len = 0; + set_phase(dev, SCSI_PHASE_STATUS); switch(cdb[0]) { @@ -2349,7 +2355,7 @@ do_command(void *p, uint8_t *cdb) if (ret) { set_buf_len(dev, BufLen, &alloc_length); data_command_finish(dev, alloc_length, alloc_length, - len, 0); + alloc_length, 0); } else buf_free(dev); return; diff --git a/src/devices/sound/snd_speaker.c b/src/devices/sound/snd_speaker.c index 9ad42ef..50b5f7e 100644 --- a/src/devices/sound/snd_speaker.c +++ b/src/devices/sound/snd_speaker.c @@ -8,14 +8,14 @@ * * Implementation of the PC-Speaker device. * - * Version: @(#)snd_speaker.c 1.0.4 2018/10/16 + * Version: @(#)snd_speaker.c 1.0.5 2019/02/10 * * 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 @@ -47,28 +47,31 @@ #include "snd_speaker.h" -int speaker_mute, - speaker_gated, - speaker_enable, - was_speaker_enable; +int speaker_mute = 0, + speaker_gated = 0, + speaker_enable = 0, + was_speaker_enable = 0; int gated, speakval, speakon; -static int16_t speaker_buffer[SOUNDBUFLEN]; +static int32_t speaker_buffer[SOUNDBUFLEN]; static int speaker_pos; void speaker_update(void) { - int16_t val; + int32_t val; + + if (speaker_pos >= sound_pos_global) + return; for (; speaker_pos < sound_pos_global; speaker_pos++) { if (speaker_gated && was_speaker_enable) { - if (!pit.m[2] || pit.m[2]==4) + if (!pit.m[2] || pit.m[2] == 4) val = speakval; else if (pit.l[2] < 0x40) val = 0x0a00; @@ -88,13 +91,17 @@ speaker_update(void) static void get_buffer(int32_t *buffer, int len, void *p) { + int32_t val; int c; speaker_update(); if (! speaker_mute) { - for (c = 0; c < len * 2; c++) - buffer[c] += speaker_buffer[c >> 1]; + for (c = 0; c < len * 2; c++) { + val = speaker_buffer[c >> 1]; + buffer[c++] += val; + buffer[c] += val; + } } speaker_pos = 0; diff --git a/src/devices/system/dma.c b/src/devices/system/dma.c index cbcad74..17d2b5f 100644 --- a/src/devices/system/dma.c +++ b/src/devices/system/dma.c @@ -1,915 +1,915 @@ -/* - * 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 Intel DMA controllers. - * - * Version: @(#)dma.c 1.0.6 2018/06/25 - * - * Authors: Fred N. van Kempen, - * Miran Grca, - * Sarah Walker, - * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. - * - * 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. - */ -#include -#include -#include -#include -#include "../../emu.h" -#include "../../cpu/cpu.h" -#include "../../cpu/x86.h" -#include "../../machines/machine.h" -#include "../../mem.h" -#include "../../io.h" -#include "../../plat.h" -#include "mca.h" -#include "dma.h" - - -dma_t dma[8]; - - -static uint8_t dmaregs[16]; -static uint8_t dma16regs[16]; -static uint8_t dmapages[16]; -static int dma_wp, - dma16_wp; -static uint8_t dma_m; -static uint8_t dma_stat; -static uint8_t dma_stat_rq; -static uint8_t dma_command, - dma16_command; -static struct { - int xfr_command, - xfr_channel; - int byte_ptr; - - int is_ps2; -} dma_ps2; - - -#define DMA_PS2_IOA (1 << 0) -#define DMA_PS2_XFER_MEM_TO_IO (1 << 2) -#define DMA_PS2_XFER_IO_TO_MEM (3 << 2) -#define DMA_PS2_XFER_MASK (3 << 2) -#define DMA_PS2_DEC2 (1 << 4) -#define DMA_PS2_SIZE16 (1 << 6) - - -static uint8_t -_dma_read(int32_t addr) -{ - uint8_t temp = mem_readb_phys_dma(addr); - - return(temp); -} - - -static void -_dma_write(uint32_t addr, uint8_t val) -{ - mem_writeb_phys_dma(addr, val); - mem_invalidate_range(addr, addr); -} - - -static void -dma_ps2_run(int channel) -{ - dma_t *dma_c = &dma[channel]; - - switch (dma_c->ps2_mode & DMA_PS2_XFER_MASK) { - case DMA_PS2_XFER_MEM_TO_IO: - do { - if (! dma_c->size) { - uint8_t temp = _dma_read(dma_c->ac); - - outb(dma_c->io_addr, temp); - - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac--; - else - dma_c->ac++; - } else { - uint16_t temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); - - outw(dma_c->io_addr, temp); - - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac -= 2; - else - dma_c->ac += 2; - } - - dma_stat_rq |= (1 << channel); - dma_c->cc--; - } while (dma_c->cc > 0); - - dma_stat |= (1 << channel); - break; - - case DMA_PS2_XFER_IO_TO_MEM: - do { - if (! dma_c->size) { - uint8_t temp = inb(dma_c->io_addr); - - _dma_write(dma_c->ac, temp); - - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac--; - else - dma_c->ac++; - } else { - uint16_t temp = inw(dma_c->io_addr); - - _dma_write(dma_c->ac, temp & 0xff); - _dma_write(dma_c->ac + 1, temp >> 8); - - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac -= 2; - else - dma_c->ac += 2; - } - - dma_stat_rq |= (1 << channel); - dma_c->cc--; - } while (dma_c->cc > 0); - - ps2_cache_clean(); - dma_stat |= (1 << channel); - break; - - default: /*Memory verify*/ - do { - if (! dma_c->size) { - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac--; - else - dma_c->ac++; - } else { - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac -= 2; - else - dma_c->ac += 2; - } - - dma_stat_rq |= (1 << channel); - dma->cc--; - } while (dma->cc > 0); - - dma_stat |= (1 << channel); - break; - - } -} - - -static uint8_t -dma_ps2_read(uint16_t addr, UNUSED(void *priv)) -{ - dma_t *dma_c = &dma[dma_ps2.xfr_channel]; - uint8_t temp = 0xff; - - switch (addr) { - case 0x1a: - switch (dma_ps2.xfr_command) { - case 2: /*Address*/ - case 3: - switch (dma_ps2.byte_ptr) { - case 0: - temp = dma_c->ac & 0xff; - dma_ps2.byte_ptr = 1; - break; - case 1: - temp = (dma_c->ac >> 8) & 0xff; - dma_ps2.byte_ptr = 2; - break; - case 2: - temp = (dma_c->ac >> 16) & 0xff; - dma_ps2.byte_ptr = 0; - break; - } - break; - - case 4: /*Count*/ - case 5: - if (dma_ps2.byte_ptr) - temp = dma_c->cc >> 8; - else - temp = dma_c->cc & 0xff; - dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; - break; - - case 6: /*Read DMA status*/ - if (dma_ps2.byte_ptr) { - temp = ((dma_stat_rq & 0xf0) >> 4) | (dma_stat & 0xf0); - dma_stat &= ~0xf0; - dma_stat_rq &= ~0xf0; - } else { - temp = (dma_stat_rq & 0xf) | ((dma_stat & 0xf) << 4); - dma_stat &= ~0xf; - dma_stat_rq &= ~0xf; - } - dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; - break; - - case 7: /*Mode*/ - temp = dma_c->ps2_mode; - break; - - case 8: /*Arbitration Level*/ - temp = dma_c->arb_level; - break; - - default: - fatal("Bad XFR Read command %i channel %i\n", dma_ps2.xfr_command, dma_ps2.xfr_channel); - } - break; - } - - return(temp); -} - - -static void -dma_ps2_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) -{ - dma_t *dma_c = &dma[dma_ps2.xfr_channel]; - uint8_t mode; - - switch (addr) { - case 0x18: - dma_ps2.xfr_channel = val & 0x7; - dma_ps2.xfr_command = val >> 4; - dma_ps2.byte_ptr = 0; - switch (dma_ps2.xfr_command) { - case 9: /*Set DMA mask*/ - dma_m |= (1 << dma_ps2.xfr_channel); - break; - - case 0xa: /*Reset DMA mask*/ - dma_m &= ~(1 << dma_ps2.xfr_channel); - break; - - case 0xb: - if (!(dma_m & (1 << dma_ps2.xfr_channel))) - dma_ps2_run(dma_ps2.xfr_channel); - break; - } - break; - - case 0x1a: - switch (dma_ps2.xfr_command) { - case 0: /*I/O address*/ - if (dma_ps2.byte_ptr) - dma_c->io_addr = (dma_c->io_addr & 0x00ff) | (val << 8); - else - dma_c->io_addr = (dma_c->io_addr & 0xff00) | val; - dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; - break; - - case 2: /*Address*/ - switch (dma_ps2.byte_ptr) { - case 0: - dma_c->ac = (dma_c->ac & 0xffff00) | val; - dma_ps2.byte_ptr = 1; - break; - - case 1: - dma_c->ac = (dma_c->ac & 0xff00ff) | (val << 8); - dma_ps2.byte_ptr = 2; - break; - - case 2: - dma_c->ac = (dma_c->ac & 0x00ffff) | (val << 16); - dma_ps2.byte_ptr = 0; - break; - } - dma_c->ab = dma_c->ac; - break; - - case 4: /*Count*/ - if (dma_ps2.byte_ptr) - dma_c->cc = (dma_c->cc & 0xff) | (val << 8); - else - dma_c->cc = (dma_c->cc & 0xff00) | val; - dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; - dma_c->cb = dma_c->cc; - break; - - case 7: /*Mode register*/ - mode = 0; - if (val & DMA_PS2_DEC2) - mode |= 0x20; - if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_MEM_TO_IO) - mode |= 8; - else if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_IO_TO_MEM) - mode |= 4; - dma_c->mode = (dma_c->mode & ~0x2c) | mode; - dma_c->ps2_mode = val; - dma_c->size = val & DMA_PS2_SIZE16; - break; - - case 8: /*Arbitration Level*/ - dma_c->arb_level = val; - break; - - default: - fatal("Bad XFR command %i channel %i val %02x\n", dma_ps2.xfr_command, dma_ps2.xfr_channel, val); - } - break; - } -} - - -static uint8_t -dma_read(uint16_t addr, UNUSED(void *priv)) -{ - int channel = (addr >> 1) & 3; - uint8_t temp; - - switch (addr & 0xf) { - case 0: - case 2: - case 4: - case 6: /*Address registers*/ - dma_wp ^= 1; - if (dma_wp) - return(dma[channel].ac & 0xff); - return((dma[channel].ac >> 8) & 0xff); - - case 1: - case 3: - case 5: - case 7: /*Count registers*/ - dma_wp ^= 1; - if (dma_wp) - temp = dma[channel].cc & 0xff; - else - temp = dma[channel].cc >> 8; - return(temp); - - case 8: /*Status register*/ - temp = dma_stat & 0xf; - dma_stat &= ~0xf; - return(temp); - - case 0xd: - return(0); - } - - return(dmaregs[addr & 0xf]); -} - - -static void -dma_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) -{ - int channel = (addr >> 1) & 3; - - dmaregs[addr & 0xf] = val; - switch (addr & 0xf) { - case 0: - case 2: - case 4: - case 6: /*Address registers*/ - dma_wp ^= 1; - if (dma_wp) - dma[channel].ab = (dma[channel].ab & 0xffff00) | val; - else - dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); - dma[channel].ac = dma[channel].ab; - return; - - case 1: - case 3: - case 5: - case 7: /*Count registers*/ - dma_wp ^= 1; - if (dma_wp) - dma[channel].cb = (dma[channel].cb & 0xff00) | val; - else - dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); - dma[channel].cc = dma[channel].cb; - return; - - case 8: /*Control register*/ - dma_command = val; - return; - - case 0xa: /*Mask*/ - if (val & 4) - dma_m |= (1 << (val & 3)); - else - dma_m &= ~(1 << (val & 3)); - return; - - case 0xb: /*Mode*/ - channel = (val & 3); - dma[channel].mode = val; - if (dma_ps2.is_ps2) { - dma[channel].ps2_mode &= ~0x1c; - if (val & 0x20) - dma[channel].ps2_mode |= 0x10; - if ((val & 0xc) == 8) - dma[channel].ps2_mode |= 4; - else if ((val & 0xc) == 4) - dma[channel].ps2_mode |= 0xc; - } - return; - - case 0xc: /*Clear FF*/ - dma_wp = 0; - return; - - case 0xd: /*Master clear*/ - dma_wp = 0; - dma_m |= 0xf; - return; - - case 0xf: /*Mask write*/ - dma_m = (dma_m & 0xf0) | (val & 0xf); - return; - } -} - - -static uint8_t -dma16_read(uint16_t addr, UNUSED(void *priv)) -{ - int channel = ((addr >> 2) & 3) + 4; - uint8_t temp; - - addr >>= 1; - switch (addr & 0xf) { - case 0: - case 2: - case 4: - case 6: /*Address registers*/ - dma16_wp ^= 1; - if (dma_ps2.is_ps2) { - if (dma16_wp) - return(dma[channel].ac); - return((dma[channel].ac >> 8) & 0xff); - } - if (dma16_wp) - return((dma[channel].ac >> 1) & 0xff); - return((dma[channel].ac >> 9) & 0xff); - - case 1: - case 3: - case 5: - case 7: /*Count registers*/ - dma16_wp ^= 1; - if (dma16_wp) - temp = dma[channel].cc & 0xff; - else - temp = dma[channel].cc >> 8; - return(temp); - - case 8: /*Status register*/ - temp = dma_stat >> 4; - dma_stat &= ~0xf0; - return(temp); - } - - return(dma16regs[addr & 0xf]); -} - - -static void -dma16_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) -{ - int channel = ((addr >> 2) & 3) + 4; - addr >>= 1; - - dma16regs[addr & 0xf] = val; - switch (addr & 0xf) { - case 0: - case 2: - case 4: - case 6: /*Address registers*/ - dma16_wp ^= 1; - if (dma_ps2.is_ps2) { - if (dma16_wp) - dma[channel].ab = (dma[channel].ab & 0xffff00) | val; - else - dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); - } else { - if (dma16_wp) - dma[channel].ab = (dma[channel].ab & 0xfffe00) | (val << 1); - else - dma[channel].ab = (dma[channel].ab & 0xfe01ff) | (val << 9); - } - dma[channel].ac = dma[channel].ab; - return; - - case 1: - case 3: - case 5: - case 7: /*Count registers*/ - dma16_wp ^= 1; - if (dma16_wp) - dma[channel].cb = (dma[channel].cb & 0xff00) | val; - else - dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); - dma[channel].cc = dma[channel].cb; - return; - - case 8: /*Control register*/ - return; - - case 0xa: /*Mask*/ - if (val & 4) - dma_m |= (0x10 << (val & 3)); - else - dma_m &= ~(0x10 << (val & 3)); - return; - - case 0xb: /*Mode*/ - channel = (val & 3) + 4; - dma[channel].mode = val; - if (dma_ps2.is_ps2) { - dma[channel].ps2_mode &= ~0x1c; - if (val & 0x20) - dma[channel].ps2_mode |= 0x10; - if ((val & 0xc) == 8) - dma[channel].ps2_mode |= 4; - else if ((val & 0xc) == 4) - dma[channel].ps2_mode |= 0xc; - } - return; - - case 0xc: /*Clear FF*/ - dma16_wp = 0; - return; - - case 0xd: /*Master clear*/ - dma16_wp = 0; - dma_m |= 0xf0; - return; - - case 0xf: /*Mask write*/ - dma_m = (dma_m & 0x0f) | ((val & 0xf) << 4); - return; - } -} - - -static uint8_t -dma_page_read(uint16_t addr, UNUSED(void *priv)) -{ - return(dmapages[addr & 0xf]); -} - - -static void -dma_page_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) -{ - dmapages[addr & 0xf] = val; - - switch (addr & 0xf) { - case 1: - dma[2].page = (AT) ? val : val & 0xf; - dma[2].ab = (dma[2].ab & 0xffff) | (dma[2].page << 16); - dma[2].ac = (dma[2].ac & 0xffff) | (dma[2].page << 16); - break; - - case 2: - dma[3].page = (AT) ? val : val & 0xf; - dma[3].ab = (dma[3].ab & 0xffff) | (dma[3].page << 16); - dma[3].ac = (dma[3].ac & 0xffff) | (dma[3].page << 16); - break; - - case 3: - dma[1].page = (AT) ? val : val & 0xf; - dma[1].ab = (dma[1].ab & 0xffff) | (dma[1].page << 16); - dma[1].ac = (dma[1].ac & 0xffff) | (dma[1].page << 16); - break; - - case 7: - dma[0].page = (AT) ? val : val & 0xf; - dma[0].ab = (dma[0].ab & 0xffff) | (dma[0].page << 16); - dma[0].ac = (dma[0].ac & 0xffff) | (dma[0].page << 16); - break; - - case 0x9: - dma[6].page = val & 0xfe; - dma[6].ab = (dma[6].ab & 0x1ffff) | (dma[6].page << 16); - dma[6].ac = (dma[6].ac & 0x1ffff) | (dma[6].page << 16); - break; - - case 0xa: - dma[7].page = val & 0xfe; - dma[7].ab = (dma[7].ab & 0x1ffff) | (dma[7].page << 16); - dma[7].ac = (dma[7].ac & 0x1ffff) | (dma[7].page << 16); - break; - - case 0xb: - dma[5].page = val & 0xfe; - dma[5].ab = (dma[5].ab & 0x1ffff) | (dma[5].page << 16); - dma[5].ac = (dma[5].ac & 0x1ffff) | (dma[5].page << 16); - break; - - case 0xf: - dma[4].page = val & 0xfe; - dma[4].ab = (dma[4].ab & 0x1ffff) | (dma[4].page << 16); - dma[4].ac = (dma[4].ac & 0x1ffff) | (dma[4].page << 16); - break; - } -} - - -void -dma_reset(void) -{ - int c; - - dma_wp = dma16_wp = 0; - dma_m = 0; - - for (c = 0; c < 16; c++) - dmaregs[c] = 0; - for (c = 0; c < 8; c++) { - dma[c].mode = 0; - dma[c].ac = 0; - dma[c].cc = 0; - dma[c].ab = 0; - dma[c].cb = 0; - dma[c].size = (c & 4) ? 1 : 0; - } -} - - -void -dma_init(void) -{ - io_sethandler(0x0000, 16, - dma_read,NULL,NULL, dma_write,NULL,NULL, NULL); - io_sethandler(0x0080, 8, - dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); - dma_ps2.is_ps2 = 0; -} - - -void -dma16_init(void) -{ - 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); -} - - -void -dma_alias_set(void) -{ - io_sethandler(0x0090, 16, - dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); -} - - -void -dma_alias_remove(void) -{ - io_removehandler(0x0090, 16, - dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); -} - - -void -dma_alias_remove_piix(void) -{ - io_removehandler(0x0090, 1, - dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); - io_removehandler(0x0094, 3, - 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, - dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); -} - - -void -ps2_dma_init(void) -{ - io_sethandler(0x0018, 1, - dma_ps2_read,NULL,NULL, dma_ps2_write,NULL,NULL, NULL); - io_sethandler(0x001a, 1, - dma_ps2_read,NULL,NULL, dma_ps2_write,NULL,NULL, NULL); - dma_ps2.is_ps2 = 1; -} - - -int -dma_channel_read(int channel) -{ - dma_t *dma_c = &dma[channel]; - uint16_t temp; - int tc = 0; - - if (channel < 4) { - if (dma_command & 0x04) - return(DMA_NODATA); - } else { - if (dma16_command & 0x04) - return(DMA_NODATA); - } - - if (! AT) - refreshread(); - - if (dma_m & (1 << channel)) - return(DMA_NODATA); - if ((dma_c->mode & 0xC) != 8) - return(DMA_NODATA); - - if (! dma_c->size) { - temp = _dma_read(dma_c->ac); - - if (dma_c->mode & 0x20) { - if (dma_ps2.is_ps2) - dma_c->ac--; - else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); - } else { - if (dma_ps2.is_ps2) - dma_c->ac++; - else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); +/* + * 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 Intel DMA controllers. + * + * Version: @(#)dma.c 1.0.7 2019/02/10 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * 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 + * 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. + */ +#include +#include +#include +#include +#include "../../emu.h" +#include "../../cpu/cpu.h" +#include "../../cpu/x86.h" +#include "../../machines/machine.h" +#include "../../mem.h" +#include "../../io.h" +#include "../../plat.h" +#include "mca.h" +#include "dma.h" + + +dma_t dma[8]; + + +static uint8_t dmaregs[16]; +static uint8_t dma16regs[16]; +static uint8_t dmapages[16]; +static int dma_wp, + dma16_wp; +static uint8_t dma_m; +static uint8_t dma_stat; +static uint8_t dma_stat_rq; +static uint8_t dma_command, + dma16_command; +static struct { + int xfr_command, + xfr_channel; + int byte_ptr; + + int is_ps2; +} dma_ps2; + + +#define DMA_PS2_IOA (1 << 0) +#define DMA_PS2_XFER_MEM_TO_IO (1 << 2) +#define DMA_PS2_XFER_IO_TO_MEM (3 << 2) +#define DMA_PS2_XFER_MASK (3 << 2) +#define DMA_PS2_DEC2 (1 << 4) +#define DMA_PS2_SIZE16 (1 << 6) + + +static uint8_t +_dma_read(int32_t addr) +{ + uint8_t temp = mem_readb_phys(addr); + + return(temp); +} + + +static void +_dma_write(uint32_t addr, uint8_t val) +{ + mem_writeb_phys(addr, val); + mem_invalidate_range(addr, addr); +} + + +static void +dma_ps2_run(int channel) +{ + dma_t *dma_c = &dma[channel]; + + switch (dma_c->ps2_mode & DMA_PS2_XFER_MASK) { + case DMA_PS2_XFER_MEM_TO_IO: + do { + if (! dma_c->size) { + uint8_t temp = _dma_read(dma_c->ac); + + outb(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } else { + uint16_t temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); + + outw(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + dma_stat |= (1 << channel); + break; + + case DMA_PS2_XFER_IO_TO_MEM: + do { + if (! dma_c->size) { + uint8_t temp = inb(dma_c->io_addr); + + _dma_write(dma_c->ac, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } else { + uint16_t temp = inw(dma_c->io_addr); + + _dma_write(dma_c->ac, temp & 0xff); + _dma_write(dma_c->ac + 1, temp >> 8); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + ps2_cache_clean(); + dma_stat |= (1 << channel); + break; + + default: /*Memory verify*/ + do { + if (! dma_c->size) { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } else { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma->cc--; + } while (dma->cc > 0); + + dma_stat |= (1 << channel); + break; + + } +} + + +static uint8_t +dma_ps2_read(uint16_t addr, UNUSED(void *priv)) +{ + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; + uint8_t temp = 0xff; + + switch (addr) { + case 0x1a: + switch (dma_ps2.xfr_command) { + case 2: /*Address*/ + case 3: + switch (dma_ps2.byte_ptr) { + case 0: + temp = dma_c->ac & 0xff; + dma_ps2.byte_ptr = 1; + break; + case 1: + temp = (dma_c->ac >> 8) & 0xff; + dma_ps2.byte_ptr = 2; + break; + case 2: + temp = (dma_c->ac >> 16) & 0xff; + dma_ps2.byte_ptr = 0; + break; + } + break; + + case 4: /*Count*/ + case 5: + if (dma_ps2.byte_ptr) + temp = dma_c->cc >> 8; + else + temp = dma_c->cc & 0xff; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + + case 6: /*Read DMA status*/ + if (dma_ps2.byte_ptr) { + temp = ((dma_stat_rq & 0xf0) >> 4) | (dma_stat & 0xf0); + dma_stat &= ~0xf0; + dma_stat_rq &= ~0xf0; + } else { + temp = (dma_stat_rq & 0xf) | ((dma_stat & 0xf) << 4); + dma_stat &= ~0xf; + dma_stat_rq &= ~0xf; + } + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + + case 7: /*Mode*/ + temp = dma_c->ps2_mode; + break; + + case 8: /*Arbitration Level*/ + temp = dma_c->arb_level; + break; + + default: + fatal("Bad XFR Read command %i channel %i\n", dma_ps2.xfr_command, dma_ps2.xfr_channel); + } + break; + } + + return(temp); +} + + +static void +dma_ps2_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) +{ + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; + uint8_t mode; + + switch (addr) { + case 0x18: + dma_ps2.xfr_channel = val & 0x7; + dma_ps2.xfr_command = val >> 4; + dma_ps2.byte_ptr = 0; + switch (dma_ps2.xfr_command) { + case 9: /*Set DMA mask*/ + dma_m |= (1 << dma_ps2.xfr_channel); + break; + + case 0xa: /*Reset DMA mask*/ + dma_m &= ~(1 << dma_ps2.xfr_channel); + break; + + case 0xb: + if (!(dma_m & (1 << dma_ps2.xfr_channel))) + dma_ps2_run(dma_ps2.xfr_channel); + break; + } + break; + + case 0x1a: + switch (dma_ps2.xfr_command) { + case 0: /*I/O address*/ + if (dma_ps2.byte_ptr) + dma_c->io_addr = (dma_c->io_addr & 0x00ff) | (val << 8); + else + dma_c->io_addr = (dma_c->io_addr & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + + case 2: /*Address*/ + switch (dma_ps2.byte_ptr) { + case 0: + dma_c->ac = (dma_c->ac & 0xffff00) | val; + dma_ps2.byte_ptr = 1; + break; + + case 1: + dma_c->ac = (dma_c->ac & 0xff00ff) | (val << 8); + dma_ps2.byte_ptr = 2; + break; + + case 2: + dma_c->ac = (dma_c->ac & 0x00ffff) | (val << 16); + dma_ps2.byte_ptr = 0; + break; + } + dma_c->ab = dma_c->ac; + break; + + case 4: /*Count*/ + if (dma_ps2.byte_ptr) + dma_c->cc = (dma_c->cc & 0xff) | (val << 8); + else + dma_c->cc = (dma_c->cc & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + dma_c->cb = dma_c->cc; + break; + + case 7: /*Mode register*/ + mode = 0; + if (val & DMA_PS2_DEC2) + mode |= 0x20; + if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_MEM_TO_IO) + mode |= 8; + else if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_IO_TO_MEM) + mode |= 4; + dma_c->mode = (dma_c->mode & ~0x2c) | mode; + dma_c->ps2_mode = val; + dma_c->size = val & DMA_PS2_SIZE16; + break; + + case 8: /*Arbitration Level*/ + dma_c->arb_level = val; + break; + + default: + fatal("Bad XFR command %i channel %i val %02x\n", dma_ps2.xfr_command, dma_ps2.xfr_channel, val); + } + break; + } +} + + +static uint8_t +dma_read(uint16_t addr, UNUSED(void *priv)) +{ + int channel = (addr >> 1) & 3; + uint8_t temp; + + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma_wp ^= 1; + if (dma_wp) + return(dma[channel].ac & 0xff); + return((dma[channel].ac >> 8) & 0xff); + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma_wp ^= 1; + if (dma_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; + return(temp); + + case 8: /*Status register*/ + temp = dma_stat & 0xf; + dma_stat &= ~0xf; + return(temp); + + case 0xd: + return(0); + } + + return(dmaregs[addr & 0xf]); +} + + +static void +dma_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) +{ + int channel = (addr >> 1) & 3; + + dmaregs[addr & 0xf] = val; + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma_wp ^= 1; + if (dma_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + dma[channel].ac = dma[channel].ab; + return; + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma_wp ^= 1; + if (dma_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; + return; + + case 8: /*Control register*/ + dma_command = val; + return; + + case 0xa: /*Mask*/ + if (val & 4) + dma_m |= (1 << (val & 3)); + else + dma_m &= ~(1 << (val & 3)); + return; + + case 0xb: /*Mode*/ + channel = (val & 3); + dma[channel].mode = val; + if (dma_ps2.is_ps2) { + dma[channel].ps2_mode &= ~0x1c; + if (val & 0x20) + dma[channel].ps2_mode |= 0x10; + if ((val & 0xc) == 8) + dma[channel].ps2_mode |= 4; + else if ((val & 0xc) == 4) + dma[channel].ps2_mode |= 0xc; + } + return; + + case 0xc: /*Clear FF*/ + dma_wp = 0; + return; + + case 0xd: /*Master clear*/ + dma_wp = 0; + dma_m |= 0xf; + return; + + case 0xf: /*Mask write*/ + dma_m = (dma_m & 0xf0) | (val & 0xf); + return; + } +} + + +static uint8_t +dma16_read(uint16_t addr, UNUSED(void *priv)) +{ + int channel = ((addr >> 2) & 3) + 4; + uint8_t temp; + + addr >>= 1; + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { + if (dma16_wp) + return(dma[channel].ac); + return((dma[channel].ac >> 8) & 0xff); + } + if (dma16_wp) + return((dma[channel].ac >> 1) & 0xff); + return((dma[channel].ac >> 9) & 0xff); + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma16_wp ^= 1; + if (dma16_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; + return(temp); + + case 8: /*Status register*/ + temp = dma_stat >> 4; + dma_stat &= ~0xf0; + return(temp); + } + + return(dma16regs[addr & 0xf]); +} + + +static void +dma16_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) +{ + int channel = ((addr >> 2) & 3) + 4; + addr >>= 1; + + dma16regs[addr & 0xf] = val; + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + } else { + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xfffe00) | (val << 1); + else + dma[channel].ab = (dma[channel].ab & 0xfe01ff) | (val << 9); + } + dma[channel].ac = dma[channel].ab; + return; + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma16_wp ^= 1; + if (dma16_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; + return; + + case 8: /*Control register*/ + return; + + case 0xa: /*Mask*/ + if (val & 4) + dma_m |= (0x10 << (val & 3)); + else + dma_m &= ~(0x10 << (val & 3)); + return; + + case 0xb: /*Mode*/ + channel = (val & 3) + 4; + dma[channel].mode = val; + if (dma_ps2.is_ps2) { + dma[channel].ps2_mode &= ~0x1c; + if (val & 0x20) + dma[channel].ps2_mode |= 0x10; + if ((val & 0xc) == 8) + dma[channel].ps2_mode |= 4; + else if ((val & 0xc) == 4) + dma[channel].ps2_mode |= 0xc; + } + return; + + case 0xc: /*Clear FF*/ + dma16_wp = 0; + return; + + case 0xd: /*Master clear*/ + dma16_wp = 0; + dma_m |= 0xf0; + return; + + case 0xf: /*Mask write*/ + dma_m = (dma_m & 0x0f) | ((val & 0xf) << 4); + return; + } +} + + +static uint8_t +dma_page_read(uint16_t addr, UNUSED(void *priv)) +{ + return(dmapages[addr & 0xf]); +} + + +static void +dma_page_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) +{ + dmapages[addr & 0xf] = val; + + switch (addr & 0xf) { + case 1: + dma[2].page = (AT) ? val : val & 0xf; + dma[2].ab = (dma[2].ab & 0xffff) | (dma[2].page << 16); + dma[2].ac = (dma[2].ac & 0xffff) | (dma[2].page << 16); + break; + + case 2: + dma[3].page = (AT) ? val : val & 0xf; + dma[3].ab = (dma[3].ab & 0xffff) | (dma[3].page << 16); + dma[3].ac = (dma[3].ac & 0xffff) | (dma[3].page << 16); + break; + + case 3: + dma[1].page = (AT) ? val : val & 0xf; + dma[1].ab = (dma[1].ab & 0xffff) | (dma[1].page << 16); + dma[1].ac = (dma[1].ac & 0xffff) | (dma[1].page << 16); + break; + + case 7: + dma[0].page = (AT) ? val : val & 0xf; + dma[0].ab = (dma[0].ab & 0xffff) | (dma[0].page << 16); + dma[0].ac = (dma[0].ac & 0xffff) | (dma[0].page << 16); + break; + + case 0x9: + dma[6].page = val & 0xfe; + dma[6].ab = (dma[6].ab & 0x1ffff) | (dma[6].page << 16); + dma[6].ac = (dma[6].ac & 0x1ffff) | (dma[6].page << 16); + break; + + case 0xa: + dma[7].page = val & 0xfe; + dma[7].ab = (dma[7].ab & 0x1ffff) | (dma[7].page << 16); + dma[7].ac = (dma[7].ac & 0x1ffff) | (dma[7].page << 16); + break; + + case 0xb: + dma[5].page = val & 0xfe; + dma[5].ab = (dma[5].ab & 0x1ffff) | (dma[5].page << 16); + dma[5].ac = (dma[5].ac & 0x1ffff) | (dma[5].page << 16); + break; + + case 0xf: + dma[4].page = val & 0xfe; + dma[4].ab = (dma[4].ab & 0x1ffff) | (dma[4].page << 16); + dma[4].ac = (dma[4].ac & 0x1ffff) | (dma[4].page << 16); + break; + } +} + + +void +dma_reset(void) +{ + int c; + + dma_wp = dma16_wp = 0; + dma_m = 0; + + for (c = 0; c < 16; c++) + dmaregs[c] = 0; + for (c = 0; c < 8; c++) { + dma[c].mode = 0; + dma[c].ac = 0; + dma[c].cc = 0; + dma[c].ab = 0; + dma[c].cb = 0; + dma[c].size = (c & 4) ? 1 : 0; + } +} + + +void +dma_init(void) +{ + io_sethandler(0x0000, 16, + dma_read,NULL,NULL, dma_write,NULL,NULL, NULL); + io_sethandler(0x0080, 8, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + dma_ps2.is_ps2 = 0; +} + + +void +dma16_init(void) +{ + 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); +} + + +void +dma_alias_set(void) +{ + io_sethandler(0x0090, 16, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + +void +dma_alias_remove(void) +{ + io_removehandler(0x0090, 16, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + +void +dma_alias_remove_piix(void) +{ + io_removehandler(0x0090, 1, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_removehandler(0x0094, 3, + 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, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + +void +ps2_dma_init(void) +{ + io_sethandler(0x0018, 1, + dma_ps2_read,NULL,NULL, dma_ps2_write,NULL,NULL, NULL); + io_sethandler(0x001a, 1, + dma_ps2_read,NULL,NULL, dma_ps2_write,NULL,NULL, NULL); + dma_ps2.is_ps2 = 1; +} + + +int +dma_channel_read(int channel) +{ + dma_t *dma_c = &dma[channel]; + uint16_t temp; + int tc = 0; + + if (channel < 4) { + if (dma_command & 0x04) + return(DMA_NODATA); + } else { + if (dma16_command & 0x04) + return(DMA_NODATA); + } + + if (dma_m & (1 << channel)) + return(DMA_NODATA); + if ((dma_c->mode & 0xC) != 8) + return(DMA_NODATA); + + if (!AT && !channel) + refreshread(); + + if (! dma_c->size) { + temp = _dma_read(dma_c->ac); + + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac--; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac++; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); + } + } else { + temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); + + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac -= 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac += 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); + } + } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) { + tc = 1; + if (dma_c->mode & 0x10) { /*Auto-init*/ + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } + + if (tc) + return(temp | DMA_OVER); + + return(temp); +} + + +int +dma_channel_write(int channel, uint16_t val) +{ + dma_t *dma_c = &dma[channel]; + + if (channel < 4) { + if (dma_command & 0x04) + return(DMA_NODATA); + } else { + if (dma16_command & 0x04) + return(DMA_NODATA); + } + + if (dma_m & (1 << channel)) + return(DMA_NODATA); + if ((dma_c->mode & 0xC) != 4) + return(DMA_NODATA); + + if (!AT && !channel) + refreshread(); + + if (! dma_c->size) { + _dma_write(dma_c->ac, val & 0xff); + + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac--; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac++; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); + } + } else { + _dma_write(dma_c->ac, val & 0xff); + _dma_write(dma_c->ac + 1, val >> 8); + + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac -= 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac += 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); } - } else { - temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); - - if (dma_c->mode & 0x20) { - if (dma_ps2.is_ps2) - dma_c->ac -= 2; - else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); - } else { - if (dma_ps2.is_ps2) - dma_c->ac += 2; - else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); - } - } - - dma_stat_rq |= (1 << channel); - - dma_c->cc--; - if (dma_c->cc < 0) { - tc = 1; - if (dma_c->mode & 0x10) { /*Auto-init*/ - dma_c->cc = dma_c->cb; - dma_c->ac = dma_c->ab; - } else - dma_m |= (1 << channel); - dma_stat |= (1 << channel); - } - - if (tc) - return(temp | DMA_OVER); - - return(temp); -} - - -int -dma_channel_write(int channel, uint16_t val) -{ - dma_t *dma_c = &dma[channel]; - - if (channel < 4) { - if (dma_command & 0x04) - return(DMA_NODATA); - } else { - if (dma16_command & 0x04) - return(DMA_NODATA); - } - - if (! AT) - refreshread(); - - if (dma_m & (1 << channel)) - return(DMA_NODATA); - if ((dma_c->mode & 0xC) != 4) - return(DMA_NODATA); - - if (! dma_c->size) { - _dma_write(dma_c->ac, val & 0xff); - - if (dma_c->mode & 0x20) { - if (dma_ps2.is_ps2) - dma_c->ac--; - else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); - } else { - if (dma_ps2.is_ps2) - dma_c->ac++; - else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); - } - } else { - _dma_write(dma_c->ac, val & 0xff); - _dma_write(dma_c->ac + 1, val >> 8); - - if (dma_c->mode & 0x20) { - if (dma_ps2.is_ps2) - dma_c->ac -= 2; - else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); - } else { - if (dma_ps2.is_ps2) - dma_c->ac += 2; - else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); - } - } - - dma_stat_rq |= (1 << channel); - - dma_c->cc--; - if (dma_c->cc < 0) { - if (dma_c->mode & 0x10) { /*Auto-init*/ - dma_c->cc = dma_c->cb; - dma_c->ac = dma_c->ab; - } else - dma_m |= (1 << channel); - dma_stat |= (1 << channel); - } - - if (dma_m & (1 << channel)) - return(DMA_OVER); - - return(0); -} - - -int -dma_mode(int channel) -{ - if (channel < 4) - return(dma[channel].mode); - else - return(dma[channel & 3].mode); -} - - -/* DMA Bus Master Page Read/Write */ -void -DMAPageRead(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize) -{ - uint32_t i = 0; - -#if 0 - memcpy(DataRead, &ram[PhysAddress], TotalSize); -#else - for (i = 0; i < TotalSize; i++) - DataRead[i] = mem_readb_phys_dma(PhysAddress + i); -#endif -} - - -void -DMAPageWrite(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize) -{ - uint32_t i = 0; - -#if 0 - mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); - memcpy(&ram[PhysAddress], DataWrite, TotalSize); -#else - for (i = 0; i < TotalSize; i++) - mem_writeb_phys_dma(PhysAddress + i, DataWrite[i]); - - mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); -#endif -} + } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) { + if (dma_c->mode & 0x10) { /*Auto-init*/ + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } + + if (dma_m & (1 << channel)) + return(DMA_OVER); + + return(0); +} + + +int +dma_mode(int channel) +{ + if (channel < 4) + return(dma[channel].mode); + else + return(dma[channel & 3].mode); +} + + +/* DMA Bus Master Page Read/Write */ +void +DMAPageRead(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize) +{ + uint32_t i = 0; + +#if 0 + memcpy(DataRead, &ram[PhysAddress], TotalSize); +#else + for (i = 0; i < TotalSize; i++) + DataRead[i] = mem_readb_phys(PhysAddress + i); +#endif +} + + +void +DMAPageWrite(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize) +{ + uint32_t i = 0; + +#if 0 + mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); + memcpy(&ram[PhysAddress], DataWrite, TotalSize); +#else + for (i = 0; i < TotalSize; i++) + mem_writeb_phys(PhysAddress + i, DataWrite[i]); + + mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); +#endif +} diff --git a/src/devices/system/pic.c b/src/devices/system/pic.c index 16204d7..5dcaa2f 100644 --- a/src/devices/system/pic.c +++ b/src/devices/system/pic.c @@ -8,14 +8,14 @@ * * Implementation of Intel 8259 interrupt controller. * - * Version: @(#)pic.c 1.0.3 2018/10/05 + * Version: @(#)pic.c 1.0.4 2019/02/10 * * 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 @@ -61,7 +61,7 @@ pic_updatepending(void) uint16_t temp_pending = 0; if (AT) { - if ((pic2.pend&~pic2.mask)&~pic2.mask2) + if ((pic2.pend & ~pic2.mask) & ~pic2.mask2) pic.pend |= pic.icw3; else pic.pend &= ~pic.icw3; @@ -145,7 +145,7 @@ pic_autoeoi(void) pic_update_mask(&pic.mask2, pic.ins); if (AT) { - if (((1 << c) == pic.icw3) && (pic2.pend&~pic2.mask)&~pic2.mask2) + if (((1 << c) == pic.icw3) && (pic2.pend & ~pic2.mask) & ~pic2.mask2) pic.pend |= pic.icw3; } @@ -169,34 +169,34 @@ pic_write(uint16_t addr, uint8_t val, void *priv) if (addr&1) { switch (pic.icw) { case 0: /*OCW1*/ - pic.mask=val; + pic.mask = val; pic_updatepending(); break; case 1: /*ICW2*/ - pic.vector=val&0xF8; - if (pic.icw1 & 2) pic.icw=3; - else pic.icw=2; + pic.vector = val & 0xF8; + if (pic.icw1 & 2) pic.icw = 3; + else pic.icw = 2; break; case 2: /*ICW3*/ pic.icw3 = val; DBGLOG(1, "PIC1 ICW3 now %02X\n", val); - if (pic.icw1 & 1) pic.icw=3; - else pic.icw=0; + if (pic.icw1 & 1) pic.icw = 3; + else pic.icw = 0; break; case 3: /*ICW4*/ pic.icw4 = val; - pic.icw=0; + pic.icw = 0; break; } } else { if (val & 16) { /*ICW1*/ pic.mask = 0; - pic.mask2=0; - pic.icw=1; - pic.icw1=val; + pic.mask2 = 0; + pic.icw = 1; + pic.icw1 = val; pic.ins = 0; pic_updatepending(); } @@ -205,7 +205,7 @@ pic_write(uint16_t addr, uint8_t val, void *priv) pic.ins &= ~(1 << (val & 7)); pic_update_mask(&pic.mask2, pic.ins); if (AT) { - if (((val&7) == pic2.icw3) && (pic2.pend&~pic2.mask)&~pic2.mask2) + if (((val&7) == pic2.icw3) && (pic2.pend & ~pic2.mask) & ~pic2.mask2) pic.pend |= pic.icw3; } @@ -222,7 +222,7 @@ pic_write(uint16_t addr, uint8_t val, void *priv) pic_update_mask(&pic.mask2, pic.ins); if (AT) { - if (((1 << c) == pic.icw3) && (pic2.pend&~pic2.mask)&~pic2.mask2) + if (((1 << c) == pic.icw3) && (pic2.pend & ~pic2.mask) & ~pic2.mask2) pic.pend |= pic.icw3; } @@ -231,8 +231,8 @@ pic_write(uint16_t addr, uint8_t val, void *priv) pic.pend |= 1 << c; } - if (c==1 && keywaiting) - intclear&=~1; + if (c == 1 && keywaiting) + intclear &= ~1; pic_updatepending(); return; } @@ -240,7 +240,7 @@ pic_write(uint16_t addr, uint8_t val, void *priv) } } else { /*OCW3*/ if (val & 2) - pic.read=(val & 1); + pic.read = (val & 1); } } } @@ -256,7 +256,10 @@ pic_read(uint16_t addr, void *priv) if (pic.read) { DBGLOG(1, "Read PIC ins %02X\n", pic.ins); - return pic.ins | (pic2.ins ? 4 : 0); + if (AT) + return pic.ins | (pic2.ins ? 4 : 0); + else + return pic.ins; } return pic.pend; @@ -301,34 +304,34 @@ pic2_write(uint16_t addr, uint8_t val, void *priv) if (addr & 1) { switch (pic2.icw) { case 0: /*OCW1*/ - pic2.mask=val; + pic2.mask = val; pic_updatepending(); break; case 1: /*ICW2*/ - pic2.vector=val & 0xF8; + pic2.vector = val & 0xF8; DBGLOG(1, "PIC2 vector now: %02X\n", pic2.vector); - if (pic2.icw1 & 2) pic2.icw=3; - else pic2.icw=2; + if (pic2.icw1 & 2) pic2.icw = 3; + else pic2.icw = 2; break; case 2: /*ICW3*/ pic2.icw3 = val; DBGLOG(1, "PIC2 ICW3 now %02X\n", val); - if (pic2.icw1 & 1) pic2.icw=3; - else pic2.icw=0; + if (pic2.icw1 & 1) pic2.icw = 3; + else pic2.icw = 0; break; case 3: /*ICW4*/ pic2.icw4 = val; - pic2.icw=0; + pic2.icw = 0; break; } } else { if (val & 16) { /*ICW1*/ pic2.mask = 0; - pic2.mask2=0; - pic2.icw=1; + pic2.mask2 = 0; + pic2.icw = 1; pic2.icw1 = val; pic2.ins = 0; pic_updatepending(); @@ -345,7 +348,7 @@ pic2_write(uint16_t addr, uint8_t val, void *priv) pic_updatepending(); } else { for (c = 0; c < 8; c++) { - if (pic2.ins&(1<ins & (pic_int_num - 1)); + + if (AT && (c >= 8)) + in_service |= (pic.ins & 0x03); + + if ((pending & pic_int_num) && !in_service) { target_pic->pend &= ~pic_int_num; target_pic->ins |= pic_int_num; pic_update_mask(&target_pic->mask2, target_pic->ins); - if (c >= 8) { + if (AT && (c >= 8)) { pic.ins |= (1 << pic2.icw3); /*Cascade IRQ*/ pic_update_mask(&pic.mask2, pic.ins); } @@ -527,7 +536,7 @@ pic_process_interrupt(PIC* target_pic, int c) pic_updatepending(); if (target_pic->icw4 & 0x02) - (c >= 8) ? pic2_autoeoi() : pic_autoeoi(); + (AT && (c >= 8)) ? pic2_autoeoi() : pic_autoeoi(); if (! c) pit_set_gate(&pit2, 0, 0); diff --git a/src/devices/system/pit.c b/src/devices/system/pit.c index a1dcfe6..aa8a314 100644 --- a/src/devices/system/pit.c +++ b/src/devices/system/pit.c @@ -13,14 +13,14 @@ * B4 to 40, two writes to 43, then two reads * - value _does_ change! * - * Version: @(#)pit.c 1.0.7 2018/09/22 + * Version: @(#)pit.c 1.0.8 2019/02/10 * * 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 @@ -310,7 +310,7 @@ pit_read_timer(PIT *dev, int t) timer_clock(); if (dev->using_timer[t] && !(dev->m[t] == 3 && !dev->gate[t])) { - r = (int)((int64_t)((dev->c[t] + ((1LL << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT); + r = (int)((dev->c[t] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; if (dev->m[t] == 2) r++; @@ -335,6 +335,7 @@ static void pit_write(uint16_t addr, uint8_t val, void *priv) { PIT *dev = (PIT *)priv; + double sv = 0.0; int t; switch (addr & 3) { @@ -426,7 +427,9 @@ pit_write(uint16_t addr, uint8_t val, void *priv) break; } - speakval = (int)(((float)dev->l[2]/(float)dev->l[0])*0x4000)-0x2000; + /* PIT latches are in fractions of 60 ms, so convert to sample using the formula below. */ + sv = (((double) dev->l[2]) / 60.0) * 16384.0; + speakval = ((int) sv) - 0x2000; if (speakval > 0x2000) speakval = 0x2000; break; @@ -645,21 +648,47 @@ setrtcconst(float clock) void setpitclock(float clock) { + /* + * Some calculations are done differently for 4.77 MHz, 7.16 MHz, + * and 9.54 MHz CPU's, so that loss of precision is avoided and + * the various component kept in better synchronization. + */ cpuclock = clock; - PITCONST = clock/(1193181.0f + (2.0f / 3.0f)); - CGACONST = (clock/(19687503.0f/11.0f)); - MDACONST = (clock/2032125.0f); - VGACONST1 = (clock/25175000.0f); - VGACONST2 = (clock/28322000.0f); + if (clock == 4772728.0) { + PITCONST = 4.0; + CGACONST = (float)(8.0 / 3.0); + } else if (clock == 7159092.0) { + /* 7.16 MHz - simplify the calculation to avoid loss of precision. */ + PITCONST = 6.0; + CGACONST = 4.0; + } else if (clock == 9545456.0) { + /* 9.54 MHz - simplify the calculation to avoid loss of precision. */ + PITCONST = 8.0; + CGACONST = (float)(8.0 / 1.5); + } else { + PITCONST = clock / 1193182.0; + CGACONST = (float)(clock / (19687503.0 / 11.0)); + } - isa_timing = clock/8000000.0f; - bus_timing = clock/(float)cpu_busspeed; + MDACONST = (clock / 2032125.0f); + VGACONST1 = (clock / 25175000.0f); + VGACONST2 = (clock / 28322000.0f); + + isa_timing = clock / 8000000.0f; + bus_timing = clock / (float)cpu_busspeed; video_update_timing(); - xt_cpu_multi = (int)((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)machine_speed()); -// TIMER_USEC = (int64_t)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); + if (clock == 4772728.0) { + xt_cpu_multi = (int) (3 * (1 << TIMER_SHIFT)); + } else if (clock == 7159092.0) { + xt_cpu_multi = (int) (2 * (1 << TIMER_SHIFT)); + } else if (clock == 9545456.0) { + xt_cpu_multi = (int) (1.5*(double)(1 << TIMER_SHIFT)); + } else { + xt_cpu_multi = (int) ((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + } device_speed_changed(); } @@ -675,7 +704,7 @@ clearpit(void) int pit_get_timer_0(void) { - int r = (int)((int64_t)((pit.c[0] + ((1LL << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT); + int r = (int)((pit.c[0] + ((1LL << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; if (pit.m[0] == 2) r++; @@ -690,16 +719,6 @@ pit_get_timer_0(void) } -float -pit_timer0_freq(void) -{ - if (pit.l[0]) - return (1193181.0f + (2.0f / 3.0f))/(float)pit.l[0]; - else - return (1193181.0f + (2.0f / 3.0f))/(float)0x10000; -} - - void pit_set_gate(PIT *dev, int t, int gate) { diff --git a/src/devices/video/vid_ati18800.c b/src/devices/video/vid_ati18800.c index d9144ea..d680175 100644 --- a/src/devices/video/vid_ati18800.c +++ b/src/devices/video/vid_ati18800.c @@ -8,14 +8,14 @@ * * ATI 18800 emulation (VGA Edge-16) * - * Version: @(#)vid_ati18800.c 1.0.9 2018/10/05 + * Version: @(#)vid_ati18800.c 1.0.10 2019/02/10 * * 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 @@ -193,7 +193,7 @@ static void ati18800_recalctimings(svga_t *svga) svga->vblankstart <<= 1; } - if (!svga->scrblank && (ati18800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ + if (!svga->scrblank && ((ati18800->regs[0xb0] & 0x02) || (ati18800->regs[0xb0] & 0x04))) /*Extended 256 color modes*/ { svga->render = svga_render_8bpp_highres; svga->bpp = 8; @@ -236,7 +236,7 @@ ati18800_init(const device_t *info) 0, MEM_MAPPING_EXTERNAL); } - svga_init(&dev->svga, dev, 1 << 19, /*512kb*/ + svga_init(&dev->svga, dev, 1 << 20, /*512KB*/ ati18800_recalctimings, ati18800_in, ati18800_out, NULL, NULL); io_sethandler(0x01ce, 0x0002, diff --git a/src/devices/video/vid_ati28800.c b/src/devices/video/vid_ati28800.c index 71d9a50..04c903e 100644 --- a/src/devices/video/vid_ati28800.c +++ b/src/devices/video/vid_ati28800.c @@ -8,15 +8,15 @@ * * ATI 28800 emulation (VGA Charger and Korean VGA) * - * Version: @(#)vid_ati28800.c 1.0.15 2018/10/05 + * Version: @(#)vid_ati28800.c 1.0.16 2019/02/10 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * greatpsycho, * - * 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 @@ -119,25 +119,14 @@ ati28800_out(uint16_t port, uint8_t val, void *priv) old = dev->regs[dev->index]; dev->regs[dev->index] = val; switch (dev->index) { - case 0xb2: case 0xbd: case 0xbe: if (dev->regs[0xbe] & 8) /*Read/write bank mode*/ { - if (dev->regs[0xbd] & 4) { - svga->read_bank = (((dev->regs[0xb2] >> 5) & 7) * 0x20000); - svga->write_bank = (((dev->regs[0xb2] >> 1) & 7) * 0x20000); - } else { - svga->read_bank = (((dev->regs[0xb2] >> 5) & 7) * 0x10000); - svga->write_bank = (((dev->regs[0xb2] >> 1) & 7) * 0x10000); - } + svga->read_bank = (((dev->regs[0xb2] >> 5) & 7) * 0x10000); + svga->write_bank = (((dev->regs[0xb2] >> 1) & 7) * 0x10000); } else { /*Single bank mode*/ - if (dev->regs[0xbd] & 4) { - svga->read_bank = (((dev->regs[0xb2] >> 1) & 7) * 0x20000); - svga->write_bank = (((dev->regs[0xb2] >> 1) & 7) * 0x20000); - } else { - svga->read_bank = (((dev->regs[0xb2] >> 1) & 7) * 0x10000); - svga->write_bank = (((dev->regs[0xb2] >> 1) & 7) * 0x10000); - } + svga->read_bank = (((dev->regs[0xb2] >> 1) & 7) * 0x10000); + svga->write_bank = (((dev->regs[0xb2] >> 1) & 7) * 0x10000); } break; @@ -180,6 +169,7 @@ ati28800_out(uint16_t port, uint8_t val, void *priv) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; if (old != val) { @@ -382,9 +372,15 @@ ati28800_recalctimings(svga_t *svga) 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; +#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; +#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; @@ -397,7 +393,8 @@ ati28800_recalctimings(svga_t *svga) default: break; } - if (dev->regs[0xb8] & 0x40) svga->clock *= 2; + if (dev->regs[0xb8] & 0x40) + svga->clock *= 2; if (dev->regs[0xb6] & 0x10) { svga->hdisp <<= 1; diff --git a/src/devices/video/vid_att20c49x_ramdac.c b/src/devices/video/vid_att20c49x_ramdac.c new file mode 100644 index 0000000..b89084d --- /dev/null +++ b/src/devices/video/vid_att20c49x_ramdac.c @@ -0,0 +1,181 @@ +/* + * 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. + * + * Emulation of a AT&T 20c490/491 and 492/493 RAMDAC. + * + * Version: @(#)vid_att20c49x_ramdac.c 1.0.1 2019/01/12 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 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 + * 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. + */ +#include +#include +#include +#include +#include +#include "../../emu.h" +#include "../../mem.h" +#include "../../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_att20c49x_ramdac.h" + + +enum { + ATT_490_1 = 0, + ATT_492_3 +}; + + +void +att49x_ramdac_out(uint16_t addr, uint8_t val, att49x_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) { + case 0x03c6: + if (ramdac->state == 4) { + ramdac->state = 0; + ramdac->ctrl = val; + if (ramdac->type == ATT_490_1) + svga_set_ramdac_type(svga, (val & 2) ? RAMDAC_8BIT : RAMDAC_6BIT); + switch (val) { + case 0: + svga->bpp = 8; + break; + + case 0x20: + svga->bpp = 15; + break; + + case 0x40: + svga->bpp = 24; + break; + + case 0x60: + svga->bpp = 16; + break; + + case 0x80: + case 0xa0: + svga->bpp = 15; + break; + + case 0xc0: + svga->bpp = 16; + break; + + case 0xe0: + svga->bpp = 24; + break; + } + svga_recalctimings(svga); + return; + } + ramdac->state = 0; + break; + + case 0x3c7: + case 0x3c8: + case 0x3c9: + ramdac->state = 0; + break; + } + + svga_out(addr, val, svga); +} + + +uint8_t +att49x_ramdac_in(uint16_t addr, att49x_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp; + + temp = svga_in(addr, svga); + + switch (addr) { + case 0x3c6: + if (ramdac->state == 4) { + ramdac->state = 0; + temp = ramdac->ctrl; + break; + } + ramdac->state++; + break; + + case 0x3c7: + case 0x3c8: + case 0x3c9: + ramdac->state = 0; + break; + } + + return temp; +} + + +static void * +att49x_ramdac_init(const device_t *info) +{ + att49x_ramdac_t *dev; + + dev = (att49x_ramdac_t *)mem_alloc(sizeof(att49x_ramdac_t)); + memset(dev, 0x00, sizeof(att49x_ramdac_t)); + + dev->type = info->local; + + return dev; +} + + +static void +att49x_ramdac_close(void *priv) +{ + att49x_ramdac_t *dev = (att49x_ramdac_t *)priv; + + if (dev) + free(dev); +} + + +const device_t att490_ramdac_device = { + "AT&T 20c490/20c491 RAMDAC", + 0, + ATT_490_1, + att49x_ramdac_init, att49x_ramdac_close, NULL, + NULL, NULL, NULL, NULL, + NULL +}; + +const device_t att492_ramdac_device = { + "AT&T 20c492/20c493 RAMDAC", + 0, + ATT_492_3, + att49x_ramdac_init, att49x_ramdac_close, NULL, + NULL, NULL, NULL, NULL, + NULL +}; diff --git a/src/devices/video/vid_att20c49x_ramdac.h b/src/devices/video/vid_att20c49x_ramdac.h new file mode 100644 index 0000000..70c0423 --- /dev/null +++ b/src/devices/video/vid_att20c49x_ramdac.h @@ -0,0 +1,56 @@ +/* + * 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 AT&T 20c490/491 and 492/493 RAMDAC. + * + * Version: @(#)vid_att20c49x_ramdac.h 1.0.1 2019/01/12 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 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 + * 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. + */ +#ifndef VIDEO_ATT20C49X_RAMDAC_H +# define VIDEO_ATT20C49X_RAMDAC_H + + +typedef struct { + int type; + int state; + uint8_t ctrl; +} att49x_ramdac_t; + + +extern const device_t att490_ramdac_device; +extern const device_t att492_ramdac_device; + + +extern void att49x_ramdac_out(uint16_t addr, uint8_t val, att49x_ramdac_t *ramdac, svga_t *svga); +extern uint8_t att49x_ramdac_in(uint16_t addr, att49x_ramdac_t *ramdac, svga_t *svga); + + +#endif /*VIDEO_ATT20C49X_RAMDAC_H*/ diff --git a/src/devices/video/vid_av9194.c b/src/devices/video/vid_av9194.c new file mode 100644 index 0000000..a7a1c4f --- /dev/null +++ b/src/devices/video/vid_av9194.c @@ -0,0 +1,133 @@ +/* + * 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. + * + * AV9194 clock generator emulation.. + * + * Version: @(#)vid_av9194.c 1.0.1 2019/01/12 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 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 + * 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. + */ +#include +#include +#include +#include +#include +#include "../../emu.h" +#include "../../device.h" +#include "video.h" +#include "vid_av9194.h" + + +float +av9194_getclock(int clock, void *priv) +{ + float ret = 0.0; + + switch (clock & 0x0f) { + case 0: + ret = 25175000.0; + break; + + case 1: + ret = 28322000.0; + break; + + case 2: + ret = 40000000.0; + break; + + case 4: + ret = 50000000.0; + break; + case 5: + ret = 77000000.0; + break; + + case 6: + ret = 36000000.0; + break; + + case 7: + ret = 44900000.0; + break; + + case 8: + ret = 130000000.0; + break; + + case 9: + ret = 120000000.0; + break; + + case 0xa: + ret = 80000000.0; + break; + + case 0xb: + ret = 31500000.0; + break; + + case 0xc: + ret = 110000000.0; + break; + + case 0xd: + ret = 65000000.0; + break; + + case 0xe: + ret = 75000000.0; + break; + + case 0xf: + ret = 94500000.0; + break; + } + + return ret; +} + + +static void * +av9194_init(const device_t *info) +{ + /* Return something non-NULL. */ + return (void *)&av9194_device; +} + + +const device_t av9194_device = { + "AV9194 Clock Generator", + 0, + 0, + av9194_init, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL +}; diff --git a/src/devices/video/vid_av9194.h b/src/devices/video/vid_av9194.h new file mode 100644 index 0000000..5822e38 --- /dev/null +++ b/src/devices/video/vid_av9194.h @@ -0,0 +1,47 @@ +/* + * 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 AV9194 driver. + * + * Version: @(#)vid_av9194.h 1.0.1 2019/01/12 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 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 + * 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. + */ +#ifndef VIDEO_AV9194_H +# define VIDEO_AV9194_H + + +extern const device_t av9194_device; + + +extern float av9194_getclock(int clock, void *priv); + + +#endif /*VIDEO_AV9194_H*/ diff --git a/src/devices/video/vid_bt48x_ramdac.c b/src/devices/video/vid_bt48x_ramdac.c index 8f745d9..ccf0a93 100644 --- a/src/devices/video/vid_bt48x_ramdac.c +++ b/src/devices/video/vid_bt48x_ramdac.c @@ -8,13 +8,13 @@ * * Brooktree Bt48x series true color RAMDAC emulation. * - * Version: @(#)vid_bt48x_ramdac.c 1.0.9 2018/10/21 + * Version: @(#)vid_bt48x_ramdac.c 1.0.10 2019/02/10 * * Authors: Fred N. van Kempen, * Miran Grca, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. + * Copyright 2018,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 @@ -59,27 +59,31 @@ enum { static void set_bpp(bt48x_ramdac_t *dev, svga_t *svga) { - if (dev->cr2 & 0x20) switch ((dev->cr1 >> 5) & 0x03) { - case 0: + if ((!(dev->cr2 & 0x20)) || ((dev->type >= BT485A) && + ((dev->cr3 & 0x60) == 0x60))) + svga->bpp = 8; + else if ((dev->type >= BT485A) && ((dev->cr3 & 0x60) == 0x40)) + svga->bpp = 24; + else switch (dev->cr1 & 0x60) { + case 0x00: svga->bpp = 32; break; - case 1: + case 0x20: if (dev->cr1 & 0x08) svga->bpp = 16; else svga->bpp = 15; break; - case 2: + case 0x40: svga->bpp = 8; break; - case 3: + case 0x60: svga->bpp = 4; break; - } else - svga->bpp = 8; + } svga_recalctimings(svga); } @@ -102,7 +106,9 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *d switch (rs) { case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ case 0x03: + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ svga->dac_pos = 0; svga->dac_status = addr & 0x03; svga->dac_addr = val; @@ -117,13 +123,6 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *d svga_out(addr, val, svga); break; - case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ - case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ - svga->dac_pos = 0; - svga->dac_status = rs & 0x03; - dev->ext_addr = (val + (rs & 0x01)) & 255; - break; - case 0x05: /* Ext Palette Data Register (RS value = 0101) */ svga->dac_status = 0; svga->fullchange = changeframecount; @@ -139,7 +138,7 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *d break; case 2: - indx = dev->ext_addr & 3; + indx = svga->dac_addr & 3; dev->extpal[indx].r = svga->dac_r; dev->extpal[indx].g = svga->dac_g; dev->extpal[indx].b = val; @@ -154,7 +153,7 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *d if (o32 != svga->overscan_color) svga_recalctimings(svga); } - dev->ext_addr = (dev->ext_addr + 1) & 0xff; + svga->dac_addr = (svga->dac_addr + 1) & 0xff; svga->dac_pos = 0; break; } @@ -178,10 +177,12 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *d case 0x0a: if ((dev->type >= BT485) && (dev->cr0 & 0x80)) { - switch ((svga->dac_addr & 0xff)) { + switch ((svga->dac_addr & ((dev->type >= BT485A) ? 0xff : 0x3f))) { case 0x01: /* Command Register 3 (RS value = 1010) */ dev->cr3 = val; + if (dev->type >= BT485A) + set_bpp(dev, svga); svga->hwcursor.xsize = svga->hwcursor.ysize = (val & 4) ? 64 : 32; svga->hwcursor.yoff = (svga->hwcursor.ysize == 32) ? 32 : 0; svga->hwcursor.x = dev->hwc_x - svga->hwcursor.xsize; @@ -259,19 +260,17 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_ramdac_t *dev, svga_t *sv case 0x00: /* Palette Write Index Register (RS value = 0000) */ case 0x01: /* Palette Data Register (RS value = 0001) */ case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ temp = svga_in(addr, svga); break; case 0x03: /* Palette Read Index Register (RS value = 0011) */ + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ temp = svga->dac_addr & 0xff; break; - case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ - temp = dev->ext_addr; - break; - case 0x05: /* Ext Palette Data Register (RS value = 0101) */ - indx = (dev->ext_addr - 1) & 3; + indx = (svga->dac_addr - 1) & 3; svga->dac_status = 3; switch (svga->dac_pos) { case 0: @@ -292,7 +291,7 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_ramdac_t *dev, svga_t *sv case 2: svga->dac_pos = 0; - dev->ext_addr = dev->ext_addr + 1; + svga->dac_addr = svga->dac_addr + 1; if (svga->ramdac_type == RAMDAC_8BIT) temp = dev->extpal[indx].b; else @@ -305,10 +304,6 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_ramdac_t *dev, svga_t *sv temp = dev->cr0; break; - case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ - temp = dev->ext_addr; - break; - case 0x08: /* Command Register 1 (RS value = 1000) */ temp = dev->cr1; break; @@ -319,8 +314,9 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_ramdac_t *dev, svga_t *sv case 0x0a: if ((dev->type >= BT485) && (dev->cr0 & 0x80)) { - switch ((svga->dac_addr & 0xff)) { + switch ((svga->dac_addr & ((dev->type >= BT485A) ? 0xff : 0x3f))) { case 0x00: + default: temp = dev->status | (svga->dac_status ? 0x04 : 0x00); break; diff --git a/src/devices/video/vid_bt48x_ramdac.h b/src/devices/video/vid_bt48x_ramdac.h index 0db3450..86655c6 100644 --- a/src/devices/video/vid_bt48x_ramdac.h +++ b/src/devices/video/vid_bt48x_ramdac.h @@ -8,14 +8,14 @@ * * Definitions for the Bt48x RAMDAC series driver. * - * Version: @(#)vid_bt485_ramdac.h 1.0.3 2018/10/05 + * Version: @(#)vid_bt485_ramdac.h 1.0.4 2019/02/10 * * 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 @@ -45,7 +45,8 @@ typedef struct { uint32_t extpallook[256]; uint8_t cursor32_data[256]; uint8_t cursor64_data[1024]; - int hwc_y, hwc_x; + int hwc_y, + hwc_x; uint8_t cr0; uint8_t cr1; uint8_t cr2; @@ -53,7 +54,6 @@ typedef struct { uint8_t cr4; uint8_t status; uint8_t type; - uint8_t ext_addr; } bt48x_ramdac_t; diff --git a/src/devices/video/vid_cga.c b/src/devices/video/vid_cga.c index 08e224e..9073327 100644 --- a/src/devices/video/vid_cga.c +++ b/src/devices/video/vid_cga.c @@ -8,14 +8,14 @@ * * Emulation of the old and new IBM CGA graphics cards. * - * Version: @(#)vid_cga.c 1.0.8 2019/02/09 + * Version: @(#)vid_cga.c 1.0.9 2019/02/10 * * 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-2019 Sarah Walker. * * This program is free software; you can redistribute it and/or modify @@ -70,6 +70,58 @@ static const uint8_t crtcmask[32] = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const int ws_array[16] = {3,4,5,6,7,8,4,5,6,7,8,4,5,6,7,8}; +static const video_timings_t cga_timing = { VID_ISA,8,16,32,8,16,32 }; + + +#ifdef _DEBUG +void +cga_print(cga_t *dev) +{ + int x_res = dev->crtc[0x02]; + int hchar = 3; + char ncol = '4'; + + if (! (dev->cgamode & 0x08)) + return; + +#if 0 + if (dev->cgamode & 1) + x_res <<= 3; + else if (! (dev->cgamode & 2)) + x_res <<= 4; + else if (! (dev->cgamode & 16)) + x_res <<= 3; + else + x_res <<= 4; +#else + if ((dev->cgamode & 0x12) == 0x02) + hchar++; + else if ((dev->cgamode & 0x03) == 0x00) + hchar++; + x_res <<= hchar; +#endif + + if ((dev->cgamode & 0x12) == 0x12) + ncol = '8'; + else if ((dev->cgamode & 0x03) == 0x01) + ncol = '8'; + if ((dev->cgamode & 0x12) == 0x10) + ncol = 't'; + else if ((dev->cgamode & 0x03) == 0x03) + ncol = 'g'; + +#if 0 + INFO("CGA: HSync Pos: %i chars (%i p), VSync Pos: %i chars (%i p)\n", + dev->crtc[0x02], x_res, dev->crtc[0x07], dev->crtc[0x07] * (dev->crtc[0x09] + 1)); +#else + INFO("CGA: [%c%c%i] HSync Pos: %i chars (%i p), VSync Pos: %i chars (%i p)\n", + (dev->cgamode & 2) ? 'G' : 'T', ncol, hchar, + dev->crtc[0x02], x_res, + dev->crtc[0x07], dev->crtc[0x07] * (dev->crtc[0x09] + 1)); +#endif +} +#endif void @@ -101,37 +153,36 @@ cga_out(uint16_t port, uint8_t val, void *priv) uint8_t old; switch (port) { - case 0x3d4: + case 0x03d4: dev->crtcreg = val & 31; return; - case 0x3d5: + case 0x03d5: old = dev->crtc[dev->crtcreg]; dev->crtc[dev->crtcreg] = val & crtcmask[dev->crtcreg]; if (old != val) { - if (dev->crtcreg < 0xe || dev->crtcreg > 0x10) { + if ((dev->crtcreg < 0x0e) || (dev->crtcreg > 0x10)) { fullchange = changeframecount; cga_recalctimings(dev); } } return; - case 0x3d8: - if (((dev->cgamode ^ val) & 5) != 0) { - dev->cgamode = val; - update_cga16_color(dev->cgamode); - } - - if ((dev->cgamode ^ val) & 1) { - cga_palette = (dev->rgb_type << 1); - cgapal_rebuild(); - } - + case 0x03d8: + old = dev->cgamode; dev->cgamode = val; + if (old ^ val) { + if ((old ^ val) & 0x05) + update_cga16_color(val); + cga_recalctimings(dev); + } return; - case 0x3d9: + case 0x03d9: + old = dev->cgacol; dev->cgacol = val; + if (old ^ val) + cga_recalctimings(dev); return; } } @@ -144,15 +195,15 @@ cga_in(uint16_t port, void *priv) uint8_t ret = 0xff; switch (port) { - case 0x3d4: + case 0x03d4: ret = dev->crtcreg; break; - case 0x3d5: + case 0x03d5: ret = dev->crtc[dev->crtcreg]; break; - case 0x3da: + case 0x03da: ret = dev->cgastat; break; @@ -164,18 +215,29 @@ cga_in(uint16_t port, void *priv) } +void +cga_waitstates(void *priv) +{ + int ws; + + ws = ws_array[cycles & 0x0f]; + cycles -= ws; +} + + void cga_write(uint32_t addr, uint8_t val, void *priv) { cga_t *dev = (cga_t *)priv; dev->vram[addr & 0x3fff] = val; + if (dev->snow_enabled) { dev->charbuffer[ ((int)(((dev->dispontime - dev->vidtime) * 2) / CGACONST)) & 0xfc] = val; dev->charbuffer[(((int)(((dev->dispontime - dev->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; } - cycles -= 4; + cga_waitstates(dev); } @@ -184,7 +246,7 @@ cga_read(uint32_t addr, void *priv) { cga_t *dev = (cga_t *)priv; - cycles -= 4; + cga_waitstates(dev); if (dev->snow_enabled) { dev->charbuffer[ ((int)(((dev->dispontime - dev->vidtime) * 2) / CGACONST)) & 0xfc] = dev->vram[addr & 0x3fff]; @@ -217,6 +279,7 @@ cga_poll(void *priv) int x, c; int oldvc; uint8_t chr, attr; + uint8_t border; uint16_t dat; int cols[4]; int col; @@ -229,7 +292,7 @@ cga_poll(void *priv) oldsc = dev->sc; if ((dev->crtc[8] & 3) == 3) - dev->sc = ((dev->sc << 1) + dev->oddeven) & 7; + dev->sc = ((dev->sc << 1) + dev->oddeven) & 7; if (dev->cgadispon) { if (dev->displine < dev->firstline) { @@ -240,80 +303,93 @@ cga_poll(void *priv) for (c = 0; c < 8; c++) { if ((dev->cgamode & 0x12) == 0x12) { - buffer->line[dev->displine][c] = 0; - if (dev->cgamode & 1) - buffer->line[dev->displine][c + (dev->crtc[1] << 3) + 8] = 0; - else - buffer->line[dev->displine][c + (dev->crtc[1] << 4) + 8] = 0; + buffer->line[(dev->displine << 1)][c] = + buffer->line[(dev->displine << 1) + 1][c] = 0; + if (dev->cgamode & 1) { + buffer->line[(dev->displine << 1)][c + (dev->crtc[1] << 3) + 8] = + buffer->line[(dev->displine << 1) + 1][c + (dev->crtc[1] << 3) + 8] = 0; + } else { + buffer->line[(dev->displine << 1)][c + (dev->crtc[1] << 4) + 8] = + buffer->line[(dev->displine << 1) + 1][c + (dev->crtc[1] << 4) + 8] = 0; + } } else { - buffer->line[dev->displine][c] = (dev->cgacol & 15) + 16; - if (dev->cgamode & 1) - buffer->line[dev->displine][c + (dev->crtc[1] << 3) + 8] = (dev->cgacol & 15) + 16; - else - buffer->line[dev->displine][c + (dev->crtc[1] << 4) + 8] = (dev->cgacol & 15) + 16; + buffer->line[(dev->displine << 1)][c] = + buffer->line[(dev->displine << 1) + 1][c] = (dev->cgacol & 15) + 16; + if (dev->cgamode & 1) { + buffer->line[(dev->displine << 1)][c + (dev->crtc[1] << 3) + 8] = + buffer->line[(dev->displine << 1) + 1][c + (dev->crtc[1] << 3) + 8] = (dev->cgacol & 15) + 16; + } else { + buffer->line[(dev->displine << 1)][c + (dev->crtc[1] << 4) + 8] = + buffer->line[(dev->displine << 1) + 1][c + (dev->crtc[1] << 4) + 8] = (dev->cgacol & 15) + 16; + } } } if (dev->cgamode & 1) { for (x = 0; x < dev->crtc[1]; x++) { - if (dev->cgamode & 8) { + if (dev->cgamode & 8) { chr = dev->charbuffer[x << 1]; attr = dev->charbuffer[(x << 1) + 1]; - } else { - chr = 0; - attr = 0; - } - + } else + chr = attr = 0; drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + cols[1] = (attr & 15) + 16; if (dev->cgamode & 0x20) { - cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; if ((dev->cgablink & 8) && (attr & 0x80) && !dev->drawcursor) cols[1] = cols[0]; - } else { - cols[1] = (attr & 15) + 16; + } else cols[0] = (attr >> 4) + 16; - } - if (drawcursor) { - for (c = 0; c < 8; c++) - buffer->line[dev->displine][(x << 3) + c + 8] = cols[(fontdat[chr + dev->fontbase][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + for (c = 0; c < 8; c++) { + buffer->line[(dev->displine << 1)][(x << 3) + c + 8] = + buffer->line[(dev->displine << 1) + 1][(x << 3) + c + 8] = + cols[(fontdat[chr + dev->fontbase][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } } else { - for (c = 0; c < 8; c++) - buffer->line[dev->displine][(x << 3) + c + 8] = cols[(fontdat[chr + dev->fontbase][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + for (c = 0; c < 8; c++) { + buffer->line[(dev->displine << 1)][(x << 3) + c + 8] = + buffer->line[(dev->displine << 1) + 1][(x << 3) + c + 8] = + cols[(fontdat[chr + dev->fontbase][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } } dev->ma++; } - } else if (!(dev->cgamode & 2)) { + } else if (! (dev->cgamode & 2)) { for (x = 0; x < dev->crtc[1]; x++) { if (dev->cgamode & 8) { chr = dev->vram[((dev->ma << 1) & 0x3fff)]; attr = dev->vram[(((dev->ma << 1) + 1) & 0x3fff)]; - } else { - chr = 0; - attr = 0; - } - + } else + chr = attr = 0; drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + cols[1] = (attr & 15) + 16; if (dev->cgamode & 0x20) { - cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; - if ((dev->cgablink & 8) && (attr & 0x80)) cols[1] = cols[0]; - } else { - cols[1] = (attr & 15) + 16; + if ((dev->cgablink & 8) && (attr & 0x80)) + cols[1] = cols[0]; + } else cols[0] = (attr >> 4) + 16; - } dev->ma++; - if (drawcursor) { - for (c = 0; c < 8; c++) - buffer->line[dev->displine][(x << 4)+(c << 1) + 8] = buffer->line[dev->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + dev->fontbase][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + for (c = 0; c < 8; c++) { + buffer->line[(dev->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer->line[(dev->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer->line[(dev->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer->line[(dev->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[(fontdat[chr + dev->fontbase][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } } else { - for (c = 0; c < 8; c++) - buffer->line[dev->displine][(x << 4) + (c << 1) + 8] = buffer->line[dev->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + dev->fontbase][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + for (c = 0; c < 8; c++) { + buffer->line[(dev->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer->line[(dev->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer->line[(dev->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer->line[(dev->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[(fontdat[chr + dev->fontbase][dev->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } } } - } else if (!(dev->cgamode & 16)) { + } else if (! (dev->cgamode & 16)) { cols[0] = (dev->cgacol & 15) | 16; col = (dev->cgacol & 16) ? 24 : 16; if (dev->cgamode & 4) { @@ -333,38 +409,43 @@ cga_poll(void *priv) for (x = 0; x < dev->crtc[1]; x++) { if (dev->cgamode & 8) dat = (dev->vram[((dev->ma << 1) & 0x1fff) + ((dev->sc & 1) * 0x2000)] << 8) | dev->vram[((dev->ma << 1) & 0x1fff) + ((dev->sc & 1) * 0x2000) + 1]; - else + else dat = 0; - dev->ma++; - for (c = 0; c < 8; c++) { - buffer->line[dev->displine][(x << 4) + (c << 1) + 8] = buffer->line[dev->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + buffer->line[(dev->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer->line[(dev->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer->line[(dev->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer->line[(dev->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + cols[dat >> 14]; dat <<= 2; } } } else { cols[0] = 0; cols[1] = (dev->cgacol & 15) + 16; for (x = 0; x < dev->crtc[1]; x++) { - if (dev->cgamode & 8) + if (dev->cgamode & 8) dat = (dev->vram[((dev->ma << 1) & 0x1fff) + ((dev->sc & 1) * 0x2000)] << 8) | dev->vram[((dev->ma << 1) & 0x1fff) + ((dev->sc & 1) * 0x2000) + 1]; - else + else dat = 0; - dev->ma++; - for (c = 0; c < 16; c++) { - buffer->line[dev->displine][(x << 4) + c + 8] = cols[dat >> 15]; + buffer->line[(dev->displine << 1)][(x << 4) + c + 8] = + buffer->line[(dev->displine << 1) + 1][(x << 4) + c + 8] = + cols[dat >> 15]; dat <<= 1; } } } } else { cols[0] = ((dev->cgamode & 0x12) == 0x12) ? 0 : (dev->cgacol & 15) + 16; - if (dev->cgamode & 1) - cga_hline(buffer, 0, dev->displine, (dev->crtc[1] << 3) + 16, cols[0]); - else - cga_hline(buffer, 0, dev->displine, (dev->crtc[1] << 4) + 16, cols[0]); + if (dev->cgamode & 1) { + cga_hline(buffer, 0, (dev->displine << 1), (dev->crtc[1] << 3) + 16, cols[0]); + cga_hline(buffer, 0, (dev->displine << 1) + 1, (dev->crtc[1] << 3) + 16, cols[0]); + } else { + cga_hline(buffer, 0, (dev->displine << 1), (dev->crtc[1] << 4) + 16, cols[0]); + cga_hline(buffer, 0, (dev->displine << 1) + 1, (dev->crtc[1] << 4) + 16, cols[0]); + } } if (dev->cgamode & 1) @@ -373,15 +454,23 @@ cga_poll(void *priv) x = (dev->crtc[1] << 4) + 16; if (dev->composite) { - for (c = 0; c < x; c++) - buffer32->line[dev->displine][c] = buffer->line[dev->displine][c] & 0xf; + for (c = 0; c < x; c++) { + buffer32->line[(dev->displine << 1)][c] = buffer->line[(dev->displine << 1)][c] & 0xf; + buffer32->line[(dev->displine << 1) + 1][c] = buffer->line[(dev->displine << 1) + 1][c] & 0xf; + } - Composite_Process(dev->cgamode, 0, x >> 2, buffer32->line[dev->displine]); + if (dev->cgamode & 0x10) + border = 0x00; + else + border = dev->cgacol & 0x0f; + + Composite_Process(dev->cgamode, border, x >> 2, buffer32->line[(dev->displine << 1)]); + Composite_Process(dev->cgamode, border, x >> 2, buffer32->line[(dev->displine << 1) + 1]); } dev->sc = oldsc; if (dev->vc == dev->crtc[7] && !dev->sc) - dev->cgastat |= 8; + dev->cgastat |= 8; dev->displine++; if (dev->displine >= 360) dev->displine = 0; @@ -390,8 +479,8 @@ cga_poll(void *priv) dev->linepos = 0; if (dev->vsynctime) { dev->vsynctime--; - if (!dev->vsynctime) - dev->cgastat &= ~8; + if (! dev->vsynctime) + dev->cgastat &= ~8; } if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { @@ -400,7 +489,7 @@ cga_poll(void *priv) } if ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1)) - dev->maback = dev->ma; + dev->maback = dev->ma; if (dev->vadj) { dev->sc++; @@ -425,10 +514,10 @@ cga_poll(void *priv) if (oldvc == dev->crtc[4]) { dev->vc = 0; dev->vadj = dev->crtc[5]; - if (! dev->vadj) + if (! dev->vadj) { dev->cgadispon = 1; - if (! dev->vadj) dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + } switch (dev->crtc[10] & 0x60) { case 0x20: @@ -449,28 +538,35 @@ cga_poll(void *priv) dev->cgadispon = 0; dev->displine = 0; dev->vsynctime = 16; + if (dev->crtc[7]) { if (dev->cgamode & 1) x = (dev->crtc[1] << 3) + 16; else x = (dev->crtc[1] << 4) + 16; dev->lastline++; - - if ((x != xsize) || ((dev->lastline - dev->firstline) != ysize) || video_force_resize_get()) { +#ifdef _DEBUG + cga_print(dev); +#endif + if ((dev->cgamode & 8) && x && (dev->lastline - dev->firstline) && + ((x != xsize) || (((dev->lastline - dev->firstline) << 1) != ysize) || + video_force_resize_get())) { xsize = x; - ysize = dev->lastline - dev->firstline; + ysize = (dev->lastline - dev->firstline) << 1; if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, (ysize << 1) + 16); + if (ysize < 32) ysize = 400; + set_screen_size(xsize, ysize + 16); if (video_force_resize_get()) video_force_resize_set(0); } - + if (dev->composite) - video_blit_memtoscreen(0, dev->firstline - 4, 0, (dev->lastline - dev->firstline) + 8, xsize, (dev->lastline - dev->firstline) + 8); - else - video_blit_memtoscreen_8(0, dev->firstline - 4, 0, (dev->lastline - dev->firstline) + 8, xsize, (dev->lastline - dev->firstline) + 8); + video_blit_memtoscreen(0, (dev->firstline - 4) << 1, 0, ((dev->lastline - dev->firstline) + 8) << 1, + xsize, ((dev->lastline - dev->firstline) + 8) << 1); + else + video_blit_memtoscreen_8(0, (dev->firstline - 4) << 1, 0, ((dev->lastline - dev->firstline) + 8) << 1, + xsize, ((dev->lastline - dev->firstline) + 8) << 1); frames++; video_res_x = xsize - 16; @@ -479,16 +575,15 @@ cga_poll(void *priv) video_res_x /= 8; video_res_y /= dev->crtc[9] + 1; video_bpp = 0; - } else if (!(dev->cgamode & 2)) { + } else if (! (dev->cgamode & 2)) { video_res_x /= 16; video_res_y /= dev->crtc[9] + 1; video_bpp = 0; - } else if (!(dev->cgamode & 16)) { + } else if (! (dev->cgamode & 16)) { video_res_x /= 2; video_bpp = 2; - } else { + } else video_bpp = 1; - } } dev->firstline = 1000; dev->lastline = 0; @@ -509,7 +604,7 @@ cga_poll(void *priv) if (dev->cgadispon && (dev->cgamode & 1)) { for (x = 0; x < (dev->crtc[1] << 1); x++) - dev->charbuffer[x] = dev->vram[(((dev->ma << 1) + x) & 0x3fff)]; + dev->charbuffer[x] = dev->vram[(((dev->ma << 1) + x) & 0x3fff)]; } } } @@ -525,8 +620,8 @@ cga_init(cga_t *dev) void * cga_standalone_init(const device_t *info) { - cga_t *dev; int display_type; + cga_t *dev; dev = (cga_t *)mem_alloc(sizeof(cga_t)); memset(dev, 0x00, sizeof(cga_t)); @@ -546,7 +641,7 @@ cga_standalone_init(const device_t *info) mem_map_add(&dev->mapping, 0xb8000, 0x08000, cga_read,NULL,NULL, cga_write,NULL,NULL, - NULL, MEM_MAPPING_EXTERNAL, dev); + dev->vram, MEM_MAPPING_EXTERNAL, dev); io_sethandler(0x03d0, 16, cga_in,NULL,NULL, cga_out,NULL,NULL, dev); @@ -657,7 +752,6 @@ const device_config_t cga_config[] = { } }; -static const video_timings_t cga_timings = { VID_ISA,8,16,32,8,16,32 }; const device_t cga_device = { "CGA", @@ -666,6 +760,6 @@ const device_t cga_device = { NULL, cga_speed_changed, NULL, - &cga_timings, + &cga_timing, cga_config }; diff --git a/src/devices/video/vid_cga_compaq.c b/src/devices/video/vid_cga_compaq.c index c500639..1854986 100644 --- a/src/devices/video/vid_cga_compaq.c +++ b/src/devices/video/vid_cga_compaq.c @@ -8,14 +8,14 @@ * * Implementation of CGA used by Compaq PC's. * - * Version: @(#)vid_cga_compaq.c 1.0.4 2018/09/22 + * Version: @(#)vid_cga_compaq.c 1.0.5 2019/02/10 * * Authors: Fred N. van Kempen, * Miran Grca, * TheCollector1995, * - * 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 @@ -387,7 +387,7 @@ compaq_cga_init(const device_t *info) mem_map_add(&dev->cga.mapping, 0xb8000, 0x08000, cga_read,NULL,NULL, cga_write,NULL,NULL, - NULL, MEM_MAPPING_EXTERNAL, dev); + dev->cga.vram, MEM_MAPPING_EXTERNAL, dev); io_sethandler(0x03d0, 16, cga_in,NULL,NULL, cga_out,NULL,NULL, dev); diff --git a/src/devices/video/vid_cl54xx.c b/src/devices/video/vid_cl54xx.c index 71cd7dc..2b01120 100644 --- a/src/devices/video/vid_cl54xx.c +++ b/src/devices/video/vid_cl54xx.c @@ -9,7 +9,7 @@ * Emulation of select Cirrus Logic cards (CL-GD 5428, * CL-GD 5429, 5430, 5434 and 5436 are supported). * - * Version: @(#)vid_cl54xx.c 1.0.24 2019/01/07 + * Version: @(#)vid_cl54xx.c 1.0.25 2019/02/10 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -17,8 +17,8 @@ * Barry Rodewald, * 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 2018 Barry Rodewald. * Copyright 2008-2018 Sarah Walker. * @@ -58,7 +58,6 @@ #include "vid_svga_render.h" - #define BIOS_GD5420_PATH L"video/cirruslogic/5420.vbi" #define BIOS_GD5422_PATH L"video/cirruslogic/cl5422.bin" #define BIOS_GD5426_PATH L"video/cirruslogic/diamond speedstar pro vlb v3.04.bin" @@ -75,7 +74,6 @@ #define BIOS_GD5480_PATH L"video/cirruslogic/gd5480.rom" - #define CIRRUS_ID_CLGD5402 0x89 #define CIRRUS_ID_CLGD5420 0x8a #define CIRRUS_ID_CLGD5422 0x8c @@ -91,7 +89,6 @@ #define CIRRUS_ID_CLGD5480 0xbc - /* sequencer 0x07 */ #define CIRRUS_SR7_BPP_VGA 0x00 #define CIRRUS_SR7_BPP_SVGA 0x01 @@ -106,18 +103,18 @@ /* sequencer 0x12 */ #define CIRRUS_CURSOR_SHOW 0x01 #define CIRRUS_CURSOR_HIDDENPEL 0x02 -#define CIRRUS_CURSOR_LARGE 0x04 /* 64x64 if set, 32x32 if clear */ +#define CIRRUS_CURSOR_LARGE 0x04 /* 64x64 if set, else 32x32 */ -// sequencer 0x17 -#define CIRRUS_BUSTYPE_VLBFAST 0x10 -#define CIRRUS_BUSTYPE_PCI 0x20 -#define CIRRUS_BUSTYPE_VLBSLOW 0x30 -#define CIRRUS_BUSTYPE_ISA 0x38 -#define CIRRUS_MMIO_ENABLE 0x04 -#define CIRRUS_MMIO_USE_PCIADDR 0x40 /* 0xb8000 if cleared. */ -#define CIRRUS_MEMSIZEEXT_DOUBLE 0x80 +/* sequencer 0x17 */ +#define CIRRUS_BUSTYPE_VLBFAST 0x10 +#define CIRRUS_BUSTYPE_PCI 0x20 +#define CIRRUS_BUSTYPE_VLBSLOW 0x30 +#define CIRRUS_BUSTYPE_ISA 0x38 +#define CIRRUS_MMIO_ENABLE 0x04 +#define CIRRUS_MMIO_USE_PCIADDR 0x40 /* 0xb8000 if cleared. */ +#define CIRRUS_MEMSIZEEXT_DOUBLE 0x80 -// control 0x0b +/* control 0x0b */ #define CIRRUS_BANKING_DUAL 0x01 #define CIRRUS_BANKING_GRANULARITY_16K 0x20 /* set:16k, clear:4k */ @@ -134,41 +131,43 @@ #define CIRRUS_BLTMODE_PIXELWIDTH24 0x20 #define CIRRUS_BLTMODE_PIXELWIDTH32 0x30 -// control 0x31 +/* control 0x31 */ #define CIRRUS_BLT_BUSY 0x01 #define CIRRUS_BLT_START 0x02 #define CIRRUS_BLT_RESET 0x04 #define CIRRUS_BLT_FIFOUSED 0x10 #define CIRRUS_BLT_AUTOSTART 0x80 -// control 0x33 +/* control 0x33 */ #define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 #define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02 #define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 -#define CL_GD5429_SYSTEM_BUS_VESA 5 -#define CL_GD5429_SYSTEM_BUS_ISA 7 +#define CL_GD5429_SYSTEM_BUS_VESA 5 +#define CL_GD5429_SYSTEM_BUS_ISA 7 -#define CL_GD543X_SYSTEM_BUS_PCI 4 -#define CL_GD543X_SYSTEM_BUS_VESA 6 -#define CL_GD543X_SYSTEM_BUS_ISA 7 +#define CL_GD543X_SYSTEM_BUS_PCI 4 +#define CL_GD543X_SYSTEM_BUS_VESA 6 +#define CL_GD543X_SYSTEM_BUS_ISA 7 -typedef struct gd54xx_t -{ - mem_map_t mmio_mapping; - mem_map_t linear_mapping; - svga_t svga; +typedef struct { + mem_map_t mmio_mapping; + mem_map_t linear_mapping; - int has_bios, rev; - rom_t bios_rom; + svga_t svga; - uint32_t vram_size; - uint32_t vram_mask; + int has_bios, + rev; - uint8_t vclk_n[4]; - uint8_t vclk_d[4]; - uint32_t bank[2]; + rom_t bios_rom; + + uint32_t vram_size; + uint32_t vram_mask; + + uint8_t vclk_n[4]; + uint8_t vclk_d[4]; + uint32_t bank[2]; struct { uint8_t state; @@ -201,8 +200,8 @@ typedef struct gd54xx_t uint8_t pci_regs[256]; uint8_t int_line; - uint8_t fc; /* Feature Connector */ - //FIXME: move to SVGA? --FvK + /* FIXME: move to SVGA? --FvK */ + uint8_t fc; /* Feature Connector */ uint8_t clgd_latch[8]; @@ -223,608 +222,109 @@ static void gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p); static uint8_t gd543x_mmio_read(uint32_t addr, void *p); static uint16_t gd543x_mmio_readw(uint32_t addr, void *p); static uint32_t gd543x_mmio_readl(uint32_t addr, void *p); -static void gd54xx_recalc_banking(gd54xx_t *gd54xx); -static void gd543x_recalc_mapping(gd54xx_t *gd54xx); static void gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga); + /* Returns 1 if the card is a 5422+ */ static int -gd54xx_is_5422(svga_t *svga) +is_5422(svga_t *svga) { - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) - return 1; - else - return 0; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) + return 1; + + return 0; } + /* Returns 1 if the card is a 5434, 5436/46, or 5480. */ static int -gd54xx_is_5434(svga_t *svga) +is_5434(svga_t *svga) { if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) return 1; - else - return 0; + + return 0; } static void -gd54xx_out(uint16_t addr, uint8_t val, void *p) +recalc_banking(gd54xx_t *dev) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; - uint8_t old; - int c; - uint8_t o, indx; - uint32_t o32; + svga_t *svga = &dev->svga; - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && - !(svga->miscout & 1)) addr ^= 0x60; + if (! is_5422(svga)) { + dev->bank[0] = (svga->gdcreg[0x09] & 0x7f) << 12; - switch (addr) { - case 0x3ba: - case 0x3da: - gd54xx->fc = val; //FIXME: move to SVGA? --FvK - break; - case 0x3c0: - case 0x3c1: - if (!svga->attrff) { - svga->attraddr = val & 0x3f; - if ((val & 0x20) != svga->attr_palette_enable) { - svga->fullchange = 3; - svga->attr_palette_enable = val & 0x20; - svga_recalctimings(svga); - } - } else { - o = svga->attrregs[svga->attraddr & 0x3f]; - if ((svga->attraddr < 0x20) || (svga->attraddr >= 0x30)) - svga->attrregs[svga->attraddr & 0x3f] = val; - if (svga->attraddr < 0x10) - svga->fullchange = changeframecount; - if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { - for (c = 0; c < 16; c++) { - if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); - else svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4); - } - } - /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ - if (svga->attraddr == 0x10) { - if (o != val) - svga_recalctimings(svga); - } else if (svga->attraddr == 0x11) { - if (!(svga->seqregs[0x12] & 0x80)) { - svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; - if (o != val) svga_recalctimings(svga); - } - } else if (svga->attraddr == 0x12) { - if ((val & 0xf) != svga->plane_mask) - svga->fullchange = changeframecount; - svga->plane_mask = val & 0xf; - } - } - svga->attrff ^= 1; - return; - case 0x3c4: - svga->seqaddr = val; - break; - case 0x3c5: - if (svga->seqaddr > 5) { - o = svga->seqregs[svga->seqaddr & 0x1f]; - svga->seqregs[svga->seqaddr & 0x1f] = val; - switch (svga->seqaddr) { - case 0x06: - val &= 0x17; - if (val == 0x12) - svga->seqregs[6] = 0x12; - else - svga->seqregs[6] = 0x0f; - break; - - - case 0x08: // Todo EEPROM - break; - - case 0x0a: - if (gd54xx_is_5434(svga)) - { - svga->seqregs[0x0a] = val; - } - else { /* Hack to force memory size on some GD-542x BIOSes*/ - val &= 0xe7; - switch (gd54xx->vram_size) { - case 0x80000: - svga->seqregs[0x0a] = val | 0x08; - break; - - case 0x100000: - svga->seqregs[0x0a] = val | 0x10; - break; - - case 0x200000: - svga->seqregs[0x0a] = val | 0x18; - break; - } - } - break; - case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */ - gd54xx->vclk_n[svga->seqaddr-0x0b] = val; - break; - case 0x1b: case 0x1c: case 0x1d: case 0x1e: /* VCLK stuff */ - gd54xx->vclk_d[svga->seqaddr-0x1b] = val; - break; - case 0x10: case 0x30: case 0x50: case 0x70: - case 0x90: case 0xb0: case 0xd0: case 0xf0: - svga->hwcursor.x = (val << 3) | (svga->seqaddr >> 5); - break; - case 0x11: case 0x31: case 0x51: case 0x71: - case 0x91: case 0xb1: case 0xd1: case 0xf1: - svga->hwcursor.y = (val << 3) | (svga->seqaddr >> 5); - break; - case 0x12: - svga->ext_overscan = !!(val & 0x80); - if (svga->ext_overscan) - svga->overscan_color = gd54xx->extpallook[2]; - else - svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; - svga_recalctimings(svga); - svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW; - svga->hwcursor.xsize = svga->hwcursor.ysize = (val & CIRRUS_CURSOR_LARGE) ? 64 : 32; - svga->hwcursor.yoff = (svga->hwcursor.ysize == 32) ? 32 : 0; - if (val & CIRRUS_CURSOR_LARGE) - svga->hwcursor.addr = (((svga->vram_display_mask + 1)-0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); - else - svga->hwcursor.addr = (((svga->vram_display_mask + 1)-0x4000) + ((svga->seqregs[0x13] & 0x3f) * 256)); - break; - case 0x13: - if (svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) - svga->hwcursor.addr = (((svga->vram_display_mask + 1)-0x4000) + ((val & 0x3c) * 256)); - else - svga->hwcursor.addr = (((svga->vram_display_mask + 1)-0x4000) + ((val & 0x3f) * 256)); - break; - case 0x15: - if (gd54xx_is_5434(svga)) { - /* Hack to force memory size on some GD-543x BIOSes*/ - val &= 0xf8; - switch (gd54xx->vram_size) { - case 0x100000: - svga->seqregs[0x15] = val | 0x2; - break; - - case 0x200000: - svga->seqregs[0x15] = val | 0x3; - break; - - case 0x400000: - svga->seqregs[0x15] = val | 0x4; - break; - } - } else - return; - break; - case 0x07: - if (!gd54xx_is_5422(svga)) { - svga->seqregs[svga->seqaddr] &= 0x0f; - gd543x_recalc_mapping(gd54xx); - } - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) - svga->set_reset_disabled = svga->seqregs[7] & 1; - case 0x17: - if (gd54xx_is_5422(svga)) - gd543x_recalc_mapping(gd54xx); - else - return; - break; - } - return; - } - break; - case 0x3C6: - if (gd54xx->ramdac.state == 4) { - gd54xx->ramdac.state = 0; - gd54xx->ramdac.ctrl = val; - svga_recalctimings(svga); - return; - } - gd54xx->ramdac.state = 0; - break; - case 0x3C9: - svga->dac_status = 0; - svga->fullchange = changeframecount; - switch (svga->dac_pos) { - case 0: - svga->dac_r = val; - svga->dac_pos++; - break; - case 1: - svga->dac_g = val; - svga->dac_pos++; - break; - case 2: - indx = svga->dac_addr & 0xff; - if (svga->seqregs[0x12] & 2) { - indx &= 0x0f; - gd54xx->extpal[indx].r = svga->dac_r; - gd54xx->extpal[indx].g = svga->dac_g; - gd54xx->extpal[indx].b = val; - gd54xx->extpallook[indx] = makecol32(video_6to8[gd54xx->extpal[indx].r & 0x3f], video_6to8[gd54xx->extpal[indx].g & 0x3f], video_6to8[gd54xx->extpal[indx].b & 0x3f]); - if (svga->ext_overscan && (indx == 2)) { - o32 = svga->overscan_color; - svga->overscan_color = gd54xx->extpallook[2]; - if (o32 != svga->overscan_color) - svga_recalctimings(svga); - } - } else { - svga->vgapal[indx].r = svga->dac_r; - svga->vgapal[indx].g = svga->dac_g; - svga->vgapal[indx].b = val; - svga->pallook[indx] = makecol32(video_6to8[svga->vgapal[indx].r & 0x3f], video_6to8[svga->vgapal[indx].g & 0x3f], video_6to8[svga->vgapal[indx].b & 0x3f]); - } - svga->dac_addr = (svga->dac_addr + 1) & 255; - svga->dac_pos = 0; - break; - } - return; - case 0x3cf: - if (svga->gdcaddr == 0) - gd543x_mmio_write(0xb8000, val, gd54xx); - if (svga->gdcaddr == 1) - gd543x_mmio_write(0xb8004, val, gd54xx); - - if (svga->gdcaddr == 5) { - svga->gdcreg[5] = val; - if (svga->gdcreg[0xb] & 0x04) - svga->writemode = svga->gdcreg[5] & 7; - else - svga->writemode = svga->gdcreg[5] & 3; - svga->readmode = val & 8; - svga->chain2_read = val & 0x10; - return; - } - - if (svga->gdcaddr == 6) { - if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { - svga->gdcreg[6] = val; - gd543x_recalc_mapping(gd54xx); - } - svga->gdcreg[6] = val; - return; - } - - if (svga->gdcaddr > 8) { - svga->gdcreg[svga->gdcaddr & 0x3f] = val; - switch (svga->gdcaddr) { - case 0x09: case 0x0a: case 0x0b: - gd54xx_recalc_banking(gd54xx); - if (svga->gdcreg[0xb] & 0x04) - svga->writemode = svga->gdcreg[5] & 7; - else - svga->writemode = svga->gdcreg[5] & 3; - break; - - case 0x10: - gd543x_mmio_write(0xb8001, val, gd54xx); - break; - case 0x11: - gd543x_mmio_write(0xb8005, val, gd54xx); - break; - case 0x12: - gd543x_mmio_write(0xb8002, val, gd54xx); - break; - case 0x13: - gd543x_mmio_write(0xb8006, val, gd54xx); - break; - case 0x14: - gd543x_mmio_write(0xb8003, val, gd54xx); - break; - case 0x15: - gd543x_mmio_write(0xb8007, val, gd54xx); - break; - - case 0x20: - gd543x_mmio_write(0xb8008, val, gd54xx); - break; - case 0x21: - gd543x_mmio_write(0xb8009, val, gd54xx); - break; - case 0x22: - gd543x_mmio_write(0xb800a, val, gd54xx); - break; - case 0x23: - gd543x_mmio_write(0xb800b, val, gd54xx); - break; - case 0x24: - gd543x_mmio_write(0xb800c, val, gd54xx); - break; - case 0x25: - gd543x_mmio_write(0xb800d, val, gd54xx); - break; - case 0x26: - gd543x_mmio_write(0xb800e, val, gd54xx); - break; - case 0x27: - gd543x_mmio_write(0xb800f, val, gd54xx); - break; - - case 0x28: - gd543x_mmio_write(0xb8010, val, gd54xx); - break; - case 0x29: - gd543x_mmio_write(0xb8011, val, gd54xx); - break; - case 0x2a: - gd543x_mmio_write(0xb8012, val, gd54xx); - break; - - case 0x2c: - gd543x_mmio_write(0xb8014, val, gd54xx); - break; - case 0x2d: - gd543x_mmio_write(0xb8015, val, gd54xx); - break; - case 0x2e: - gd543x_mmio_write(0xb8016, val, gd54xx); - break; - - case 0x2f: - gd543x_mmio_write(0xb8017, val, gd54xx); - break; - case 0x30: - gd543x_mmio_write(0xb8018, val, gd54xx); - break; - - case 0x32: - gd543x_mmio_write(0xb801a, val, gd54xx); - break; - - case 0x33: - gd543x_mmio_write(0xb801b, val, gd54xx); - break; - - case 0x31: - gd543x_mmio_write(0xb8040, val, gd54xx); - break; - - case 0x34: - gd543x_mmio_write(0xb801c, val, gd54xx); - break; - - case 0x35: - gd543x_mmio_write(0xb801d, val, gd54xx); - break; - - case 0x38: - gd543x_mmio_write(0xb8020, val, gd54xx); - break; - - case 0x39: - gd543x_mmio_write(0xb8021, val, gd54xx); - break; - } - return; - } - break; - case 0x3D4: - svga->crtcreg = val & 0x3f; - return; - case 0x3D5: - if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) - return; - if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) - val = (svga->crtc[7] & ~0x10) | (val & 0x10); - if ((svga->crtcreg == 0x25) || (svga->crtcreg == 0x27)) - return; - old = svga->crtc[svga->crtcreg]; - svga->crtc[svga->crtcreg] = val; - - if (old != val) { - if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { - svga->fullchange = changeframecount; - svga_recalctimings(svga); - } - } - break; - } - svga_out(addr, val, svga); -} - - -static uint8_t -gd54xx_in(uint16_t addr, void *p) -{ - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; - uint8_t indx, temp; - - if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3d0) && - !(svga->miscout & 1)) addr ^= 0x60; - - switch (addr) { - case 0x3c4: - if ((svga->seqregs[6] & 0x17) == 0x12) { - temp = svga->seqaddr; - if ((temp & 0x1e) == 0x10) { - if (temp & 1) - temp = ((svga->hwcursor.y & 7) << 5) | 0x11; - else - temp = ((svga->hwcursor.x & 7) << 5) | 0x10; - } - return temp; - } - return svga->seqaddr; - - case 0x3c5: - if (svga->seqaddr > 5) { - switch (svga->seqaddr) { - case 6: - return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f; - case 0x0b: case 0x0c: case 0x0d: case 0x0e: - return gd54xx->vclk_n[svga->seqaddr-0x0b]; - case 0x17: - temp = svga->gdcreg[0x17] & ~(7 << 3); - if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) { - if (gd54xx->vlb) - temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3); - else - temp |= (CL_GD5429_SYSTEM_BUS_ISA << 3); - } else { - if (gd54xx->pci) - temp |= (CL_GD543X_SYSTEM_BUS_PCI << 3); - else if (gd54xx->vlb) - temp |= (CL_GD543X_SYSTEM_BUS_VESA << 3); - else - temp |= (CL_GD543X_SYSTEM_BUS_ISA << 3); - } - return temp; - case 0x1b: case 0x1c: case 0x1d: case 0x1e: - return gd54xx->vclk_d[svga->seqaddr-0x1b]; - } - return svga->seqregs[svga->seqaddr & 0x3f]; - } - break; - - case 0x3c6: - if (gd54xx->ramdac.state == 4) { - gd54xx->ramdac.state = 0; - return gd54xx->ramdac.ctrl; - } - gd54xx->ramdac.state++; - break; - - case 0x3ca: - return gd54xx->fc; //FIXME: move to SVGA? --FvK - - case 0x3c9: - svga->dac_status = 3; - indx = (svga->dac_addr - 1) & 0xff; - if (svga->seqregs[0x12] & 2) - indx &= 0x0f; - switch (svga->dac_pos) { - case 0: - svga->dac_pos++; - if (svga->seqregs[0x12] & 2) - return gd54xx->extpal[indx].r & 0x3f; - else - return svga->vgapal[indx].r & 0x3f; - case 1: - svga->dac_pos++; - if (svga->seqregs[0x12] & 2) - return gd54xx->extpal[indx].g & 0x3f; - else - return svga->vgapal[indx].g & 0x3f; - case 2: - svga->dac_pos = 0; - svga->dac_addr = (svga->dac_addr + 1) & 255; - if (svga->seqregs[0x12] & 2) - return gd54xx->extpal[indx].b & 0x3f; - else - return svga->vgapal[indx].b & 0x3f; - } - return 0xFF; - - case 0x3cf: - if (svga->gdcaddr > 8) { - return svga->gdcreg[svga->gdcaddr & 0x3f]; - } - break; - - case 0x3d4: - return svga->crtcreg; - - case 0x3d5: - switch (svga->crtcreg) { - case 0x24: /*Attribute controller toggle readback (R)*/ - return svga->attrff << 7; - case 0x26: /*Attribute controller index readback (R)*/ - return svga->attraddr & 0x3f; - case 0x27: /*ID*/ - return svga->crtc[0x27]; /*GD542x/GD543x*/ - case 0x28: /*Class ID*/ - if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5430) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5440)) - return 0xff; /*Standard CL-GD5430/40*/ - break; - } - return svga->crtc[svga->crtcreg]; - } - return svga_in(addr, svga); -} - - -static void -gd54xx_recalc_banking(gd54xx_t *gd54xx) -{ - svga_t *svga = &gd54xx->svga; - - if (!gd54xx_is_5422(svga)) { - gd54xx->bank[0] = (svga->gdcreg[0x09] & 0x7f) << 12; - - if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL) - gd54xx->bank[1] = (svga->gdcreg[0x0a] & 0x7f) << 12; - else - gd54xx->bank[1] = gd54xx->bank[0] + 0x8000; - } - else { - if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) - gd54xx->bank[0] = svga->gdcreg[0x09] << 14; - else - gd54xx->bank[0] = svga->gdcreg[0x09] << 12; - - if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL) { - if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) - gd54xx->bank[1] = svga->gdcreg[0x0a] << 14; + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL) + dev->bank[1] = (svga->gdcreg[0x0a] & 0x7f) << 12; else - gd54xx->bank[1] = svga->gdcreg[0x0a] << 12; - } - else + dev->bank[1] = dev->bank[0] + 0x8000; + } else { + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) + dev->bank[0] = svga->gdcreg[0x09] << 14; + else + dev->bank[0] = svga->gdcreg[0x09] << 12; - gd54xx->bank[1] = gd54xx->bank[0] + 0x8000; - } + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL) { + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) + dev->bank[1] = svga->gdcreg[0x0a] << 14; + else + dev->bank[1] = svga->gdcreg[0x0a] << 12; + } else + dev->bank[1] = dev->bank[0] + 0x8000; + } } static void -gd543x_recalc_mapping(gd54xx_t *gd54xx) +recalc_mapping(gd54xx_t *dev) { - svga_t *svga = &gd54xx->svga; + svga_t *svga = &dev->svga; + uint32_t base, size; - if (!(gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { + if (! (dev->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { mem_map_disable(&svga->mapping); - mem_map_disable(&gd54xx->linear_mapping); - mem_map_disable(&gd54xx->mmio_mapping); + mem_map_disable(&dev->linear_mapping); + mem_map_disable(&dev->mmio_mapping); return; } - - gd54xx->mmio_vram_overlap = 0; - if (!(svga->seqregs[7] & 0xf0)) { - mem_map_disable(&gd54xx->linear_mapping); + dev->mmio_vram_overlap = 0; + + if (! (svga->seqregs[7] & 0xf0)) { + mem_map_disable(&dev->linear_mapping); + switch (svga->gdcreg[6] & 0x0c) { - case 0x0: /*128k at A0000*/ + case 0x00: /*128K at A0000*/ mem_map_set_addr(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0x1ffff; break; - case 0x4: /*64k at A0000*/ + + case 0x04: /*64K at A0000*/ mem_map_set_addr(&svga->mapping, 0xa0000, 0x10000); svga->banked_mask = 0xffff; break; - case 0x8: /*32k at B0000*/ + + case 0x08: /*32K at B0000*/ mem_map_set_addr(&svga->mapping, 0xb0000, 0x08000); svga->banked_mask = 0x7fff; break; - case 0xC: /*32k at B8000*/ + + case 0x0c: /*32K at B8000*/ mem_map_set_addr(&svga->mapping, 0xb8000, 0x08000); svga->banked_mask = 0x7fff; - gd54xx->mmio_vram_overlap = 1; + dev->mmio_vram_overlap = 1; break; } - if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) - mem_map_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); - else - mem_map_disable(&gd54xx->mmio_mapping); - } else { - uint32_t base, size; - if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429 || (!gd54xx->pci && !gd54xx->vlb)) { + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) + mem_map_set_addr(&dev->mmio_mapping, 0xb8000, 0x00100); + else + mem_map_disable(&dev->mmio_mapping); + } else { + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429 || + (!dev->pci && !dev->vlb)) { if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) { base = (svga->seqregs[7] & 0xf0) << 16; size = 1 * 1024 * 1024; @@ -832,14 +332,15 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) base = (svga->seqregs[7] & 0xe0) << 16; size = 2 * 1024 * 1024; } - } else if (gd54xx->pci) { - base = gd54xx->lfb_base; + } else if (dev->pci) { + base = dev->lfb_base; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) size = 16 * 1024 * 1024; else size = 4 * 1024 * 1024; } else { /*VLB*/ - base = 128*1024*1024; + base = 128 * 1024 * 1024; if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) size = 16 * 1024 * 1024; else @@ -847,27 +348,28 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) } mem_map_disable(&svga->mapping); - mem_map_set_addr(&gd54xx->linear_mapping, base, size); + mem_map_set_addr(&dev->linear_mapping, base, size); + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) { if (size >= (4 * 1024 * 1024)) - mem_map_disable(&gd54xx->mmio_mapping); /* MMIO is handled in the linear read/write functions */ + mem_map_disable(&dev->mmio_mapping); /* MMIO is handled in the linear read/write functions */ else { - mem_map_set_addr(&gd54xx->linear_mapping, base, size - 256); - mem_map_set_addr(&gd54xx->mmio_mapping, base + size - 256, 0x00100); + mem_map_set_addr(&dev->linear_mapping, base, size - 256); + mem_map_set_addr(&dev->mmio_mapping, base + size - 256, 0x00100); } } else - mem_map_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + mem_map_set_addr(&dev->mmio_mapping, 0xb8000, 0x00100); } else - mem_map_disable(&gd54xx->mmio_mapping); + mem_map_disable(&dev->mmio_mapping); } } static void -gd54xx_recalctimings(svga_t *svga) +recalc_timings(svga_t *svga) { - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *dev = (gd54xx_t *)svga->p; uint8_t clocksel; svga->rowoffset = (svga->crtc[0x13]) | ((svga->crtc[0x1b] & 0x10) << 4); @@ -883,11 +385,11 @@ gd54xx_recalctimings(svga_t *svga) svga->bpp = 8; - if (gd54xx->ramdac.ctrl & 0x80) { /* Extended Color Mode enabled */ - if (gd54xx->ramdac.ctrl & 0x40) { /* Enable all Extended modes */ - switch (gd54xx->ramdac.ctrl & 0xf) { + if (dev->ramdac.ctrl & 0x80) { /* Extended Color Mode enabled */ + if (dev->ramdac.ctrl & 0x40) { /* Enable all Extended modes */ + switch (dev->ramdac.ctrl & 0xf) { case 0: - if (gd54xx->ramdac.ctrl & 0x10) { /* Mixed Mode */ + if (dev->ramdac.ctrl & 0x10) { /* Mixed Mode */ svga->render = svga_render_mixed_highres; } else { svga->bpp = 15; @@ -901,7 +403,7 @@ gd54xx_recalctimings(svga_t *svga) break; case 5: - if (gd54xx_is_5434(svga) && (svga->seqregs[7] & CIRRUS_SR7_BPP_32)) { + if (is_5434(svga) && (svga->seqregs[7] & CIRRUS_SR7_BPP_32)) { svga->bpp = 32; svga->render = svga_render_32bpp_highres; if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) @@ -955,46 +457,591 @@ gd54xx_recalctimings(svga_t *svga) clocksel = (svga->miscout >> 2) & 3; - if (!gd54xx->vclk_n[clocksel] || !gd54xx->vclk_d[clocksel]) + if (!dev->vclk_n[clocksel] || !dev->vclk_d[clocksel]) svga->clock = cpuclock / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); else { - int n = gd54xx->vclk_n[clocksel] & 0x7f; - int d = (gd54xx->vclk_d[clocksel] & 0x3e) >> 1; - int m = gd54xx->vclk_d[clocksel] & 0x01 ? 2 : 1; + int n = dev->vclk_n[clocksel] & 0x7f; + int d = (dev->vclk_d[clocksel] & 0x3e) >> 1; + int m = dev->vclk_d[clocksel] & 0x01 ? 2 : 1; float freq = ((float)14318184.0 * ((float)n / ((float)d * m))); - if (gd54xx_is_5422(svga)) { - switch (svga->seqregs[7] & (gd54xx_is_5434(svga) ? 0xe : 6)) { - case 2: - freq /= 2.0; - break; - case 4: - if (!gd54xx_is_5434(svga)) - freq /= 3.0; - break; - } + if (is_5422(svga)) { + switch (svga->seqregs[7] & (is_5434(svga) ? 0xe : 6)) { + case 2: + freq /= 2.0; + break; + + case 4: + if (! is_5434(svga)) + freq /= 3.0; + break; + } } + svga->clock = cpuclock / freq; } - if (gd54xx->vram_size == (1 << 19)) /* Note : why 512Kb VRAM cards does not wrap */ - svga->vram_display_mask = gd54xx->vram_mask; - else - svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; - - + if (dev->vram_size == (1 << 19)) /* Note : why 512KB VRAM cards does not wrap */ + svga->vram_display_mask = dev->vram_mask; + else + svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? dev->vram_mask : 0x3ffff; } -static -void gd54xx_hwcursor_draw(svga_t *svga, int displine) + +static void +gd54xx_out(uint16_t addr, uint8_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; + uint8_t o, indx, old; + uint32_t o32; + int c; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && + !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x03ba: + case 0x03da: + dev->fc = val; //FIXME: move to SVGA? --FvK + break; + + case 0x03c0: + case 0x03c1: + if (! svga->attrff) { + svga->attraddr = val & 0x3f; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + o = svga->attrregs[svga->attraddr & 0x3f]; + if ((svga->attraddr < 0x20) || (svga->attraddr >= 0x30)) + svga->attrregs[svga->attraddr & 0x3f] = val; + if (svga->attraddr < 0x10) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); + else svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4); + } + } + + /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ + if (svga->attraddr == 0x10) { + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + if (! (svga->seqregs[0x12] & 0x80)) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (o != val) svga_recalctimings(svga); + } + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + return; + + case 0x03c4: + svga->seqaddr = val; + break; + + case 0x03c5: + if (svga->seqaddr > 5) { + o = svga->seqregs[svga->seqaddr & 0x1f]; + svga->seqregs[svga->seqaddr & 0x1f] = val; + switch (svga->seqaddr) { + case 0x06: + val &= 0x17; + if (val == 0x12) + svga->seqregs[6] = 0x12; + else + svga->seqregs[6] = 0x0f; + break; + + case 0x08: // Todo EEPROM + break; + + case 0x0a: + if (is_5434(svga)) { + svga->seqregs[0x0a] = val; + } else { + /* Hack to force memory size on some GD-542x BIOSes*/ + val &= 0xe7; + switch (dev->vram_size) { + case 0x080000: + svga->seqregs[0x0a] = val | 0x08; + break; + + case 0x100000: + svga->seqregs[0x0a] = val | 0x10; + break; + + case 0x200000: + svga->seqregs[0x0a] = val | 0x18; + break; + } + } + break; + + case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */ + dev->vclk_n[svga->seqaddr - 0x0b] = val; + break; + + case 0x1b: case 0x1c: case 0x1d: case 0x1e: /* VCLK stuff */ + dev->vclk_d[svga->seqaddr-0x1b] = val; + break; + + case 0x10: case 0x30: case 0x50: case 0x70: + case 0x90: case 0xb0: case 0xd0: case 0xf0: + svga->hwcursor.x = (val << 3) | (svga->seqaddr >> 5); + break; + + case 0x11: case 0x31: case 0x51: case 0x71: + case 0x91: case 0xb1: case 0xd1: case 0xf1: + svga->hwcursor.y = (val << 3) | (svga->seqaddr >> 5); + break; + + case 0x12: + svga->ext_overscan = !!(val & 0x80); + if (svga->ext_overscan) + svga->overscan_color = dev->extpallook[2]; + else + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + svga_recalctimings(svga); + svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW; + svga->hwcursor.xsize = svga->hwcursor.ysize = (val & CIRRUS_CURSOR_LARGE) ? 64 : 32; + svga->hwcursor.yoff = (svga->hwcursor.ysize == 32) ? 32 : 0; + if (val & CIRRUS_CURSOR_LARGE) + svga->hwcursor.addr = (((svga->vram_display_mask + 1) - 0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); + else + svga->hwcursor.addr = (((svga->vram_display_mask + 1) - 0x4000) + ((svga->seqregs[0x13] & 0x3f) * 256)); + break; + + case 0x13: + if (svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) + svga->hwcursor.addr = (((svga->vram_display_mask + 1) - 0x4000) + ((val & 0x3c) * 256)); + else + svga->hwcursor.addr = (((svga->vram_display_mask + 1) - 0x4000) + ((val & 0x3f) * 256)); + break; + + case 0x15: + if (is_5434(svga)) { + /* Hack to force memory size on some GD-543x BIOSes*/ + val &= 0xf8; + switch (dev->vram_size) { + case 0x100000: + svga->seqregs[0x15] = val | 0x2; + break; + + case 0x200000: + svga->seqregs[0x15] = val | 0x3; + break; + + case 0x400000: + svga->seqregs[0x15] = val | 0x4; + break; + } + } else + return; + break; + + case 0x07: + if (! is_5422(svga)) { + svga->seqregs[svga->seqaddr] &= 0x0f; + recalc_mapping(dev); + } + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) + svga->set_reset_disabled = svga->seqregs[7] & 1; + break; + + case 0x17: + if (is_5422(svga)) + recalc_mapping(dev); + else + return; + break; + } + return; + } + break; + + case 0x03c6: + if (dev->ramdac.state == 4) { + dev->ramdac.state = 0; + dev->ramdac.ctrl = val; + svga_recalctimings(svga); + return; + } + dev->ramdac.state = 0; + break; + + case 0x03c9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + + case 2: + indx = svga->dac_addr & 0xff; + if (svga->seqregs[0x12] & 2) { + indx &= 0x0f; + dev->extpal[indx].r = svga->dac_r; + dev->extpal[indx].g = svga->dac_g; + dev->extpal[indx].b = val; + dev->extpallook[indx] = makecol32(video_6to8[dev->extpal[indx].r & 0x3f], video_6to8[dev->extpal[indx].g & 0x3f], video_6to8[dev->extpal[indx].b & 0x3f]); + if (svga->ext_overscan && (indx == 2)) { + o32 = svga->overscan_color; + svga->overscan_color = dev->extpallook[2]; + if (o32 != svga->overscan_color) + svga_recalctimings(svga); + } + } else { + svga->vgapal[indx].r = svga->dac_r; + svga->vgapal[indx].g = svga->dac_g; + svga->vgapal[indx].b = val; + svga->pallook[indx] = makecol32(video_6to8[svga->vgapal[indx].r & 0x3f], video_6to8[svga->vgapal[indx].g & 0x3f], video_6to8[svga->vgapal[indx].b & 0x3f]); + } + svga->dac_addr = (svga->dac_addr + 1) & 255; + svga->dac_pos = 0; + break; + } + return; + + case 0x03cf: + if (svga->gdcaddr == 0) + gd543x_mmio_write(0xb8000, val, dev); + if (svga->gdcaddr == 1) + gd543x_mmio_write(0xb8004, val, dev); + + if (svga->gdcaddr == 5) { + svga->gdcreg[5] = val; + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + return; + } + + if (svga->gdcaddr == 6) { + if ((svga->gdcreg[6] & 0x0c) != (val & 0x0c)) { + svga->gdcreg[6] = val; + recalc_mapping(dev); + } + svga->gdcreg[6] = val; + return; + } + + if (svga->gdcaddr > 8) { + svga->gdcreg[svga->gdcaddr & 0x3f] = val; + switch (svga->gdcaddr) { + case 0x09: case 0x0a: case 0x0b: + recalc_banking(dev); + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + break; + + case 0x10: + gd543x_mmio_write(0xb8001, val, dev); + break; + + case 0x11: + gd543x_mmio_write(0xb8005, val, dev); + break; + + case 0x12: + gd543x_mmio_write(0xb8002, val, dev); + break; + + case 0x13: + gd543x_mmio_write(0xb8006, val, dev); + break; + + case 0x14: + gd543x_mmio_write(0xb8003, val, dev); + break; + + case 0x15: + gd543x_mmio_write(0xb8007, val, dev); + break; + + case 0x20: + gd543x_mmio_write(0xb8008, val, dev); + break; + + case 0x21: + gd543x_mmio_write(0xb8009, val, dev); + break; + + case 0x22: + gd543x_mmio_write(0xb800a, val, dev); + break; + + case 0x23: + gd543x_mmio_write(0xb800b, val, dev); + break; + + case 0x24: + gd543x_mmio_write(0xb800c, val, dev); + break; + + case 0x25: + gd543x_mmio_write(0xb800d, val, dev); + break; + + case 0x26: + gd543x_mmio_write(0xb800e, val, dev); + break; + + case 0x27: + gd543x_mmio_write(0xb800f, val, dev); + break; + + case 0x28: + gd543x_mmio_write(0xb8010, val, dev); + break; + + case 0x29: + gd543x_mmio_write(0xb8011, val, dev); + break; + + case 0x2a: + gd543x_mmio_write(0xb8012, val, dev); + break; + + case 0x2c: + gd543x_mmio_write(0xb8014, val, dev); + break; + + case 0x2d: + gd543x_mmio_write(0xb8015, val, dev); + break; + + case 0x2e: + gd543x_mmio_write(0xb8016, val, dev); + break; + + case 0x2f: + gd543x_mmio_write(0xb8017, val, dev); + break; + + case 0x30: + gd543x_mmio_write(0xb8018, val, dev); + break; + + case 0x32: + gd543x_mmio_write(0xb801a, val, dev); + break; + + case 0x33: + gd543x_mmio_write(0xb801b, val, dev); + break; + + case 0x31: + gd543x_mmio_write(0xb8040, val, dev); + break; + + case 0x34: + gd543x_mmio_write(0xb801c, val, dev); + break; + + case 0x35: + gd543x_mmio_write(0xb801d, val, dev); + break; + + case 0x38: + gd543x_mmio_write(0xb8020, val, dev); + break; + + case 0x39: + gd543x_mmio_write(0xb8021, val, dev); + break; + } + return; + } + break; + + case 0x03d4: + svga->crtcreg = val & 0x3f; + return; + + case 0x03d5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if ((svga->crtcreg == 0x25) || (svga->crtcreg == 0x27)) + return; + + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + + svga_out(addr, val, svga); +} + + +static uint8_t +gd54xx_in(uint16_t addr, void *priv) +{ + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; + uint8_t indx, temp; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3d0) && + !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x03c4: + if ((svga->seqregs[6] & 0x17) == 0x12) { + temp = svga->seqaddr; + if ((temp & 0x1e) == 0x10) { + if (temp & 1) + temp = ((svga->hwcursor.y & 7) << 5) | 0x11; + else + temp = ((svga->hwcursor.x & 7) << 5) | 0x10; + } + return temp; + } + return svga->seqaddr; + + case 0x03c5: + if (svga->seqaddr > 5) { + switch (svga->seqaddr) { + case 0x06: + return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f; + + case 0x0b: case 0x0c: case 0x0d: case 0x0e: + return dev->vclk_n[svga->seqaddr-0x0b]; + + case 0x17: + temp = svga->gdcreg[0x17] & ~(7 << 3); + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) { + if (dev->vlb) + temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD5429_SYSTEM_BUS_ISA << 3); + } else { + if (dev->pci) + temp |= (CL_GD543X_SYSTEM_BUS_PCI << 3); + else if (dev->vlb) + temp |= (CL_GD543X_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD543X_SYSTEM_BUS_ISA << 3); + } + return temp; + + case 0x1b: case 0x1c: case 0x1d: case 0x1e: + return dev->vclk_d[svga->seqaddr-0x1b]; + } + return svga->seqregs[svga->seqaddr & 0x3f]; + } + break; + + case 0x03c6: + if (dev->ramdac.state == 4) { + dev->ramdac.state = 0; + return dev->ramdac.ctrl; + } + dev->ramdac.state++; + break; + + case 0x03ca: + return dev->fc; //FIXME: move to SVGA? --FvK + + case 0x03c9: + svga->dac_status = 3; + indx = (svga->dac_addr - 1) & 0xff; + if (svga->seqregs[0x12] & 2) + indx &= 0x0f; + + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return dev->extpal[indx].r & 0x3f; + return svga->vgapal[indx].r & 0x3f; + + case 1: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return dev->extpal[indx].g & 0x3f; + return svga->vgapal[indx].g & 0x3f; + + case 2: + svga->dac_pos = 0; + svga->dac_addr = (svga->dac_addr + 1) & 255; + if (svga->seqregs[0x12] & 2) + return dev->extpal[indx].b & 0x3f; + return svga->vgapal[indx].b & 0x3f; + } + return 0xff; + + case 0x03cf: + if (svga->gdcaddr > 8) + return svga->gdcreg[svga->gdcaddr & 0x3f]; + break; + + case 0x03d4: + return svga->crtcreg; + + case 0x03d5: + switch (svga->crtcreg) { + case 0x24: /*Attribute controller toggle readback (R)*/ + return svga->attrff << 7; + + case 0x26: /*Attribute controller index readback (R)*/ + return svga->attraddr & 0x3f; + + case 0x27: /*ID*/ + return svga->crtc[0x27]; /*GD542x/GD543x*/ + + case 0x28: /*Class ID*/ + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5430) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5440)) + return 0xff; /*Standard CL-GD5430/40*/ + break; + } + return svga->crtc[svga->crtcreg]; + } + + return svga_in(addr, svga); +} + + +static void +hwcursor_draw(svga_t *svga, int displine) +{ + gd54xx_t *dev = (gd54xx_t *)svga->p; int x, xx, comb, b0, b1; uint8_t dat[2]; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; int y_add, x_add; int pitch = (svga->hwcursor.xsize == 64) ? 16 : 4; - uint32_t bgcol = gd54xx->extpallook[0x00]; - uint32_t fgcol = gd54xx->extpallook[0x0f]; + uint32_t bgcol = dev->extpallook[0x00]; + uint32_t fgcol = dev->extpallook[0x0f]; y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; @@ -1045,118 +1092,131 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) svga->hwcursor_latch.addr += pitch; } + static void -gd54xx_memsrc_rop(gd54xx_t *gd54xx, svga_t *svga, uint8_t src, uint8_t dst) +gd54xx_rop(gd54xx_t *dev, uint8_t *res, uint8_t *dst, const uint8_t *src) { - uint8_t res = src; - svga->changedvram[(gd54xx->blt.dst_addr_backup & svga->vram_mask) >> 12] = changeframecount; - - switch (gd54xx->blt.rop) { - case 0x00: res = 0; break; - case 0x05: res = src & dst; break; - case 0x06: res = dst; break; - case 0x09: res = src & ~dst; break; - case 0x0b: res = ~ dst; break; - case 0x0d: res = src; break; - case 0x0e: res = 0xff; break; - case 0x50: res = ~ src & dst; break; - case 0x59: res = src ^ dst; break; - case 0x6d: res = src | dst; break; - case 0x90: res = ~(src | dst); break; - case 0x95: res = ~(src ^ dst); break; - case 0xad: res = src | ~dst; break; - case 0xd0: res = ~src; break; - case 0xd6: res = ~src | dst; break; - case 0xda: res = ~(src & dst); break; + switch (dev->blt.rop) { + case 0x00: *res = 0x00; break; + case 0x05: *res = *src & *dst; break; + case 0x06: *res = *dst; break; + case 0x09: *res = *src & ~*dst; break; + case 0x0b: *res = ~*dst; break; + case 0x0d: *res = *src; break; + case 0x0e: *res = 0xff; break; + case 0x50: *res = ~*src & *dst; break; + case 0x59: *res = *src ^ *dst; break; + case 0x6d: *res = *src | *dst; break; + case 0x90: *res = ~(*src | *dst); break; + case 0x95: *res = ~(*src ^ *dst); break; + case 0xad: *res = *src | ~*dst; break; + case 0xd0: *res = ~*src; break; + case 0xd6: *res = ~*src | *dst; break; + case 0xda: *res = ~(*src & *dst); break; } - - /* handle transparency compare */ - if(gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { /* TODO: 16-bit compare */ - /* if ROP result matches the transparency colour, don't change the pixel */ - if((res & (~gd54xx->blt.trans_mask & 0xff)) == ((gd54xx->blt.trans_col & 0xff) & (~gd54xx->blt.trans_mask & 0xff))) - return; - } - - svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask] = res; } -/* non colour-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored */ +static void +memsrc_rop(gd54xx_t *dev, svga_t *svga, uint8_t src, uint8_t dst) +{ + uint8_t res = src; + + svga->changedvram[(dev->blt.dst_addr_backup & svga->vram_mask) >> 12] = changeframecount; + + gd54xx_rop(dev, &res, &dst, (const uint8_t *) &src); + + /* Handle transparency compare. */ + if (dev->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { + /* TODO: 16-bit compare */ + /* if ROP result matches the transparency color, don't change the pixel */ + if ((res & (~dev->blt.trans_mask & 0xff)) == ((dev->blt.trans_col & 0xff) & (~dev->blt.trans_mask & 0xff))) + return; + } + + svga->vram[dev->blt.dst_addr_backup & svga->vram_mask] = res; +} + + +/* non color-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored */ static void -gd54xx_blit_dword(gd54xx_t *gd54xx, svga_t *svga) +blit_dword(gd54xx_t *dev, svga_t *svga) { /* TODO: add support for reverse direction */ uint8_t x, pixel; - for (x=0;x<32;x+=8) { - pixel = ((gd54xx->blt.sys_buf & (0xff << x)) >> x); - if(gd54xx->blt.pixel_cnt <= gd54xx->blt.width) - gd54xx_memsrc_rop(gd54xx, svga, pixel, svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask]); - gd54xx->blt.dst_addr_backup++; - gd54xx->blt.pixel_cnt++; + for (x = 0; x < 32; x += 8) { + pixel = ((dev->blt.sys_buf & (0xff << x)) >> x); + if (dev->blt.pixel_cnt <= dev->blt.width) + memsrc_rop(dev, svga, pixel, + svga->vram[dev->blt.dst_addr_backup & svga->vram_mask]); + dev->blt.dst_addr_backup++; + dev->blt.pixel_cnt++; } - if (gd54xx->blt.pixel_cnt > gd54xx->blt.width) { - gd54xx->blt.pixel_cnt = 0; - gd54xx->blt.scan_cnt++; - gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch*gd54xx->blt.scan_cnt); + + if (dev->blt.pixel_cnt > dev->blt.width) { + dev->blt.pixel_cnt = 0; + dev->blt.scan_cnt++; + dev->blt.dst_addr_backup = dev->blt.dst_addr + (dev->blt.dst_pitch*dev->blt.scan_cnt); } - if (gd54xx->blt.scan_cnt > gd54xx->blt.height) { - gd54xx->blt.sys_tx = 0; /* BitBLT complete */ - gd543x_recalc_mapping(gd54xx); + + if (dev->blt.scan_cnt > dev->blt.height) { + dev->blt.sys_tx = 0; /* BitBLT complete */ + recalc_mapping(dev); } } static void -gd54xx_blt_write_w(uint32_t addr, uint16_t val, void *p) +blit_write_w(uint32_t addr, uint16_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; + gd54xx_t *dev = (gd54xx_t *)priv; - gd54xx_start_blit(val, 16, gd54xx, &gd54xx->svga); + gd54xx_start_blit(val, 16, dev, &dev->svga); } static void -gd54xx_blt_write_l(uint32_t addr, uint32_t val, void *p) +blit_write_l(uint32_t addr, uint32_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; + gd54xx_t *dev = (gd54xx_t *)priv; - if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) { - gd54xx_start_blit(val & 0xff, 8, gd54xx, &gd54xx->svga); - gd54xx_start_blit((val>>8) & 0xff, 8, gd54xx, &gd54xx->svga); - gd54xx_start_blit((val>>16) & 0xff, 8, gd54xx, &gd54xx->svga); - gd54xx_start_blit((val>>24) & 0xff, 8, gd54xx, &gd54xx->svga); + if ((dev->blt.mode & (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) { + gd54xx_start_blit(val & 0xff, 8, dev, &dev->svga); + gd54xx_start_blit((val>>8) & 0xff, 8, dev, &dev->svga); + gd54xx_start_blit((val>>16) & 0xff, 8, dev, &dev->svga); + gd54xx_start_blit((val>>24) & 0xff, 8, dev, &dev->svga); } else - gd54xx_start_blit(val, 32, gd54xx, &gd54xx->svga); + gd54xx_start_blit(val, 32, dev, &dev->svga); } static void -gd54xx_write(uint32_t addr, uint8_t val, void *p) +gd54xx_write(uint32_t addr, uint8_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; - if (svga->gdcreg[0x0b] & 1) { - svga->write_bank = gd54xx->bank[(addr >> 15) & 1]; - addr = addr & 0x7fff; - } - else - svga->write_bank = gd54xx->bank[0]; + if (svga->gdcreg[0x0b] & 1) { + svga->write_bank = dev->bank[(addr >> 15) & 1]; + addr = addr & 0x7fff; + } + else + svga->write_bank = dev->bank[0]; if ((svga->seqregs[0x07] & 0x01) == 0) { svga_write(addr, val, svga); return; } - if (gd54xx->blt.sys_tx) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_cnt++; - if (gd54xx->blt.sys_cnt >= 4) { - gd54xx_blit_dword(gd54xx, svga); - gd54xx->blt.sys_cnt = 0; + if (dev->blt.sys_tx) { + if (dev->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + dev->blt.sys_buf &= ~(0xff << (dev->blt.sys_cnt * 8)); + dev->blt.sys_buf |= (val << (dev->blt.sys_cnt * 8)); + dev->blt.sys_cnt++; + if (dev->blt.sys_cnt >= 4) { + blit_dword(dev, svga); + dev->blt.sys_cnt = 0; } } return; @@ -1164,39 +1224,38 @@ gd54xx_write(uint32_t addr, uint8_t val, void *p) addr &= svga->banked_mask; if (svga->banked_mask != 0x1ffff) - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + addr = (addr & 0x7fff) + dev->bank[(addr >> 15) & 1]; svga_write_linear(addr, val, svga); } static void -gd54xx_writew(uint32_t addr, uint16_t val, void *p) +gd54xx_writew(uint32_t addr, uint16_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; - if (svga->gdcreg[0x0b] & 1) { - svga->write_bank = gd54xx->bank[(addr >> 15) & 1]; - addr = addr & 0x7fff; - } - else - svga->write_bank = gd54xx->bank[0]; + if (svga->gdcreg[0x0b] & 1) { + svga->write_bank = dev->bank[(addr >> 15) & 1]; + addr = addr & 0x7fff; + } else + svga->write_bank = dev->bank[0]; - if ((svga->seqregs[0x07] & 0x01) == 0) { + if ((svga->seqregs[0x07] & 0x01) == 0) { svga_writew(addr, val, svga); return; } - if (gd54xx->blt.sys_tx) { - gd54xx_write(addr, val & 0xff, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); + if (dev->blt.sys_tx) { + gd54xx_write(addr, val & 0xff, dev); + gd54xx_write(addr+1, val >> 8, dev); return; } addr &= svga->banked_mask; if (svga->banked_mask != 0x1ffff) - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + addr = (addr & 0x7fff) + dev->bank[(addr >> 15) & 1]; if (svga->writemode < 4) svga_writew_linear(addr, val, svga); @@ -1208,27 +1267,27 @@ gd54xx_writew(uint32_t addr, uint16_t val, void *p) static void -gd54xx_writel(uint32_t addr, uint32_t val, void *p) +gd54xx_writel(uint32_t addr, uint32_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; - if ((svga->seqregs[0x07] & 0x01) == 0) { + if ((svga->seqregs[0x07] & 0x01) == 0) { svga_writel(addr, val, svga); return; } - if (gd54xx->blt.sys_tx) { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); - gd54xx_write(addr+2, val >> 16, gd54xx); - gd54xx_write(addr+3, val >> 24, gd54xx); + if (dev->blt.sys_tx) { + gd54xx_write(addr, val, dev); + gd54xx_write(addr+1, val >> 8, dev); + gd54xx_write(addr+2, val >> 16, dev); + gd54xx_write(addr+3, val >> 24, dev); return; } addr &= svga->banked_mask; if (svga->banked_mask != 0x1ffff) - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + addr = (addr & 0x7fff) + dev->bank[(addr >> 15) & 1]; if (svga->writemode < 4) svga_writel_linear(addr, val, svga); @@ -1301,15 +1360,16 @@ static uint8_t gd54xx_get_aperture(uint32_t addr) { uint32_t ap = addr >> 22; + return (uint8_t) (ap & 0x03); } static uint8_t -gd54xx_readb_linear(uint32_t addr, void *p) +gd54xx_readb_linear(uint32_t addr, void *priv) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + svga_t *svga = (svga_t *)priv; + gd54xx_t *dev = (gd54xx_t *)svga->p; uint8_t ap = gd54xx_get_aperture(addr); addr &= 0x003fffff; /* 4 MB mask */ @@ -1318,32 +1378,35 @@ gd54xx_readb_linear(uint32_t addr, void *p) case 0: default: break; + case 1: /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ addr ^= 0x00000001; break; + case 2: /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ addr ^= 0x00000003; break; + case 3: return 0xff; } if ((addr & 0x003fff00) == 0x003fff00) { if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) - return gd543x_mmio_read(addr & 0x000000ff, gd54xx); + return gd543x_mmio_read(addr & 0x000000ff, dev); } - return svga_read_linear(addr, p); + return svga_read_linear(addr, priv); } static uint16_t -gd54xx_readw_linear(uint32_t addr, void *p) +gd54xx_readw_linear(uint32_t addr, void *priv) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + svga_t *svga = (svga_t *)priv; + gd54xx_t *dev = (gd54xx_t *)svga->p; uint8_t ap = gd54xx_get_aperture(addr); uint16_t temp, temp2; @@ -1355,17 +1418,19 @@ gd54xx_readw_linear(uint32_t addr, void *p) if (ap == 2) addr ^= 0x00000002; - temp = gd543x_mmio_readw(addr & 0x000000ff, gd54xx); + temp = gd543x_mmio_readw(addr & 0x000000ff, dev); switch(ap) { case 0: default: return temp; + case 1: case 2: temp2 = temp >> 8; temp2 |= ((temp & 0xff) << 8); return temp; + case 3: return 0xffff; } @@ -1375,18 +1440,21 @@ gd54xx_readw_linear(uint32_t addr, void *p) switch (ap) { case 0: default: - return svga_readw_linear(addr, p); + return svga_readw_linear(addr, priv); + case 2: /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ addr ^= 0x00000002; + case 1: - temp = svga_readb_linear(addr + 1, p); - temp |= (svga_readb_linear(addr, p) << 8); + temp = svga_readb_linear(addr + 1, priv); + temp |= (svga_readb_linear(addr, priv) << 8); if (svga->fast) cycles -= video_timing_read_w; return temp; + case 3: return 0xffff; } @@ -1394,10 +1462,10 @@ gd54xx_readw_linear(uint32_t addr, void *p) static uint32_t -gd54xx_readl_linear(uint32_t addr, void *p) +gd54xx_readl_linear(uint32_t addr, void *priv) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + svga_t *svga = (svga_t *)priv; + gd54xx_t *dev = (gd54xx_t *)svga->p; uint8_t ap = gd54xx_get_aperture(addr); uint32_t temp, temp2; @@ -1406,26 +1474,27 @@ gd54xx_readl_linear(uint32_t addr, void *p) if ((addr & 0x003fff00) == 0x003fff00) { if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { - temp = gd543x_mmio_readl(addr & 0x000000ff, gd54xx); + temp = gd543x_mmio_readl(addr & 0x000000ff, dev); switch(ap) { case 0: default: return temp; + case 1: temp2 = temp >> 24; temp2 |= ((temp >> 16) & 0xff) << 8; temp2 |= ((temp >> 8) & 0xff) << 16; temp2 |= (temp & 0xff) << 24; - return temp2; + case 2: temp2 = (temp >> 8) & 0xff; temp2 |= (temp & 0xff) << 8; temp2 = ((temp >> 24) & 0xff) << 16; temp2 = ((temp >> 16) & 0xff) << 24; - return temp2; + case 3: return 0xffffffff; } @@ -1435,27 +1504,30 @@ gd54xx_readl_linear(uint32_t addr, void *p) switch (ap) { case 0: default: - return svga_readw_linear(addr, p); + return svga_readw_linear(addr, priv); + case 1: - temp = svga_readb_linear(addr + 1, p); - temp |= (svga_readb_linear(addr, p) << 8); - temp |= (svga_readb_linear(addr + 3, p) << 16); - temp |= (svga_readb_linear(addr + 2, p) << 24); + temp = svga_readb_linear(addr + 1, priv); + temp |= (svga_readb_linear(addr, priv) << 8); + temp |= (svga_readb_linear(addr + 3, priv) << 16); + temp |= (svga_readb_linear(addr + 2, priv) << 24); if (svga->fast) cycles -= video_timing_read_l; return temp; + case 2: - temp = svga_readb_linear(addr + 3, p); - temp |= (svga_readb_linear(addr + 2, p) << 8); - temp |= (svga_readb_linear(addr + 1, p) << 16); - temp |= (svga_readb_linear(addr, p) << 24); + temp = svga_readb_linear(addr + 3, priv); + temp |= (svga_readb_linear(addr + 2, priv) << 8); + temp |= (svga_readb_linear(addr + 1, priv) << 16); + temp |= (svga_readb_linear(addr, priv) << 24); if (svga->fast) cycles -= video_timing_read_l; return temp; + case 3: return 0xffffffff; } @@ -1463,10 +1535,10 @@ gd54xx_readl_linear(uint32_t addr, void *p) static void -gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) +gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *priv) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + svga_t *svga = (svga_t *)priv; + gd54xx_t *dev = (gd54xx_t *)svga->p; uint8_t ap = gd54xx_get_aperture(addr); addr &= 0x003fffff; /* 4 MB mask */ @@ -1475,31 +1547,34 @@ gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) case 0: default: break; + case 1: /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ addr ^= 0x00000001; break; + case 2: /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ addr ^= 0x00000003; break; + case 3: return; } if ((addr & 0x003fff00) == 0x003fff00) { if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) - gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); + gd543x_mmio_write(addr & 0x000000ff, val, dev); } - if (gd54xx->blt.sys_tx) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_cnt++; - if (gd54xx->blt.sys_cnt >= 4) { - gd54xx_blit_dword(gd54xx, svga); - gd54xx->blt.sys_cnt = 0; + if (dev->blt.sys_tx) { + if (dev->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + dev->blt.sys_buf &= ~(0xff << (dev->blt.sys_cnt * 8)); + dev->blt.sys_buf |= (val << (dev->blt.sys_cnt * 8)); + dev->blt.sys_cnt++; + if (dev->blt.sys_cnt >= 4) { + blit_dword(dev, svga); + dev->blt.sys_cnt = 0; } } return; @@ -1510,10 +1585,10 @@ gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) static void -gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) +gd54xx_writew_linear(uint32_t addr, uint16_t val, void *priv) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + svga_t *svga = (svga_t *)priv; + gd54xx_t *dev = (gd54xx_t *)svga->p; uint8_t ap = gd54xx_get_aperture(addr); uint16_t temp; @@ -1523,21 +1598,26 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) switch(ap) { case 0: default: - gd543x_mmio_writew(addr & 0x000000ff, val, gd54xx); + gd543x_mmio_writew(addr & 0x000000ff, val, dev); return; + case 2: addr ^= 0x00000002; + /*FALLTHROUGH*/ + case 1: temp = (val >> 8); temp |= ((val & 0xff) << 8); - gd543x_mmio_writew(addr & 0x000000ff, temp, gd54xx); + gd543x_mmio_writew(addr & 0x000000ff, temp, dev); + return; + case 3: return; } } } - if (gd54xx->blt.sys_tx) { + if (dev->blt.sys_tx) { gd54xx_writeb_linear(addr, val & 0xff, svga); gd54xx_writeb_linear(addr+1, val >> 8, svga); return; @@ -1551,14 +1631,19 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) default: svga_writew_linear(addr, val, svga); return; + case 2: addr ^= 0x00000002; + /*FALLTHROUGH*/ + case 1: svga_writeb_linear(addr + 1, val & 0xff, svga); svga_writeb_linear(addr, val >> 8, svga); if (svga->fast) cycles -= video_timing_write_w; + return; + case 3: return; } @@ -1569,11 +1654,16 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) svga_write_linear(addr, val & 0xff, svga); svga_write_linear(addr + 1, val >> 8, svga); return; + case 2: addr ^= 0x00000002; + /*FALLTHROUGH*/ + case 1: svga_write_linear(addr + 1, val & 0xff, svga); svga_write_linear(addr, val >> 8, svga); + return; + case 3: return; } @@ -1582,10 +1672,10 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) static void -gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) +gd54xx_writel_linear(uint32_t addr, uint32_t val, void *priv) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + svga_t *svga = (svga_t *)priv; + gd54xx_t *dev = (gd54xx_t *)svga->p; uint8_t ap = gd54xx_get_aperture(addr); uint32_t temp; @@ -1595,29 +1685,32 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) switch(ap) { case 0: default: - gd543x_mmio_writel(addr & 0x000000ff, val, gd54xx); + gd543x_mmio_writel(addr & 0x000000ff, val, dev); return; + case 2: temp = (val >> 24); temp |= ((val >> 16) & 0xff) << 8; temp |= ((val >> 8) & 0xff) << 16; temp |= (val & 0xff) << 24; - gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + gd543x_mmio_writel(addr & 0x000000ff, temp, dev); return; + case 1: temp = ((val >> 8) & 0xff); temp |= (val & 0xff) << 8; temp |= (val >> 24) << 16; temp |= ((val >> 16) & 0xff) << 24; - gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + gd543x_mmio_writel(addr & 0x000000ff, temp, dev); return; + case 3: return; } } } - if (gd54xx->blt.sys_tx) { + if (dev->blt.sys_tx) { gd54xx_writeb_linear(addr, val, svga); gd54xx_writeb_linear(addr+1, val >> 8, svga); gd54xx_writeb_linear(addr+2, val >> 16, svga); @@ -1633,17 +1726,21 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) default: svga_writel_linear(addr, val, svga); return; + case 1: svga_writeb_linear(addr + 1, val & 0xff, svga); svga_writeb_linear(addr, val >> 8, svga); svga_writeb_linear(addr + 3, val >> 16, svga); svga_writeb_linear(addr + 2, val >> 24, svga); return; + case 2: svga_writeb_linear(addr + 3, val & 0xff, svga); svga_writeb_linear(addr + 2, val >> 8, svga); svga_writeb_linear(addr + 1, val >> 16, svga); svga_writeb_linear(addr, val >> 24, svga); + return; + case 3: return; } @@ -1659,17 +1756,21 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) svga_write_linear(addr+2, val >> 16, svga); svga_write_linear(addr+3, val >> 24, svga); return; + case 1: svga_write_linear(addr + 1, val & 0xff, svga); svga_write_linear(addr, val >> 8, svga); svga_write_linear(addr + 3, val >> 16, svga); svga_write_linear(addr + 2, val >> 24, svga); return; + case 2: svga_write_linear(addr + 3, val & 0xff, svga); svga_write_linear(addr + 2, val >> 8, svga); svga_write_linear(addr + 1, val >> 16, svga); svga_write_linear(addr, val >> 24, svga); + return; + case 3: return; } @@ -1678,53 +1779,51 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) static uint8_t -gd54xx_read(uint32_t addr, void *p) +gd54xx_read(uint32_t addr, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; if ((svga->seqregs[0x07] & 0x01) == 0) return svga_read(addr, svga); addr &= svga->banked_mask; - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + addr = (addr & 0x7fff) + dev->bank[(addr >> 15) & 1]; addr &= svga->vram_mask; - - return svga_read_linear(addr, svga); } static uint16_t -gd54xx_readw(uint32_t addr, void *p) +gd54xx_readw(uint32_t addr, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; if ((svga->seqregs[0x07] & 0x01) == 0) return svga_readw(addr, svga); addr &= svga->banked_mask; if (svga->banked_mask != 0x1ffff) - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + addr = (addr & 0x7fff) + dev->bank[(addr >> 15) & 1]; return svga_readw_linear(addr, svga); } static uint32_t -gd54xx_readl(uint32_t addr, void *p) +gd54xx_readl(uint32_t addr, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; if ((svga->seqregs[0x07] & 0x01) == 0) return svga_readl(addr, svga); addr &= svga->banked_mask; - addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + addr = (addr & 0x7fff) + dev->bank[(addr >> 15) & 1]; return svga_readl_linear(addr, svga); } @@ -1741,218 +1840,238 @@ gd543x_do_mmio(svga_t *svga, uint32_t addr) static void -gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) +gd543x_mmio_write(uint32_t addr, uint8_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; if (gd543x_do_mmio(svga, addr)) { switch (addr & 0xff) { case 0x00: - if (gd54xx_is_5434(svga)) - gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffffff00) | val; + if (is_5434(svga)) + dev->blt.bg_col = (dev->blt.bg_col & 0xffffff00) | val; else - gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00) | val; + dev->blt.bg_col = (dev->blt.bg_col & 0xff00) | val; break; + case 0x01: - if (gd54xx_is_5434(svga)) - gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffff00ff) | (val << 8); + if (is_5434(svga)) + dev->blt.bg_col = (dev->blt.bg_col & 0xffff00ff) | (val << 8); else - gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ff) | (val << 8); + dev->blt.bg_col = (dev->blt.bg_col & 0x00ff) | (val << 8); break; + case 0x02: - if (gd54xx_is_5434(svga)) - gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00ffff) | (val << 16); + if (is_5434(svga)) + dev->blt.bg_col = (dev->blt.bg_col & 0xff00ffff) | (val << 16); break; + case 0x03: - if (gd54xx_is_5434(svga)) - gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ffffff) | (val << 24); + if (is_5434(svga)) + dev->blt.bg_col = (dev->blt.bg_col & 0x00ffffff) | (val << 24); break; case 0x04: - if (gd54xx_is_5434(svga)) - gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffffff00) | val; + if (is_5434(svga)) + dev->blt.fg_col = (dev->blt.fg_col & 0xffffff00) | val; else - gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00) | val; + dev->blt.fg_col = (dev->blt.fg_col & 0xff00) | val; break; + case 0x05: - if (gd54xx_is_5434(svga)) - gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffff00ff) | (val << 8); + if (is_5434(svga)) + dev->blt.fg_col = (dev->blt.fg_col & 0xffff00ff) | (val << 8); else - gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ff) | (val << 8); + dev->blt.fg_col = (dev->blt.fg_col & 0x00ff) | (val << 8); break; + case 0x06: - if (gd54xx_is_5434(svga)) - gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00ffff) | (val << 16); + if (is_5434(svga)) + dev->blt.fg_col = (dev->blt.fg_col & 0xff00ffff) | (val << 16); break; + case 0x07: - if (gd54xx_is_5434(svga)) - gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ffffff) | (val << 24); + if (is_5434(svga)) + dev->blt.fg_col = (dev->blt.fg_col & 0x00ffffff) | (val << 24); break; case 0x08: - gd54xx->blt.width = (gd54xx->blt.width & 0xff00) | val; + dev->blt.width = (dev->blt.width & 0xff00) | val; break; + case 0x09: - gd54xx->blt.width = (gd54xx->blt.width & 0x00ff) | (val << 8); - if (gd54xx_is_5434(svga)) - gd54xx->blt.width &= 0x1fff; + dev->blt.width = (dev->blt.width & 0x00ff) | (val << 8); + if (is_5434(svga)) + dev->blt.width &= 0x1fff; else - gd54xx->blt.width &= 0x07ff; + dev->blt.width &= 0x07ff; break; + case 0x0a: - gd54xx->blt.height = (gd54xx->blt.height & 0xff00) | val; + dev->blt.height = (dev->blt.height & 0xff00) | val; break; + case 0x0b: - gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8); - gd54xx->blt.height &= 0x03ff; + dev->blt.height = (dev->blt.height & 0x00ff) | (val << 8); + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + dev->blt.height &= 0x07ff; + else + dev->blt.height &= 0x03ff; break; + case 0x0c: - gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val; + dev->blt.dst_pitch = (dev->blt.dst_pitch & 0xff00) | val; break; + case 0x0d: - gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0x00ff) | (val << 8); + dev->blt.dst_pitch = (dev->blt.dst_pitch & 0x00ff) | (val << 8); break; + case 0x0e: - gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0xff00) | val; + dev->blt.src_pitch = (dev->blt.src_pitch & 0xff00) | val; break; + case 0x0f: - gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0x00ff) | (val << 8); + dev->blt.src_pitch = (dev->blt.src_pitch & 0x00ff) | (val << 8); break; case 0x10: - gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xffff00) | val; + dev->blt.dst_addr = (dev->blt.dst_addr & 0xffff00) | val; break; case 0x11: - gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xff00ff) | (val << 8); + dev->blt.dst_addr = (dev->blt.dst_addr & 0xff00ff) | (val << 8); break; - case 0x12: - gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0x00ffff) | (val << 16); - if (gd54xx_is_5434(svga)) - gd54xx->blt.dst_addr &= 0x3fffff; - else - gd54xx->blt.dst_addr &= 0x1fffff; - if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (gd54xx->blt.status & CIRRUS_BLT_AUTOSTART)) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_tx = 1; - gd54xx->blt.sys_cnt = 0; - gd54xx->blt.sys_buf = 0; - gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; - gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; - gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + case 0x12: + dev->blt.dst_addr = (dev->blt.dst_addr & 0x00ffff) | (val << 16); + if (is_5434(svga)) + dev->blt.dst_addr &= 0x3fffff; + else + dev->blt.dst_addr &= 0x1fffff; + + if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (dev->blt.status & CIRRUS_BLT_AUTOSTART)) { + if (dev->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + dev->blt.sys_tx = 1; + dev->blt.sys_cnt = 0; + dev->blt.sys_buf = 0; + dev->blt.pixel_cnt = dev->blt.scan_cnt = 0; + dev->blt.src_addr_backup = dev->blt.src_addr; + dev->blt.dst_addr_backup = dev->blt.dst_addr; } else - gd54xx_start_blit(0, -1, gd54xx, svga); + gd54xx_start_blit(0, -1, dev, svga); } break; case 0x14: - gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xffff00) | val; + dev->blt.src_addr = (dev->blt.src_addr & 0xffff00) | val; break; + case 0x15: - gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xff00ff) | (val << 8); + dev->blt.src_addr = (dev->blt.src_addr & 0xff00ff) | (val << 8); break; + case 0x16: - gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0x00ffff) | (val << 16); - if (gd54xx_is_5434(svga)) - gd54xx->blt.src_addr &= 0x3fffff; + dev->blt.src_addr = (dev->blt.src_addr & 0x00ffff) | (val << 16); + if (is_5434(svga)) + dev->blt.src_addr &= 0x3fffff; else - gd54xx->blt.src_addr &= 0x1fffff; + dev->blt.src_addr &= 0x1fffff; break; case 0x17: - gd54xx->blt.mask = val; + dev->blt.mask = val; break; + case 0x18: - gd54xx->blt.mode = val; + dev->blt.mode = val; break; case 0x1a: - gd54xx->blt.rop = val; + dev->blt.rop = val; break; case 0x1b: if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) - gd54xx->blt.modeext = val; + dev->blt.modeext = val; break; case 0x1c: - gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val; + dev->blt.trans_col = (dev->blt.trans_col & 0xff00) | val; break; case 0x1d: - gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8); + dev->blt.trans_col = (dev->blt.trans_col & 0x00ff) | (val << 8); break; case 0x20: - gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0xff00) | val; + dev->blt.trans_mask = (dev->blt.trans_mask & 0xff00) | val; break; case 0x21: - gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0x00ff) | (val << 8); + dev->blt.trans_mask = (dev->blt.trans_mask & 0x00ff) | (val << 8); break; case 0x40: - gd54xx->blt.status = val; - if (gd54xx->blt.status & CIRRUS_BLT_START) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_tx = 1; - gd54xx->blt.sys_cnt = 0; - gd54xx->blt.sys_buf = 0; - gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; - gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; - gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + dev->blt.status = val; + if (dev->blt.status & CIRRUS_BLT_START) { + if (dev->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + dev->blt.sys_tx = 1; + dev->blt.sys_cnt = 0; + dev->blt.sys_buf = 0; + dev->blt.pixel_cnt = dev->blt.scan_cnt = 0; + dev->blt.src_addr_backup = dev->blt.src_addr; + dev->blt.dst_addr_backup = dev->blt.dst_addr; } else - gd54xx_start_blit(0, -1, gd54xx, svga); + gd54xx_start_blit(0, -1, dev, svga); } break; } - } else if (gd54xx->mmio_vram_overlap) - gd54xx_write(addr, val, gd54xx); + } else if (dev->mmio_vram_overlap) + gd54xx_write(addr, val, dev); } static void -gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p) +gd543x_mmio_writew(uint32_t addr, uint16_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; if (gd543x_do_mmio(svga, addr)) { - gd543x_mmio_write(addr, val & 0xff, gd54xx); - gd543x_mmio_write(addr+1, val >> 8, gd54xx); - } else if (gd54xx->mmio_vram_overlap) { - gd54xx_write(addr, val & 0xff, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); + gd543x_mmio_write(addr, val & 0xff, dev); + gd543x_mmio_write(addr+1, val >> 8, dev); + } else if (dev->mmio_vram_overlap) { + gd54xx_write(addr, val & 0xff, dev); + gd54xx_write(addr+1, val >> 8, dev); } } static void -gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p) +gd543x_mmio_writel(uint32_t addr, uint32_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; if (gd543x_do_mmio(svga, addr)) { - gd543x_mmio_write(addr, val & 0xff, gd54xx); - gd543x_mmio_write(addr+1, val >> 8, gd54xx); - gd543x_mmio_write(addr+2, val >> 16, gd54xx); - gd543x_mmio_write(addr+3, val >> 24, gd54xx); - } else if (gd54xx->mmio_vram_overlap) { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); - gd54xx_write(addr+2, val >> 16, gd54xx); - gd54xx_write(addr+3, val >> 24, gd54xx); + gd543x_mmio_write(addr, val & 0xff, dev); + gd543x_mmio_write(addr+1, val >> 8, dev); + gd543x_mmio_write(addr+2, val >> 16, dev); + gd543x_mmio_write(addr+3, val >> 24, dev); + } else if (dev->mmio_vram_overlap) { + gd54xx_write(addr, val, dev); + gd54xx_write(addr+1, val >> 8, dev); + gd54xx_write(addr+2, val >> 16, dev); + gd54xx_write(addr+3, val >> 24, dev); } } static uint8_t -gd543x_mmio_read(uint32_t addr, void *p) +gd543x_mmio_read(uint32_t addr, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; if (gd543x_do_mmio(svga, addr)) { switch (addr & 0xff) { @@ -1961,67 +2080,85 @@ gd543x_mmio_read(uint32_t addr, void *p) } return 0xff; /*All other registers read-only*/ } - else if (gd54xx->mmio_vram_overlap) - return gd54xx_read(addr, gd54xx); + else if (dev->mmio_vram_overlap) + return gd54xx_read(addr, dev); return 0xff; } static uint16_t -gd543x_mmio_readw(uint32_t addr, void *p) +gd543x_mmio_readw(uint32_t addr, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; if (gd543x_do_mmio(svga, addr)) - return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8); - else if (gd54xx->mmio_vram_overlap) - return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8); + return gd543x_mmio_read(addr, dev) | (gd543x_mmio_read(addr+1, dev) << 8); + else if (dev->mmio_vram_overlap) + return gd54xx_read(addr, dev) | (gd54xx_read(addr+1, dev) << 8); return 0xffff; } static uint32_t -gd543x_mmio_readl(uint32_t addr, void *p) +gd543x_mmio_readl(uint32_t addr, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; if (gd543x_do_mmio(svga, addr)) - return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8) | (gd543x_mmio_read(addr+2, gd54xx) << 16) | (gd543x_mmio_read(addr+3, gd54xx) << 24); - else if (gd54xx->mmio_vram_overlap) - return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8) | (gd54xx_read(addr+2, gd54xx) << 16) | (gd54xx_read(addr+3, gd54xx) << 24); + return gd543x_mmio_read(addr, dev) | (gd543x_mmio_read(addr+1, dev) << 8) | (gd543x_mmio_read(addr+2, dev) << 16) | (gd543x_mmio_read(addr+3, dev) << 24); + else if (dev->mmio_vram_overlap) + return gd54xx_read(addr, dev) | (gd54xx_read(addr+1, dev) << 8) | (gd54xx_read(addr+2, dev) << 16) | (gd54xx_read(addr+3, dev) << 24); return 0xffffffff; } +static uint8_t +gd54xx_color_expand(gd54xx_t *dev, int mask, int shift) +{ + uint8_t ret; + + if (dev->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) + ret = dev->blt.fg_col >> (shift << 3); + else + ret = mask ? (dev->blt.fg_col >> (shift << 3)) + : (dev->blt.bg_col >> (shift << 3)); + + return ret; +} + + static void -gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) +gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *dev, svga_t *svga) { int blt_mask = 0; int x_max = 0; - int shift = 0, last_x = 0; - - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + uint32_t src_addr = dev->blt.src_addr; + + switch (dev->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { case CIRRUS_BLTMODE_PIXELWIDTH8: - blt_mask = gd54xx->blt.mask & 7; + blt_mask = dev->blt.mask & 7; x_max = 8; break; + case CIRRUS_BLTMODE_PIXELWIDTH16: - blt_mask = gd54xx->blt.mask & 7; + blt_mask = dev->blt.mask & 7; x_max = 16; blt_mask *= 2; break; + case CIRRUS_BLTMODE_PIXELWIDTH24: - blt_mask = (gd54xx->blt.mask & 0x1f); + blt_mask = (dev->blt.mask & 0x1f); x_max = 24; break; + case CIRRUS_BLTMODE_PIXELWIDTH32: - blt_mask = gd54xx->blt.mask & 7; + blt_mask = dev->blt.mask & 7; x_max = 32; blt_mask *= 4; break; @@ -2030,67 +2167,66 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) last_x = (x_max >> 3) - 1; if (count == -1) { - gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; - gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; - gd54xx->blt.width_backup = gd54xx->blt.width; - gd54xx->blt.height_internal = gd54xx->blt.height; - gd54xx->blt.x_count = 0; - if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) - gd54xx->blt.y_count = gd54xx->blt.src_addr & 7; + dev->blt.dst_addr_backup = dev->blt.dst_addr; + dev->blt.src_addr_backup = dev->blt.src_addr; + dev->blt.width_backup = dev->blt.width; + dev->blt.height_internal = dev->blt.height; + dev->blt.x_count = 0; + if ((dev->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) + dev->blt.y_count = src_addr & 7; else - gd54xx->blt.y_count = 0; + dev->blt.y_count = 0; - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (dev->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { if (!(svga->seqregs[7] & 0xf0)) { - mem_map_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); - mem_map_set_p(&svga->mapping, gd54xx); + mem_map_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, blit_write_w, blit_write_l); + mem_map_set_p(&svga->mapping, dev); } else { - mem_map_set_handler(&gd54xx->linear_mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); - mem_map_set_p(&gd54xx->linear_mapping, gd54xx); + mem_map_set_handler(&dev->linear_mapping, NULL, NULL, NULL, NULL, blit_write_w, blit_write_l); + mem_map_set_p(&dev->linear_mapping, dev); } - gd543x_recalc_mapping(gd54xx); + recalc_mapping(dev); return; } else { if (!(svga->seqregs[7] & 0xf0)) { mem_map_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); - mem_map_set_p(&gd54xx->svga.mapping, gd54xx); + mem_map_set_p(&dev->svga.mapping, dev); } else { - mem_map_set_handler(&gd54xx->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); - mem_map_set_p(&gd54xx->linear_mapping, svga); + mem_map_set_handler(&dev->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); + mem_map_set_p(&dev->linear_mapping, svga); } - gd543x_recalc_mapping(gd54xx); + recalc_mapping(dev); } - } else if (gd54xx->blt.height_internal == 0xffff) + } else if (dev->blt.height_internal == 0xffff) return; while (count) { uint8_t src = 0, dst; int mask = 0; - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { - if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { - if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) - mask = (cpu_dat >> 31); + if (dev->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (dev->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (dev->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) + mask = !!(cpu_dat >> 31); else - mask = cpu_dat & 0x80; + mask = !!(cpu_dat & 0x80); - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; + switch (dev->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: shift = 0; break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - shift = (gd54xx->blt.x_count & 1); + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (dev->blt.x_count & 1); break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - shift = (gd54xx->blt.x_count % 3); + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (dev->blt.x_count % 3); break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - shift = (gd54xx->blt.x_count & 3); + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (dev->blt.x_count & 3); break; } - src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + src = gd54xx_color_expand(dev, mask, shift); if (shift == last_x) { cpu_dat <<= 1; @@ -2104,176 +2240,155 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) mask = 1; } } else { - switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + switch (dev->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { case 0x00: - src = svga->vram[gd54xx->blt.src_addr & svga->vram_mask]; - gd54xx->blt.src_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + src = svga->vram[dev->blt.src_addr & svga->vram_mask]; + src_addr += ((dev->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + dev->blt.src_addr += ((dev->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); mask = 1; break; case CIRRUS_BLTMODE_PATTERNCOPY: - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~7)) + (gd54xx->blt.y_count << 3) + (gd54xx->blt.x_count & 7)]; + switch (dev->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + src = svga->vram[(src_addr & (svga->vram_mask & ~7)) + (dev->blt.y_count << 3) + (dev->blt.x_count & 7)]; break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~15)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; + case CIRRUS_BLTMODE_PIXELWIDTH16: + src = svga->vram[(src_addr & (svga->vram_mask & ~15)) + (dev->blt.y_count << 4) + (dev->blt.x_count & 15)]; break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count % 24)]; + case CIRRUS_BLTMODE_PIXELWIDTH24: + src = svga->vram[(src_addr & (svga->vram_mask & ~31)) + (dev->blt.y_count << 5) + (dev->blt.x_count % 24)]; break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; + case CIRRUS_BLTMODE_PIXELWIDTH32: + src = svga->vram[(src_addr & (svga->vram_mask & ~31)) + (dev->blt.y_count << 5) + (dev->blt.x_count & 31)]; break; } mask = 1; break; + case CIRRUS_BLTMODE_COLOREXPAND: - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> gd54xx->blt.x_count); + switch (dev->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> dev->blt.x_count); shift = 0; break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 1)); - shift = (gd54xx->blt.dst_addr & 1); + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> (dev->blt.x_count >> 1)); + shift = (dev->blt.x_count & 1); break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); - shift = (gd54xx->blt.dst_addr % 3); + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> (dev->blt.x_count / 3)); + shift = (dev->blt.x_count % 3); break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 2)); - shift = (gd54xx->blt.dst_addr & 3); + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> (dev->blt.x_count >> 2)); + shift = (dev->blt.x_count & 3); break; } - src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + src = gd54xx_color_expand(dev, mask, shift); break; + case CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND: - if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) { - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: + if (dev->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) { + switch (dev->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: shift = 0; break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - shift = (gd54xx->blt.dst_addr & 1); + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (dev->blt.x_count & 1); break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - shift = (gd54xx->blt.dst_addr % 3); + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (dev->blt.x_count % 3); break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - shift = (gd54xx->blt.dst_addr & 3); + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (dev->blt.x_count & 3); break; } - src = (gd54xx->blt.fg_col >> (shift << 3)); + src = (dev->blt.fg_col >> (shift << 3)); } else { - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> gd54xx->blt.x_count); + switch (dev->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[(src_addr & svga->vram_mask & ~7) | dev->blt.y_count] & (0x80 >> dev->blt.x_count); shift = 0; break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 1)); - shift = (gd54xx->blt.dst_addr & 1); + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[(src_addr & svga->vram_mask & ~7) | dev->blt.y_count] & (0x80 >> (dev->blt.x_count >> 1)); + shift = (dev->blt.x_count & 1); break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); - shift = (gd54xx->blt.dst_addr % 3); + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[(src_addr & svga->vram_mask & ~7) | dev->blt.y_count] & (0x80 >> (dev->blt.x_count / 3)); + shift = (dev->blt.x_count % 3); break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 2)); - shift = (gd54xx->blt.dst_addr & 3); + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[(src_addr & svga->vram_mask & ~7) | dev->blt.y_count] & (0x80 >> (dev->blt.x_count >> 2)); + shift = (dev->blt.x_count & 3); break; } - - src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + src = gd54xx_color_expand(dev, mask, shift); } break; } count--; } - dst = svga->vram[gd54xx->blt.dst_addr & svga->vram_mask]; - svga->changedvram[(gd54xx->blt.dst_addr & svga->vram_mask) >> 12] = changeframecount; + dst = svga->vram[dev->blt.dst_addr & svga->vram_mask]; + svga->changedvram[(dev->blt.dst_addr & svga->vram_mask) >> 12] = changeframecount; - switch (gd54xx->blt.rop) { - case 0x00: dst = 0; break; - case 0x05: dst = src & dst; break; -#if 0 /* Does NOT DO anything! */ - case 0x06: dst = dst; break; -#endif - case 0x09: dst = src & ~dst; break; - case 0x0b: dst = ~ dst; break; - case 0x0d: dst = src; break; - case 0x0e: dst = 0xff; break; - case 0x50: dst = ~ src & dst; break; - case 0x59: dst = src ^ dst; break; - case 0x6d: dst = src | dst; break; - case 0x90: dst = ~(src | dst); break; - case 0x95: dst = ~(src ^ dst); break; - case 0xad: dst = src | ~dst; break; - case 0xd0: dst = ~src; break; - case 0xd6: dst = ~src | dst; break; - case 0xda: dst = ~(src & dst); break; - } - - if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { - if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && - !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && mask)) - svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; - } else { - if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && - !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask)) - svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; + gd54xx_rop(dev, (uint8_t *)&dst, (uint8_t *)&dst, (const uint8_t *) &src); + + if ((dev->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && (dev->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)) + mask = !mask; + + if ((dev->blt.width_backup - dev->blt.width) >= blt_mask && + !((dev->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask)) + svga->vram[dev->blt.dst_addr & svga->vram_mask] = dst; + + dev->blt.dst_addr += ((dev->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + + dev->blt.x_count++; + if (dev->blt.x_count == x_max) { + dev->blt.x_count = 0; + if ((dev->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == CIRRUS_BLTMODE_COLOREXPAND) + src_addr++; } - gd54xx->blt.dst_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + dev->blt.width--; + if (dev->blt.width == 0xffff) { + dev->blt.width = dev->blt.width_backup; - gd54xx->blt.x_count++; + dev->blt.dst_addr = dev->blt.dst_addr_backup = dev->blt.dst_addr_backup + ((dev->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -dev->blt.dst_pitch : dev->blt.dst_pitch); - if (gd54xx->blt.x_count == x_max) { - gd54xx->blt.x_count = 0; - if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == CIRRUS_BLTMODE_COLOREXPAND) - gd54xx->blt.src_addr++; - } - - gd54xx->blt.width--; - - if (gd54xx->blt.width == 0xffff) { - gd54xx->blt.width = gd54xx->blt.width_backup; - - gd54xx->blt.dst_addr = gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.dst_pitch : gd54xx->blt.dst_pitch); - - switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + switch (dev->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { case 0x00: - gd54xx->blt.src_addr = gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.src_pitch : gd54xx->blt.src_pitch); + src_addr = dev->blt.src_addr_backup = dev->blt.src_addr_backup + ((dev->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -dev->blt.src_pitch : dev->blt.src_pitch); break; + case CIRRUS_BLTMODE_COLOREXPAND: - if (gd54xx->blt.x_count != 0) - gd54xx->blt.src_addr++; + if (dev->blt.x_count != 0) + src_addr++; break; } - gd54xx->blt.x_count = 0; - if (gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) - gd54xx->blt.y_count = (gd54xx->blt.y_count - 1) & 7; + dev->blt.x_count = 0; + if (dev->blt.mode & CIRRUS_BLTMODE_BACKWARDS) + dev->blt.y_count = (dev->blt.y_count - 1) & 7; else - gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) & 7; + dev->blt.y_count = (dev->blt.y_count + 1) & 7; - gd54xx->blt.height_internal--; - if (gd54xx->blt.height_internal == 0xffff) { - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + dev->blt.height_internal--; + if (dev->blt.height_internal == 0xffff) { + if (dev->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { if (!(svga->seqregs[7] & 0xf0)) { mem_map_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); - mem_map_set_p(&svga->mapping, gd54xx); + mem_map_set_p(&svga->mapping, dev); } else { - mem_map_set_handler(&gd54xx->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); - mem_map_set_p(&gd54xx->linear_mapping, svga); + mem_map_set_handler(&dev->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); + mem_map_set_p(&dev->linear_mapping, svga); } - gd543x_recalc_mapping(gd54xx); + recalc_mapping(dev); } return; } - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) + if (dev->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) return; } } @@ -2281,12 +2396,12 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) static uint8_t -cl_pci_read(int func, int addr, void *p) +cl_pci_read(int func, int addr, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)priv; + svga_t *svga = &dev->svga; - if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + if ((addr >= 0x30) && (addr <= 0x33) && (!dev->has_bios)) return 0; switch (addr) { @@ -2298,12 +2413,12 @@ cl_pci_read(int func, int addr, void *p) case 0x03: return 0x00; case PCI_REG_COMMAND: - return gd54xx->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + return dev->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ // case 0x07: return 0 << 1; /*Fast DEVSEL timing*/ case 0x07: return 0x02; /*Fast DEVSEL timing*/ - case 0x08: return gd54xx->rev; /*Revision ID*/ + case 0x08: return dev->rev; /*Revision ID*/ case 0x09: return 0x00; /*Programming interface*/ case 0x0a: return 0x00; /*Supports VGA interface*/ @@ -2312,53 +2427,54 @@ cl_pci_read(int func, int addr, void *p) case 0x10: return 0x08; /*Linear frame buffer address*/ case 0x11: return 0x00; case 0x12: return 0x00; - case 0x13: return gd54xx->lfb_base >> 24; + case 0x13: return dev->lfb_base >> 24; - case 0x30: return (gd54xx->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ + case 0x30: return (dev->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ case 0x31: return 0x00; - case 0x32: return gd54xx->pci_regs[0x32]; - case 0x33: return gd54xx->pci_regs[0x33]; + case 0x32: return dev->pci_regs[0x32]; + case 0x33: return dev->pci_regs[0x33]; - case 0x3c: return gd54xx->int_line; + case 0x3c: return dev->int_line; case 0x3d: return PCI_INTA; } + return 0; } static void -cl_pci_write(int func, int addr, uint8_t val, void *p) +cl_pci_write(int func, int addr, uint8_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; + gd54xx_t *dev = (gd54xx_t *)priv; - if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + if ((addr >= 0x30) && (addr <= 0x33) && (!dev->has_bios)) return; switch (addr) { case PCI_REG_COMMAND: - gd54xx->pci_regs[PCI_REG_COMMAND] = val & 0x23; - io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + dev->pci_regs[PCI_REG_COMMAND] = val & 0x23; + io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, dev); if (val & PCI_COMMAND_IO) - io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); - gd543x_recalc_mapping(gd54xx); + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, dev); + recalc_mapping(dev); break; case 0x13: - gd54xx->lfb_base = val << 24; - gd543x_recalc_mapping(gd54xx); + dev->lfb_base = val << 24; + recalc_mapping(dev); break; case 0x30: case 0x32: case 0x33: - gd54xx->pci_regs[addr] = val; - if (gd54xx->pci_regs[0x30] & 0x01) { - uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24); - mem_map_set_addr(&gd54xx->bios_rom.mapping, addr, 0x8000); + dev->pci_regs[addr] = val; + if (dev->pci_regs[0x30] & 0x01) { + uint32_t addr = (dev->pci_regs[0x32] << 16) | (dev->pci_regs[0x33] << 24); + mem_map_set_addr(&dev->bios_rom.mapping, addr, 0x8000); } else - mem_map_disable(&gd54xx->bios_rom.mapping); + mem_map_disable(&dev->bios_rom.mapping); return; case 0x3c: - gd54xx->int_line = val; + dev->int_line = val; return; } } @@ -2367,24 +2483,24 @@ cl_pci_write(int func, int addr, uint8_t val, void *p) static void * gd54xx_init(const device_t *info) { - gd54xx_t *gd54xx = (gd54xx_t *)mem_alloc(sizeof(gd54xx_t)); - svga_t *svga = &gd54xx->svga; + gd54xx_t *dev = (gd54xx_t *)mem_alloc(sizeof(gd54xx_t)); + svga_t *svga = &dev->svga; int id = info->local & 0xff; - int vram; wchar_t *romfn = NULL; - memset(gd54xx, 0, sizeof(gd54xx_t)); + int vram; - gd54xx->pci = !!(info->flags & DEVICE_PCI); - gd54xx->vlb = !!(info->flags & DEVICE_VLB); + memset(dev, 0x00, sizeof(gd54xx_t)); + dev->pci = !!(info->flags & DEVICE_PCI); + dev->vlb = !!(info->flags & DEVICE_VLB); + dev->rev = 0; + dev->has_bios = 1; - gd54xx->rev = 0; - gd54xx->has_bios = 1; switch (id) { - case CIRRUS_ID_CLGD5402: case CIRRUS_ID_CLGD5420: romfn = BIOS_GD5420_PATH; break; + case CIRRUS_ID_CLGD5422: case CIRRUS_ID_CLGD5424: romfn = BIOS_GD5422_PATH; @@ -2395,7 +2511,7 @@ gd54xx_init(const device_t *info) break; case CIRRUS_ID_CLGD5428: - if (gd54xx->vlb) + if (dev->vlb) romfn = BIOS_GD5428_VLB_PATH; else romfn = BIOS_GD5428_ISA_PATH; @@ -2416,15 +2532,15 @@ gd54xx_init(const device_t *info) case CIRRUS_ID_CLGD5430: if (info->local & 0x400) { /* CL-GD 5440 */ - gd54xx->rev = 0x47; + dev->rev = 0x47; if (info->local & 0x200) { romfn = NULL; - gd54xx->has_bios = 0; + dev->has_bios = 0; } else romfn = BIOS_GD5440_PATH; } else { /* CL-GD 5430 */ - if (gd54xx->pci) + if (dev->pci) romfn = BIOS_GD5430_PCI_PATH; else romfn = BIOS_GD5430_VLB_PATH; @@ -2443,108 +2559,119 @@ gd54xx_init(const device_t *info) break; } - if (id >= CIRRUS_ID_CLGD5420) - vram = device_get_config_int("memory"); - else - vram = 0; - if (vram) - gd54xx->vram_size = vram << 20; + if (id >= CIRRUS_ID_CLGD5420) + vram = device_get_config_int("memory"); else - gd54xx->vram_size = 1 << 19; - gd54xx->vram_mask = gd54xx->vram_size - 1; + vram = 0; + + if (vram) + dev->vram_size = vram << 20; + else + dev->vram_size = 1 << 19; + dev->vram_mask = dev->vram_size - 1; if (romfn) - rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&dev->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, + 0, MEM_MAPPING_EXTERNAL); - svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size, - gd54xx_recalctimings, gd54xx_in, gd54xx_out, - gd54xx_hwcursor_draw, NULL); + svga_init(&dev->svga, dev, dev->vram_size, + recalc_timings, gd54xx_in, gd54xx_out, + hwcursor_draw, NULL); svga->ven_write = gd54xx_write_modes45; - mem_map_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); - mem_map_set_p(&svga->mapping, gd54xx); + mem_map_set_handler(&svga->mapping, + gd54xx_read, gd54xx_readw, gd54xx_readl, + gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_map_set_p(&svga->mapping, dev); - mem_map_add(&gd54xx->mmio_mapping, 0, 0, gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, gd543x_mmio_write, gd543x_mmio_writew, gd543x_mmio_writel, NULL, 0, gd54xx); - mem_map_add(&gd54xx->linear_mapping, 0, 0, gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, NULL, 0, svga); + mem_map_add(&dev->mmio_mapping, 0, 0, + gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, + gd543x_mmio_write, gd543x_mmio_writew, gd543x_mmio_writel, + NULL, 0, dev); - io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + mem_map_add(&dev->linear_mapping, 0, 0, + gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, + gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, + NULL, 0, svga); + + io_sethandler(0x03c0, 32, + gd54xx_in,NULL,NULL, gd54xx_out,NULL,NULL, dev); svga->hwcursor.yoff = 32; svga->hwcursor.xoff = 0; - if (id >= CIRRUS_ID_CLGD5420) { - gd54xx->vclk_n[0] = 0x4a; - gd54xx->vclk_d[0] = 0x2b; - gd54xx->vclk_n[1] = 0x5b; - gd54xx->vclk_d[1] = 0x2f; - gd54xx->vclk_n[2] = 0x45; - gd54xx->vclk_d[2] = 0x30; - gd54xx->vclk_n[3] = 0x7e; - gd54xx->vclk_d[3] = 0x33; - } - else { - gd54xx->vclk_n[0] = 0x66; - gd54xx->vclk_d[0] = 0x3b; - gd54xx->vclk_n[1] = 0x5b; - gd54xx->vclk_d[1] = 0x2f; - gd54xx->vclk_n[1] = 0x45; - gd54xx->vclk_d[1] = 0x2c; - gd54xx->vclk_n[1] = 0x7e; - gd54xx->vclk_d[1] = 0x33; - } + if (id >= CIRRUS_ID_CLGD5420) { + dev->vclk_n[0] = 0x4a; + dev->vclk_d[0] = 0x2b; + dev->vclk_n[1] = 0x5b; + dev->vclk_d[1] = 0x2f; + dev->vclk_n[2] = 0x45; + dev->vclk_d[2] = 0x30; + dev->vclk_n[3] = 0x7e; + dev->vclk_d[3] = 0x33; + } else { + dev->vclk_n[0] = 0x66; + dev->vclk_d[0] = 0x3b; + dev->vclk_n[1] = 0x5b; + dev->vclk_d[1] = 0x2f; + dev->vclk_n[1] = 0x45; + dev->vclk_d[1] = 0x2c; + dev->vclk_n[1] = 0x7e; + dev->vclk_d[1] = 0x33; + } - gd54xx->bank[1] = 0x8000; + dev->bank[1] = 0x8000; - if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) - pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx); + if (dev->pci && id >= CIRRUS_ID_CLGD5430) + pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, dev); - gd54xx->pci_regs[PCI_REG_COMMAND] = 7; + dev->pci_regs[PCI_REG_COMMAND] = 7; - gd54xx->pci_regs[0x30] = 0x00; - gd54xx->pci_regs[0x32] = 0x0c; - gd54xx->pci_regs[0x33] = 0x00; + dev->pci_regs[0x30] = 0x00; + dev->pci_regs[0x32] = 0x0c; + dev->pci_regs[0x33] = 0x00; svga->crtc[0x27] = id; - video_inform(VID_TYPE_SPEC, - (const video_timings_t *)info->vid_timing); + video_inform(VID_TYPE_SPEC, (const video_timings_t *)info->vid_timing); - return gd54xx; + return dev; } static void -gd54xx_close(void *p) +gd54xx_close(void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; + gd54xx_t *dev = (gd54xx_t *)priv; - svga_close(&gd54xx->svga); + svga_close(&dev->svga); - free(gd54xx); + free(dev); } static void -gd54xx_speed_changed(void *p) +gd54xx_speed_changed(void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; + gd54xx_t *dev = (gd54xx_t *)priv; - svga_recalctimings(&gd54xx->svga); + svga_recalctimings(&dev->svga); } static void -gd54xx_force_redraw(void *p) +gd54xx_force_redraw(void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *)p; + gd54xx_t *dev = (gd54xx_t *)priv; - gd54xx->svga.fullchange = changeframecount; + dev->svga.fullchange = changeframecount; } + static int gd5420_available(void) { - return rom_present(BIOS_GD5420_PATH); + return rom_present(BIOS_GD5420_PATH); } static int @@ -2714,40 +2841,36 @@ static const video_timings_t cl_gd_isa_timing = {VID_ISA,3,3,6,8,8,12}; static const video_timings_t cl_gd_vlb_timing = {VID_BUS,4,4,8,10,10,20}; static const video_timings_t cl_gd_pci_timing = {VID_BUS,4,4,8,10,10,20}; -const device_t gd5402_isa_device = -{ - "Cirrus Logic GD-5402 (ACUMOS AVGA2)", - DEVICE_AT | DEVICE_ISA, - CIRRUS_ID_CLGD5402, - gd54xx_init, gd54xx_close, - NULL, - gd5420_available, /* Common BIOS between 5402 and 5420 */ - gd54xx_speed_changed, - gd54xx_force_redraw, - &cl_gd_isa_timing, - NULL, +const device_t gd5402_isa_device = { + "Cirrus Logic GD-5402 (ACUMOS AVGA2)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5402, + gd54xx_init, gd54xx_close, NULL, + gd5420_available, /* Common BIOS between 5402 and 5420 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + &cl_gd_isa_timing, + NULL, }; -const device_t gd5420_isa_device = -{ - "Cirrus Logic GD-5420", - DEVICE_AT | DEVICE_ISA, - CIRRUS_ID_CLGD5420, - gd54xx_init, gd54xx_close, - NULL, - gd5420_available, /* Common BIOS between 5402 and 5420 */ - gd54xx_speed_changed, - gd54xx_force_redraw, - &cl_gd_isa_timing, - gd5422_config, +const device_t gd5420_isa_device = { + "Cirrus Logic GD-5420", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5420, + gd54xx_init, gd54xx_close, NULL, + gd5420_available, /* Common BIOS between 5402 and 5420 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + &cl_gd_isa_timing, + gd5422_config, }; + const device_t gd5422_isa_device = { "Cirrus Logic GD-5422", DEVICE_AT | DEVICE_ISA, CIRRUS_ID_CLGD5422, - gd54xx_init, gd54xx_close, - NULL, - gd5422_available, /* Common BIOS between 5422 and 5424 */ + gd54xx_init, gd54xx_close, NULL, + gd5422_available, /* Common BIOS between 5422 and 5424 */ gd54xx_speed_changed, gd54xx_force_redraw, &cl_gd_isa_timing, @@ -2758,9 +2881,8 @@ const device_t gd5424_vlb_device = { "Cirrus Logic GD-5424", DEVICE_VLB, CIRRUS_ID_CLGD5424, - gd54xx_init, gd54xx_close, - NULL, - gd5422_available, /* Common BIOS between 5422 and 5424 */ + gd54xx_init, gd54xx_close, NULL, + gd5422_available, /* Common BIOS between 5422 and 5424 */ gd54xx_speed_changed, gd54xx_force_redraw, &cl_gd_vlb_timing, @@ -2771,9 +2893,7 @@ const device_t gd5426_vlb_device = { "Cirrus Logic GD-5426", DEVICE_VLB, CIRRUS_ID_CLGD5426, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5426_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2785,9 +2905,7 @@ const device_t gd5428_isa_device = { "Cirrus Logic GD-5428", DEVICE_AT | DEVICE_ISA, CIRRUS_ID_CLGD5428, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5428_isa_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2799,9 +2917,7 @@ const device_t gd5428_vlb_device = { "Cirrus Logic GD-5428", DEVICE_VLB, CIRRUS_ID_CLGD5428, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5428_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2813,9 +2929,7 @@ const device_t gd5429_isa_device = { "Cirrus Logic GD-5429", DEVICE_AT | DEVICE_ISA, CIRRUS_ID_CLGD5429, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5429_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2827,9 +2941,7 @@ const device_t gd5429_vlb_device = { "Cirrus Logic GD-5429", DEVICE_VLB, CIRRUS_ID_CLGD5429, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5429_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2841,9 +2953,7 @@ const device_t gd5430_vlb_device = { "Cirrus Logic GD-5430", DEVICE_VLB, CIRRUS_ID_CLGD5430, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5430_vlb_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2855,9 +2965,7 @@ const device_t gd5430_pci_device = { "Cirrus Logic GD-5430", DEVICE_PCI, CIRRUS_ID_CLGD5430, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5430_pci_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2869,9 +2977,7 @@ const device_t gd5434_isa_device = { "Cirrus Logic GD-5434", DEVICE_AT | DEVICE_ISA, CIRRUS_ID_CLGD5434, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5434_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2883,9 +2989,7 @@ const device_t gd5434_vlb_device = { "Cirrus Logic GD-5434", DEVICE_VLB, CIRRUS_ID_CLGD5434, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5434_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2897,9 +3001,7 @@ const device_t gd5434_pci_device = { "Cirrus Logic GD-5434", DEVICE_PCI, CIRRUS_ID_CLGD5434, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5434_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2911,9 +3013,7 @@ const device_t gd5436_pci_device = { "Cirrus Logic GD-5436", DEVICE_PCI, CIRRUS_ID_CLGD5436, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5436_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2925,9 +3025,7 @@ const device_t gd5440_onboard_pci_device = { "Onboard Cirrus Logic GD-5440", DEVICE_PCI, CIRRUS_ID_CLGD5440 | 0x600, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, NULL, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2939,9 +3037,7 @@ const device_t gd5440_pci_device = { "Cirrus Logic GD-5440", DEVICE_PCI, CIRRUS_ID_CLGD5440 | 0x400, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5440_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2953,9 +3049,7 @@ const device_t gd5446_pci_device = { "Cirrus Logic GD-5446", DEVICE_PCI, CIRRUS_ID_CLGD5446, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5446_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2967,9 +3061,7 @@ const device_t gd5446_stb_pci_device = { "STB Nitro 64V", DEVICE_PCI, CIRRUS_ID_CLGD5446 | 0x100, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5446_stb_available, gd54xx_speed_changed, gd54xx_force_redraw, @@ -2981,9 +3073,7 @@ const device_t gd5480_pci_device = { "Cirrus Logic GD-5480", DEVICE_PCI, CIRRUS_ID_CLGD5480, - gd54xx_init, - gd54xx_close, - NULL, + gd54xx_init, gd54xx_close, NULL, gd5480_available, gd54xx_speed_changed, gd54xx_force_redraw, diff --git a/src/devices/video/vid_ega.c b/src/devices/video/vid_ega.c index f59a02c..5431b5f 100644 --- a/src/devices/video/vid_ega.c +++ b/src/devices/video/vid_ega.c @@ -9,14 +9,14 @@ * Emulation of the EGA, Chips & Technologies SuperEGA, and * AX JEGA graphics cards. * - * Version: @(#)vid_ega.c 1.0.9 2018/09/22 + * Version: @(#)vid_ega.c 1.0.10 2019/02/10 * * 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 @@ -495,7 +495,7 @@ ega_out(uint16_t port, uint8_t val, void *priv) break; case 0x3c2: - egaswitchread = val & 0xc; + egaswitchread = (val & 0xc) >> 2; dev->vres = !(val & 0x80); dev->pallook = dev->vres ? pallook16 : pallook64; dev->vidclock = val & 4; /*printf("3C2 write %02X\n",val);*/ @@ -620,12 +620,7 @@ ega_in(uint16_t port, void *priv) break; case 0x3c2: - switch (egaswitchread) { - case 0xc: ret = (egaswitches & 1) ? 0x10 : 0; break; - case 0x8: ret = (egaswitches & 2) ? 0x10 : 0; break; - case 0x4: ret = (egaswitches & 4) ? 0x10 : 0; break; - case 0x0: ret = (egaswitches & 8) ? 0x10 : 0; break; - } + return (egaswitches & (8 >> egaswitchread)) ? 0x10 : 0x00; break; case 0x3c4: @@ -912,8 +907,8 @@ ega_init(ega_t *dev, int monitor_type, int is_mono) dev->vram = (uint8_t *)mem_alloc(0x40000); dev->vram_limit = 256 * 1024; - dev->vrammask = dev->vram_limit-1; - + dev->vrammask = dev->vram_limit - 1; + for (c = 0; c < 256; c++) { e = c; for (d = 0; d < 8; d++) { @@ -1096,10 +1091,10 @@ ega_standalone_init(const device_t *info) } c = device_get_config_int("monitor_type"); - ega_init(dev, c, (c & 0xf) == 10); + ega_init(dev, c, (c & 0x0f) == 0x0b); dev->vram_limit = device_get_config_int("memory") * 1024; - dev->vrammask = dev->vram_limit-1; + dev->vrammask = dev->vram_limit - 1; mem_map_add(&dev->mapping, 0xa0000, 0x20000, ega_read,NULL,NULL, ega_write,NULL,NULL, @@ -1248,6 +1243,17 @@ sega_standalone_available(void) } +/* + * SW1 SW2 SW3 SW4 + * OFF OFF ON OFF Monochrome (5151) 1011 0x0b + * ON OFF OFF ON Color 40x25 (5153) 0110 0x06 + * OFF OFF OFF ON Color 80x25 (5153) 0111 0x07 + * ON ON ON OFF Enhanced Color - Normal Mode (5154) 1000 0x08 + * OFF ON ON OFF Enhanced Color - Enhanced Mode (5154) 1001 0x09 + * + * 0 = Switch closed (ON); + * 1 = Switch open (OFF). + */ static const device_config_t ega_config[] = { { "memory", "Memory size", CONFIG_SELECTION, "", 256, @@ -1270,22 +1276,28 @@ static const device_config_t ega_config[] = { "monitor_type","Monitor type",CONFIG_SELECTION,"",9, { { - "EGA Color, 40x25",6 + "Monochrome (5151/MDA) (white)", + 0x0b | (DISPLAY_WHITE << 4) + }, + { + "Monochrome (5151/MDA) (green)", + 0x0b | (DISPLAY_GREEN << 4) }, { - "EGA Color, 80x25",7 + "Monochrome (5151/MDA) (amber)", + 0x0b | (DISPLAY_AMBER << 4) }, { - "EGA Color, ECD",9 + "Color 40x25 (5153/CGA)", 0x06 }, { - "EGA Monochrome (white)",10 | (DISPLAY_WHITE << 4) + "Color 80x25 (5153/CGA)", 0x07 }, { - "EGA Monochrome (green)",10 | (DISPLAY_GREEN << 4) + "Enhanced Color - Normal Mode (5154/ECD)", 0x08 }, { - "EGA Monochrome (amber)",10 | (DISPLAY_AMBER << 4) + "Enhanced Color - Enhanced Mode (5154/ECD)", 0x09 }, { "" diff --git a/src/devices/video/vid_hercules.c b/src/devices/video/vid_hercules.c index 7d37690..55a6a3f 100644 --- a/src/devices/video/vid_hercules.c +++ b/src/devices/video/vid_hercules.c @@ -8,14 +8,14 @@ * * Hercules emulation. * - * Version: @(#)vid_hercules.c 1.0.11 2018/11/17 + * Version: @(#)vid_hercules.c 1.0.12 2019/02/10 * * 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 diff --git a/src/devices/video/vid_herculesplus.c b/src/devices/video/vid_herculesplus.c index 243c450..72df006 100644 --- a/src/devices/video/vid_herculesplus.c +++ b/src/devices/video/vid_herculesplus.c @@ -8,14 +8,14 @@ * * Hercules InColor emulation. * - * Version: @(#)vid_hercules_plus.c 1.0.12 2018/11/11 + * Version: @(#)vid_hercules_plus.c 1.0.13 2019/02/10 * * 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 @@ -642,7 +642,7 @@ herculesplus_init(const device_t *info) mem_map_add(&dev->mapping, 0xb0000, 0x10000, herculesplus_read,NULL,NULL, herculesplus_write,NULL,NULL, - NULL, MEM_MAPPING_EXTERNAL, dev); + dev->vram, MEM_MAPPING_EXTERNAL, dev); io_sethandler(0x03b0, 16, herculesplus_in,NULL, NULL, herculesplus_out,NULL,NULL, dev); diff --git a/src/devices/video/vid_s3.c b/src/devices/video/vid_s3.c index 4d1a095..a6f7b38 100644 --- a/src/devices/video/vid_s3.c +++ b/src/devices/video/vid_s3.c @@ -10,14 +10,14 @@ * * NOTE: ROM images need more/better organization per chipset. * - * Version: @(#)vid_s3.c 1.0.13 2018/10/08 + * Version: @(#)vid_s3.c 1.0.14 2019/02/10 * * 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 @@ -54,11 +54,15 @@ #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_sdac_ramdac.h" +#include "vid_att20c49x_ramdac.h" #include "vid_bt48x_ramdac.h" #include "vid_icd2061.h" +#include "vid_av9194.h" #define ROM_PARADISE_BAHAMAS64 L"video/s3/s3/bahamas64.bin" +#define ROM_V7MIRAGE_86C801 L"video/s3/s3/v7mirage.vbi" +#define ROM_PHOENIX_86C805 L"video/s3/s3/805.vbi" #define ROM_PHOENIX_VISION864 L"video/s3/s3/86c864p.bin" #define ROM_EXPERTCOLOR_DSV3868P_CF55 L"video/s3/s3/1-dsv3868.bin" #define ROM_DIAMOND_STEALTH64_964 L"video/s3/s3/stealth64-vram.bin" @@ -76,22 +80,20 @@ enum { S3_PHOENIX_TRIO64, S3_PHOENIX_TRIO64_ONBOARD, S3_PHOENIX_VISION864, - S3_DIAMOND_STEALTH64_764 + S3_DIAMOND_STEALTH64_764, + S3_V7MIRAGE_86C801, + S3_PHOENIX_86C805 }; enum { + S3_86C801, + S3_86C805, S3_VISION864, S3_VISION964, S3_TRIO32, S3_TRIO64 }; -static const video_timings_t timing_s3_stealth64 = {VID_BUS,2,2,4,26,26,42}; -static const video_timings_t timing_s3_vision864 = {VID_BUS,4,4,5,20,20,35}; -static const video_timings_t timing_s3_vision964 = {VID_BUS,2,2,4,20,20,35}; -static const video_timings_t timing_s3_trio32 = {VID_BUS,4,3,5,26,26,42}; -static const video_timings_t timing_s3_trio64 = {VID_BUS,3,2,4,25,25,40}; - enum { VRAM_4MB = 0, VRAM_8MB = 3, @@ -134,7 +136,6 @@ typedef struct { rom_t bios_rom; svga_t svga; - icd2061_t icd2061; uint8_t bank; uint8_t ma_ext; @@ -149,8 +150,6 @@ typedef struct { int packed_mmio; - int p86c911_compat; - uint32_t linear_base, linear_size; uint8_t pci_regs[256]; @@ -158,6 +157,7 @@ typedef struct { uint32_t vram_mask; uint8_t status_9ae8; + uint8_t data_available; struct { uint16_t subsys_cntl; @@ -224,6 +224,15 @@ typedef struct { #define INT_MASK 0xf +static const video_timings_t timing_s3_86c801 = {VID_ISA,4,4,5,20,20,35}; +static const video_timings_t timing_s3_86c805 = {VID_BUS,4,4,5,20,20,35}; +static const video_timings_t timing_s3_stealth64 = {VID_BUS,2,2,4,26,26,42}; +static const video_timings_t timing_s3_vision864 = {VID_BUS,4,4,5,20,20,35}; +static const video_timings_t timing_s3_vision964 = {VID_BUS,2,2,4,20,20,35}; +static const video_timings_t timing_s3_trio32 = {VID_BUS,4,3,5,26,26,42}; +static const video_timings_t timing_s3_trio64 = {VID_BUS,3,2,4,25,25,40}; + + void s3_updatemapping(); void s3_accel_write(uint32_t addr, uint8_t val, void *p); void s3_accel_write_w(uint32_t addr, uint16_t val, void *p); @@ -1033,7 +1042,7 @@ void s3_out(uint16_t addr, uint8_t val, void *p) case 0x3c2: if (s3->chip == S3_VISION964) { if (((val >> 2) & 3) != 3) - icd2061_write(&s3->icd2061, (val >> 2) & 3); + icd2061_write(svga->clock_gen, (val >> 2) & 3); } break; @@ -1059,18 +1068,20 @@ void s3_out(uint16_t addr, uint8_t val, void *p) case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: if ((svga->crtc[0x55] & 0x03) == 0x00) - rs2 = !!(svga->crtc[0x43] & 2); + rs2 = !!(svga->crtc[0x43] & 0x02); else rs2 = (svga->crtc[0x55] & 0x01); if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) svga_out(addr, val, svga); else if (s3->chip == S3_VISION964) { - if (!(svga->crtc[0x45] & 0x02)) + if (!(svga->crtc[0x45] & 0x20)) rs3 = !!(svga->crtc[0x55] & 0x02); else rs3 = 0; bt48x_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); - } else + } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805) + att49x_ramdac_out(addr, val, svga->ramdac, svga); + else sdac_ramdac_out(addr, rs2, val, svga->ramdac, svga); return; @@ -1082,7 +1093,14 @@ void s3_out(uint16_t addr, uint8_t val, void *p) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) val = (svga->crtc[7] & ~0x10) | (val & 0x10); - if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) return; + if ((svga->crtcreg >= 0x20) && (svga->crtcreg < 0x40) && + (svga->crtcreg != 0x36) && (svga->crtcreg != 0x38) && + (svga->crtcreg != 0x39) && ((svga->crtc[0x38] & 0xcc) != 0x48)) + return; + if ((svga->crtcreg >= 0x40) && ((svga->crtc[0x39] & 0xe0) != 0xa0)) + return; + if ((svga->crtcreg == 0x36) && (svga->crtc[0x39] != 0xa5)) + return; old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; switch (svga->crtcreg) @@ -1154,6 +1172,8 @@ void s3_out(uint16_t addr, uint8_t val, void *p) svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32) svga->hwcursor.x <<= 1; + else if ((s3->chip == S3_86C801 || s3->chip == S3_86C805) && (svga->bpp == 15 || svga->bpp == 16)) + svga->hwcursor.x >>= 1; break; case 0x4a: @@ -1195,7 +1215,7 @@ void s3_out(uint16_t addr, uint8_t val, void *p) case 0x42: if (s3->chip == S3_VISION964) { if (((svga->miscout >> 2) & 3) == 3) - icd2061_write(&s3->icd2061, svga->crtc[0x42] & 0x0f); + icd2061_write(svga->clock_gen, svga->crtc[0x42] & 0x0f); } break; @@ -1255,7 +1275,9 @@ uint8_t s3_in(uint16_t addr, void *p) else if (s3->chip == S3_VISION964) { rs3 = !!(svga->crtc[0x55] & 0x02); return bt48x_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); - } else + } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805) + return att49x_ramdac_in(addr, svga->ramdac, svga); + else return sdac_ramdac_in(addr, rs2, svga->ramdac, svga); break; @@ -1281,6 +1303,10 @@ uint8_t s3_in(uint16_t addr, void *p) return temp; case 0x69: return s3->ma_ext; case 0x6a: return s3->bank; + /* Phoenix S3 video BIOS'es seem to expect CRTC registers 6B and 6C + to be mirrors of 59 and 5A. */ + case 0x6b: return svga->crtc[0x59]; + case 0x6c: return svga->crtc[0x5a] & 0x80; } return svga->crtc[svga->crtcreg]; } @@ -1318,6 +1344,12 @@ void s3_recalctimings(svga_t *svga) svga->clock = cpuclock / svga->getclock(svga->crtc[0x42] & 0x0f, svga->clock_gen); else svga->clock = cpuclock / 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); + else + svga->clock = cpuclock / 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); @@ -1340,17 +1372,20 @@ void s3_recalctimings(svga_t *svga) break; case 15: svga->render = svga_render_15bpp_highres; - if (s3->chip != S3_VISION964) + if (s3->chip != S3_VISION964 && s3->chip != S3_86C801) svga->hdisp /= 2; break; case 16: svga->render = svga_render_16bpp_highres; - if (s3->chip != S3_VISION964) + if (s3->chip != S3_VISION964 && s3->chip != S3_86C801) svga->hdisp /= 2; break; - case 24: + case 24: svga->render = svga_render_24bpp_highres; - svga->hdisp /= 3; + if (s3->chip != S3_86C801 && s3->chip != S3_86C805) + svga->hdisp /= 3; + else + svga->hdisp = (svga->hdisp * 2) / 3; break; case 32: svga->render = svga_render_32bpp_highres; @@ -1400,8 +1435,9 @@ void s3_updatemapping(s3_t *s3) break; } - if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ + if ((svga->crtc[0x58] & 0x10) || (s3->accel.advfunc_cntl & 0x10)) { + /*Linear framebuffer*/ mem_map_disable(&svga->mapping); s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); @@ -1420,6 +1456,8 @@ void s3_updatemapping(s3_t *s3) switch (s3->chip) { case S3_TRIO32: case S3_TRIO64: + case S3_86C801: + case S3_86C805: s3->linear_size = 0x400000; break; default: @@ -1492,6 +1530,7 @@ void s3_accel_out(uint16_t port, uint8_t val, void *p) break; case 0x4ae8: s3->accel.advfunc_cntl = val; + s3_updatemapping(s3); break; } } @@ -1564,19 +1603,29 @@ uint8_t s3_accel_in(uint16_t port, void *p) case 0x9ae8: if (!s3->blitter_busy) wake_fifo_thread(s3); - if (FIFO_FULL) + if (FIFO_FULL && s3->chip != S3_86C801 && s3->chip != S3_86C805) return 0xff; /*FIFO full*/ return 0; /*FIFO empty*/ case 0x9ae9: if (!s3->blitter_busy) wake_fifo_thread(s3); temp = 0; - if (!FIFO_EMPTY) - temp |= 0x02; /*Hardware busy*/ + if (s3->chip == S3_86C801 || s3->chip == S3_86C805) + { + if (!FIFO_EMPTY) + temp |= 0x02; + if (s3->data_available) + temp |= 0x01; + } else - temp |= s3->status_9ae8; /*FIFO empty*/ - if (FIFO_FULL) - temp |= 0xf8; /*FIFO full*/ + { + if (!FIFO_EMPTY) + temp |= 0x02; /*Hardware busy*/ + else + temp |= s3->status_9ae8; /*FIFO empty*/ + if (FIFO_FULL) + temp |= 0xf8; /*FIFO full*/ + } return temp; case 0xa2e8: @@ -1828,7 +1877,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; uint32_t rd_mask = s3->accel.rd_mask; int cmd = s3->accel.cmd >> 13; - + if ((s3->chip == S3_TRIO64) && (s3->accel.cmd & (1 << 11))) cmd |= 8; @@ -1868,6 +1917,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->bpp == 0) compare &= 0xff; if (s3->bpp == 1) compare &= 0xffff; + switch (cmd) { case 1: /*Draw line*/ @@ -1883,9 +1933,12 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + s3->data_available = 0; + if ((s3->accel.cmd & 0x100) && !cpu_input) { s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + s3->data_available = 1; return; /*Wait for data from CPU*/ } @@ -2032,9 +2085,12 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + s3->data_available = 0; + if ((s3->accel.cmd & 0x100) && !cpu_input) { s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + s3->data_available = 1; return; /*Wait for data from CPU*/ } @@ -2765,16 +2821,13 @@ void s3_pci_write(int func, int addr, uint8_t val, void *p) break; case 0x12: - svga->crtc[0x5a] = val & 0x80; -#if 0 svga->crtc[0x5a] = (svga->crtc[0x5a] & 0x7f) | (val & 0x80); -#endif - s3_updatemapping(s3); + s3_updatemapping(s3); + break; + case 0x13: + svga->crtc[0x59] = val; + s3_updatemapping(s3); break; - case 0x13: - svga->crtc[0x59] = val; - s3_updatemapping(s3); - break; case 0x30: case 0x32: case 0x33: if (!s3->has_bios) @@ -2822,6 +2875,16 @@ s3_init(const device_t *info) uint32_t vram_size; switch(info->local) { + case S3_V7MIRAGE_86C801: + bios_fn = ROM_V7MIRAGE_86C801; + chip = S3_86C801; + video_inform(VID_TYPE_SPEC, &timing_s3_86c801); + break; + case S3_PHOENIX_86C805: + bios_fn = ROM_PHOENIX_86C805; + chip = S3_86C805; + video_inform(VID_TYPE_SPEC, &timing_s3_86c805); + break; case S3_PARADISE_BAHAMAS64: bios_fn = ROM_PARADISE_BAHAMAS64; chip = S3_VISION864; @@ -2909,38 +2972,42 @@ s3_init(const device_t *info) s3_hwcursor_draw, NULL); - switch (vram) { - case 0: /* 512 kB */ - svga->vram_mask = (1 << 19) - 1; - svga->vram_max = 2 << 20; - break; - case 1: /* 1 MB */ - /* VRAM in first MB, mirrored in 2nd MB, 3rd and 4th MBs are open bus. - This works with the #9 9FX BIOS, and matches how my real Trio64 behaves, - but does not work with the Phoenix EDO BIOS. Possibly an FPM/EDO difference? */ - svga->vram_mask = (1 << 20) - 1; - svga->vram_max = 2 << 20; - break; - case 2: - default: /*2 MB */ - /* VRAM in first 2 MB, 3rd and 4th MBs are open bus. */ - svga->vram_mask = (2 << 20) - 1; - svga->vram_max = 2 << 20; - break; - case 4: /*4MB*/ - svga->vram_mask = (4 << 20) - 1; - svga->vram_max = 4 << 20; - break; - case 8: /*8MB*/ - svga->vram_mask = (8 << 20) - 1; - svga->vram_max = 8 << 20; - break; + if (s3->chip != S3_86C801 && s3->chip != S3_86C805) { + switch (vram) { + case 0: /* 512 kB */ + svga->vram_mask = (1 << 19) - 1; + svga->vram_max = 2 << 20; + break; + case 1: /* 1 MB */ + /* VRAM in first MB, mirrored in 2nd MB, 3rd and 4th MBs are open bus. + This works with the #9 9FX BIOS, and matches how my real Trio64 behaves, + but does not work with the Phoenix EDO BIOS. Possibly an FPM/EDO difference? */ + svga->vram_mask = (1 << 20) - 1; + svga->vram_max = 2 << 20; + break; + case 2: + default: /*2 MB */ + /* VRAM in first 2 MB, 3rd and 4th MBs are open bus. */ + svga->vram_mask = (2 << 20) - 1; + svga->vram_max = 2 << 20; + break; + case 4: /*4MB*/ + svga->vram_mask = (4 << 20) - 1; + svga->vram_max = 4 << 20; + break; + case 8: /*8MB*/ + svga->vram_mask = (8 << 20) - 1; + svga->vram_max = 8 << 20; + break; + } } if (info->flags & DEVICE_PCI) svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); - else + else if (info->flags & DEVICE_VLB) svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + else + svga->crtc[0x36] = 3 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); svga->crtc[0x37] = 1 | (7 << 5); svga->vblank_start = s3_vblank_start; @@ -2965,6 +3032,34 @@ s3_init(const device_t *info) s3->int_line = 0; switch(info->local) { + case S3_V7MIRAGE_86C801: + svga->decode_mask = (2 << 20) - 1; + stepping = 0xa0; /*86C801/86C805*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + + svga->ramdac = device_add(&att490_ramdac_device); + svga->clock_gen = device_add(&av9194_device); + svga->getclock = av9194_getclock; + break; + + case S3_PHOENIX_86C805: + svga->decode_mask = (2 << 20) - 1; + stepping = 0xa0; /*86C801/86C805*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + + svga->ramdac = device_add(&att492_ramdac_device); + svga->clock_gen = device_add(&av9194_device); + svga->getclock = av9194_getclock; + break; + case S3_PARADISE_BAHAMAS64: case S3_PHOENIX_VISION864: svga->decode_mask = (8 << 20) - 1; @@ -3029,6 +3124,17 @@ s3_init(const device_t *info) return s3; } + +static int s3_v7mirage_86c801_available(void) +{ + return rom_present(ROM_V7MIRAGE_86C801); +} + +static int s3_phoenix_86c805_available(void) +{ + return rom_present(ROM_PHOENIX_86C805); +} + static int s3_bahamas64_available(void) { return rom_present(ROM_PARADISE_BAHAMAS64); @@ -3186,6 +3292,30 @@ static const device_config_t s3_config[] = }; +const device_t s3_v7mirage_86c801_isa_device = { + "SPEA V7 Mirage (S3 86c801) ISA", + DEVICE_AT | DEVICE_ISA, + S3_V7MIRAGE_86C801, + s3_init, s3_close, NULL, + s3_v7mirage_86c801_available, + s3_speed_changed, + s3_force_redraw, + NULL, + s3_9fx_config +}; + +const device_t s3_phoenix_86c805_vlb_device = { + "Phoenix S3 86c805 VLB", + DEVICE_VLB, + S3_PHOENIX_86C805, + s3_init, s3_close, NULL, + s3_phoenix_86c805_available, + s3_speed_changed, + s3_force_redraw, + NULL, + s3_9fx_config +}; + const device_t s3_bahamas64_vlb_device = { "Paradise Bahamas 64 (S3 Vision864)", DEVICE_VLB, diff --git a/src/devices/video/vid_s3_virge.c b/src/devices/video/vid_s3_virge.c index 86c4a28..51eafb3 100644 --- a/src/devices/video/vid_s3_virge.c +++ b/src/devices/video/vid_s3_virge.c @@ -8,14 +8,14 @@ * * S3 ViRGE emulation. * - * Version: @(#)vid_s3_virge.c 1.0.14 2018/10/26 + * Version: @(#)vid_s3_virge.c 1.0.15 2019/02/10 * * 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 @@ -2984,7 +2984,7 @@ static void dest_pixel_lit_texture_modulate(s3d_state_t *state) static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) { svga_t *svga = &virge->svga; - uint8_t *vram = virge->svga.vram; + uint8_t *vram = svga->vram; int x_dir = s3d_tri->tlr ? 1 : -1; @@ -3039,7 +3039,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 y_count -= diff_y; } if ((state->y - y_count) < s3d_tri->clip_t) - y_count = state->y - s3d_tri->clip_t; + y_count = (state->y - s3d_tri->clip_t) + 1; } dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str); @@ -3082,7 +3082,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 if (xe < s3d_tri->clip_l) goto tri_skip_line; if (xe > s3d_tri->clip_r) - xe = s3d_tri->clip_r; + xe = s3d_tri->clip_r + 1; if (x < s3d_tri->clip_l) { int diff_x = s3d_tri->clip_l - x; @@ -3107,7 +3107,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 if (xe > s3d_tri->clip_r) goto tri_skip_line; if (xe < s3d_tri->clip_l) - xe = s3d_tri->clip_l; + xe = s3d_tri->clip_l - 1; if (x > s3d_tri->clip_r) { int diff_x = x - s3d_tri->clip_r; @@ -3132,6 +3132,9 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 dest_addr = dest_offset + (x * (bpp + 1)); z_addr = z_offset + (x << 1); + x &= 0xfff; + xe &= 0xfff; + for (; x != xe; x = (x + x_dir) & 0xfff) { update = 1; diff --git a/src/devices/video/vid_tgui9440.c b/src/devices/video/vid_tgui9440.c index 8a87024..d2e966c 100644 --- a/src/devices/video/vid_tgui9440.c +++ b/src/devices/video/vid_tgui9440.c @@ -47,14 +47,14 @@ * access size or host data has any affect, but the Windows 3.1 * driver always reads bytes and write words of 0xffff. * - * Version: @(#)vid_tgui9440.c 1.0.10 2018/10/08 + * Version: @(#)vid_tgui9440.c 1.0.11 2019/02/10 * * 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 @@ -281,7 +281,7 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) break; case 0xC: if (svga->seqregs[0xe] & 0x80) - svga->seqregs[0xc] = val; + svga->seqregs[0xc] = val; break; case 0xd: if (tgui->oldmode) @@ -541,15 +541,6 @@ void tgui_recalctimings(svga_t *svga) if (svga->interlace && tgui->type < TGUI_9440) svga->rowoffset >>= 1; - if (svga->crtc[0x17] & 4) - { - svga->vtotal *= 2; - svga->dispend *= 2; - svga->vsyncstart *= 2; - svga->split *= 2; - svga->vblankstart *= 2; - } - if (tgui->type >= TGUI_9440) { if (svga->miscout & 8) diff --git a/src/devices/video/vid_tvga.c b/src/devices/video/vid_tvga.c index 8326414..195bdfd 100644 --- a/src/devices/video/vid_tvga.c +++ b/src/devices/video/vid_tvga.c @@ -6,16 +6,16 @@ * * This file is part of the VARCem Project. * - * Trident TVGA (8900C/8900D) emulation. + * Trident TVGA (8900B/8900C/8900D) emulation. * - * Version: @(#)vid_tvga.c 1.0.10 2018/11/20 + * Version: @(#)vid_tvga.c 1.0.11 2019/02/10 * * 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 @@ -52,8 +52,13 @@ #include "vid_tkd8001_ramdac.h" -#define ROM_T8900CX_BIOS L"video/trident/8916cx2/bios.bin" -#define ROM_T8900D_BIOS L"video/trident/tvga/trident.bin" +#define ROM_TVGA_8900B L"video/trident/tvga/tvga8900b.vbi" +#define ROM_TVGA_8900CLD L"video/trident/tvga/trident.bin" +#define ROM_TVGA_8900CX L"video/trident/8916cx2/bios.bin" +#define ROM_TVGA_8900D L"video/trident/tvga/trident.bin" + +#define TVGA8900B_ID 0x03 +#define TVGA8900CLD_ID 0x33 typedef struct { @@ -63,6 +68,7 @@ typedef struct { svga_t svga; rom_t bios_rom; + uint8_t card_id; uint8_t tvga_3d8, tvga_3d9; int oldmode; @@ -214,7 +220,7 @@ tvga_in(uint16_t addr, void *priv) case 0x3c5: if ((svga->seqaddr & 0x0f) == 0x0b) { tvga->oldmode = 0; - return 0x33; /*TVGA8900D*/ + return tvga->card_id; /*Must be at least a TVGA8900*/ } if ((svga->seqaddr & 0x0f) == 0x0d) { if (tvga->oldmode) @@ -292,6 +298,7 @@ tvga_recalctimings(svga_t *svga) svga->rowoffset <<= 1; svga->ma_latch <<= 1; } + if (svga->gdcreg[0xf] & 0x08) { svga->htotal *= 2; svga->hdisp *= 2; @@ -315,7 +322,7 @@ tvga_recalctimings(svga_t *svga) if (tvga->oldctrl2 & 0x10) { switch (svga->bpp) { case 8: - svga->render = svga_render_8bpp_highres; + svga->render = svga_render_8bpp_highres; break; case 15: @@ -341,9 +348,12 @@ tvga_recalctimings(svga_t *svga) static void * tvga_init(const device_t *info) { - tvga_t *tvga = (tvga_t *)mem_alloc(sizeof(tvga_t)); - memset(tvga, 0x00, sizeof(tvga_t)); const wchar_t *fn = NULL; + tvga_t *tvga; + + tvga = (tvga_t *)mem_alloc(sizeof(tvga_t)); + memset(tvga, 0x00, sizeof(tvga_t)); + tvga->card_id = info->local; tvga->vram_size = device_get_config_int("memory") << 10; tvga->vram_mask = tvga->vram_size - 1; @@ -352,15 +362,22 @@ tvga_init(const device_t *info) tvga_recalctimings, tvga_in, tvga_out, NULL, NULL); switch(info->local) { - case 0: /* TVGA 8900CX LC2 */ - fn = ROM_T8900CX_BIOS; + case TVGA8900B_ID: /* TVGA 8900B */ + fn = ROM_TVGA_8900B; tvga->svga.ramdac = device_add(&tkd8001_ramdac_device); break; - case 1: /* TVGA 8900D */ - fn = ROM_T8900D_BIOS; + case TVGA8900CLD_ID: /* TVGA 8900CX LC2 */ + fn = ROM_TVGA_8900CLD; tvga->svga.ramdac = device_add(&tkd8001_ramdac_device); break; + +#if 0 + case 1: /* TVGA 8900D */ + fn = ROM_TVGA_8900D; + tvga->svga.ramdac = device_add(&tkd8001_ramdac_device); + break; +#endif } if (fn != NULL) @@ -407,16 +424,21 @@ tvga_force_redraw(void *p) static int -tvga8900c_available(void) +tvga8900b_available(void) { - return rom_present(ROM_T8900CX_BIOS); + return rom_present(ROM_TVGA_8900B); } +static int +tvga8900cx_available(void) +{ + return rom_present(ROM_TVGA_8900CLD); +} static int tvga8900d_available(void) { - return rom_present(ROM_T8900D_BIOS); + return rom_present(ROM_TVGA_8900D); } @@ -448,12 +470,24 @@ static const device_config_t tvga_config[] = static const video_timings_t tvga8900_timing = {VID_ISA,3,3,6,8,8,12}; +const device_t tvga8900b_device = { + "Trident TVGA 8900B", + DEVICE_ISA, + TVGA8900B_ID, + tvga_init, tvga_close, NULL, + tvga8900b_available, + tvga_speed_changed, + tvga_force_redraw, + &tvga8900_timing, + tvga_config +}; + const device_t tvga8900cx_device = { "Trident TVGA 8900CX 2/4/8 LC2 Rev.A", DEVICE_ISA, - 0, + TVGA8900CLD_ID, tvga_init, tvga_close, NULL, - tvga8900c_available, + tvga8900cx_available, tvga_speed_changed, tvga_force_redraw, &tvga8900_timing, diff --git a/src/devices/video/video.h b/src/devices/video/video.h index 4a71289..ec4d798 100644 --- a/src/devices/video/video.h +++ b/src/devices/video/video.h @@ -8,7 +8,7 @@ * * Definitions for the video controller module. * - * Version: @(#)video.h 1.0.24 2019/01/08 + * Version: @(#)video.h 1.0.25 2019/02/10 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -248,6 +248,8 @@ extern const device_t paradise_wd90c11_device; extern const device_t paradise_wd90c30_device; /* S3, Inc standard series cards. */ +extern const device_t s3_v7mirage_86c801_isa_device; +extern const device_t s3_phoenix_86c805_vlb_device; extern const device_t s3_bahamas64_vlb_device; extern const device_t s3_bahamas64_pci_device; extern const device_t s3_9fx_vlb_device; @@ -278,6 +280,7 @@ extern const device_t s3_virge_375_4_pci_device; extern const device_t sigma_device; /* Trident 8900 series cards. */ +extern const device_t tvga8900b_device; extern const device_t tvga8900cx_device; extern const device_t tvga8900d_device; diff --git a/src/devices/video/video_dev.c b/src/devices/video/video_dev.c index 41581e2..004915c 100644 --- a/src/devices/video/video_dev.c +++ b/src/devices/video/video_dev.c @@ -12,13 +12,13 @@ * "extern" reference to its device into the video.h file, * and add an entry for it into the table here. * - * Version: @(#)video_dev.c 1.0.29 2019/01/08 + * Version: @(#)video_dev.c 1.0.30 2019/02/10 * * 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 @@ -73,6 +73,9 @@ static const struct { { "hercules", &hercules_device }, { "mach64gx_isa", &mach64gx_isa_device }, +#if 0 + { "mach8_isa", &mach8_device }, +#endif { "ati28800k", &ati28800k_device }, { "ati18800v", &ati18800_vga88_device }, { "ati28800", &ati28800_device }, @@ -104,12 +107,14 @@ static const struct { { "oti077", &oti077_device }, { "pvga1a", ¶dise_pvga1a_device }, { "sigma400", &sigma_device }, + { "px_s3_v7_801_isa", &s3_v7mirage_86c801_isa_device }, { "wd90c11", ¶dise_wd90c11_device }, { "wd90c30", ¶dise_wd90c30_device }, { "plantronics", &colorplus_device }, #if defined(DEV_BRANCH) && defined(USE_TI) { "ti_cf62011", &ti_cf62011_device }, #endif + { "tvga8900b", &tvga8900b_device }, { "tvga8900cx", &tvga8900cx_device }, { "tvga8900d", &tvga8900d_device }, { "et4000ax", &et4000_isa_device }, @@ -147,6 +152,7 @@ static const struct { #if defined(DEV_BRANCH) { "cl_gd5424_vlb", &gd5424_vlb_device }, #endif + { "cl_gd5428_vlb", &gd5428_vlb_device }, { "cl_gd5429_vlb", &gd5429_vlb_device }, { "cl_gd5434_vlb", &gd5434_vlb_device }, { "stealth32_vlb", &et4000w32p_vlb_device }, @@ -158,6 +164,7 @@ static const struct { { "stealth64v_vlb", &s3_diamond_stealth64_964_vlb_device}, { "n9_9fx_vlb", &s3_9fx_vlb_device }, { "bahamas64_vlb", &s3_bahamas64_vlb_device }, + { "px_86c805_vlb", &s3_phoenix_86c805_vlb_device }, { "px_vision864_vlb", &s3_phoenix_vision864_vlb_device}, { "px_trio32_vlb", &s3_phoenix_trio32_vlb_device }, { "px_trio64_vlb", &s3_phoenix_trio64_vlb_device }, diff --git a/src/machines/m_at_commodore.c b/src/machines/m_at_commodore.c index 1632c4a..858be42 100644 --- a/src/machines/m_at_commodore.c +++ b/src/machines/m_at_commodore.c @@ -8,14 +8,14 @@ * * Implementation of the Commodore PC3 system. * - * Version: @(#)m_at_commodore.c 1.0.10 2018/11/11 + * Version: @(#)m_at_commodore.c 1.0.11 2019/02/10 * * 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 diff --git a/src/mem.c b/src/mem.c index a683e67..3e9f78d 100644 --- a/src/mem.c +++ b/src/mem.c @@ -8,14 +8,14 @@ * * Memory handling and MMU. * - * Version: @(#)mem.c 1.0.25 2018/10/18 + * Version: @(#)mem.c 1.0.26 2019/02/10 * * 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 @@ -442,10 +442,12 @@ getpccache(uint32_t a) a &= rammask; if (_mem_exec[a >> 14]) { - if (_mem_map_r[a >> 14]->flags & MEM_MAPPING_ROM) - cpu_prefetch_cycles = cpu_rom_prefetch_cycles; - else - cpu_prefetch_cycles = cpu_mem_prefetch_cycles; + if (is286) { + if (_mem_map_r[a >> 14]->flags & MEM_MAPPING_ROM) + cpu_prefetch_cycles = cpu_rom_prefetch_cycles; + else + cpu_prefetch_cycles = cpu_mem_prefetch_cycles; + } return &_mem_exec[a >> 14][(uintptr_t)(a & 0x3000) - (uintptr_t)(a2 & ~0xfff)]; } @@ -934,22 +936,6 @@ writememql(uint32_t seg, uint32_t addr, uint64_t val) uint8_t mem_readb_phys(uint32_t addr) -{ - mem_logical_addr = 0xffffffff; - - if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); - - return 0xff; -} - - -/* - * Version of mem_readby_phys that doesn't go through - * the CPU paging mechanism. - */ -uint8_t -mem_readb_phys_dma(uint32_t addr) { if (_mem_exec[addr >> 14]) return _mem_exec[addr >> 14][addr & 0x3fff]; @@ -963,31 +949,23 @@ mem_readb_phys_dma(uint32_t addr) uint16_t mem_readw_phys(uint32_t addr) { - mem_logical_addr = 0xffffffff; + uint16_t temp; - if (_mem_read_w[addr >> 14]) - return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]); + if (_mem_exec[addr >> 14]) + return ((uint16_t *) _mem_exec[addr >> 14])[(addr >> 1) & 0x1fff]; + else if (_mem_read_w[addr >> 14]) + return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]); + else { + temp = mem_readb_phys(addr + 1) << 8; + temp |= mem_readb_phys(addr); + } - return 0xff; + return temp; } void mem_writeb_phys(uint32_t addr, uint8_t val) -{ - mem_logical_addr = 0xffffffff; - - if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); -} - - -/* - * Version of mem_readby_phys that doesn't go through - * the CPU paging mechanism. - */ -void -mem_writeb_phys_dma(uint32_t addr, uint8_t val) { if (_mem_exec[addr >> 14]) _mem_exec[addr >> 14][addr & 0x3fff] = val; @@ -996,16 +974,6 @@ mem_writeb_phys_dma(uint32_t addr, uint8_t val) } -void -mem_writew_phys(uint32_t addr, uint16_t val) -{ - mem_logical_addr = 0xffffffff; - - if (_mem_write_w[addr >> 14]) - _mem_write_w[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); -} - - uint8_t mem_read_ram(uint32_t addr, void *priv) { diff --git a/src/mem.h b/src/mem.h index 4112cba..c01297c 100644 --- a/src/mem.h +++ b/src/mem.h @@ -8,12 +8,12 @@ * * Definitions for the memory interface. * - * Version: @(#)mem.h 1.0.11 2018/10/07 + * Version: @(#)mem.h 1.0.12 2019/02/10 * * Authors: Fred N. van Kempen, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * Copyright 2008-2018 Sarah Walker. * * This program is free software; you can redistribute it and/or modify @@ -134,7 +134,6 @@ extern uint32_t get_phys_virt,get_phys_phys; extern int shadowbios, shadowbios_write; -extern int nopageerrors; extern int memspeed[11]; extern int mmu_perm; @@ -210,11 +209,8 @@ extern void mem_map_enable(mem_map_t *); extern void mem_set_mem_state(uint32_t base, uint32_t size, int state); extern uint8_t mem_readb_phys(uint32_t addr); -extern uint8_t mem_readb_phys_dma(uint32_t addr); extern uint16_t mem_readw_phys(uint32_t addr); extern void mem_writeb_phys(uint32_t addr, uint8_t val); -extern void mem_writeb_phys_dma(uint32_t addr, uint8_t val); -extern void mem_writew_phys(uint32_t addr, uint16_t val); extern uint8_t mem_read_ram(uint32_t addr, void *priv); extern uint16_t mem_read_ramw(uint32_t addr, void *priv); diff --git a/src/ui/ui_new_image.c b/src/ui/ui_new_image.c index bf7d0a1..37bf82a 100644 --- a/src/ui/ui_new_image.c +++ b/src/ui/ui_new_image.c @@ -12,13 +12,13 @@ * format handlers, and re-integrated with that code. This is * just the wrong place for it.. * - * Version: @(#)ui_new_image.c 1.0.5 2018/10/26 + * Version: @(#)ui_new_image.c 1.0.6 2019/02/10 * * Authors: Fred N. van Kempen, * Miran Grca, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2018 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. + * Copyright 2018,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 @@ -96,7 +96,7 @@ floppy_create_86f(const wchar_t *fn, int8_t ds, int8_t rpm_mode) FILE *f; uint32_t magic = 0x46423638; - uint16_t version = 0x020B; + uint16_t version = 0x020C; uint16_t dflags = 0; uint16_t tflags = 0; uint32_t index_hole_pos = 0; diff --git a/src/win/mingw/Makefile.MinGW b/src/win/mingw/Makefile.MinGW index 14bc63a..db8c061 100644 --- a/src/win/mingw/Makefile.MinGW +++ b/src/win/mingw/Makefile.MinGW @@ -8,11 +8,11 @@ # # Makefile for Windows systems using the MinGW32 environment. # -# Version: @(#)Makefile.mingw 1.0.72 2019/01/13 +# Version: @(#)Makefile.mingw 1.0.74 2019/02/10 # # Author: Fred N. van Kempen, # -# Copyright 2017-2018 Fred N. van Kempen. +# Copyright 2017-2019 Fred N. van Kempen. # # Redistribution and use in source and binary forms, with # or without modification, are permitted provided that the @@ -657,7 +657,7 @@ FDDOBJ := fdc.o \ fdd.o \ fdd_common.o fdd_86f.o \ fdd_fdi.o fdi2raw.o lzf_c.o lzf_d.o \ - fdd_imd.o fdd_img.o fdd_json.o fdd_td0.o + fdd_imd.o fdd_img.o fdd_json.o fdd_mfm.o fdd_td0.o HDDOBJ := hdd.o \ hdd_image.o hdd_table.o \ @@ -726,7 +726,8 @@ VIDOBJ := video.o \ vid_ati_eeprom.o \ vid_ati18800.o vid_ati28800.o \ vid_ati_mach64.o vid_ati68860_ramdac.o \ - vid_bt48x_ramdac.o vid_icd2061.o vid_ics2595.o \ + vid_att20c49x_ramdac.o vid_bt48x_ramdac.o \ + vid_av9194.o vid_icd2061.o vid_ics2595.o \ vid_cl54xx.o \ vid_et4000.o vid_sc1502x_ramdac.o \ vid_et4000w32.o vid_stg_ramdac.o \ diff --git a/src/win/msvc/Makefile.VC b/src/win/msvc/Makefile.VC index 0a8a0bb..b35c7a9 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.58 2019/01/13 +# Version: @(#)Makefile.VC 1.0.60 2019/02/10 # # Author: Fred N. van Kempen, # @@ -631,7 +631,8 @@ FDDOBJ := fdc.obj \ fdd.obj \ fdd_common.obj fdd_86f.obj \ fdd_fdi.obj fdi2raw.obj lzf_c.obj lzf_d.obj \ - fdd_imd.obj fdd_img.obj fdd_json.obj fdd_td0.obj + fdd_imd.obj fdd_img.obj fdd_json.obj fdd_mfm.obj \ + fdd_td0.obj HDDOBJ := hdd.obj \ hdd_image.obj hdd_table.obj \ @@ -701,7 +702,8 @@ VIDOBJ := video.obj \ vid_ati_eeprom.obj \ vid_ati18800.obj vid_ati28800.obj \ vid_ati_mach64.obj vid_ati68860_ramdac.obj \ - vid_bt48x_ramdac.obj vid_icd2061.obj vid_ics2595.obj \ + vid_att20c49x_ramdac.obj vid_bt48x_ramdac.obj \ + vid_av9194.obj vid_icd2061.obj vid_ics2595.obj \ vid_cl54xx.obj \ vid_et4000.obj vid_sc1502x_ramdac.obj \ vid_et4000w32.obj vid_stg_ramdac.obj \