diff --git a/src/Makefile.local b/src/Makefile.local index 8b528ff28..095b60024 100644 --- a/src/Makefile.local +++ b/src/Makefile.local @@ -74,8 +74,11 @@ STUFF := # chipset/ logging: # -DENABLE_I420EX_LOG=N sets logging level at N. # -DENABLE_NEAT_LOG=N sets logging level at N. +# -DENABLE_OPTI495_LOG=N sets logging level at N. +# -DENABLE_OPTI895_LOG=N sets logging level at N. # -DENABLE_PIIX_LOG=N sets logging level at N. # -DENABLE_SIO_LOG=N sets logging level at N. +# -DENABLE_SIS_85C496_LOG=N sets logging level at N. # codegen/, codegen_new/, cpu/ logging: # -DENABLE_X86SEG_LOG=N sets logging level at N. # cpu/ logging: diff --git a/src/chipset/opti495.c b/src/chipset/opti495.c index 47ee25582..c192062a7 100644 --- a/src/chipset/opti495.c +++ b/src/chipset/opti495.c @@ -1,256 +1,21 @@ -/*OPTi 82C495 emulation - This is the chipset used in the AMI386 model - - Details for the chipset from Ralph Brown's interrupt list - This describes the OPTi 82C493, the 82C495 seems similar except there is one - more register (2C) - -----------P00220024-------------------------- -PORT 0022-0024 - OPTi 82C493 System Controller (SYSC) - CONFIGURATION REGISTERS -Desc: The OPTi 486SXWB contains three chips and is designed for systems - running at 20, 25 and 33MHz. The chipset includes an 82C493 System - Controller (SYSC), the 82C392 Data Buffer Controller, and the - 82C206 Integrated peripheral Controller (IPC). -Note: every access to PORT 0024h must be preceded by a write to PORT 0022h, - even if the same register is being accessed a second time -SeeAlso: PORT 0022h"82C206" - -0022 ?W configuration register index (see #P0178) -0024 RW configuration register data - -(Table P0178) -Values for OPTi 82C493 System Controller configuration register index: - 20h Control Register 1 (see #P0179) - 21h Control Register 2 (see #P0180) - 22h Shadow RAM Control Register 1 (see #P0181) - 23h Shadow RAM Control Register 2 (see #P0182) - 24h DRAM Control Register 1 (see #P0183) - 25h DRAM Control Register 2 (see #P0184) - 26h Shadow RAM Control Register 3 (see #P0185) - 27h Control Register 3 (see #P0186) - 28h Non-cachable Block 1 Register 1 (see #P0187) - 29h Non-cachable Block 1 Register 2 (see #P0188) - 2Ah Non-cachable Block 2 Register 1 (see #P0187) - 2Bh Non-cachable Block 2 Register 2 (see #P0188) - -Bitfields for OPTi-82C493 Control Register 1: -Bit(s) Description (Table P0179) - 7-6 Revision of 82C493 (readonly) (default=01) - 5 Burst wait state control - 1 = Secondary cache read hit cycle is 3-2-2-2 or 2-2-2-2 - 0 = Secondary cache read hit cycle is 3-1-1-1 or 2-1-1-1 (default) - (if bit 5 is set to 1, bit 4 must be set to 0) - 4 Cache memory data buffer output enable control - 0 = disable (default) - 1 = enable - (must be disabled for frequency <= 33Mhz) - 3 Single Address Latch Enable (ALE) - 0 = disable (default) - 1 = enable - (if enabled, SYSC will activate single ALE rather than multiples - during bus conversion cycles) - 2 enable Extra AT Cycle Wait State (default is 0 = disabled) - 1 Emulation keyboard Reset Control - 0 = disable (default) - 1 = enable - Note: This bit must be enabled in BIOS default value; enabling this - bit requires HALT instruction to be executed before SYSC - generates processor reset (CPURST) - 0 enable Alternative Fast Reset (default is 0 = disabled) -SeeAlso: #P0180,#P0186 - -Bitfields for OPTi-82C493 Control Register 2: -Bit(s) Description (Table P0180) - 7 Master Mode Byte Swap Enable - 0 = disable (default) - 1 = enable - 6 Emulation Keyboard Reset Delay Control - 0 = Generate reset pulse 2us later (default) - 1 = Generate reset pulse immediately - 5 disable Parity Check (default is 0 = enabled) - 4 Cache Enable - 0 = Cache disabled and DRAM burst mode enabled (default) - 1 = Cache enabled and DRAM burst mode disabled - 3-2 Cache Size - 00 64KB (default) - 01 128KB - 10 256KB - 11 512KB - 1 Secondary Cache Read Burst Cycles Control - 0 = 3-1-1-1 cycle (default) - 1 = 2-1-1-1 cycle - 0 Cache Write Wait State Control - 0 = 1 wait state (default) - 1 = 0 wait state -SeeAlso: #P0179,#P0186 - -Bitfields for OPTi-82C493 Shadow RAM Control Register 1: -Bit(s) Description (Table P0181) - 7 ROM(F0000h - FFFFFh) Enable - 0 = read/write on write-protected DRAM - 1 = read from ROM, write to DRAM (default) - 6 Shadow RAM at D0000h - EFFFFh Area - 0 = disable (default) - 1 = enable - 5 Shadow RAM at E0000h - EFFFFh Area - 0 = disable shadow RAM (default) - E0000h - EFFFFh ROM is defaulted to reside on XD bus - 1 = enable shadow RAM - 4 enable write-protect for Shadow RAM at D0000h - DFFFFh Area - 0 = disable (default) - 1 = enable - 3 enable write-protect for Shadow RAM at E0000h - EFFFFh Area - 0 = disable (default) - 1 = enable - 2 Hidden refresh enable (with holding CPU) - (Hidden refresh must be disabled if 4Mx1 or 1M x4 bit DRAM are used) - 1 = disable (default) - 0 = enable - 1 unused - 0 enable Slow Refresh (four times slower than normal refresh) - (default is 0 = disable) -SeeAlso: #P0182 - -Bitfields for OPTi-82C493 Shadow RAM Control Register 2: -Bit(s) Description (Table P0182) - 7 enable Shadow RAM at EC000h - EFFFFh area - 6 enable Shadow RAM at E8000h - EBFFFh area - 5 enable Shadow RAM at E4000h - E7FFFh area - 4 enable Shadow RAM at E0000h - E3FFFh area - 3 enable Shadow RAM at DC000h - DFFFFh area - 2 enable Shadow RAM at D8000h - DBFFFh area - 1 enable Shadow RAM at D4000h - D7FFFh area - 0 enable Shadow RAM at D0000h - D3FFFh area -Note: the default is disabled (0) for all areas - -Bitfields for OPTi-82C493 DRAM Control Register 1: -Bit(s) Description (Table P0183) - 7 DRAM size - 0 = 256K DRAM mode - 1 = 1M and 4M DRAM mode - 6-4 DRAM types used for bank0 and bank1 - bits 7-4 Bank0 Bank1 - 0000 256K x - 0001 256K 256K - 0010 256K 1M - 0011 x x - 01xx x x - 1000 1M x (default) - 1001 1M 1M - 1010 1M 4M - 1011 4M 1M - 1100 4M x - 1101 4M 4M - 111x x x - 3 unused - 2-0 DRAM types used for bank2 and bank3 - bits 7,2-0 Bank2 Bank3 - x000 1M x - x001 1M 1M - x010 x x - x011 4M 1M - x100 4M x - x101 4M 4M - x11x x x (default) -SeeAlso: #P0184 - -Bitfields for OPTi-82C493 DRAM Control Register 2: -Bit(s) Description (Table P0184) - 7-6 Read cycle additional wait states - 00 not used - 01 = 0 - 10 = 1 - 11 = 2 (default) - 5-4 Write cycle additional wait states - 00 = 0 - 01 = 1 - 10 = 2 - 11 = 3 (default) - 3 Fast decode enable - 0 = disable fast decode. DRAM base wait states not changed (default) - 1 = enable fast decode. DRAM base wait state is decreased by 1 - Note: This function may be enabled in 20/25Mhz operation to speed up - DRAM access. If bit 4 of index register 21h (cache enable - bit) is enabled, this bit is automatically disabled--even if - set to 1 - 2 unused - 1-0 ATCLK selection - 00 ATCLK = CLKI/6 (default) - 01 ATCLK = CLKI/4 (default) - 10 ATCLK = CLKI/3 - 11 ATCLK = CLK2I/5 (CLKI * 2 /5) - Note: bit 0 will reflect the BCLKS (pin 142) status and bit 1 will be - set to 0 when 82C493 is reset. -SeeAlso: #P0183,#P0185 - -Bitfields for OPTi-82C493 Shadow RAM Control Register 3: -Bit(s) Description (Table P0185) - 7 unused - 6 Shadow RAM copy enable for address C0000h - CFFFFh - 0 = Read/write at AT bus (default) - 1 = Read from AT bus and write into shadow RAM - 5 Shadow write protect at address C0000h - CFFFFh - 0 = Write protect disable (default) - 1 = Write protect enable - 4 enable Shadow RAM at C0000h - CFFFFh - 3 enable Shadow RAM at CC000h - CFFFFh - 2 enable Shadow RAM at C8000h - CBFFFh - 1 enable Shadow RAM at C4000h - C7FFFh - 0 enable Shadow RAM at C0000h - C3FFFh -Note: the default is disabled (0) for bits 4-0 -SeeAlso: #P0183,#P0184 - -Bitfields for OPTi-82C493 Control Register 3: -Bit(s) Description (Table P0186) - 7 enable NCA# pin to low state (default is 1 = enabled) - 6-5 unused - 4 Video BIOS at C0000h - C8000h non-cacheable - 0 = cacheable - 1 = non-cacheable (default) - 3-0 Cacheable address range for local memory - 0000 0 - 64MB - 0001 0 - 4MB (default) - 0010 0 - 8MB - 0011 0 - 12MB - 0100 0 - 16MB - 0101 0 - 20MB - 0110 0 - 24MB - 0111 0 - 28MB - 1000 0 - 32MB - 1001 0 - 36MB - 1010 0 - 40MB - 1011 0 - 44MB - 1100 0 - 48MB - 1101 0 - 52MB - 1110 0 - 56MB - 1111 0 - 60MB - Note: If total memory is 1MB or 2MB the cacheable range is 0-1 MB or - 0-2 MB and independent of the value of bits 3-0 -SeeAlso: #P0179,#P0180 - -Bitfields for OPTi-82C493 Non-cacheable Block Register 1: -Bit(s) Description (Table P0187) - 7-5 Size of non-cachable memory block - 000 64K - 001 128K - 010 256K - 011 512K - 1xx disabled (default) - 4-2 unused - 1-0 Address bits 25 and 24 of non-cachable memory block (default = 00) -Note: this register is used together with configuration register 29h - (non-cacheable block 1) or register 2Bh (block 2) (see #P0188) to - define a non-cacheable block. The starting address must be a - multiple of the block size -SeeAlso: #P0178,#P0188 - -Bitfields for OPTi-82C493 Non-cacheable Block Register 2: -Bit(s) Description (Table P0188) - 7-0 Address bits 23-16 of non-cachable memory block (default = 0001xxxx) -Note: the block address is forced to be a multiple of the block size by - ignoring the appropriate number of the least-significant bits -SeeAlso: #P0178,#P0187 -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the OPTi 82C493/82C495 chipset. + * + * + * + * Authors: Tiseno100, + * Miran Grca, + * + * Copyright 2008-2020 Tiseno100. + * Copyright 2016-2020 Miran Grca. + */ #include #include #include @@ -267,17 +32,96 @@ SeeAlso: #P0178,#P0187 #include <86box/mem.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/port_92.h> #include <86box/chipset.h> typedef struct { - uint8_t cur_reg, - regs[16], + uint8_t idx, + regs[256], scratch[2]; } opti495_t; +#ifdef ENABLE_OPTI495_LOG +int opti495_do_log = ENABLE_OPTI495_LOG; + + +static void +opti495_log(const char *fmt, ...) +{ + va_list ap; + + if (opti495_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define opti495_log(fmt, ...) +#endif + + +static void +opti495_recalc(opti495_t *dev) +{ + uint32_t base; + uint32_t i, shflags = 0; + + shadowbios = 0; + shadowbios_write = 0; + + if (dev->regs[0x22] & 0x80) { + shadowbios = 1; + shadowbios_write = 0; + shflags = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; + } else { + shadowbios = 0; + shadowbios_write = 1; + shflags = MEM_READ_INTERNAL | MEM_WRITE_DISABLED; + } + + mem_set_mem_state_both(0xf0000, 0x10000, shflags); + + for (i = 0; i < 8; i++) { + base = 0xd0000 + (i << 14); + + if ((dev->regs[0x22] & ((base >= 0xe0000) ? 0x20 : 0x40)) && + (dev->regs[0x23] & (1 << i))) { + if (dev->regs[0x26] & 0x40) + shflags = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; + else { + shflags = MEM_READ_INTERNAL; + shflags |= (dev->regs[0x22] & ((base >= 0xe0000) ? 0x08 : 0x10)) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } + } else + shflags = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + + mem_set_mem_state_both(base, 0x4000, shflags); + } + + for (i = 0; i < 4; i++) { + base = 0xc0000 + (i << 14); + + if ((dev->regs[0x26] & 0x10) && (dev->regs[0x26] & (1 << i))) { + if (dev->regs[0x26] & 0x40) + shflags = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; + else { + shflags = MEM_READ_INTERNAL; + shflags |= (dev->regs[0x26] & 0x20) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + } + } else + shflags = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + + mem_set_mem_state_both(base, 0x4000, shflags); + } + + flushmmucache(); +} + + static void opti495_write(uint16_t addr, uint8_t val, void *priv) { @@ -285,26 +129,31 @@ opti495_write(uint16_t addr, uint8_t val, void *priv) switch (addr) { case 0x22: - dev->cur_reg = val; + dev->idx = val; break; case 0x24: - if ((dev->cur_reg >= 0x20) && (dev->cur_reg <= 0x2C)) { - dev->regs[dev->cur_reg - 0x20] = val; - if (dev->cur_reg == 0x21) { - cpu_cache_ext_enabled = val & 0x10; - cpu_update_waitstates(); - } - if (dev->cur_reg == 0x22) { - if (!(val & 0x80)) - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); - else - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + if ((dev->idx >= 0x20) && (dev->idx <= 0x2c)) { + dev->regs[dev->idx] = val; + opti495_log("dev->regs[%04x] = %08x\n", dev->idx, val); + + switch(dev->idx) { + case 0x21: + cpu_cache_ext_enabled = !!(dev->regs[0x21] & 0x10); + cpu_update_waitstates(); + break; + + case 0x22: + case 0x23: + case 0x26: + opti495_recalc(dev); + break; } } break; + case 0xe1: case 0xe2: - dev->scratch[addr - 0xe1] = val; + dev->scratch[addr] = val; break; } } @@ -318,12 +167,12 @@ opti495_read(uint16_t addr, void *priv) switch (addr) { case 0x24: - if ((dev->cur_reg >= 0x20) && (dev->cur_reg <= 0x2C)) - ret = dev->regs[dev->cur_reg - 0x20]; + if ((dev->idx >= 0x20) && (dev->idx <= 0x2c)) + ret = dev->regs[dev->idx]; break; case 0xe1: case 0xe2: - ret = dev->scratch[addr - 0xe1]; + ret = dev->scratch[addr]; break; } @@ -351,19 +200,52 @@ opti495_init(const device_t *info) dev->scratch[0] = dev->scratch[1] = 0xff; - io_sethandler(0x00e1, 0x0002, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); + if (info->local == 1) { + /* 85C495 */ + dev->regs[0x20] = 0x02; + dev->regs[0x21] = 0x20; + dev->regs[0x22] = 0xe4; + dev->regs[0x25] = 0xf0; + dev->regs[0x26] = 0x80; + dev->regs[0x27] = 0xb1; + dev->regs[0x28] = 0x80; + dev->regs[0x29] = 0x10; + } else { + /* 85C493 */ + dev->regs[0x20] = 0x40; + dev->regs[0x22] = 0x84; + dev->regs[0x24] = 0x87; + dev->regs[0x25] = 0xf1; /* Note: 0xf0 is also valid default. */ + dev->regs[0x27] = 0x91; + dev->regs[0x28] = 0x80; + dev->regs[0x29] = 0x10; + dev->regs[0x2a] = 0x80; + dev->regs[0x2b] = 0x10; + } - dev->regs[0x22 - 0x20] = 0x80; + opti495_recalc(dev); + + io_sethandler(0x00e1, 0x0002, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); return dev; } -const device_t opti495_device = { - "OPTi 82C495", +const device_t opti493_device = { + "OPTi 82C493", 0, 0, opti495_init, opti495_close, NULL, NULL, NULL, NULL, NULL }; + + +const device_t opti495_device = { + "OPTi 82C495", + 0, + 1, + opti495_init, opti495_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/opti895.c b/src/chipset/opti895.c index 32fd30bac..a01bf099d 100644 --- a/src/chipset/opti895.c +++ b/src/chipset/opti895.c @@ -9,13 +9,6 @@ * Implementation of the OPTi 82C802G/82C895 chipset. * * - * Note: The shadowing of the chipset is enough to get the current machine - * to work. Getting anything other to work will require excessive amount - * of rewrites and improvements. Also, considering the similarities with the - * 82C495XLC & 82C802G it can be merged with opti495.c and also get 82C802G - * implemented. - * - * * * Authors: Tiseno100, * Miran Grca, @@ -145,47 +138,46 @@ opti895_write(uint16_t addr, uint8_t val, void *priv) dev->idx = val; break; case 0x23: - if (dev->idx != 0x01) - break; - - dev->regs[dev->idx] = val; - opti895_log("dev->regs[%04x] = %08x\n", dev->idx, val); + if (dev->idx == 0x01) { + dev->regs[dev->idx] = val; + opti895_log("dev->regs[%04x] = %08x\n", dev->idx, val); + } break; case 0x24: - if (dev->idx == 0x01) - break; + if (((dev->idx >= 0x20) && (dev->idx <= 0x2c)) || + ((dev->idx >= 0xe0) && (dev->idx <= 0xef))) { + dev->regs[dev->idx] = val; + opti895_log("dev->regs[%04x] = %08x\n", dev->idx, val); - dev->regs[dev->idx] = val; - opti895_log("dev->regs[%04x] = %08x\n", dev->idx, val); - - switch(dev->idx) { - case 0x21: - cpu_cache_ext_enabled = !!(dev->regs[0x21] & 0x10); - cpu_update_waitstates(); - break; - - case 0x22: - case 0x23: - case 0x26: - opti895_recalc(dev); - break; - - case 0x24: - opti895_smram_map(0, smram[0].host_base, smram[0].size, !!(val & 0x80)); - break; - - case 0xe0: - if (!(val & 0x01)) - dev->forced_green = 0; - break; - - case 0xe1: - if ((val & 0x08) && (dev->regs[0xe0] & 0x01)) { - smi_line = 1; - dev->forced_green = 1; + switch(dev->idx) { + case 0x21: + cpu_cache_ext_enabled = !!(dev->regs[0x21] & 0x10); + cpu_update_waitstates(); break; - } - break; + + case 0x22: + case 0x23: + case 0x26: + opti895_recalc(dev); + break; + + case 0x24: + opti895_smram_map(0, smram[0].host_base, smram[0].size, !!(val & 0x80)); + break; + + case 0xe0: + if (!(val & 0x01)) + dev->forced_green = 0; + break; + + case 0xe1: + if ((val & 0x08) && (dev->regs[0xe0] & 0x01)) { + smi_line = 1; + dev->forced_green = 1; + break; + } + break; + } } break; @@ -205,18 +197,16 @@ opti895_read(uint16_t addr, void *priv) switch (addr) { case 0x23: - if (dev->idx != 0x01) - break; - - ret = dev->regs[dev->idx]; + if (dev->idx == 0x01) + ret = dev->regs[dev->idx]; break; case 0x24: - if (dev->idx == 0x01) - break; - - ret = dev->regs[dev->idx]; - if (dev->idx == 0xe0) - ret = (ret & 0xf6) | (in_smm ? 0x00 : 0x08) | !!dev->forced_green; + if (((dev->idx >= 0x20) && (dev->idx <= 0x2c)) || + ((dev->idx >= 0xe0) && (dev->idx <= 0xef))) { + ret = dev->regs[dev->idx]; + if (dev->idx == 0xe0) + ret = (ret & 0xf6) | (in_smm ? 0x00 : 0x08) | !!dev->forced_green; + } break; case 0xe1: case 0xe2: diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 84661e3cb..de25fca32 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -60,6 +60,7 @@ extern const device_t slc90e66_device; extern const device_t ioapic_device; /* OPTi */ +extern const device_t opti493_device; extern const device_t opti495_device; extern const device_t opti802g_device; extern const device_t opti895_device;