2017-10-11 05:40:44 -04:00
|
|
|
/*
|
2023-01-06 15:36:05 -05:00
|
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
|
|
|
* running old operating systems and software designed for IBM
|
|
|
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
|
|
|
* system designs based on the PCI bus.
|
2017-10-11 05:40:44 -04:00
|
|
|
*
|
2023-01-06 15:36:05 -05:00
|
|
|
* This file is part of the 86Box distribution.
|
2017-10-11 05:40:44 -04:00
|
|
|
*
|
2023-01-06 15:36:05 -05:00
|
|
|
* Oak OTI037C/67/077 emulation.
|
2017-10-11 05:40:44 -04:00
|
|
|
*
|
2020-03-25 00:46:02 +02:00
|
|
|
*
|
2017-10-11 05:40:44 -04:00
|
|
|
*
|
2023-01-06 15:36:29 -05:00
|
|
|
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
|
2023-01-06 15:36:05 -05:00
|
|
|
* Miran Grca, <mgrca8@gmail.com>
|
2017-10-11 05:40:44 -04:00
|
|
|
*
|
2023-01-06 15:36:05 -05:00
|
|
|
* Copyright 2008-2018 Sarah Walker.
|
|
|
|
|
* Copyright 2016-2018 Miran Grca.
|
2017-10-11 05:40:44 -04:00
|
|
|
*/
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <stdint.h>
|
2016-06-26 00:34:39 +02:00
|
|
|
#include <stdlib.h>
|
2018-10-02 22:54:28 +02:00
|
|
|
#include <string.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <wchar.h>
|
2020-03-29 14:24:42 +02:00
|
|
|
#include <86box/86box.h>
|
|
|
|
|
#include <86box/io.h>
|
|
|
|
|
#include <86box/timer.h>
|
|
|
|
|
#include <86box/mem.h>
|
|
|
|
|
#include <86box/rom.h>
|
|
|
|
|
#include <86box/device.h>
|
|
|
|
|
#include <86box/video.h>
|
|
|
|
|
#include <86box/vid_svga.h>
|
2021-10-24 19:06:05 +02:00
|
|
|
#include <86box/vid_svga_render.h>
|
2023-06-09 23:46:54 -04:00
|
|
|
#include <86box/plat_unused.h>
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2022-08-31 19:19:29 -04:00
|
|
|
#define BIOS_037C_PATH "roms/video/oti/bios.bin"
|
|
|
|
|
#define BIOS_067_AMA932J_PATH "roms/machines/ama932j/OTI067.BIN"
|
|
|
|
|
#define BIOS_067_M300_08_PATH "roms/machines/m30008/EVC_BIOS.ROM"
|
|
|
|
|
#define BIOS_067_M300_15_PATH "roms/machines/m30015/EVC_BIOS.ROM"
|
|
|
|
|
#define BIOS_077_PATH "roms/video/oti/oti077.vbi"
|
2017-11-01 01:51:19 -05:00
|
|
|
|
2018-10-08 00:22:40 +02:00
|
|
|
enum {
|
2023-08-21 20:25:05 -04:00
|
|
|
OTI_037C = 0,
|
|
|
|
|
OTI_067 = 2,
|
|
|
|
|
OTI_067_AMA932J = 3,
|
|
|
|
|
OTI_067_M300 = 4,
|
|
|
|
|
OTI_077 = 5
|
2018-10-08 00:22:40 +02:00
|
|
|
};
|
|
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
typedef struct {
|
|
|
|
|
svga_t svga;
|
|
|
|
|
|
|
|
|
|
rom_t bios_rom;
|
|
|
|
|
|
2022-08-31 19:19:29 -04:00
|
|
|
int index;
|
2017-10-11 05:40:44 -04:00
|
|
|
uint8_t regs[32];
|
|
|
|
|
|
2018-10-08 00:22:40 +02:00
|
|
|
uint8_t chip_id;
|
2017-10-11 05:40:44 -04:00
|
|
|
uint8_t pos;
|
2018-10-08 00:22:40 +02:00
|
|
|
uint8_t enable_register;
|
|
|
|
|
uint8_t dipswitch_val;
|
2022-02-20 02:26:27 -05:00
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
uint32_t vram_size;
|
|
|
|
|
uint32_t vram_mask;
|
|
|
|
|
} oti_t;
|
|
|
|
|
|
2022-08-31 19:19:29 -04:00
|
|
|
static video_timings_t timing_oti = { .type = VIDEO_ISA, .write_b = 6, .write_w = 8, .write_l = 16, .read_b = 6, .read_w = 8, .read_l = 16 };
|
2017-10-11 05:40:44 -04:00
|
|
|
|
|
|
|
|
static void
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_out(uint16_t addr, uint8_t val, void *priv)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_t *oti = (oti_t *) priv;
|
2017-10-11 05:40:44 -04:00
|
|
|
svga_t *svga = &oti->svga;
|
|
|
|
|
uint8_t old;
|
2023-06-01 18:32:25 -04:00
|
|
|
uint8_t idx;
|
|
|
|
|
uint8_t enable;
|
2018-10-08 00:22:40 +02:00
|
|
|
|
|
|
|
|
if (!oti->chip_id && !(oti->enable_register & 1) && (addr != 0x3C3))
|
2022-08-31 19:19:29 -04:00
|
|
|
return;
|
2017-10-11 05:40:44 -04:00
|
|
|
|
2022-08-31 19:19:29 -04:00
|
|
|
if ((((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1))
|
|
|
|
|
addr ^= 0x60;
|
2017-10-11 05:40:44 -04:00
|
|
|
|
|
|
|
|
switch (addr) {
|
2022-08-31 19:19:29 -04:00
|
|
|
case 0x3C3:
|
|
|
|
|
if (!oti->chip_id) {
|
|
|
|
|
oti->enable_register = val & 1;
|
|
|
|
|
return;
|
Video changes:
1. The passthrough from VGA to 8514/A and/or 8514/A to VGA no longer relies on hackish places where to switch from/to, instead, relying on port 0x3c3 of VGA doing so (though the Mach8/32 still needs some places where to manually switch from/to, mainly the MCA one when configuring the EEPROM).
2. Implemented the MCA behalf of the Mach32 and its corresponding reset function.
3. Properly implemented (more or less) true color, including 24-bit BGR rendering
4. Other fixes such as color patterns and mono patterns being more correct than before in various operating systems and in 24-bit true color.
5. Implemented the onboard Mach32 video of the IBM PS/ValuePoint P60 machine.
6. Made the onboard internal video detect when it's 8514/A compatible or not (CGA/EGA/MDA/VGA/etc.). If the former is selected, then the video monitor flag is used instead (for QT).
7. The TGUI9400 and 9440, if on VLB, now detect the right amount of memory if on 2MB.
8. Initial implementation of the ATI 68875 ramdac used by the Mach32 and made the ATI 68860 8514/A aware when selected with the Mach32AX PCI.
9. Separated the 8514/A ramdac ports from the VGA ramdac ports, allowing seamless transition from/to 8514/A/VGA.
10. Fixed a hdisp problem in the ET4000/W32 cards, where it was doubling the horizontal display in 15bpp+ graphics mode.
11. Removed the 0x3da/0x3ba port hack that was on the Mach8/32 code, relying on the (S)VGA core instead.
12. Reworked and simplified the TGUI9440 pitch register based on logging due to no documentation at all.
2023-08-12 00:00:46 +02:00
|
|
|
}
|
|
|
|
|
svga_out(addr, val, svga);
|
|
|
|
|
return;
|
2022-08-31 19:19:29 -04:00
|
|
|
|
|
|
|
|
case 0x3c6:
|
|
|
|
|
case 0x3c7:
|
|
|
|
|
case 0x3c8:
|
|
|
|
|
case 0x3c9:
|
|
|
|
|
if (oti->chip_id == OTI_077)
|
|
|
|
|
sc1148x_ramdac_out(addr, 0, val, svga->ramdac, svga);
|
|
|
|
|
else
|
|
|
|
|
svga_out(addr, val, svga);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 0x3D4:
|
|
|
|
|
if (oti->chip_id)
|
|
|
|
|
svga->crtcreg = val & 0x3f;
|
|
|
|
|
else
|
|
|
|
|
svga->crtcreg = val; /* FIXME: The BIOS wants to set the test bit? */
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 0x3D5:
|
|
|
|
|
if (oti->chip_id && (svga->crtcreg & 0x20))
|
|
|
|
|
return;
|
|
|
|
|
idx = svga->crtcreg;
|
|
|
|
|
if (!oti->chip_id)
|
|
|
|
|
idx &= 0x1f;
|
|
|
|
|
if ((idx < 7) && (svga->crtc[0x11] & 0x80))
|
|
|
|
|
return;
|
|
|
|
|
if ((idx == 7) && (svga->crtc[0x11] & 0x80))
|
|
|
|
|
val = (svga->crtc[7] & ~0x10) | (val & 0x10);
|
|
|
|
|
old = svga->crtc[idx];
|
|
|
|
|
svga->crtc[idx] = val;
|
|
|
|
|
if (old != val) {
|
|
|
|
|
if ((idx < 0x0e) || (idx > 0x10)) {
|
|
|
|
|
if (idx == 0x0c || idx == 0x0d) {
|
|
|
|
|
svga->fullchange = 3;
|
|
|
|
|
svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5);
|
|
|
|
|
} else {
|
|
|
|
|
svga->fullchange = changeframecount;
|
|
|
|
|
svga_recalctimings(svga);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x3DE:
|
|
|
|
|
if (oti->chip_id)
|
|
|
|
|
oti->index = val & 0x1f;
|
|
|
|
|
else
|
|
|
|
|
oti->index = val;
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 0x3DF:
|
|
|
|
|
idx = oti->index;
|
|
|
|
|
if (!oti->chip_id)
|
|
|
|
|
idx &= 0x1f;
|
|
|
|
|
oti->regs[idx] = val;
|
|
|
|
|
switch (idx) {
|
|
|
|
|
case 0xD:
|
|
|
|
|
if (oti->chip_id == OTI_067) {
|
|
|
|
|
svga->vram_display_mask = (val & 0x0c) ? oti->vram_mask : 0x3ffff;
|
|
|
|
|
if (!(val & 0x80))
|
|
|
|
|
svga->vram_display_mask = 0x3ffff;
|
|
|
|
|
|
|
|
|
|
if ((val & 0x80) && oti->vram_size == 256)
|
|
|
|
|
mem_mapping_disable(&svga->mapping);
|
|
|
|
|
else
|
|
|
|
|
mem_mapping_enable(&svga->mapping);
|
|
|
|
|
} else if (oti->chip_id == OTI_077) {
|
|
|
|
|
svga->vram_display_mask = (val & 0x0c) ? oti->vram_mask : 0x3ffff;
|
|
|
|
|
|
|
|
|
|
switch ((val & 0xc0) >> 6) {
|
|
|
|
|
default:
|
2023-08-21 20:25:05 -04:00
|
|
|
case 0x00: /* 256 kB of memory */
|
2022-08-31 19:19:29 -04:00
|
|
|
enable = (oti->vram_size >= 256);
|
|
|
|
|
if (val & 0x0c)
|
|
|
|
|
svga->vram_display_mask = MIN(oti->vram_mask, 0x3ffff);
|
|
|
|
|
break;
|
|
|
|
|
case 0x01: /* 1 MB of memory */
|
|
|
|
|
case 0x03:
|
|
|
|
|
enable = (oti->vram_size >= 1024);
|
|
|
|
|
if (val & 0x0c)
|
|
|
|
|
svga->vram_display_mask = MIN(oti->vram_mask, 0xfffff);
|
|
|
|
|
break;
|
|
|
|
|
case 0x02: /* 512 kB of memory */
|
|
|
|
|
enable = (oti->vram_size >= 512);
|
|
|
|
|
if (val & 0x0c)
|
|
|
|
|
svga->vram_display_mask = MIN(oti->vram_mask, 0x7ffff);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (enable)
|
|
|
|
|
mem_mapping_enable(&svga->mapping);
|
|
|
|
|
else
|
|
|
|
|
mem_mapping_disable(&svga->mapping);
|
|
|
|
|
} else {
|
|
|
|
|
if (val & 0x80)
|
|
|
|
|
mem_mapping_disable(&svga->mapping);
|
|
|
|
|
else
|
|
|
|
|
mem_mapping_enable(&svga->mapping);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x11:
|
|
|
|
|
svga->read_bank = (val & 0xf) * 65536;
|
|
|
|
|
svga->write_bank = (val >> 4) * 65536;
|
|
|
|
|
break;
|
2023-08-21 20:25:05 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2022-08-31 19:19:29 -04:00
|
|
|
}
|
|
|
|
|
return;
|
2023-08-21 20:25:05 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2017-10-11 05:40:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
svga_out(addr, val, svga);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
static uint8_t
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_in(uint16_t addr, void *priv)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_t *oti = (oti_t *) priv;
|
2017-10-11 05:40:44 -04:00
|
|
|
svga_t *svga = &oti->svga;
|
2023-06-01 18:32:25 -04:00
|
|
|
uint8_t idx;
|
|
|
|
|
uint8_t temp;
|
2022-02-20 02:26:27 -05:00
|
|
|
|
2018-10-08 00:22:40 +02:00
|
|
|
if (!oti->chip_id && !(oti->enable_register & 1) && (addr != 0x3C3))
|
2022-08-31 19:19:29 -04:00
|
|
|
return 0xff;
|
2018-10-08 00:22:40 +02:00
|
|
|
|
2022-08-31 19:19:29 -04:00
|
|
|
if ((((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1))
|
|
|
|
|
addr ^= 0x60;
|
2022-02-20 02:26:27 -05:00
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
switch (addr) {
|
2022-08-31 19:19:29 -04:00
|
|
|
case 0x3C2:
|
|
|
|
|
if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50)
|
|
|
|
|
temp = 0;
|
|
|
|
|
else
|
|
|
|
|
temp = 0x10;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x3C3:
|
|
|
|
|
if (oti->chip_id)
|
|
|
|
|
temp = svga_in(addr, svga);
|
|
|
|
|
else
|
|
|
|
|
temp = oti->enable_register;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x3c6:
|
|
|
|
|
case 0x3c7:
|
|
|
|
|
case 0x3c8:
|
|
|
|
|
case 0x3c9:
|
|
|
|
|
if (oti->chip_id == OTI_077)
|
|
|
|
|
return sc1148x_ramdac_in(addr, 0, svga->ramdac, svga);
|
|
|
|
|
return svga_in(addr, svga);
|
|
|
|
|
|
|
|
|
|
case 0x3CF:
|
|
|
|
|
return svga->gdcreg[svga->gdcaddr & 0xf];
|
|
|
|
|
|
|
|
|
|
case 0x3D4:
|
|
|
|
|
temp = svga->crtcreg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x3D5:
|
|
|
|
|
if (oti->chip_id) {
|
|
|
|
|
if (svga->crtcreg & 0x20)
|
|
|
|
|
temp = 0xff;
|
|
|
|
|
else
|
|
|
|
|
temp = svga->crtc[svga->crtcreg];
|
|
|
|
|
} else
|
|
|
|
|
temp = svga->crtc[svga->crtcreg & 0x1f];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x3DA:
|
|
|
|
|
if (oti->chip_id) {
|
|
|
|
|
temp = svga_in(addr, svga);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
svga->attrff = 0;
|
|
|
|
|
/*The OTI-037C BIOS waits for bits 0 and 3 in 0x3da to go low, then reads 0x3da again
|
|
|
|
|
and expects the diagnostic bits to equal the current border colour. As I understand
|
|
|
|
|
it, the 0x3da active enable status does not include the border time, so this may be
|
|
|
|
|
an area where OTI-037C is not entirely VGA compatible.*/
|
|
|
|
|
svga->cgastat &= ~0x30;
|
|
|
|
|
/* copy color diagnostic info from the overscan color register */
|
|
|
|
|
switch (svga->attrregs[0x12] & 0x30) {
|
|
|
|
|
case 0x00: /* P0 and P2 */
|
|
|
|
|
if (svga->attrregs[0x11] & 0x01)
|
|
|
|
|
svga->cgastat |= 0x10;
|
|
|
|
|
if (svga->attrregs[0x11] & 0x04)
|
|
|
|
|
svga->cgastat |= 0x20;
|
|
|
|
|
break;
|
|
|
|
|
case 0x10: /* P4 and P5 */
|
|
|
|
|
if (svga->attrregs[0x11] & 0x10)
|
|
|
|
|
svga->cgastat |= 0x10;
|
|
|
|
|
if (svga->attrregs[0x11] & 0x20)
|
|
|
|
|
svga->cgastat |= 0x20;
|
|
|
|
|
break;
|
|
|
|
|
case 0x20: /* P1 and P3 */
|
|
|
|
|
if (svga->attrregs[0x11] & 0x02)
|
|
|
|
|
svga->cgastat |= 0x10;
|
|
|
|
|
if (svga->attrregs[0x11] & 0x08)
|
|
|
|
|
svga->cgastat |= 0x20;
|
|
|
|
|
break;
|
|
|
|
|
case 0x30: /* P6 and P7 */
|
|
|
|
|
if (svga->attrregs[0x11] & 0x40)
|
|
|
|
|
svga->cgastat |= 0x10;
|
|
|
|
|
if (svga->attrregs[0x11] & 0x80)
|
|
|
|
|
svga->cgastat |= 0x20;
|
|
|
|
|
break;
|
2023-08-21 20:25:05 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2022-08-31 19:19:29 -04:00
|
|
|
}
|
|
|
|
|
temp = svga->cgastat;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x3DE:
|
|
|
|
|
temp = oti->index;
|
|
|
|
|
if (oti->chip_id)
|
|
|
|
|
temp |= (oti->chip_id << 5);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x3DF:
|
|
|
|
|
idx = oti->index;
|
|
|
|
|
if (!oti->chip_id)
|
|
|
|
|
idx &= 0x1f;
|
|
|
|
|
if (idx == 0x10)
|
|
|
|
|
temp = oti->dipswitch_val;
|
|
|
|
|
else
|
|
|
|
|
temp = oti->regs[idx];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
temp = svga_in(addr, svga);
|
|
|
|
|
break;
|
2017-10-11 05:40:44 -04:00
|
|
|
}
|
|
|
|
|
|
2023-06-01 18:32:25 -04:00
|
|
|
return temp;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
static void
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_pos_out(UNUSED(uint16_t addr), uint8_t val, void *priv)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_t *oti = (oti_t *) priv;
|
2017-10-11 05:40:44 -04:00
|
|
|
|
2018-10-08 00:22:40 +02:00
|
|
|
if ((val ^ oti->pos) & 8) {
|
2022-08-31 19:19:29 -04:00
|
|
|
if (val & 8)
|
|
|
|
|
io_sethandler(0x03c0, 32, oti_in, NULL, NULL,
|
|
|
|
|
oti_out, NULL, NULL, oti);
|
|
|
|
|
else
|
|
|
|
|
io_removehandler(0x03c0, 32, oti_in, NULL, NULL,
|
|
|
|
|
oti_out, NULL, NULL, oti);
|
2017-10-11 05:40:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
oti->pos = val;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
static uint8_t
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_pos_in(UNUSED(uint16_t addr), void *priv)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2023-08-21 20:25:05 -04:00
|
|
|
const oti_t *oti = (oti_t *) priv;
|
2017-10-11 05:40:44 -04:00
|
|
|
|
2022-08-31 19:19:29 -04:00
|
|
|
return (oti->pos);
|
2022-02-20 02:26:27 -05:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2022-08-02 02:30:41 +02:00
|
|
|
static float
|
|
|
|
|
oti_getclock(int clock)
|
|
|
|
|
{
|
|
|
|
|
float ret = 0.0;
|
|
|
|
|
|
|
|
|
|
switch (clock) {
|
2022-08-31 19:19:29 -04:00
|
|
|
default:
|
2023-08-21 20:25:05 -04:00
|
|
|
case 0:
|
2022-08-31 19:19:29 -04:00
|
|
|
ret = 25175000.0;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
ret = 28322000.0;
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
ret = 14318000.0;
|
|
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
ret = 16257000.0;
|
|
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
ret = 35500000.0;
|
|
|
|
|
break;
|
2022-08-02 02:30:41 +02:00
|
|
|
}
|
|
|
|
|
|
2022-08-04 01:41:52 +02:00
|
|
|
return ret;
|
2022-08-02 02:30:41 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
static void
|
|
|
|
|
oti_recalctimings(svga_t *svga)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2023-08-21 20:25:05 -04:00
|
|
|
const oti_t *oti = (oti_t *) svga->priv;
|
|
|
|
|
int clk_sel = ((svga->miscout >> 2) & 3) | ((oti->regs[0x0d] & 0x20) >> 3);
|
2022-08-02 02:30:41 +02:00
|
|
|
|
2023-06-01 18:32:25 -04:00
|
|
|
svga->clock = (cpuclock * (double) (1ULL << 32)) / oti_getclock(clk_sel);
|
2017-10-11 05:40:44 -04:00
|
|
|
|
2022-08-02 02:30:41 +02:00
|
|
|
if (oti->chip_id > 0) {
|
2022-08-31 19:19:29 -04:00
|
|
|
if (oti->regs[0x14] & 0x08)
|
|
|
|
|
svga->ma_latch |= 0x10000;
|
|
|
|
|
if (oti->regs[0x16] & 0x08)
|
|
|
|
|
svga->ma_latch |= 0x20000;
|
|
|
|
|
|
|
|
|
|
if (oti->regs[0x14] & 0x01)
|
|
|
|
|
svga->vtotal += 0x400;
|
|
|
|
|
if (oti->regs[0x14] & 0x02)
|
|
|
|
|
svga->dispend += 0x400;
|
|
|
|
|
if (oti->regs[0x14] & 0x04)
|
|
|
|
|
svga->vsyncstart += 0x400;
|
|
|
|
|
|
|
|
|
|
svga->interlace = oti->regs[0x14] & 0x80;
|
2022-08-02 02:30:41 +02:00
|
|
|
}
|
2017-10-11 05:40:44 -04:00
|
|
|
|
2022-08-31 19:19:29 -04:00
|
|
|
if ((oti->regs[0x0d] & 0x0c) && !(oti->regs[0x0d] & 0x10))
|
|
|
|
|
svga->rowoffset <<= 1;
|
2022-02-20 02:26:27 -05:00
|
|
|
|
2022-08-02 02:30:41 +02:00
|
|
|
if (svga->bpp == 16) {
|
2022-08-31 19:19:29 -04:00
|
|
|
svga->render = svga_render_16bpp_highres;
|
|
|
|
|
svga->hdisp >>= 1;
|
2022-08-02 02:30:41 +02:00
|
|
|
} else if (svga->bpp == 15) {
|
2022-08-31 19:19:29 -04:00
|
|
|
svga->render = svga_render_15bpp_highres;
|
|
|
|
|
svga->hdisp >>= 1;
|
2022-08-02 02:30:41 +02:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
static void *
|
2018-03-19 01:02:04 +01:00
|
|
|
oti_init(const device_t *info)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2023-08-21 20:25:05 -04:00
|
|
|
oti_t *oti = malloc(sizeof(oti_t));
|
|
|
|
|
const char *romfn = NULL;
|
2017-10-11 05:40:44 -04:00
|
|
|
|
|
|
|
|
memset(oti, 0x00, sizeof(oti_t));
|
2017-11-01 01:51:19 -05:00
|
|
|
oti->chip_id = info->local;
|
|
|
|
|
|
2018-10-08 00:22:40 +02:00
|
|
|
oti->dipswitch_val = 0x18;
|
|
|
|
|
|
2022-08-31 19:19:29 -04:00
|
|
|
switch (oti->chip_id) {
|
|
|
|
|
case OTI_037C:
|
|
|
|
|
romfn = BIOS_037C_PATH;
|
|
|
|
|
oti->vram_size = 256;
|
|
|
|
|
oti->regs[0] = 0x08; /* FIXME: The BIOS wants to read this at index 0? This index is undocumented. */
|
2023-08-21 20:25:05 -04:00
|
|
|
#if 0
|
|
|
|
|
io_sethandler(0x03c0, 32,
|
|
|
|
|
oti_in, NULL, NULL, oti_out, NULL, NULL, oti);
|
|
|
|
|
#endif
|
2022-08-31 19:19:29 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OTI_067_AMA932J:
|
|
|
|
|
romfn = BIOS_067_AMA932J_PATH;
|
|
|
|
|
oti->chip_id = 2;
|
|
|
|
|
oti->vram_size = device_get_config_int("memory");
|
|
|
|
|
oti->dipswitch_val |= 0x20;
|
|
|
|
|
oti->pos = 0x08; /* Tell the BIOS the I/O ports are already enabled to avoid a double I/O handler mess. */
|
|
|
|
|
io_sethandler(0x46e8, 1, oti_pos_in, NULL, NULL, oti_pos_out, NULL, NULL, oti);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OTI_067_M300:
|
|
|
|
|
if (rom_present(BIOS_067_M300_15_PATH))
|
|
|
|
|
romfn = BIOS_067_M300_15_PATH;
|
|
|
|
|
else
|
|
|
|
|
romfn = BIOS_067_M300_08_PATH;
|
|
|
|
|
oti->vram_size = device_get_config_int("memory");
|
|
|
|
|
oti->pos = 0x08; /* Tell the BIOS the I/O ports are already enabled to avoid a double I/O handler mess. */
|
|
|
|
|
io_sethandler(0x46e8, 1, oti_pos_in, NULL, NULL, oti_pos_out, NULL, NULL, oti);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OTI_067:
|
|
|
|
|
case OTI_077:
|
|
|
|
|
romfn = BIOS_077_PATH;
|
|
|
|
|
oti->vram_size = device_get_config_int("memory");
|
|
|
|
|
oti->pos = 0x08; /* Tell the BIOS the I/O ports are already enabled to avoid a double I/O handler mess. */
|
|
|
|
|
io_sethandler(0x46e8, 1, oti_pos_in, NULL, NULL, oti_pos_out, NULL, NULL, oti);
|
|
|
|
|
break;
|
2023-08-21 20:25:05 -04:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2017-11-01 01:51:19 -05:00
|
|
|
}
|
2017-10-11 05:40:44 -04:00
|
|
|
|
2020-01-14 20:51:06 +01:00
|
|
|
if (romfn != NULL) {
|
2022-08-31 19:19:29 -04:00
|
|
|
rom_init(&oti->bios_rom, romfn,
|
|
|
|
|
0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
2020-01-14 20:51:06 +01:00
|
|
|
}
|
2017-10-11 05:40:44 -04:00
|
|
|
|
2017-11-01 01:51:19 -05:00
|
|
|
oti->vram_mask = (oti->vram_size << 10) - 1;
|
2018-09-19 20:13:32 +02:00
|
|
|
|
|
|
|
|
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_oti);
|
|
|
|
|
|
2020-05-06 00:23:07 +02:00
|
|
|
svga_init(info, &oti->svga, oti, oti->vram_size << 10,
|
2022-08-31 19:19:29 -04:00
|
|
|
oti_recalctimings, oti_in, oti_out, NULL, NULL);
|
2017-10-11 05:40:44 -04:00
|
|
|
|
2022-08-31 19:19:29 -04:00
|
|
|
if (oti->chip_id == OTI_077)
|
|
|
|
|
oti->svga.ramdac = device_add(&sc11487_ramdac_device); /*Actually a 82c487, probably a clone.*/
|
2021-10-24 19:06:05 +02:00
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
io_sethandler(0x03c0, 32,
|
2022-08-31 19:19:29 -04:00
|
|
|
oti_in, NULL, NULL, oti_out, NULL, NULL, oti);
|
2018-09-19 20:13:32 +02:00
|
|
|
|
2022-08-31 19:19:29 -04:00
|
|
|
oti->svga.miscout = 1;
|
|
|
|
|
oti->svga.packed_chain4 = 1;
|
2018-09-19 20:13:32 +02:00
|
|
|
|
2023-06-01 18:32:25 -04:00
|
|
|
return oti;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
static void
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_close(void *priv)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_t *oti = (oti_t *) priv;
|
2017-10-11 05:40:44 -04:00
|
|
|
|
|
|
|
|
svga_close(&oti->svga);
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
free(oti);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
static void
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_speed_changed(void *priv)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_t *oti = (oti_t *) priv;
|
2017-10-11 05:40:44 -04:00
|
|
|
|
|
|
|
|
svga_recalctimings(&oti->svga);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2022-02-20 02:26:27 -05:00
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
static void
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_force_redraw(void *priv)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2023-06-09 23:46:54 -04:00
|
|
|
oti_t *oti = (oti_t *) priv;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-10-11 05:40:44 -04:00
|
|
|
oti->svga.fullchange = changeframecount;
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2018-02-24 15:56:48 +01:00
|
|
|
static int
|
|
|
|
|
oti037c_available(void)
|
|
|
|
|
{
|
2022-08-31 19:19:29 -04:00
|
|
|
return (rom_present(BIOS_037C_PATH));
|
2018-02-24 15:56:48 +01:00
|
|
|
}
|
2017-10-11 05:40:44 -04:00
|
|
|
|
2018-08-16 00:25:20 +02:00
|
|
|
static int
|
|
|
|
|
oti067_ama932j_available(void)
|
|
|
|
|
{
|
2022-08-31 19:19:29 -04:00
|
|
|
return (rom_present(BIOS_067_AMA932J_PATH));
|
2018-08-16 00:25:20 +02:00
|
|
|
}
|
2018-03-02 21:57:37 +01:00
|
|
|
|
2017-11-01 01:51:19 -05:00
|
|
|
static int
|
2018-03-02 21:57:37 +01:00
|
|
|
oti067_077_available(void)
|
2017-11-01 01:51:19 -05:00
|
|
|
{
|
2022-08-31 19:19:29 -04:00
|
|
|
return (rom_present(BIOS_077_PATH));
|
2017-11-01 01:51:19 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-04 18:22:52 +03:00
|
|
|
static int
|
|
|
|
|
oti067_m300_available(void)
|
|
|
|
|
{
|
|
|
|
|
if (rom_present(BIOS_067_M300_15_PATH))
|
2022-08-31 19:19:29 -04:00
|
|
|
return (rom_present(BIOS_067_M300_15_PATH));
|
2022-02-26 23:31:28 -05:00
|
|
|
else
|
2022-08-31 19:19:29 -04:00
|
|
|
return (rom_present(BIOS_067_M300_08_PATH));
|
2021-07-04 18:22:52 +03:00
|
|
|
}
|
|
|
|
|
|
2022-02-26 23:31:28 -05:00
|
|
|
// clang-format off
|
|
|
|
|
static const device_config_t oti067_config[] = {
|
|
|
|
|
{
|
2022-04-09 20:09:14 -04:00
|
|
|
.name = "memory",
|
|
|
|
|
.description = "Memory size",
|
|
|
|
|
.type = CONFIG_SELECTION,
|
|
|
|
|
.default_int = 512,
|
|
|
|
|
.selection = {
|
|
|
|
|
{
|
|
|
|
|
.description = "256 kB",
|
|
|
|
|
.value = 256
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.description = "512 kB",
|
|
|
|
|
.value = 512
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.description = ""
|
|
|
|
|
}
|
2022-02-26 23:31:28 -05:00
|
|
|
}
|
|
|
|
|
},
|
2022-04-09 20:09:14 -04:00
|
|
|
{
|
|
|
|
|
.type = CONFIG_END
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
};
|
|
|
|
|
|
2022-02-26 23:31:28 -05:00
|
|
|
static const device_config_t oti067_ama932j_config[] = {
|
|
|
|
|
{
|
2022-04-09 20:09:14 -04:00
|
|
|
.name = "memory",
|
|
|
|
|
.description = "Memory size",
|
|
|
|
|
.type = CONFIG_SELECTION,
|
|
|
|
|
.default_int = 256,
|
|
|
|
|
.selection = {
|
|
|
|
|
{
|
|
|
|
|
.description = "256 kB",
|
|
|
|
|
.value = 256
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.description = "512 kB",
|
|
|
|
|
.value = 512
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.description = ""
|
|
|
|
|
}
|
2022-02-26 23:31:28 -05:00
|
|
|
}
|
|
|
|
|
},
|
2022-04-09 20:09:14 -04:00
|
|
|
{
|
|
|
|
|
.type = CONFIG_END
|
|
|
|
|
}
|
2018-10-09 05:53:09 +02:00
|
|
|
};
|
|
|
|
|
|
2022-02-26 23:31:28 -05:00
|
|
|
static const device_config_t oti077_config[] = {
|
|
|
|
|
{
|
2022-04-09 20:09:14 -04:00
|
|
|
.name = "memory",
|
|
|
|
|
.description = "Memory size",
|
|
|
|
|
.type = CONFIG_SELECTION,
|
|
|
|
|
.default_int = 1024,
|
|
|
|
|
.selection = {
|
|
|
|
|
{
|
|
|
|
|
.description = "256 kB",
|
|
|
|
|
.value = 256
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.description = "512 kB",
|
|
|
|
|
.value = 512
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.description = "1 MB",
|
|
|
|
|
.value = 1024
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.description = ""
|
|
|
|
|
}
|
2022-02-26 23:31:28 -05:00
|
|
|
}
|
|
|
|
|
},
|
2022-04-09 20:09:14 -04:00
|
|
|
{
|
|
|
|
|
.type = CONFIG_END
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
};
|
2022-02-26 23:31:28 -05:00
|
|
|
// clang-format on
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2022-02-26 23:31:28 -05:00
|
|
|
const device_t oti037c_device = {
|
2022-08-31 19:19:29 -04:00
|
|
|
.name = "Oak OTI-037C",
|
2022-03-13 21:43:45 -04:00
|
|
|
.internal_name = "oti037c",
|
2022-08-31 19:19:29 -04:00
|
|
|
.flags = DEVICE_ISA,
|
|
|
|
|
.local = 0,
|
|
|
|
|
.init = oti_init,
|
|
|
|
|
.close = oti_close,
|
|
|
|
|
.reset = NULL,
|
2022-03-13 21:43:45 -04:00
|
|
|
{ .available = oti037c_available },
|
|
|
|
|
.speed_changed = oti_speed_changed,
|
2022-08-31 19:19:29 -04:00
|
|
|
.force_redraw = oti_force_redraw,
|
|
|
|
|
.config = NULL
|
2018-02-24 15:56:48 +01:00
|
|
|
};
|
2017-10-11 05:40:44 -04:00
|
|
|
|
2022-02-26 23:31:28 -05:00
|
|
|
const device_t oti067_device = {
|
2022-08-31 19:19:29 -04:00
|
|
|
.name = "Oak OTI-067",
|
2022-03-13 21:43:45 -04:00
|
|
|
.internal_name = "oti067",
|
2022-08-31 19:19:29 -04:00
|
|
|
.flags = DEVICE_ISA,
|
|
|
|
|
.local = 2,
|
|
|
|
|
.init = oti_init,
|
|
|
|
|
.close = oti_close,
|
|
|
|
|
.reset = NULL,
|
2022-03-13 21:43:45 -04:00
|
|
|
{ .available = oti067_077_available },
|
|
|
|
|
.speed_changed = oti_speed_changed,
|
2022-08-31 19:19:29 -04:00
|
|
|
.force_redraw = oti_force_redraw,
|
|
|
|
|
.config = oti067_config
|
2016-06-26 00:34:39 +02:00
|
|
|
};
|
2017-10-11 05:40:44 -04:00
|
|
|
|
2022-02-26 23:31:28 -05:00
|
|
|
const device_t oti067_m300_device = {
|
2022-08-31 19:19:29 -04:00
|
|
|
.name = "Oak OTI-067 (Olivetti M300-08/15)",
|
2022-03-13 21:43:45 -04:00
|
|
|
.internal_name = "oti067_m300",
|
2022-08-31 19:19:29 -04:00
|
|
|
.flags = DEVICE_ISA,
|
|
|
|
|
.local = 4,
|
|
|
|
|
.init = oti_init,
|
|
|
|
|
.close = oti_close,
|
|
|
|
|
.reset = NULL,
|
2022-03-13 21:43:45 -04:00
|
|
|
{ .available = oti067_m300_available },
|
|
|
|
|
.speed_changed = oti_speed_changed,
|
2022-08-31 19:19:29 -04:00
|
|
|
.force_redraw = oti_force_redraw,
|
|
|
|
|
.config = oti067_config
|
2021-07-04 18:22:52 +03:00
|
|
|
};
|
|
|
|
|
|
2022-02-26 23:31:28 -05:00
|
|
|
const device_t oti067_ama932j_device = {
|
2022-08-31 19:19:29 -04:00
|
|
|
.name = "Oak OTI-067 (AMA-932J)",
|
2022-03-13 21:43:45 -04:00
|
|
|
.internal_name = "oti067_ama932j",
|
2022-08-31 19:19:29 -04:00
|
|
|
.flags = DEVICE_ISA,
|
|
|
|
|
.local = 3,
|
|
|
|
|
.init = oti_init,
|
|
|
|
|
.close = oti_close,
|
|
|
|
|
.reset = NULL,
|
2022-03-13 21:43:45 -04:00
|
|
|
{ .available = oti067_ama932j_available },
|
|
|
|
|
.speed_changed = oti_speed_changed,
|
2022-08-31 19:19:29 -04:00
|
|
|
.force_redraw = oti_force_redraw,
|
|
|
|
|
.config = oti067_ama932j_config
|
2018-08-16 00:25:20 +02:00
|
|
|
};
|
|
|
|
|
|
2022-02-26 23:31:28 -05:00
|
|
|
const device_t oti077_device = {
|
2022-08-31 19:19:29 -04:00
|
|
|
.name = "Oak OTI-077",
|
2022-03-13 21:43:45 -04:00
|
|
|
.internal_name = "oti077",
|
2022-08-31 19:19:29 -04:00
|
|
|
.flags = DEVICE_ISA,
|
|
|
|
|
.local = 5,
|
|
|
|
|
.init = oti_init,
|
|
|
|
|
.close = oti_close,
|
|
|
|
|
.reset = NULL,
|
2022-03-13 21:43:45 -04:00
|
|
|
{ .available = oti067_077_available },
|
|
|
|
|
.speed_changed = oti_speed_changed,
|
2022-08-31 19:19:29 -04:00
|
|
|
.force_redraw = oti_force_redraw,
|
|
|
|
|
.config = oti077_config
|
2016-06-26 00:34:39 +02:00
|
|
|
};
|