Merge remote-tracking branch 'upstream/master' into feature/ich2

This commit is contained in:
Jasmine Iwanek
2023-11-20 21:23:01 -05:00
92 changed files with 11270 additions and 2641 deletions

View File

@@ -35,7 +35,7 @@ if(MUNT_EXTERNAL)
endif()
project(86Box
VERSION 4.0.2
VERSION 4.1
DESCRIPTION "Emulator of x86-based systems"
HOMEPAGE_URL "https://86box.net"
LANGUAGES C CXX)

2
debian/changelog vendored
View File

@@ -1,4 +1,4 @@
86box (4.0.2) UNRELEASED; urgency=medium
86box (4.1) UNRELEASED; urgency=medium
* Bump release.

View File

@@ -49,6 +49,8 @@ int acpi_enabled = 0;
static double cpu_to_acpi;
static int acpi_power_on = 0;
#ifdef ENABLE_ACPI_LOG
int acpi_do_log = ENABLE_ACPI_LOG;
@@ -136,7 +138,7 @@ acpi_update_irq(acpi_t *dev)
if (dev->vendor == VEN_SMC)
sci_level |= (dev->regs.pmsts & BM_STS);
if (sci_level) {
if ((dev->regs.pmcntrl & 0x01) && sci_level) {
if (dev->irq_mode == 1)
pci_set_irq(dev->slot, dev->irq_pin, &dev->irq_state);
else if (dev->irq_mode == 2)
@@ -777,6 +779,7 @@ acpi_reg_write_common_regs(UNUSED(int size), uint16_t addr, uint8_t val, void *p
acpi_t *dev = (acpi_t *) priv;
int shift16;
int sus_typ;
uint8_t old;
addr &= 0x3f;
#ifdef ENABLE_ACPI_LOG
@@ -803,6 +806,7 @@ acpi_reg_write_common_regs(UNUSED(int size), uint16_t addr, uint8_t val, void *p
case 0x04:
case 0x05:
/* PMCNTRL - Power Management Control Register (IO) */
old = dev->regs.pmcntrl & 0xff;
if ((addr == 0x05) && !!(val & 0x20) && !!(val & 4) && !!(dev->regs.smi_en & 0x00000010) && (dev->vendor == VEN_INTEL_ICH2)) {
dev->regs.smi_sts |= 0x00000010; /* ICH2 Specific. Trigger an SMI if SLP_SMI_EN bit is set instead of transistioning to a Sleep State. */
acpi_raise_smi(dev, 1);
@@ -848,6 +852,8 @@ acpi_reg_write_common_regs(UNUSED(int size), uint16_t addr, uint8_t val, void *p
}
}
dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3f07 /* 0x3c07 */;
if ((addr == 0x04) && ((old ^ val) & 0x01))
acpi_update_irq(dev);
break;
default:
@@ -911,7 +917,7 @@ acpi_reg_write_ali(int size, uint16_t addr, uint8_t val, void *priv)
dev->regs.gpcntrl = ((dev->regs.gpcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x00000001;
break;
case 0x30:
/* PM2_CNTRL - Power Management 2 Control Register( */
/* PM2_CNTRL - Power Management 2 Control Register */
dev->regs.pmcntrl = val & 1;
break;
default:
@@ -1878,7 +1884,10 @@ acpi_reset(void *priv)
acpi_t *dev = (acpi_t *) priv;
memset(&dev->regs, 0x00, sizeof(acpi_regs_t));
dev->regs.gpireg[0] = 0xff;
/* PC Chips M773:
- Bit 3: 80-conductor cable on unknown IDE channel (active low)
- Bit 1: 80-conductor cable on unknown IDE channel (active low) */
dev->regs.gpireg[0] = !strcmp(machine_get_internal_name(), "m773") ? 0xf5 : 0xff;
dev->regs.gpireg[1] = 0xff;
/* A-Trend ATC7020BXII:
- Bit 3: 80-conductor cable on secondary IDE channel (active low)
@@ -1912,8 +1921,11 @@ acpi_reset(void *priv)
dev->regs.gpi_val |= 0x00000004;
}
/* Power on always generates a resume event. */
dev->regs.pmsts |= 0x8100;
if (acpi_power_on) {
/* Power on always generates a resume event. */
dev->regs.pmsts |= 0x8100;
acpi_power_on = 0;
}
acpi_rtc_status = 0;
@@ -2028,7 +2040,9 @@ acpi_init(const device_t *info)
acpi_reset(dev);
acpi_enabled = 1;
acpi_enabled = 1;
acpi_power_on = 1;
return dev;
}

View File

@@ -1414,7 +1414,7 @@ cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, in
b[3] = ti.attr;
cdrom_log("CD-ROM %i: Returned Toshiba/NEC disc information (type 2) at %02i:%02i.%02i, track=%d, m=%02i,s=%02i,f=%02i, tno=%02x.\n", dev->id, b[0], b[1], b[2], bcd2bin(track), m, s, f, ti.attr);
break;
case 3: /*Undocumented on NEC CD-ROM's, from information based on sr_vendor.c from Android's source code*/
case 3: /* Undocumented on NEC CD-ROM's, from information based on sr_vendor.c from the Linux kernel */
switch (dev->type) {
case CDROM_TYPE_NEC_25_10a:
case CDROM_TYPE_NEC_38_103:

View File

@@ -1172,8 +1172,6 @@ piix_read(int func, int addr, void *priv)
if ((func <= dev->max_func) || ((func == 1) && (dev->max_func == 0))) {
fregs = (uint8_t *) dev->regs[func];
ret = fregs[addr];
if ((func == 2) && (addr == 0xff))
ret |= 0xef;
piix_log("PIIX function %i read: %02X from %02X\n", func, ret, addr);
}

View File

@@ -33,7 +33,7 @@
#include <86box/chipset.h>
typedef struct opti499_t {
uint8_t idx,
uint8_t idx;
uint8_t regs[256];
uint8_t scratch[2];
} opti499_t;

View File

@@ -176,6 +176,8 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv)
valxor = val ^ dev->regs[rel_reg];
if (rel_reg == 0x19)
dev->regs[rel_reg] &= ~val;
else if (rel_reg == 0x00)
dev->regs[rel_reg] = (dev->regs[rel_reg] & 0x1f) | (val & 0xe0);
else
dev->regs[rel_reg] = val;

View File

@@ -139,6 +139,8 @@ load_general(void)
rctrl_is_lalt = ini_section_get_int(cat, "rctrl_is_lalt", 0);
update_icons = ini_section_get_int(cat, "update_icons", 1);
status_icons_fullscreen = !!ini_section_get_int(cat, "status_icons_fullscreen", 0);
window_remember = ini_section_get_int(cat, "window_remember", 0);
if (!window_remember && !(vid_resize & 2))
@@ -1782,6 +1784,11 @@ save_general(void)
else
ini_section_delete_var(cat, "open_dir_usr_path");
if (status_icons_fullscreen)
ini_section_set_int(cat, "status_icons_fullscreen", status_icons_fullscreen);
else
ini_section_delete_var(cat, "status_icons_fullscreen");
if (video_framerate != -1)
ini_section_set_int(cat, "video_gl_framerate", video_framerate);
else

File diff suppressed because it is too large Load Diff

View File

@@ -1389,7 +1389,6 @@ cpu_set(void)
cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME;
if (cpu_s->cpu_type == CPU_PENTIUMMMX)
cpu_features |= CPU_FEATURE_MMX;
msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21);
cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE;
#ifdef USE_DYNAREC
codegen_timing_set(&codegen_timing_pentium);
@@ -1503,7 +1502,6 @@ cpu_set(void)
cpu_features |= CPU_FEATURE_MSR | CPU_FEATURE_CR4;
if (cpu_s->cpu_type == CPU_Cx6x86MX)
cpu_features |= CPU_FEATURE_MMX;
msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21);
if (cpu_s->cpu_type >= CPU_CxGX1)
cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE;
@@ -1598,7 +1596,6 @@ cpu_set(void)
cpu_features |= CPU_FEATURE_3DNOW;
if ((cpu_s->cpu_type == CPU_K6_2P) || (cpu_s->cpu_type == CPU_K6_3P))
cpu_features |= CPU_FEATURE_3DNOWE;
msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21);
#if defined(DEV_BRANCH) && defined(USE_AMD_K5)
cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE;
if (cpu_s->cpu_type >= CPU_K6) {
@@ -1701,7 +1698,6 @@ cpu_set(void)
cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME;
if (cpu_s->cpu_type >= CPU_PENTIUM2)
cpu_features |= CPU_FEATURE_MMX;
msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21);
cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PAE | CR4_PCE | CR4_PGE;
if (cpu_s->cpu_type == CPU_PENTIUM2D)
cpu_CR4_mask |= CR4_OSFXSR;
@@ -1749,8 +1745,8 @@ cpu_set(void)
timing_misaligned = 2;
cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_3DNOW;
msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21);
cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE;
msr.fcr = (1 << 7) | (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21);
cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE | CR4_PGE;
cpu_cyrix_alignment = 1;
@@ -1816,12 +1812,13 @@ cpu_set_isa_speed(int speed)
{
if (speed) {
cpu_isa_speed = speed;
pc_speed_changed();
} else if (cpu_busspeed >= 8000000)
cpu_isa_speed = 8000000;
else
cpu_isa_speed = cpu_busspeed;
pc_speed_changed();
cpu_log("cpu_set_isa_speed(%d) = %d\n", speed, cpu_isa_speed);
}
@@ -2373,9 +2370,14 @@ cpu_CPUID(void)
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_SEP | CPUID_CMOV;
} else if (EAX == 2) {
EAX = 0x00000001;
EAX = 0x03020101; /* Instruction TLB: 4 KB pages, 4-way set associative, 32 entries
Instruction TLB: 4 MB pages, fully associative, 2 entries
Data TLB: 4 KB pages, 4-way set associative, 64 entries */
EBX = ECX = 0;
EDX = 0x00000000;
EDX = 0x06040a42; /* 2nd-level cache: 256 KB, 4-way set associative, 32-byte line size
1st-level data cache: 8 KB, 2-way set associative, 32-byte line size
Data TLB: 4 MB pages, 4-way set associative, 8 entries
1st-level instruction cache:8 KB, 4-way set associative, 32-byte line size */
} else
EAX = EBX = ECX = EDX = 0;
break;
@@ -2391,9 +2393,14 @@ cpu_CPUID(void)
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_SEP | CPUID_CMOV;
} else if (EAX == 2) {
EAX = 0x00000001;
EAX = 0x03020101; /* Instruction TLB: 4 KB pages, 4-way set associative, 32 entries
Instruction TLB: 4 MB pages, fully associative, 2 entries
Data TLB: 4 KB pages, 4-way set associative, 64 entries */
EBX = ECX = 0;
EDX = 0x00000000;
EDX = 0x0c040843; /* 2nd-level cache: 512 KB, 4-way set associative, 32-byte line size
1st-level data cache: 16 KB, 4-way set associative, 32-byte line size
Data TLB: 4 MB pages, 4-way set associative, 8 entries
1st-level instruction cache: 16 KB, 4-way set associative, 32-byte line size */
} else
EAX = EBX = ECX = EDX = 0;
break;
@@ -2409,9 +2416,22 @@ cpu_CPUID(void)
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_SEP | CPUID_FXSR | CPUID_CMOV;
} else if (EAX == 2) {
EAX = 0x00000001;
EAX = 0x03020101; /* Instruction TLB: 4 KB pages, 4-way set associative, 32 entries
Instruction TLB: 4 MB pages, fully associative, 2 entries
Data TLB: 4 KB pages, 4-way set associative, 64 entries */
EBX = ECX = 0;
EDX = 0x00000000;
if (cpu_f->package == CPU_PKG_SLOT2) /* Pentium II Xeon Drake */
EDX = 0x0c040844; /* 2nd-level cache: 1 MB, 4-way set associative, 32-byte line size
1st-level data cache: 16 KB, 4-way set associative, 32-byte line size
Data TLB: 4 MB pages, 4-way set associative, 8 entries
1st-level instruction cache: 16 KB, 4-way set associative, 32-byte line size */
else if (!strncmp(cpu_f->internal_name, "celeron", 7)) { /* Celeron */
if (CPUID >= 0x660) /* Mendocino */
EDX = 0x0c040841; /* 2nd-level cache: 128 KB, 4-way set associative, 32-byte line size */
else /* Covington */
EDX = 0x0c040840; /* No 2nd-level cache */
} else /* Pentium II Deschutes and OverDrive */
EDX = 0x0c040843; /* 2nd-level cache: 512 KB, 4-way set associative, 32-byte line size */
} else
EAX = EBX = ECX = EDX = 0;
break;
@@ -2436,6 +2456,8 @@ cpu_CPUID(void)
EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_MMX | CPUID_MTRR;
if (cpu_has_feature(CPU_FEATURE_CX8))
EDX |= CPUID_CMPXCHG8B;
if (msr.fcr & (1 << 7))
EDX |= CPUID_PGE;
break;
case 0x80000000:
EAX = 0x80000005;
@@ -2445,6 +2467,8 @@ cpu_CPUID(void)
EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MCE | CPUID_MMX | CPUID_MTRR | CPUID_3DNOW;
if (cpu_has_feature(CPU_FEATURE_CX8))
EDX |= CPUID_CMPXCHG8B;
if (msr.fcr & (1 << 7))
EDX |= CPUID_PGE;
break;
case 0x80000002: /* Processor name string */
EAX = 0x20414956; /* VIA Samuel */
@@ -2471,6 +2495,13 @@ cpu_ven_reset(void)
memset(&msr, 0, sizeof(msr));
switch (cpu_s->cpu_type) {
case CPU_WINCHIP:
case CPU_WINCHIP2:
msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21);
if (cpu_s->cpu_type == CPU_WINCHIP2)
msr.fcr |= (1 << 18) | (1 << 20);
break;
case CPU_K6_2P:
case CPU_K6_3P:
case CPU_K6_3:
@@ -2491,6 +2522,11 @@ cpu_ven_reset(void)
case CPU_PENTIUM2D:
msr.mtrr_cap = 0x00000508ULL;
break;
case CPU_CYRIX3S:
msr.fcr = (1 << 7) | (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 18) | (1 << 19) |
(1 << 20) | (1 << 21);
break;
}
}
@@ -3105,6 +3141,10 @@ cpu_WRMSR(void)
cpu_features |= CPU_FEATURE_CX8;
else
cpu_features &= ~CPU_FEATURE_CX8;
if (EAX & (1 << 7))
cpu_CR4_mask |= CR4_PGE;
else
cpu_CR4_mask &= ~CR4_PGE;
break;
case 0x1108:
msr.fcr2 = EAX | ((uint64_t) EDX << 32);

File diff suppressed because it is too large Load Diff

View File

@@ -1796,7 +1796,9 @@ pmodeiret(int is32)
}
if (cpu_state.flags & NT_FLAG) {
cpl_override = 1;
seg = readmemw(tr.base, 0);
cpl_override = 0;
addr = seg & 0xfff8;
if (seg & 0x0004) {
x86seg_log("TS LDT %04X %04X IRET\n", seg, gdt.limit);
@@ -1809,8 +1811,8 @@ pmodeiret(int is32)
}
addr += gdt.base;
}
cpl_override = 1;
read_descriptor(addr, segdat, segdat32, 1);
cpl_override = 1;
op_taskswitch286(seg, segdat, segdat[2] & 0x0800);
cpl_override = 0;
return;

View File

@@ -31,11 +31,13 @@
#define CLAMP(a, min, max) (((a) < (min)) ? (min) : (((a) > (max)) ? (max) : (a)))
/* Formulas and factors derived from Linux's gl518sm.c driver. */
#define GL518SM_RPM_TO_REG(r, d) ((r) ? CLAMP((480000 + (r) * (d) / 2) / (r) * (d), 1, 255) : 0)
/* Formulas and factors derived from Linux's gl518sm.c and gl520sm.c drivers. */
#define GL518SM_RPM_TO_REG(r, d) ((r) ? (480000 / (CLAMP((r), (480000 >> (d)) / 255, (480000 >> (d))) << (d))) : 0)
#define GL518SM_VOLTAGE_TO_REG(v) ((uint8_t) round((v) / 19.0))
#define GL518SM_VDD_TO_REG(v) ((uint8_t) (((v) *4) / 95.0))
#define GL520SM 0x100
typedef struct gl518sm_t {
uint32_t local;
hwm_values_t *values;
@@ -128,18 +130,22 @@ gl518sm_read(gl518sm_t *dev, uint8_t reg)
switch (reg) {
case 0x04: /* temperature */
ret = (dev->values->temperatures[0] + 119) & 0xff;
ret = (dev->values->temperatures[0] + ((dev->local & GL520SM) ? 130 : 119)) & 0xff;
break;
case 0x07: /* fan speeds */
ret = GL518SM_RPM_TO_REG(dev->values->fans[0], 1 << ((dev->regs[0x0f] >> 6) & 0x3)) << 8;
ret |= GL518SM_RPM_TO_REG(dev->values->fans[1], 1 << ((dev->regs[0x0f] >> 4) & 0x3));
ret = GL518SM_RPM_TO_REG(dev->values->fans[0], (dev->regs[0x0f] >> 6) & 0x3) << 8;
ret |= GL518SM_RPM_TO_REG(dev->values->fans[1], (dev->regs[0x0f] >> 4) & 0x3);
break;
case 0x0d: /* VIN3 */
ret = GL518SM_VOLTAGE_TO_REG(dev->values->voltages[2]);
break;
case 0x0e: /* temperature 2 */
ret = (dev->local & GL520SM) ? ((dev->values->temperatures[1] + 130) & 0xff) : dev->regs[reg];
break;
case 0x13: /* VIN2 */
ret = GL518SM_VOLTAGE_TO_REG(dev->values->voltages[1]);
break;
@@ -217,6 +223,11 @@ gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val)
gl518sm_reset(dev);
break;
case 0x0e:
if (dev->local & GL520SM)
return 0;
break;
case 0x0f:
dev->regs[reg] = val & 0xf8;
break;
@@ -238,10 +249,16 @@ gl518sm_reset(gl518sm_t *dev)
{
memset(dev->regs, 0, sizeof(dev->regs));
dev->regs[0x00] = 0x80;
dev->regs[0x01] = 0x80; /* revision 0x80 can read all voltages */
dev->regs[0x05] = 0xc7;
dev->regs[0x06] = 0xc2;
if (dev->local & GL520SM) {
dev->regs[0x00] = 0x20;
dev->regs[0x01] = 0x00;
dev->regs[0x03] = 0x04;
} else {
dev->regs[0x00] = 0x80;
dev->regs[0x01] = 0x80; /* revision 0x80 can read all voltages */
dev->regs[0x05] = 0xc7;
dev->regs[0x06] = 0xc2;
}
dev->regs[0x08] = 0x6464;
dev->regs[0x09] = 0xdac5;
dev->regs[0x0a] = 0xdac5;
@@ -279,7 +296,8 @@ gl518sm_init(const device_t *info)
},
{
/* temperatures */
30 /* usually CPU */
30, /* usually CPU */
30 /* GL520SM only: usually System */
},
{
/* voltages */
@@ -327,3 +345,34 @@ const device_t gl518sm_2d_device = {
.force_redraw = NULL,
.config = NULL
};
/* GL520SM on SMBus address 2Ch */
const device_t gl520sm_2c_device = {
.name = "Genesys Logic GL520SM Hardware Monitor",
.internal_name = "gl520sm_2c",
.flags = DEVICE_ISA,
.local = GL520SM | 0x2c,
.init = gl518sm_init,
.close = gl518sm_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
/* GL520SM on SMBus address 2Dh */
const device_t gl520sm_2d_device = {
.name = "Genesys Logic GL520SM Hardware Monitor",
.internal_name = "gl520sm_2d",
.flags = DEVICE_ISA,
.local = GL520SM | 0x2d,
.init = gl518sm_init,
.close = gl518sm_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -29,29 +29,21 @@
#include <86box/plat_unused.h>
#define CHECK_CURRENT_LD() \
if (!dev->current_ld) { \
if (!ld) { \
isapnp_log("ISAPnP: No logical device selected\n"); \
break; \
goto vendor_defined; \
}
#define CHECK_CURRENT_CARD() \
if (1) { \
card = dev->first_card; \
while (card) { \
if (card->enable && (card->state == PNP_STATE_CONFIG)) \
break; \
card = card->next; \
} \
if (!card) { \
isapnp_log("ISAPnP: No card in CONFIG state\n"); \
break; \
} \
#define CHECK_CURRENT_CARD() \
if (!card) { \
isapnp_log("ISAPnP: No card in CONFIG state\n"); \
break; \
}
static const uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,
0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,
0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,
0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 };
const uint8_t isapnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,
0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,
0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,
0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 };
static const device_t isapnp_device;
#ifdef ENABLE_ISAPNP_LOG
@@ -95,6 +87,7 @@ typedef struct _isapnp_card_ {
uint8_t enable;
uint8_t state;
uint8_t csn;
uint8_t ld;
uint8_t id_checksum;
uint8_t serial_read;
uint8_t serial_read_pair;
@@ -265,15 +258,13 @@ isapnp_read_rangecheck(UNUSED(uint16_t addr), void *priv)
}
static uint8_t
isapnp_read_data(UNUSED(uint16_t addr), void *priv)
isapnp_read_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uint8_t reg)
{
isapnp_t *dev = (isapnp_t *) priv;
uint8_t ret = 0xff;
uint8_t bit;
uint8_t next_shift;
isapnp_card_t *card;
uint8_t ret = 0xff;
uint8_t bit;
uint8_t next_shift;
switch (dev->reg) {
switch (reg) {
case 0x01: /* Serial Isolation */
card = dev->first_card;
while (card) {
@@ -342,78 +333,52 @@ isapnp_read_data(UNUSED(uint16_t addr), void *priv)
ret = 0x00;
CHECK_CURRENT_LD();
isapnp_log("ISAPnP: Query LDN for CSN %02X device %02X\n", dev->current_ld_card->csn, dev->current_ld->number);
ret = dev->current_ld->number;
isapnp_log("ISAPnP: Query LDN for CSN %02X device %02X\n", card->csn, ld->number);
ret = ld->number;
break;
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
case 0x27:
case 0x28:
case 0x29:
case 0x2a:
case 0x2b:
case 0x2c:
case 0x2d:
case 0x2e:
case 0x2f:
case 0x20 ... 0x2f:
case 0x38 ... 0x3f:
case 0xa9 ... 0xff:
vendor_defined:
CHECK_CURRENT_CARD();
isapnp_log("ISAPnP: Read vendor-defined register %02X from CSN %02X\n", dev->reg, card->csn);
isapnp_log("ISAPnP: Read vendor-defined register %02X from CSN %02X device %02X\n", reg, card->csn, ld ? ld->number : -1);
if (card->read_vendor_reg)
ret = card->read_vendor_reg(0, dev->reg, card->priv);
break;
case 0x38:
case 0x39:
case 0x3a:
case 0x3b:
case 0x3c:
case 0x3d:
case 0x3e:
case 0x3f:
case 0xf0:
case 0xf1:
case 0xf2:
case 0xf3:
case 0xf4:
case 0xf5:
case 0xf6:
case 0xf7:
case 0xf8:
case 0xf9:
case 0xfa:
case 0xfb:
case 0xfc:
case 0xfd:
case 0xfe:
CHECK_CURRENT_LD();
isapnp_log("ISAPnP: Read vendor-defined register %02X from CSN %02X device %02X\n", dev->reg, dev->current_ld_card->csn, dev->current_ld->number);
if (dev->current_ld_card->read_vendor_reg)
ret = dev->current_ld_card->read_vendor_reg(dev->current_ld->number, dev->reg, dev->current_ld_card->priv);
ret = card->read_vendor_reg(ld ? ld->number : -1, reg, card->priv);
break;
default:
if (dev->reg >= 0x30) {
if (reg >= 0x30) {
CHECK_CURRENT_LD();
isapnp_log("ISAPnP: Read register %02X from CSN %02X device %02X\n", dev->reg, dev->current_ld_card->csn, dev->current_ld->number);
ret = dev->current_ld->regs[dev->reg];
isapnp_log("ISAPnP: Read register %02X from CSN %02X device %02X\n", reg, card->csn, ld->number);
ret = ld->regs[reg];
}
break;
}
isapnp_log("ISAPnP: read_data(%02X) = %02X\n", dev->reg, ret);
isapnp_log("ISAPnP: read_common(%02X) = %02X\n", reg, ret);
return ret;
}
static uint8_t
isapnp_read_data(UNUSED(uint16_t addr), void *priv)
{
isapnp_t *dev = (isapnp_t *) priv;
isapnp_card_t *card = dev->first_card;
while (card) {
if (card->enable && (card->state == PNP_STATE_CONFIG))
break;
card = card->next;
}
isapnp_log("ISAPnP: read_data() => ");
return isapnp_read_common(dev, card, dev->current_ld, dev->reg);
}
static void
isapnp_set_read_data(uint16_t addr, isapnp_t *dev)
{
@@ -445,7 +410,7 @@ isapnp_write_addr(UNUSED(uint16_t addr), uint8_t val, void *priv)
if (card->state == PNP_STATE_WAIT_FOR_KEY) { /* checking only the first card should be fine */
/* Check written value against LFSR key. */
if (val == pnp_init_key[dev->key_pos]) {
if (val == isapnp_init_key[dev->key_pos]) {
dev->key_pos++;
if (!dev->key_pos) {
isapnp_log("ISAPnP: Key unlocked, putting cards to SLEEP\n");
@@ -462,17 +427,14 @@ isapnp_write_addr(UNUSED(uint16_t addr), uint8_t val, void *priv)
}
static void
isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv)
isapnp_write_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uint8_t reg, uint8_t val)
{
isapnp_t *dev = (isapnp_t *) priv;
isapnp_card_t *card;
isapnp_device_t *ld;
uint16_t io_addr;
uint16_t reset_cards = 0;
uint16_t io_addr;
uint16_t reset_cards = 0;
isapnp_log("ISAPnP: write_data(%02X)\n", val);
isapnp_log("ISAPnP: write_common(%02X, %02X)\n", reg, val);
switch (dev->reg) {
switch (reg) {
case 0x00: /* Set RD_DATA Port */
isapnp_set_read_data((val << 2) | 3, dev);
isapnp_log("ISAPnP: Read data port set to %04X\n", dev->read_data_addr);
@@ -526,7 +488,7 @@ isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv)
while (card) {
if (card->csn == val) {
card->rom_pos = 0;
card->id_checksum = pnp_init_key[0];
card->id_checksum = isapnp_init_key[0];
if (card->state == PNP_STATE_SLEEP)
card->state = (val == 0) ? PNP_STATE_ISOLATION : PNP_STATE_CONFIG;
} else {
@@ -551,6 +513,7 @@ isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv)
case 0x07: /* Logical Device Number */
CHECK_CURRENT_CARD();
card->ld = val;
ld = card->first_ld;
while (ld) {
if (ld->number == val) {
@@ -570,10 +533,10 @@ isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv)
case 0x30: /* Activate */
CHECK_CURRENT_LD();
isapnp_log("ISAPnP: %sctivate CSN %02X device %02X\n", (val & 0x01) ? "A" : "Dea", dev->current_ld_card->csn, dev->current_ld->number);
isapnp_log("ISAPnP: %sctivate CSN %02X device %02X\n", (val & 0x01) ? "A" : "Dea", card->csn, ld->number);
dev->current_ld->regs[dev->reg] = val & 0x01;
isapnp_device_config_changed(dev->current_ld_card, dev->current_ld);
ld->regs[reg] = val & 0x01;
isapnp_device_config_changed(card, ld);
break;
@@ -581,80 +544,39 @@ isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv)
CHECK_CURRENT_LD();
for (uint8_t i = 0; i < 8; i++) {
if (!dev->current_ld->io_len[i])
if (!ld->io_len[i])
continue;
io_addr = (dev->current_ld->regs[0x60 + (2 * i)] << 8) | dev->current_ld->regs[0x61 + (2 * i)];
if (dev->current_ld->regs[dev->reg] & 0x02)
io_removehandler(io_addr, dev->current_ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, dev->current_ld);
io_addr = (ld->regs[0x60 + (2 * i)] << 8) | ld->regs[0x61 + (2 * i)];
if (ld->regs[reg] & 0x02)
io_removehandler(io_addr, ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, ld);
if (val & 0x02)
io_sethandler(io_addr, dev->current_ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, dev->current_ld);
io_sethandler(io_addr, ld->io_len[i], isapnp_read_rangecheck, NULL, NULL, NULL, NULL, NULL, ld);
}
dev->current_ld->regs[dev->reg] = val & 0x03;
isapnp_device_config_changed(dev->current_ld_card, dev->current_ld);
ld->regs[reg] = val & 0x03;
isapnp_device_config_changed(card, ld);
break;
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
case 0x27:
case 0x28:
case 0x29:
case 0x2a:
case 0x2b:
case 0x2c:
case 0x2d:
case 0x2e:
case 0x2f:
case 0x20 ... 0x2f:
case 0x38 ... 0x3f:
case 0xa9 ... 0xff:
vendor_defined:
CHECK_CURRENT_CARD();
isapnp_log("ISAPnP: Write %02X to vendor-defined register %02X on CSN %02X\n", val, dev->reg, card->csn);
isapnp_log("ISAPnP: Write %02X to vendor-defined register %02X on CSN %02X device %02X\n", val, reg, card->csn, ld ? ld->number : -1);
if (card->write_vendor_reg)
card->write_vendor_reg(0, dev->reg, val, card->priv);
break;
case 0x38:
case 0x39:
case 0x3a:
case 0x3b:
case 0x3c:
case 0x3d:
case 0x3e:
case 0x3f:
case 0xf0:
case 0xf1:
case 0xf2:
case 0xf3:
case 0xf4:
case 0xf5:
case 0xf6:
case 0xf7:
case 0xf8:
case 0xf9:
case 0xfa:
case 0xfb:
case 0xfc:
case 0xfd:
case 0xfe:
CHECK_CURRENT_LD();
isapnp_log("ISAPnP: Write %02X to vendor-defined register %02X on CSN %02X device %02X\n", val, dev->reg, dev->current_ld_card->csn, dev->current_ld->number);
if (dev->current_ld_card->write_vendor_reg)
dev->current_ld_card->write_vendor_reg(dev->current_ld->number, dev->reg, val, dev->current_ld_card->priv);
card->write_vendor_reg(ld ? ld->number : -1, reg, val, card->priv);
break;
default:
if (dev->reg >= 0x40) {
if (reg >= 0x40) {
CHECK_CURRENT_LD();
isapnp_log("ISAPnP: Write %02X to register %02X on CSN %02X device %02X\n", val, dev->reg, dev->current_ld_card->csn, dev->current_ld->number);
isapnp_log("ISAPnP: Write %02X to register %02X on CSN %02X device %02X\n", val, reg, card->csn, ld->number);
switch (dev->reg) {
switch (reg) {
case 0x42:
case 0x4a:
case 0x52:
@@ -664,7 +586,7 @@ isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv)
case 0x94:
case 0xa4:
/* Read-only memory range length / upper limit bit. */
val = (val & 0xfe) | (dev->current_ld->regs[dev->reg] & 0x01);
val = (val & 0xfe) | (ld->regs[reg] & 0x01);
break;
case 0x60:
@@ -676,21 +598,21 @@ isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv)
case 0x6c:
case 0x6e:
/* Discard upper address bits if this I/O range can only decode 10-bit. */
if (!(dev->current_ld->io_16bit & (1 << ((dev->reg >> 1) & 0x07))))
if (!(ld->io_16bit & (1 << ((reg >> 1) & 0x07))))
val &= 0x03;
break;
case 0x71:
case 0x73:
/* Limit IRQ types to supported ones. */
if ((val & 0x01) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x0c : 0xc0))) /* level, not supported = force edge */
if ((val & 0x01) && !(ld->irq_types & ((reg == 0x71) ? 0x0c : 0xc0))) /* level, not supported = force edge */
val &= ~0x01;
else if (!(val & 0x01) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x03 : 0x30))) /* edge, not supported = force level */
else if (!(val & 0x01) && !(ld->irq_types & ((reg == 0x71) ? 0x03 : 0x30))) /* edge, not supported = force level */
val |= 0x01;
if ((val & 0x02) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x05 : 0x50))) /* high, not supported = force low */
if ((val & 0x02) && !(ld->irq_types & ((reg == 0x71) ? 0x05 : 0x50))) /* high, not supported = force low */
val &= ~0x02;
else if (!(val & 0x02) && !(dev->current_ld->irq_types & ((dev->reg == 0x71) ? 0x0a : 0xa0))) /* low, not supported = force high */
else if (!(val & 0x02) && !(ld->irq_types & ((reg == 0x71) ? 0x0a : 0xa0))) /* low, not supported = force high */
val |= 0x02;
break;
@@ -699,13 +621,31 @@ isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv)
break;
}
dev->current_ld->regs[dev->reg] = val;
isapnp_device_config_changed(dev->current_ld_card, dev->current_ld);
ld->regs[reg] = val;
isapnp_device_config_changed(card, ld);
}
break;
}
}
static void
isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv)
{
isapnp_t *dev = (isapnp_t *) priv;
isapnp_card_t *card = NULL;
if (!card) {
card = dev->first_card;
while (card) {
if (card->enable && (card->state == PNP_STATE_CONFIG))
break;
card = card->next;
}
}
isapnp_log("ISAPnP: write_data(%02X) => ", val);
isapnp_write_common(dev, card, dev->current_ld, dev->reg, val);
}
static void *
isapnp_init(UNUSED(const device_t *info))
{
@@ -869,7 +809,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size)
}
#ifdef ENABLE_ISAPNP_LOG
isapnp_log(" bytes, %swritable, %sread cacheable, %s, %sshadowable, %sexpansion ROM\n",
isapnp_log(" bytes, %swritable, %sread cacheable, %s, %s, %sshadowable, %sexpansion ROM\n",
(card->rom[i + 3] & 0x01) ? "not " : "",
(card->rom[i + 3] & 0x02) ? "not " : "",
(card->rom[i + 3] & 0x04) ? "upper limit" : "range length",
@@ -1135,6 +1075,32 @@ isapnp_set_csn(void *priv, uint8_t csn)
card->csn_changed(card->csn, card->priv);
}
uint8_t
isapnp_read_reg(void *priv, uint8_t ldn, uint8_t reg)
{
isapnp_card_t *card = (isapnp_card_t *) priv;
isapnp_device_t *ld = card->first_ld;
while (ld) {
if (ld->number == ldn)
break;
ld = ld->next;
}
return isapnp_read_common(device_get_priv(&isapnp_device), card, ld, reg);
}
void
isapnp_write_reg(void *priv, uint8_t ldn, uint8_t reg, uint8_t val)
{
isapnp_card_t *card = (isapnp_card_t *) priv;
isapnp_device_t *ld = card->first_ld;
while (ld) {
if (ld->number == ldn)
break;
ld = ld->next;
}
isapnp_write_common(device_get_priv(&isapnp_device), card, ld, reg, val);
}
void
isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config)
{

View File

@@ -54,19 +54,22 @@
#define STAT_IFULL 0x02
#define STAT_OFULL 0x01
// Keyboard Types
#define KBD_TYPE_PC81 0
#define KBD_TYPE_PC82 1
#define KBD_TYPE_XT82 2
#define KBD_TYPE_XT86 3
#define KBD_TYPE_COMPAQ 4
#define KBD_TYPE_TANDY 5
#define KBD_TYPE_TOSHIBA 6
#define KBD_TYPE_VTECH 7
#define KBD_TYPE_OLIVETTI 8
#define KBD_TYPE_ZENITH 9
#define KBD_TYPE_PRAVETZ 10
#define KBD_TYPE_XTCLONE 11
/* Keyboard Types */
enum {
KBD_TYPE_PC81 = 0,
KBD_TYPE_PC82,
KBD_TYPE_XT82,
KBD_TYPE_XT86,
KBD_TYPE_COMPAQ,
KBD_TYPE_TANDY,
KBD_TYPE_TOSHIBA,
KBD_TYPE_VTECH,
KBD_TYPE_OLIVETTI,
KBD_TYPE_ZENITH,
KBD_TYPE_PRAVETZ,
KBD_TYPE_HYUNDAI,
KBD_TYPE_XTCLONE
};
typedef struct xtkbd_t {
int want_irq;
@@ -530,7 +533,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
switch (port) {
case 0x61: /* Keyboard Control Register (aka Port B) */
if (!(val & 0x80)) {
if (!(val & 0x80) || (kbd->type == KBD_TYPE_HYUNDAI)) {
new_clock = !!(val & 0x40);
if (!kbd->clock && new_clock) {
key_queue_start = key_queue_end = 0;
@@ -540,7 +543,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv)
}
}
kbd->pb = val;
if (!(kbd->pb & 0x80))
if (!(kbd->pb & 0x80) || (kbd->type == KBD_TYPE_HYUNDAI))
kbd->clock = !!(kbd->pb & 0x40);
ppi.pb = val;
@@ -603,10 +606,10 @@ kbd_read(uint16_t port, void *priv)
(kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ) ||
(kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) ||
(kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_ZENITH))) {
(kbd->type == KBD_TYPE_ZENITH) || (kbd->type == KBD_TYPE_HYUNDAI))) {
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) ||
(kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_PRAVETZ))
(kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_HYUNDAI))
ret = (kbd->pd & ~0x02) | (hasfpu ? 0x02 : 0x00);
else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86))
/* According to Ruud on the PCem forum, this is supposed to
@@ -696,7 +699,7 @@ kbd_read(uint16_t port, void *priv)
case 0x63: /* Keyboard Configuration Register (aka Port D) */
if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) ||
(kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_TOSHIBA))
(kbd->type == KBD_TYPE_TOSHIBA) || (kbd->type == KBD_TYPE_HYUNDAI))
ret = kbd->pd;
break;
@@ -762,7 +765,7 @@ kbd_init(const device_t *info)
(kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_XT82) ||
(kbd->type <= KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) ||
(kbd->type == KBD_TYPE_COMPAQ) || (kbd->type == KBD_TYPE_TOSHIBA) ||
(kbd->type == KBD_TYPE_OLIVETTI)) {
(kbd->type == KBD_TYPE_OLIVETTI) || (kbd->type == KBD_TYPE_HYUNDAI)) {
/* DIP switch readout: bit set = OFF, clear = ON. */
if (kbd->type == KBD_TYPE_OLIVETTI)
/* Olivetti M19
@@ -781,7 +784,8 @@ kbd_init(const device_t *info)
/* Switches 3, 4 - memory size. */
if ((kbd->type == KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) ||
(kbd->type == KBD_TYPE_COMPAQ) || (kbd->type == KBD_TYPE_TOSHIBA)) {
(kbd->type == KBD_TYPE_HYUNDAI) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_TOSHIBA)) {
switch (mem_size) {
case 256:
kbd->pd |= 0x00;
@@ -1076,6 +1080,20 @@ const device_t keyboard_xt_zenith_device = {
.config = NULL
};
const device_t keyboard_xt_hyundai_device = {
.name = "Hyundai XT Keyboard",
.internal_name = "keyboard_x_hyundai",
.flags = 0,
.local = KBD_TYPE_HYUNDAI,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t keyboard_xtclone_device = {
.name = "XT (Clone) Keyboard",
.internal_name = "keyboard_xtclone",

View File

@@ -82,23 +82,23 @@
#define WIN_SEEK 0x70
#define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */
#define WIN_SPECIFY 0x91 /* Initialize Drive Parameters */
#define WIN_PACKETCMD 0xA0 /* Send a packet command. */
#define WIN_PIDENTIFY 0xA1 /* Identify ATAPI device */
#define WIN_READ_MULTIPLE 0xC4
#define WIN_WRITE_MULTIPLE 0xC5
#define WIN_SET_MULTIPLE_MODE 0xC6
#define WIN_READ_DMA 0xC8
#define WIN_READ_DMA_ALT 0xC9
#define WIN_WRITE_DMA 0xCA
#define WIN_WRITE_DMA_ALT 0xCB
#define WIN_STANDBYNOW1 0xE0
#define WIN_IDLENOW1 0xE1
#define WIN_SETIDLE1 0xE3
#define WIN_CHECKPOWERMODE1 0xE5
#define WIN_SLEEP1 0xE6
#define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */
#define WIN_SET_FEATURES 0xEF
#define WIN_READ_NATIVE_MAX 0xF8
#define WIN_PACKETCMD 0xa0 /* Send a packet command. */
#define WIN_PIDENTIFY 0xa1 /* Identify ATAPI device */
#define WIN_READ_MULTIPLE 0xc4
#define WIN_WRITE_MULTIPLE 0xc5
#define WIN_SET_MULTIPLE_MODE 0xc6
#define WIN_READ_DMA 0xc8
#define WIN_READ_DMA_ALT 0xc9
#define WIN_WRITE_DMA 0xcA
#define WIN_WRITE_DMA_ALT 0xcB
#define WIN_STANDBYNOW1 0xe0
#define WIN_IDLENOW1 0xe1
#define WIN_SETIDLE1 0xe3
#define WIN_CHECKPOWERMODE1 0xe5
#define WIN_SLEEP1 0xe6
#define WIN_IDENTIFY 0xeC /* Ask drive to identify itself */
#define WIN_SET_FEATURES 0xeF
#define WIN_READ_NATIVE_MAX 0xf8
#define FEATURE_SET_TRANSFER_MODE 0x03
#define FEATURE_ENABLE_IRQ_OVERLAPPED 0x5d
@@ -138,50 +138,90 @@ typedef struct ide_board_t {
ide_board_t *ide_boards[IDE_BUS_MAX];
static uint8_t ide_ter_pnp_rom[] = {
0x09, 0xf8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* BOX0001, serial 0, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
0x82, 0x0e, 0x00, 'I', 'D', 'E', ' ', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', /* ANSI identifier */
/* BOX0001, serial 0, dummy checksum (filled in by isapnp_add_card) */
0x09, 0xf8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
/* PnP version 1.0, vendor version 1.0 */
0x0a, 0x10, 0x10,
/* ANSI identifier */
0x82, 0x0e, 0x00, 'I', 'D', 'E', ' ', 'C', 'o', 'n', 't', 'r', 'o',
'l', 'l', 'e', 'r',
0x15, 0x09, 0xf8, 0x00, 0x01, 0x00, /* logical device BOX0001 */
0x1c, 0x41, 0xd0, 0x06, 0x00, /* compatible device PNP0600 */
0x31, 0x00, /* start dependent functions, preferred */
0x22, 0x00, 0x08, /* IRQ 11 */
0x47, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x01, 0x08, /* I/O 0x1E8, decodes 16-bit, 1-byte alignment, 8 addresses */
0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x01, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */
0x30, /* start dependent functions, acceptable */
0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */
0x47, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x01, 0x08, /* I/O 0x1E8, decodes 16-bit, 1-byte alignment, 8 addresses */
0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x01, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */
0x30, /* start dependent functions, acceptable */
0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */
0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x47, 0x01, 0x00, 0x01, 0xff, 0xff, 0x01, 0x01, /* I/O 0x100-0xFFFF, decodes 16-bit, 1-byte alignment, 1 address */
0x38, /* end dependent functions */
/* Logical device BOX0001 */
0x15, 0x09, 0xf8, 0x00, 0x01, 0x00,
/* Compatible device PNP0600 */
0x1c, 0x41, 0xd0, 0x06, 0x00,
/* Start dependent functions, preferred */
0x31, 0x00,
/* IRQ 11 */
0x22, 0x00, 0x08,
/* I/O 0x1E8, decodes 16-bit, 1-byte alignment, 8 addresses */
0x47, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x01, 0x08,
/* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */
0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x01,
/* Start dependent functions, acceptable */
0x30,
/* IRQ 3/4/5/7/9/10/11/12 */
0x22, 0xb8, 0x1e,
/* I/O 0x1E8, decodes 16-bit, 1-byte alignment, 8 addresses */
0x47, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x01, 0x08,
/* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */
0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x01,
/* Start dependent functions, acceptable */
0x30,
/* IRQ 3/4/5/7/9/10/11/12 */
0x22, 0xb8, 0x1e,
/* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08,
/* I/O 0x100-0xFFFF, decodes 16-bit, 1-byte alignment, 1 address */
0x47, 0x01, 0x00, 0x01, 0xff, 0xff, 0x01, 0x01,
/* End dependent functions */
0x38,
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
/* End tag, dummy checksum (filled in by isapnp_add_card) */
0x79, 0x00
};
static uint8_t ide_qua_pnp_rom[] = {
0x09, 0xf8, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, /* BOX0001, serial 1, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
0x82, 0x0e, 0x00, 'I', 'D', 'E', ' ', 'C', 'o', 'n', 't', 'r', 'o', 'l', 'l', 'e', 'r', /* ANSI identifier */
/* BOX0001, serial 1, dummy checksum (filled in by isapnp_add_card) */
0x09, 0xf8, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
/* PnP version 1.0, vendor version 1.0 */
0x0a, 0x10, 0x10,
/* ANSI identifier */
0x82, 0x0e, 0x00, 'I', 'D', 'E', ' ', 'C', 'o', 'n', 't', 'r', 'o',
'l', 'l', 'e', 'r',
0x15, 0x09, 0xf8, 0x00, 0x01, 0x00, /* logical device BOX0001 */
0x1c, 0x41, 0xd0, 0x06, 0x00, /* compatible device PNP0600 */
0x31, 0x00, /* start dependent functions, preferred */
0x22, 0x00, 0x04, /* IRQ 10 */
0x47, 0x01, 0x68, 0x01, 0x68, 0x01, 0x01, 0x08, /* I/O 0x168, decodes 16-bit, 1-byte alignment, 8 addresses */
0x47, 0x01, 0x6e, 0x03, 0x6e, 0x03, 0x01, 0x01, /* I/O 0x36E, decodes 16-bit, 1-byte alignment, 1 address */
0x30, /* start dependent functions, acceptable */
0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */
0x47, 0x01, 0x68, 0x01, 0x68, 0x01, 0x01, 0x08, /* I/O 0x168, decodes 16-bit, 1-byte alignment, 8 addresses */
0x47, 0x01, 0x6e, 0x03, 0x6e, 0x03, 0x01, 0x01, /* I/O 0x36E, decodes 16-bit, 1-byte alignment, 1 address */
0x30, /* start dependent functions, acceptable */
0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */
0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x47, 0x01, 0x00, 0x01, 0xff, 0xff, 0x01, 0x01, /* I/O 0x100-0xFFFF, decodes 16-bit, 1-byte alignment, 1 address */
0x38, /* end dependent functions */
/* Logical device BOX0001 */
0x15, 0x09, 0xf8, 0x00, 0x01, 0x00,
/* Compatible device PNP0600 */
0x1c, 0x41, 0xd0, 0x06, 0x00,
/* Start dependent functions, preferred */
0x31, 0x00,
/* IRQ 10 */
0x22, 0x00, 0x04,
/* I/O 0x168, decodes 16-bit, 1-byte alignment, 8 addresses */
0x47, 0x01, 0x68, 0x01, 0x68, 0x01, 0x01, 0x08,
/* I/O 0x36E, decodes 16-bit, 1-byte alignment, 1 address */
0x47, 0x01, 0x6e, 0x03, 0x6e, 0x03, 0x01, 0x01,
/* Start dependent functions, acceptable */
0x30,
/* IRQ 3/4/5/7/9/10/11/12 */
0x22, 0xb8, 0x1e,
/* I/O 0x168, decodes 16-bit, 1-byte alignment, 8 addresses */
0x47, 0x01, 0x68, 0x01, 0x68, 0x01, 0x01, 0x08,
/* I/O 0x36E, decodes 16-bit, 1-byte alignment, 1 address */
0x47, 0x01, 0x6e, 0x03, 0x6e, 0x03, 0x01, 0x01,
/* Start dependent functions, acceptable */
0x30,
/* IRQ 3/4/5/7/9/10/11/12 */
0x22, 0xb8, 0x1e,
/* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08,
/* I/O 0x100-0xFFFF, decodes 16-bit, 1-byte alignment, 1 address */
0x47, 0x01, 0x00, 0x01, 0xff, 0xff, 0x01, 0x01,
/* End dependent functions */
0x38,
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
/* End tag, dummy checksum (filled in by isapnp_add_card) */
0x79, 0x00
};
ide_t *ide_drives[IDE_NUM];
@@ -336,7 +376,7 @@ ide_atapi_get_period(uint8_t channel)
}
static void
ide_irq_update(ide_board_t *dev)
ide_irq_update(ide_board_t *dev, int log)
{
ide_t *ide;
uint8_t set;
@@ -344,7 +384,10 @@ ide_irq_update(ide_board_t *dev)
if (dev == NULL)
return;
ide_log("IDE %i: IRQ update (%i)\n", dev->cur_dev >> 1, dev->irq);
#ifdef ENABLE_IDE_LOG
if (log)
ide_log("IDE %i: IRQ update (%i)\n", dev->cur_dev >> 1, dev->irq);
#endif
ide = ide_drives[dev->cur_dev];
set = !(ide_boards[ide->board]->devctl & 2) && ide->irqstat;
@@ -356,32 +399,22 @@ ide_irq_update(ide_board_t *dev)
}
void
ide_irq_raise(ide_t *ide)
ide_irq(ide_t *ide, int set, int log)
{
if (!ide_boards[ide->board])
return;
ide_log("IDE %i: IRQ raise\n", ide->channel);
#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2)
ide_log("IDE %i: IRQ %s\n", ide->channel, set ? "raise" : "lower");
#endif
ide->irqstat = 1;
ide->service = 1;
ide->irqstat = set;
if (set)
ide->service = 1;
if (ide->selected)
ide_irq_update(ide_boards[ide->board]);
}
void
ide_irq_lower(ide_t *ide)
{
if (!ide_boards[ide->board])
return;
ide_log("IDE %i: IRQ lower\n", ide->channel);
ide->irqstat = 0;
if (ide->selected)
ide_irq_update(ide_boards[ide->board]);
ide_irq_update(ide_boards[ide->board], log);
}
/**
@@ -590,7 +623,7 @@ ide_identify(ide_t *ide)
if (ide->type == IDE_ATAPI)
ide->identify(ide, !IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL));
else if (ide->type != IDE_NONE)
else if (ide->type == IDE_HDD)
ide_hd_identify(ide);
else {
fatal("IDE IDENTIFY or IDENTIFY PACKET DEVICE on non-attached IDE device\n");
@@ -682,15 +715,15 @@ ide_get_sector(ide_t *ide)
uint32_t heads;
uint32_t sectors;
if (ide->lba)
if (ide->tf->lba)
return (off64_t) ide->lba_addr;
else {
heads = ide->cfg_hpc;
sectors = ide->cfg_spt;
uint8_t sector = ide->sector ? (ide->sector - 1) : 0;
uint8_t sector = ide->tf->sector ? (ide->tf->sector - 1) : 0;
return ((((off64_t) ide->tf->cylinder * heads) + (off64_t) ide->head) * sectors) +
return ((((off64_t) ide->tf->cylinder * heads) + (off64_t) ide->tf->head) * sectors) +
(off64_t) sector;
}
}
@@ -701,15 +734,15 @@ ide_get_sector(ide_t *ide)
static void
ide_next_sector(ide_t *ide)
{
if (ide->lba)
if (ide->tf->lba)
ide->lba_addr++;
else {
ide->sector++;
if ((ide->sector == 0) || (ide->sector == (ide->cfg_spt + 1))) {
ide->sector = 1;
ide->head++;
if ((ide->head == 0) || (ide->head == ide->cfg_hpc)) {
ide->head = 0;
ide->tf->sector++;
if ((ide->tf->sector == 0) || (ide->tf->sector == (ide->cfg_spt + 1))) {
ide->tf->sector = 1;
ide->tf->head++;
if ((ide->tf->head == 0) || (ide->head == ide->cfg_hpc)) {
ide->tf->head = 0;
ide->tf->cylinder++;
}
}
@@ -736,13 +769,12 @@ loadhd(ide_t *ide, int d, UNUSED(const char *fn))
void
ide_set_signature(ide_t *ide)
{
uint16_t ide_signatures[3] = { /* 0xffff */ 0x7f7f, 0x0000, 0xeb14 };
uint16_t ide_signatures[4] = { 0x7f7f, 0x0000, 0xeb14, 0x7f7f };
ide->sector = 1;
ide->head = 0;
ide->tf->secount = 1;
ide->tf->cylinder = ide_signatures[ide->type];
ide->tf->sector = 1;
ide->tf->head = 0;
ide->tf->secount = 1;
ide->tf->cylinder = ide_signatures[ide->type & ~IDE_SHADOW];
if (ide->type == IDE_HDD)
ide->drive = 0;
@@ -846,16 +878,16 @@ ide_set_sector(ide_t *ide, int64_t sector_num)
{
unsigned int cyl;
unsigned int r;
if (ide->lba) {
ide->head = (sector_num >> 24) & 0xff;
if (ide->tf->lba) {
ide->tf->head = (sector_num >> 24) & 0xff;
ide->tf->cylinder = (sector_num >> 8) & 0xffff;
ide->sector = sector_num & 0xff;
ide->tf->sector = sector_num & 0xff;
} else {
cyl = sector_num / (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt);
r = sector_num % (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt);
ide->tf->cylinder = cyl & 0xffff;
ide->head = ((r / hdd[ide->hdd_num].spt) & 0x0f) & 0xff;
ide->sector = ((r % hdd[ide->hdd_num].spt) + 1) & 0xff;
ide->tf->head = ((r / hdd[ide->hdd_num].spt) & 0x0f) & 0xff;
ide->tf->sector = ((r % hdd[ide->hdd_num].spt) + 1) & 0xff;
}
}
@@ -961,14 +993,20 @@ ide_atapi_callback(ide_t *ide)
"Complete" };
char *phase;
if (ide->sc->packet_status <= PHASE_COMPLETE)
phase = phases[ide->sc->packet_status];
else if (ide->sc->packet_status == PHASE_ERROR)
phase = "Error";
else if (ide->sc->packet_status == PHASE_NONE)
phase = "None";
else
phase = "Unknown";
switch (ide->sc->packet_status) {
default:
phase = "Unknown";
break;
case PHASE_IDLE ... PHASE_COMPLETE:
phase = phases[ide->sc->packet_status];
break;
case PHASE_ERROR:
phase = "Error";
break;
case PHASE_NONE:
phase = "None";
break;
}
ide_log("Phase: %02X (%s)\n", ide->sc->packet_status, phase);
#endif
@@ -1169,36 +1207,38 @@ ide_write_data(ide_t *ide, uint16_t val, int length)
uint8_t *idebufferb = (uint8_t *) ide->buffer;
uint16_t *idebufferw = ide->buffer;
if (ide->command == WIN_PACKETCMD) {
if (ide->type == IDE_ATAPI)
ide_atapi_packet_write(ide, val, length);
else
ide->tf->pos = 0;
} else {
if (length == 2) {
idebufferw[ide->tf->pos >> 1] = val & 0xffff;
ide->tf->pos += 2;
if ((ide->type != IDE_NONE) && !(ide->type & IDE_SHADOW) && ide->buffer) {
if (ide->command == WIN_PACKETCMD) {
if (ide->type == IDE_ATAPI)
ide_atapi_packet_write(ide, val, length);
else
ide->tf->pos = 0;
} else {
idebufferb[ide->tf->pos] = val & 0xff;
ide->tf->pos++;
}
if (length == 2) {
idebufferw[ide->tf->pos >> 1] = val & 0xffff;
ide->tf->pos += 2;
} else {
idebufferb[ide->tf->pos] = val & 0xff;
ide->tf->pos++;
}
if (ide->tf->pos >= 512) {
ide->tf->pos = 0;
ide->tf->atastat = BSY_STAT;
double seek_time = hdd_timing_write(&hdd[ide->hdd_num], ide_get_sector(ide), 1);
double xfer_time = ide_get_xfer_time(ide, 512);
double wait_time = seek_time + xfer_time;
if (ide->command == WIN_WRITE_MULTIPLE) {
if ((ide->blockcount + 1) >= ide->blocksize || ide->tf->secount == 1) {
ide_set_callback(ide, seek_time + xfer_time + ide->pending_delay);
ide->pending_delay = 0;
} else {
ide->pending_delay += wait_time;
ide_callback(ide);
}
} else
ide_set_callback(ide, wait_time);
if (ide->tf->pos >= 512) {
ide->tf->pos = 0;
ide->tf->atastat = BSY_STAT;
double seek_time = hdd_timing_write(&hdd[ide->hdd_num], ide_get_sector(ide), 1);
double xfer_time = ide_get_xfer_time(ide, 512);
double wait_time = seek_time + xfer_time;
if (ide->command == WIN_WRITE_MULTIPLE) {
if ((ide->blockcount + 1) >= ide->blocksize || ide->tf->secount == 1) {
ide_set_callback(ide, seek_time + xfer_time + ide->pending_delay);
ide->pending_delay = 0;
} else {
ide->pending_delay += wait_time;
ide_callback(ide);
}
} else
ide_set_callback(ide, wait_time);
}
}
}
}
@@ -1214,7 +1254,9 @@ ide_writew(uint16_t addr, uint16_t val, void *priv)
ch = dev->cur_dev;
ide = ide_drives[ch];
#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2)
ide_log("ide_writew(%04X, %04X, %08X)\n", addr, val, priv);
#endif
addr &= 0x7;
@@ -1246,7 +1288,9 @@ ide_writel(uint16_t addr, uint32_t val, void *priv)
ch = dev->cur_dev;
ide = ide_drives[ch];
#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2)
ide_log("ide_writel(%04X, %08X, %08X)\n", addr, val, priv);
#endif
addr &= 0x7;
@@ -1361,22 +1405,22 @@ ide_write_devctl(UNUSED(uint16_t addr), uint8_t val, void *priv)
old = dev->devctl;
dev->devctl = val;
if (!(val & 0x02) && (old & 0x02))
ide_irq_update(ide_boards[ide->board]);
ide_irq_update(ide_boards[ide->board], 1);
}
static void
ide_reset_registers(ide_t *ide)
{
uint16_t ide_signatures[3] = { /* 0xffff */ 0x7f7f, 0x0000, 0xeb14 };
uint16_t ide_signatures[4] = { 0x7f7f, 0x0000, 0xeb14, 0x7f7f };
ide->tf->atastat = DRDY_STAT | DSC_STAT;
ide->tf->error = 1;
ide->tf->secount = 1;
ide->tf->cylinder = ide_signatures[ide->type];
ide->tf->cylinder = ide_signatures[ide->type & ~IDE_SHADOW];
ide->tf->sector = 1;
ide->tf->head = 0;
ide->sector = 1;
ide->head = 0;
ide->reset = 0;
ide->reset = 0;
if (ide->type == IDE_ATAPI)
ide->sc->callback = 0.0;
@@ -1391,7 +1435,6 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
ide_t *ide;
ide_t *ide_other;
int ch;
int absent = 0;
int bad = 0;
int reset = 0;
@@ -1399,64 +1442,74 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
ide = ide_drives[ch];
ide_other = ide_drives[ch ^ 1];
/* Absent and is master or both are absent. */
if ((ide->type == IDE_NONE) && ((ide_drives[ch ^ 1]->type == IDE_NONE) || !(ch & 1)))
absent = 1;
/* Absent and is slave and master is present. */
else if ((ide->type == IDE_NONE) && (ch & 1))
absent = 2;
ide_log("ide_writeb(%04X, %02X, %08X)\n", addr, val, priv);
addr &= 0x7;
if ((absent != 1) || ((addr != 0x0) && (addr != 0x7))) switch (addr) {
if ((ide->type != IDE_NONE) || ((addr != 0x0) && (addr != 0x7))) switch (addr) {
case 0x0: /* Data */
if (absent == 0)
ide_write_data(ide, val | (val << 8), 2);
ide_write_data(ide, val | (val << 8), 2);
break;
/* Note to self: for ATAPI, bit 0 of this is DMA if set, PIO if clear. */
case 0x1: /* Features */
ide->tf->cylprecomp = val;
if (ide->type == IDE_ATAPI)
ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO");
if (!(ide->tf->atastat & (BSY_STAT | DRQ_STAT))) {
ide->tf->cylprecomp = val;
if (ide->type == IDE_ATAPI)
ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO");
}
/* The ATA-3 specification says this register is the parameter for the
command and is unclear as to whether or not it's written to both
devices at once. Writing it to both devices at once breaks CD boot
on the AMI Apollo. */
#ifdef WRITE_PARAM_TO_BOTH_DEVICES
ide_other->tf->cylprecomp = val;
#endif
return;
if (!(ide_other->tf->atastat & (BSY_STAT | DRQ_STAT)))
ide_other->tf->cylprecomp = val;
break;
case 0x2: /* Sector count */
ide->tf->secount = val;
ide_other->tf->secount = val;
if (!(ide->tf->atastat & (BSY_STAT | DRQ_STAT)))
ide->tf->secount = val;
if (!(ide_other->tf->atastat & (BSY_STAT | DRQ_STAT)))
ide_other->tf->secount = val;
break;
case 0x3: /* Sector */
ide->sector = val;
ide->lba_addr = (ide->lba_addr & 0xfffff00) | val;
ide_other->sector = val;
ide_other->lba_addr = (ide_other->lba_addr & 0xfffff00) | val;
if (!(ide->tf->atastat & (BSY_STAT | DRQ_STAT))) {
ide->tf->sector = val;
ide->lba_addr = (ide->lba_addr & 0xfffff00) | val;
}
if (!(ide_other->tf->atastat & (BSY_STAT | DRQ_STAT))) {
ide_other->tf->sector = val;
ide_other->lba_addr = (ide_other->lba_addr & 0xfffff00) | val;
}
break;
case 0x4: /* Cylinder low */
ide->tf->cylinder = (ide->tf->cylinder & 0xff00) | val;
ide->lba_addr = (ide->lba_addr & 0xfff00ff) | (val << 8);
if (ide->type & IDE_SHADOW)
break;
ide_other->tf->cylinder = (ide_other->tf->cylinder & 0xff00) | val;
ide_other->lba_addr = (ide_other->lba_addr & 0xfff00ff) | (val << 8);
if (!(ide->tf->atastat & (BSY_STAT | DRQ_STAT))) {
ide->tf->cylinder = (ide->tf->cylinder & 0xff00) | val;
ide->lba_addr = (ide->lba_addr & 0xfff00ff) | (val << 8);
}
if (!(ide_other->tf->atastat & (BSY_STAT | DRQ_STAT))) {
ide_other->tf->cylinder = (ide_other->tf->cylinder & 0xff00) | val;
ide_other->lba_addr = (ide_other->lba_addr & 0xfff00ff) | (val << 8);
}
break;
case 0x5: /* Cylinder high */
ide->tf->cylinder = (ide->tf->cylinder & 0xff) | (val << 8);
ide->lba_addr = (ide->lba_addr & 0xf00ffff) | (val << 16);
if (ide->type & IDE_SHADOW)
break;
ide_other->tf->cylinder = (ide_other->tf->cylinder & 0xff) | (val << 8);
ide_other->lba_addr = (ide_other->lba_addr & 0xf00ffff) | (val << 16);
if (!(ide->tf->atastat & (BSY_STAT | DRQ_STAT))) {
ide->tf->cylinder = (ide->tf->cylinder & 0xff) | (val << 8);
ide->lba_addr = (ide->lba_addr & 0xf00ffff) | (val << 16);
}
if (!(ide_other->tf->atastat & (BSY_STAT | DRQ_STAT))) {
ide_other->tf->cylinder = (ide_other->tf->cylinder & 0xff) | (val << 8);
ide_other->lba_addr = (ide_other->lba_addr & 0xf00ffff) | (val << 16);
}
break;
case 0x6: /* Drive/Head */
@@ -1482,20 +1535,29 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
ide_set_board_callback(ide->board, 0.0);
reset = 1;
} else
ide_irq_update(ide_boards[ide->board]);
ide_irq_update(ide_boards[ide->board], 1);
}
if (!reset) {
ide->head = ide_other->head = val & 0xF;
ide->lba = ide_other->lba = val & 0x40;
if (!(ide->tf->atastat & (BSY_STAT | DRQ_STAT))) {
ide->tf->drvsel = val & 0xef;
ide->lba_addr = (ide->lba_addr & 0x0ffffff) |
(ide->tf->head << 24);
}
ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24);
ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24);
if (!(ide_other->tf->atastat & (BSY_STAT | DRQ_STAT))) {
ide_other->tf->drvsel = val & 0xef;
ide_other->lba_addr = (ide_other->lba_addr & 0x0ffffff) |
(ide->tf->head << 24);
}
}
break;
case 0x7: /* Command register */
if (absent != 0)
if (ide->tf->atastat & (BSY_STAT | DRQ_STAT))
break;
if ((ide->type == IDE_NONE) || ((ide->type & IDE_SHADOW) && (val != WIN_DRIVE_DIAGNOSTICS)))
break;
ide_irq_lower(ide);
@@ -1721,70 +1783,70 @@ ide_read_data(ide_t *ide, int length)
{
const uint8_t *idebufferb = (uint8_t *) ide->buffer;
const uint16_t *idebufferw = ide->buffer;
int ch = ide->channel;
uint16_t ret = 0;
double seek_us;
double xfer_us;
/* Absent and is master or both are absent. */
if ((ide->type == IDE_NONE) && ((ide_drives[ch ^ 1]->type == IDE_NONE) || !(ch & 1))) {
#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2)
ide_log("ide_read_data(): ch = %i, board = %i, type = %i\n", ch,
ide->board, ide->type);
#endif
if ((ide->type == IDE_NONE) || (ide->type & IDE_SHADOW) || !ide->buffer) {
if (length == 2)
ret = 0xff7f;
else
ret = 0x7f;
/* Absent and is slave and master is present. */
} else if ((ide->type != IDE_NONE) || !(ch & 1)) {
if (!ide->buffer) {
if (length == 2)
ret = 0xffff;
else
ret = 0xff;
} else if (ide->command == WIN_PACKETCMD) {
if (ide->type == IDE_ATAPI)
ret = ide_atapi_packet_read(ide, length);
else {
ide_log("Drive not ATAPI (position: %i)\n", ide->tf->pos);
ide->tf->pos = 0;
}
} else if (ide->command == WIN_PACKETCMD) {
if (ide->type == IDE_ATAPI)
ret = ide_atapi_packet_read(ide, length);
else {
ide_log("Drive not ATAPI (position: %i)\n", ide->tf->pos);
ide->tf->pos = 0;
}
} else {
if (length == 2) {
ret = idebufferw[ide->tf->pos >> 1];
ide->tf->pos += 2;
} else {
if (length == 2) {
ret = idebufferw[ide->tf->pos >> 1];
ide->tf->pos += 2;
} else {
ret = idebufferb[ide->tf->pos];
ide->tf->pos++;
}
ret = idebufferb[ide->tf->pos];
ide->tf->pos++;
}
if (ide->tf->pos >= 512) {
ide->tf->pos = 0;
ide->tf->atastat = DRDY_STAT | DSC_STAT;
if (ide->type == IDE_ATAPI)
ide->sc->packet_status = PHASE_IDLE;
if (ide->tf->pos >= 512) {
ide->tf->pos = 0;
ide->tf->atastat = DRDY_STAT | DSC_STAT;
if (ide->type == IDE_ATAPI)
ide->sc->packet_status = PHASE_IDLE;
if ((ide->command == WIN_READ) || (ide->command == WIN_READ_NORETRY) ||
(ide->command == WIN_READ_MULTIPLE)) {
ide->tf->secount--;
if ((ide->command == WIN_READ) ||
(ide->command == WIN_READ_NORETRY) ||
(ide->command == WIN_READ_MULTIPLE)) {
ide->tf->secount--;
if (ide->tf->secount) {
ide_next_sector(ide);
ide->tf->atastat = BSY_STAT | READY_STAT | DSC_STAT;
if (ide->command == WIN_READ_MULTIPLE) {
if (!ide->blockcount) {
uint32_t sec_count = ide->tf->secount ? ide->tf->secount : 256;
if (sec_count > ide->blocksize)
sec_count = ide->blocksize;
double seek_time = hdd_timing_read(&hdd[ide->hdd_num],
ide_get_sector(ide), sec_count);
double xfer_time = ide_get_xfer_time(ide, 512 * sec_count);
ide_set_callback(ide, seek_time + xfer_time);
} else
ide_callback(ide);
} else {
double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), 1);
double xfer_time = ide_get_xfer_time(ide, 512);
ide_set_callback(ide, seek_time + xfer_time);
}
} else
ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0);
}
if (ide->tf->secount) {
ide_next_sector(ide);
ide->tf->atastat = BSY_STAT | READY_STAT | DSC_STAT;
if (ide->command == WIN_READ_MULTIPLE) {
if (!ide->blockcount) {
uint32_t cnt = ide->tf->secount ?
ide->tf->secount : 256;
if (cnt > ide->blocksize)
cnt = ide->blocksize;
seek_us = hdd_timing_read(&hdd[ide->hdd_num],
ide_get_sector(ide), cnt);
xfer_us = ide_get_xfer_time(ide, 512 * cnt);
ide_set_callback(ide, seek_us + xfer_us);
} else
ide_callback(ide);
} else {
seek_us = hdd_timing_read(&hdd[ide->hdd_num],
ide_get_sector(ide), 1);
xfer_us = ide_get_xfer_time(ide, 512);
ide_set_callback(ide, seek_us + xfer_us);
}
} else
ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0);
}
}
}
@@ -1798,11 +1860,11 @@ ide_status(ide_t *ide, ide_t *ide_other, int ch)
uint8_t ret;
/* Absent and is master or both are absent. */
if ((ide->type == IDE_NONE) && ((ide_drives[ch ^ 1]->type == IDE_NONE) || !(ch & 1))) {
if (ide->type == IDE_NONE) {
/* Bit 7 pulled down, all other bits pulled up, per the spec. */
ret = 0x7f;
/* Absent and is slave and master is present. */
} else if ((ide->type == IDE_NONE) && (ch & 1)) {
} else if (ide->type & IDE_SHADOW) {
/* On real hardware, a slave with a present master always
returns a status of 0x00.
Confirmed by the ATA-3 and ATA-4 specifications. */
@@ -1821,21 +1883,11 @@ ide_readb(uint16_t addr, void *priv)
{
const ide_board_t *dev = (ide_board_t *) priv;
int ch;
int absent = 0;
ide_t *ide;
ide_t *ide_other;
uint8_t ret = 0xff;
ch = dev->cur_dev;
ide = ide_drives[ch];
ide_other = ide_drives[ch ^ 1];
/* Absent and is master or both are absent. */
if ((ide->type == IDE_NONE) && ((ide_drives[ch ^ 1]->type == IDE_NONE) || !(ch & 1)))
absent = 1;
/* Absent and is slave and master is present. */
else if ((ide->type == IDE_NONE) && (ch & 1))
absent = 2;
switch (addr & 0x7) {
case 0x0: /* Data */
@@ -1846,7 +1898,7 @@ ide_readb(uint16_t addr, void *priv)
Bit 2 = ABRT (aborted command), Bit 1 = EOM (end of media),
and Bit 0 = ILI (illegal length indication). */
case 0x1: /* Error */
if (absent == 1)
if (ide->type == IDE_NONE)
ret = 0x7f;
else
ret = ide->tf->error;
@@ -1866,52 +1918,52 @@ ide_readb(uint16_t addr, void *priv)
0 1 0 Data from host
1 0 1 Status. */
case 0x2: /* Sector count */
if (absent == 1)
if (ide->type == IDE_NONE)
ret = 0x7f;
else if (absent == 2)
ret = ide_other->tf->secount;
else
ret = ide->tf->secount;
break;
case 0x3: /* Sector */
if (absent == 1)
if (ide->type == IDE_NONE)
ret = 0x7f;
else if (absent == 2)
ret = (uint8_t) ide_other->sector;
else
ret = (uint8_t) ide->sector;
ret = (uint8_t) ide->tf->sector;
break;
case 0x4: /* Cylinder low */
if (absent == 1)
if (ide->type == IDE_NONE)
ret = 0x7f;
else if (absent == 2)
ret = ide_other->tf->cylinder & 0xff;
else
ret = ide->tf->cylinder & 0xff;
#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2)
ide_log("Cylinder low @ board %i, channel %i: ide->type = %i, "
"ret = %02X\n", ide->board, ide->channel, ide->type, ret);
#endif
break;
case 0x5: /* Cylinder high */
if (absent == 1)
if (ide->type == IDE_NONE)
ret = 0x7f;
else if (absent == 2)
ret = ide_other->tf->cylinder >> 8;
else
ret = ide->tf->cylinder >> 8;
#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2)
pclog("Cylinder high @ board %i, channel %i: ide->type = %i, "
"ret = %02X\n", ide->board, ide->channel, ide->type, ret);
#endif
break;
case 0x6: /* Drive/Head */
if (absent == 1)
if (ide->type == IDE_NONE)
ret = 0x7f;
else
ret = (uint8_t) (ide->head | ((ch & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0);
ret = ide->tf->drvsel | ((ch & 1) ? 0xb0 : 0xa0);
break;
/* For ATAPI: Bit 5 is DMA ready, but without overlapped or interlaved DMA, it is
DF (drive fault). */
case 0x7: /* Status */
ide_irq_lower(ide);
ide_irq(ide, 0, 0);
ret = ide_status(ide, ide_drives[ch ^ 1], ch);
break;
@@ -1969,7 +2021,9 @@ ide_readw(uint16_t addr, void *priv)
break;
}
#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2)
ide_log("ide_readw(%04X, %08X) = %04X\n", addr, priv, ret);
#endif
return ret;
}
@@ -2002,7 +2056,9 @@ ide_readl(uint16_t addr, void *priv)
break;
}
#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2)
ide_log("ide_readl(%04X, %08X) = %04X\n", addr, priv, ret);
#endif
return ret;
}
@@ -2012,9 +2068,7 @@ ide_board_callback(void *priv)
ide_board_t *dev = (ide_board_t *) priv;
ide_t *ide;
#ifdef ENABLE_IDE_LOG
ide_log("ide_board_callback(%i)\n", dev->cur_dev >> 1);
#endif
for (uint8_t i = 0; i < 2; i++) {
ide = dev->ide[i];
@@ -2060,13 +2114,13 @@ ide_callback(void *priv)
ide_log("ide_callback(%i): %02X\n", ide->channel, ide->command);
switch (ide->command) {
case WIN_SEEK ... 0x7F:
chk_chs = !ide->lba;
case WIN_SEEK ... 0x7f:
chk_chs = !ide->tf->lba;
if (ide->type == IDE_ATAPI)
atapi_error_no_ready(ide);
else {
if (chk_chs && ((ide->tf->cylinder >= ide->tracks) || (ide->head >= ide->hpc) ||
!ide->sector || (ide->sector > ide->spt)))
if (chk_chs && ((ide->tf->cylinder >= ide->tracks) || (ide->tf->head >= ide->hpc) ||
!ide->tf->sector || (ide->tf->sector > ide->spt)))
err = IDNF_ERR;
else {
ide->tf->atastat = DRDY_STAT | DSC_STAT;
@@ -2075,7 +2129,7 @@ ide_callback(void *priv)
}
break;
case WIN_RECAL ... 0x1F:
case WIN_RECAL ... 0x1f:
if (ide->type == IDE_ATAPI)
atapi_error_no_ready(ide);
else {
@@ -2091,7 +2145,7 @@ ide_callback(void *priv)
ide->tf->error = 1; /*Device passed*/
ide->tf->secount = 1;
ide->sector = 1;
ide->tf->sector = 1;
ide_set_signature(ide);
@@ -2129,7 +2183,7 @@ ide_callback(void *priv)
if (ide->type == IDE_ATAPI) {
ide_set_signature(ide);
err = ABRT_ERR;
} else if (!ide->lba && (ide->cfg_spt == 0))
} else if (!ide->tf->lba && (ide->cfg_spt == 0))
err = IDNF_ERR;
else {
if (ide->do_initial_read) {
@@ -2157,7 +2211,7 @@ ide_callback(void *priv)
if ((ide->type == IDE_ATAPI) || ide_boards[ide->board]->force_ata3 || (bm == NULL)) {
ide_log("IDE %i: DMA read aborted (bad device or board)\n", ide->channel);
err = ABRT_ERR;
} else if (!ide->lba && (ide->cfg_spt == 0)) {
} else if (!ide->tf->lba && (ide->cfg_spt == 0)) {
ide_log("IDE %i: DMA read aborted (SPECIFY failed)\n", ide->channel);
err = IDNF_ERR;
} else {
@@ -2207,7 +2261,7 @@ ide_callback(void *priv)
mand error. */
if ((ide->type == IDE_ATAPI) || !ide->blocksize)
err = ABRT_ERR;
else if (!ide->lba && (ide->cfg_spt == 0))
else if (!ide->tf->lba && (ide->cfg_spt == 0))
err = IDNF_ERR;
else {
if (ide->do_initial_read) {
@@ -2235,7 +2289,7 @@ ide_callback(void *priv)
case WIN_WRITE_NORETRY:
if (ide->type == IDE_ATAPI)
err = ABRT_ERR;
else if (!ide->lba && (ide->cfg_spt == 0))
else if (!ide->tf->lba && (ide->cfg_spt == 0))
err = IDNF_ERR;
else {
hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer);
@@ -2258,7 +2312,7 @@ ide_callback(void *priv)
if ((ide->type == IDE_ATAPI) || ide_boards[ide->board]->force_ata3 || (bm == NULL)) {
ide_log("IDE %i: DMA write aborted (bad device type or board)\n", ide->channel);
err = ABRT_ERR;
} else if (!ide->lba && (ide->cfg_spt == 0)) {
} else if (!ide->tf->lba && (ide->cfg_spt == 0)) {
ide_log("IDE %i: DMA write aborted (SPECIFY failed)\n", ide->channel);
err = IDNF_ERR;
} else {
@@ -2307,7 +2361,7 @@ ide_callback(void *priv)
mand error. */
if ((ide->type == IDE_ATAPI) || !ide->blocksize)
err = ABRT_ERR;
else if (!ide->lba && (ide->cfg_spt == 0))
else if (!ide->tf->lba && (ide->cfg_spt == 0))
err = IDNF_ERR;
else {
hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer);
@@ -2332,7 +2386,7 @@ ide_callback(void *priv)
case WIN_VERIFY_ONCE:
if (ide->type == IDE_ATAPI)
err = ABRT_ERR;
else if (!ide->lba && (ide->cfg_spt == 0))
else if (!ide->tf->lba && (ide->cfg_spt == 0))
err = IDNF_ERR;
else {
ide->tf->pos = 0;
@@ -2345,7 +2399,7 @@ ide_callback(void *priv)
case WIN_FORMAT:
if (ide->type == IDE_ATAPI)
err = ABRT_ERR;
else if (!ide->lba && (ide->cfg_spt == 0))
else if (!ide->tf->lba && (ide->cfg_spt == 0))
err = IDNF_ERR;
else {
hdd_image_zero(ide->hdd_num, ide_get_sector(ide), ide->tf->secount);
@@ -2364,7 +2418,7 @@ ide_callback(void *priv)
if (ide->cfg_spt == 0) {
/* Only accept after RESET or DIAG. */
ide->cfg_spt = ide->tf->secount;
ide->cfg_hpc = ide->head + 1;
ide->cfg_hpc = ide->tf->head + 1;
}
ide->command = 0x00;
ide->tf->atastat = DRDY_STAT | DSC_STAT;
@@ -2597,7 +2651,7 @@ ide_board_close(int board)
if (dev->type == IDE_ATAPI)
dev->tf->atastat = DRDY_STAT | DSC_STAT;
else if (dev->tf != NULL) {
else if (!(dev->type & IDE_SHADOW) && (dev->tf != NULL)) {
free(dev->tf);
dev->tf = NULL;
}
@@ -2863,8 +2917,14 @@ ide_drive_reset(int d)
{
ide_log("Resetting IDE drive %i...\n", d);
if ((d & 1) && (ide_drives[d]->type == IDE_NONE) && (ide_drives[d ^ 1]->type != IDE_NONE)) {
ide_drives[d]->type = ide_drives[d ^ 1]->type | IDE_SHADOW;
free(ide_drives[d]->tf);
ide_drives[d]->tf = ide_drives[d ^ 1]->tf;
} else
ide_drives[d]->tf->atastat = DRDY_STAT | DSC_STAT;
ide_drives[d]->channel = d;
ide_drives[d]->tf->atastat = DRDY_STAT | DSC_STAT;
ide_drives[d]->service = 0;
ide_drives[d]->board = d >> 1;
ide_drives[d]->selected = !(d & 1);

View File

@@ -27,7 +27,9 @@
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/cdrom.h>
#include <86box/hdd.h>
#include <86box/scsi_device.h>
#include <86box/scsi_disk.h>
#include <86box/scsi_cdrom.h>
#include <86box/dma.h>
#include <86box/io.h>
@@ -389,7 +391,6 @@ sff_bus_master_set_irq(uint8_t status, void *priv)
{
sff8038i_t *dev = (sff8038i_t *) priv;
uint8_t irq = !!(status & 0x04);
int irq_shift = 0;
if (!(dev->status & 0x04) || (status & 0x04))
dev->status = (dev->status & ~0x04) | status;
@@ -410,16 +411,12 @@ sff_bus_master_set_irq(uint8_t status, void *priv)
else
pci_clear_irq(dev->slot, dev->irq_pin, &dev->irq_state);
break;
case IRQ_MODE_MIRQ_0:
case IRQ_MODE_MIRQ_1:
/* MIRQ 0 or 1. */
case IRQ_MODE_MIRQ_2:
case IRQ_MODE_MIRQ_3:
/* MIRQ 2 or 3. */
case IRQ_MODE_MIRQ_0 ... IRQ_MODE_MIRQ_3:
/* MIRQ 0, 1, 2, or 3. */
if (irq)
pci_set_mirq((dev->irq_mode & 3) + irq_shift, 0, &dev->irq_state);
pci_set_mirq(dev->irq_mode & 3, 0, &dev->irq_state);
else
pci_clear_mirq((dev->irq_mode & 3) + irq_shift, 0, &dev->irq_state);
pci_clear_mirq(dev->irq_mode & 3, 0, &dev->irq_state);
break;
/* TODO: Redo this as a MIRQ. */
case IRQ_MODE_PCI_IRQ_LINE:
@@ -477,6 +474,10 @@ sff_reset(void *priv)
sff_log("SFF8038i: Reset\n");
#endif
for (uint8_t i = 0; i < HDD_NUM; i++) {
if ((hdd[i].bus == HDD_BUS_ATAPI) && (hdd[i].ide_channel < 4) && hdd[i].priv)
scsi_disk_reset((scsi_common_t *) hdd[i].priv);
}
for (uint8_t i = 0; i < CDROM_NUM; i++) {
if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && (cdrom[i].ide_channel < 4) && cdrom[i].priv)
scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv);
@@ -522,21 +523,15 @@ sff_set_irq_mode(sff8038i_t *dev, int irq_mode)
default:
case IRQ_MODE_LEGACY:
/* Legacy IRQ mode. */
sff_log("[%08X] Setting IRQ mode to legacy IRQ %i\n", dev, 14 + channel);
sff_log("[%08X] Setting IRQ mode to legacy IRQ %i\n", dev, dev->irq_line);
break;
case IRQ_MODE_PCI_IRQ_PIN:
/* Native PCI IRQ mode with interrupt pin. */
sff_log("[%08X] Setting IRQ mode to native PCI INT%c\n", dev, 0x40 + dev->irq_pin);
break;
case IRQ_MODE_MIRQ_0:
case IRQ_MODE_MIRQ_1:
/* MIRQ 0 or 1. */
sff_log("[%08X] Setting IRQ mode to PCI MIRQ%i\n", dev, irq_mode & 1);
break;
case IRQ_MODE_MIRQ_2:
case IRQ_MODE_MIRQ_3:
/* MIRQ 0 or 1. */
sff_log("[%08X] Setting IRQ mode to PCI MIRQ%i\n", dev, (irq_mode & 1) + 1);
case IRQ_MODE_MIRQ_0 ... IRQ_MODE_MIRQ_3:
/* MIRQ 0, 1, 2, or 3. */
sff_log("[%08X] Setting IRQ mode to PCI MIRQ%i\n", dev, dev->irq_mode & 3);
break;
case IRQ_MODE_PCI_IRQ_LINE:
/* Native PCI IRQ mode with specified interrupt line. */

View File

@@ -2147,6 +2147,9 @@ mo_hard_reset(void)
dev = (mo_t *) mo_drives[c].priv;
if (dev->tf == NULL)
continue;
dev->id = c;
dev->drv = &mo_drives[c];

View File

@@ -2386,6 +2386,9 @@ zip_hard_reset(void)
dev = (zip_t *) zip_drives[c].priv;
if (dev->tf == NULL)
continue;
dev->id = c;
dev->drv = &zip_drives[c];

View File

@@ -36,9 +36,13 @@
#define HDC_QUATERNARY_IRQ 10
enum {
IDE_NONE = 0,
IDE_HDD,
IDE_ATAPI
IDE_NONE = 0, /* Absent master or both. */
IDE_HDD, /* Hard disk. */
IDE_ATAPI, /* ATAPI device. */
IDE_RESERVED, /* Reserved, do not use. */
IDE_SHADOW, /* Shadow flag, do not assign on is own. */
IDE_HDD_SHADOW, /* Shadow of a hard disk. */
IDE_ATAPI_SHADOW /* Shadow of an ATAPI device. */
};
typedef struct ide_tf_s {
@@ -59,28 +63,26 @@ typedef struct ide_tf_s {
uint8_t status;
};
uint8_t error;
uint16_t pad;
uint8_t sector;
union {
uint8_t drvsel;
struct {
uint8_t head :4;
uint8_t pad :2;
uint8_t lba :1;
uint8_t pad0 :1;
};
};
uint32_t pos;
} ide_tf_t;
#ifdef _TIMER_H_
typedef struct ide_s {
#ifdef ANCIENT_CODE
/* Task file. */
uint8_t cylprecomp;
uint8_t secount;
uint16_t cylinder;
uint8_t atastat;
uint8_t error;
uint16_t pad;
uint32_t pos;
#endif
/* The rest. */
uint8_t selected;
uint8_t command;
uint8_t head;
uint8_t sector;
uint8_t pad;
int type;
int board;
int irqstat;
@@ -90,7 +92,6 @@ typedef struct ide_s {
int hdd_num;
int channel;
int sector_pos;
int lba;
int reset;
int mdma_mode;
int do_initial_read;
@@ -179,8 +180,7 @@ extern int ide_qua_enabled;
#ifdef SCSI_DEVICE_H
extern ide_t *ide_get_drive(int ch);
extern void ide_irq_raise(ide_t *ide);
extern void ide_irq_lower(ide_t *ide);
extern void ide_irq(ide_t *ide, int set, int log);
extern void ide_allocate_buffer(ide_t *dev);
extern void ide_atapi_attach(ide_t *dev);
#endif
@@ -224,6 +224,9 @@ extern uint8_t ide_read_ali_75(void);
extern uint8_t ide_read_ali_76(void);
/* Legacy #define's. */
#define ide_irq_raise(ide) ide_irq(ide, 1, 1)
#define ide_irq_lower(ide) ide_irq(ide, 0, 1)
#define ide_set_base(board, port) ide_set_base_addr(board, 0, port)
#define ide_set_side(board, port) ide_set_base_addr(board, 1, port)

View File

@@ -71,6 +71,8 @@ extern const device_t w83782d_device;
extern const device_t gl518sm_2c_device;
extern const device_t gl518sm_2d_device;
extern const device_t gl520sm_2c_device;
extern const device_t gl520sm_2d_device;
extern const device_t via_vt82c686_hwm_device;

View File

@@ -54,17 +54,21 @@ typedef struct isapnp_device_config_t {
} dma[2];
} isapnp_device_config_t;
void *isapnp_add_card(uint8_t *rom, uint16_t rom_size,
void (*config_changed)(uint8_t ld, isapnp_device_config_t *config, void *priv),
void (*csn_changed)(uint8_t csn, void *priv),
uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv),
void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv),
void *priv);
void isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size);
void isapnp_enable_card(void *priv, uint8_t enable);
void isapnp_set_csn(void *priv, uint8_t csn);
void isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config);
void isapnp_reset_card(void *priv);
void isapnp_reset_device(void *priv, uint8_t ld);
extern const uint8_t isapnp_init_key[32];
void *isapnp_add_card(uint8_t *rom, uint16_t rom_size,
void (*config_changed)(uint8_t ld, isapnp_device_config_t *config, void *priv),
void (*csn_changed)(uint8_t csn, void *priv),
uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv),
void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv),
void *priv);
void isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size);
void isapnp_enable_card(void *priv, uint8_t enable);
void isapnp_set_csn(void *priv, uint8_t csn);
uint8_t isapnp_read_reg(void *priv, uint8_t ldn, uint8_t reg);
void isapnp_write_reg(void *priv, uint8_t ldn, uint8_t reg, uint8_t val);
void isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config);
void isapnp_reset_card(void *priv);
void isapnp_reset_device(void *priv, uint8_t ld);
#endif /*EMU_ISAPNP_H*/

View File

@@ -226,6 +226,7 @@ extern const device_t keyboard_xt_lxt3_device;
# endif /*defined(DEV_BRANCH) && defined(USE_LASERXT) */
extern const device_t keyboard_xt_olivetti_device;
extern const device_t keyboard_xt_zenith_device;
extern const device_t keyboard_xt_hyundai_device;
extern const device_t keyboard_xtclone_device;
extern const device_t keyboard_at_device;
extern const device_t keyboard_at_siemens_device;

View File

@@ -447,6 +447,7 @@ extern int machine_at_quadt386sx_init(const machine_t *);
extern int machine_at_award286_init(const machine_t *);
extern int machine_at_gdc212m_init(const machine_t *);
extern int machine_at_gw286ct_init(const machine_t *);
extern int machine_at_super286c_init(const machine_t *);
extern int machine_at_super286tr_init(const machine_t *);
extern int machine_at_spc4200p_init(const machine_t *);
extern int machine_at_spc4216p_init(const machine_t *);
@@ -600,6 +601,7 @@ extern int machine_at_p5sp4_init(const machine_t *);
/* m_at_socket5.c */
extern int machine_at_plato_init(const machine_t *);
extern int machine_at_dellplato_init(const machine_t *);
extern int machine_at_ambradp90_init(const machine_t *);
extern int machine_at_430nx_init(const machine_t *);
@@ -673,6 +675,7 @@ extern int machine_at_tx97_init(const machine_t *);
extern int machine_at_an430tx_init(const machine_t *);
#endif
extern int machine_at_ym430tx_init(const machine_t *);
extern int machine_at_thunderbolt_init(const machine_t *);
extern int machine_at_mb540n_init(const machine_t *);
extern int machine_at_56a5_init(const machine_t *);
extern int machine_at_p5mms98_init(const machine_t *);
@@ -705,6 +708,7 @@ extern int machine_at_aurora_init(const machine_t *);
extern int machine_at_686nx_init(const machine_t *);
extern int machine_at_acerv60n_init(const machine_t *);
extern int machine_at_vs440fx_init(const machine_t *);
extern int machine_at_gw2kvenus_init(const machine_t *);
extern int machine_at_ap440fx_init(const machine_t *);
extern int machine_at_mb600n_init(const machine_t *);
extern int machine_at_8600ttc_init(const machine_t *);
@@ -753,6 +757,7 @@ extern int machine_at_s370slm_init(const machine_t *);
extern int machine_at_cubx_init(const machine_t *);
extern int machine_at_atc7020bxii_init(const machine_t *);
extern int machine_at_m773_init(const machine_t *);
extern int machine_at_ambx133_init(const machine_t *);
extern int machine_at_awo671r_init(const machine_t *);
extern int machine_at_63a1_init(const machine_t *);

View File

@@ -102,6 +102,7 @@ extern void midi_in_sysex(uint8_t *buffer, uint32_t len);
#ifdef EMU_DEVICE_H
extern const device_t rtmidi_output_device;
extern const device_t rtmidi_input_device;
extern const device_t opl4_midi_device;
# ifdef USE_FLUIDSYNTH
extern const device_t fluidsynth_device;
# endif

View File

@@ -0,0 +1,19 @@
struct nmc93cxx_eeprom_t;
typedef struct nmc93cxx_eeprom_t nmc93cxx_eeprom_t;
typedef struct nmc93cxx_eeprom_params_t {
uint16_t nwords;
char *filename;
uint16_t *default_content;
} nmc93cxx_eeprom_params_t;
/* Read from the EEPROM. */
uint16_t nmc93cxx_eeprom_read(nmc93cxx_eeprom_t *eeprom);
/* Write to the EEPROM. */
void nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi);
/* Get EEPROM data array. */
uint16_t *nmc93cxx_eeprom_data(nmc93cxx_eeprom_t *eeprom);
extern const device_t nmc93cxx_device;

View File

@@ -0,0 +1 @@
extern const device_t rtl8139c_plus_device;

View File

@@ -0,0 +1,3 @@
extern const device_t dec_tulip_device;
extern const device_t dec_tulip_21140_device;
extern const device_t dec_tulip_21140_vpc_device;

View File

@@ -0,0 +1,101 @@
/*
* RoboPlay for MSX
* Copyright (C) 2020 by RoboSoft Inc.
*
* opl4_defines.h
*
*/
#ifndef __OPL4_DEFINES_H
#define __OPL4_DEFINES_H
/*
* Register numbers
*/
#define OPL4_REG_TEST0 0x00
#define OPL4_REG_TEST1 0x01
#define OPL4_REG_MEMORY_CONFIGURATION 0x02
#define OPL4_MODE_BIT 0x01
#define OPL4_MTYPE_BIT 0x02
#define OPL4_TONE_HEADER_MASK 0x1C
#define OPL4_DEVICE_ID_MASK 0xE0
#define OPL4_REG_MEMORY_ADDRESS_HIGH 0x03
#define OPL4_REG_MEMORY_ADDRESS_MID 0x04
#define OPL4_REG_MEMORY_ADDRESS_LOW 0x05
#define OPL4_REG_MEMORY_DATA 0x06
/*
* Offsets to the register banks for voices. To get the
* register number just add the voice number to the bank offset.
*
* Wave Table Number low bits (0x08 to 0x1F)
*/
#define OPL4_REG_TONE_NUMBER 0x08
/* Wave Table Number high bit, F-Number low bits (0x20 to 0x37) */
#define OPL4_REG_F_NUMBER 0x20
#define OPL4_TONE_NUMBER_BIT8 0x01
#define OPL4_F_NUMBER_LOW_MASK 0xFE
/* F-Number high bits, Octave, Pseudo-Reverb (0x38 to 0x4F) */
#define OPL4_REG_OCTAVE 0x38
#define OPL4_F_NUMBER_HIGH_MASK 0x07
#define OPL4_BLOCK_MASK 0xF0
#define OPL4_PSEUDO_REVERB_BIT 0x08
/* Total Level, Level Direct (0x50 to 0x67) */
#define OPL4_REG_LEVEL 0x50
#define OPL4_TOTAL_LEVEL_MASK 0xFE
#define OPL4_LEVEL_DIRECT_BIT 0x01
/* Key On, Damp, LFO RST, CH, Panpot (0x68 to 0x7F) */
#define OPL4_REG_MISC 0x68
#define OPL4_KEY_ON_BIT 0x80
#define OPL4_DAMP_BIT 0x40
#define OPL4_LFO_RESET_BIT 0x20
#define OPL4_OUTPUT_CHANNEL_BIT 0x10
#define OPL4_PAN_POT_MASK 0x0F
/* LFO, VIB (0x80 to 0x97) */
#define OPL4_REG_LFO_VIBRATO 0x80
#define OPL4_LFO_FREQUENCY_MASK 0x38
#define OPL4_VIBRATO_DEPTH_MASK 0x07
#define OPL4_CHORUS_SEND_MASK 0xC0
/* Attack / Decay 1 rate (0x98 to 0xAF) */
#define OPL4_REG_ATTACK_DECAY1 0x98
#define OPL4_ATTACK_RATE_MASK 0xF0
#define OPL4_DECAY1_RATE_MASK 0x0F
/* Decay level / 2 rate (0xB0 to 0xC7) */
#define OPL4_REG_LEVEL_DECAY2 0xB0
#define OPL4_DECAY_LEVEL_MASK 0xF0
#define OPL4_DECAY2_RATE_MASK 0x0F
/* Release rate / Rate correction (0xC8 to 0xDF) */
#define OPL4_REG_RELEASE_CORRECTION 0xC8
#define OPL4_RELEASE_RATE_MASK 0x0F
#define OPL4_RATE_INTERPOLATION_MASK 0xF0
/* AM (0xE0 to 0xF7) */
#define OPL4_REG_TREMOLO 0xE0
#define OPL4_TREMOLO_DEPTH_MASK 0x07
#define OPL4_REVERB_SEND_MASK 0xE0
/* Mixer */
#define OPL4_REG_MIX_CONTROL_FM 0xF8
#define OPL4_REG_MIX_CONTROL_PCM 0xF9
#define OPL4_MIX_LEFT_MASK 0x07
#define OPL4_MIX_RIGHT_MASK 0x38
#define OPL4_REG_ATC 0xFA
#define OPL4_ATC_BIT 0x01
/* Bits in the OPL4 Status register */
#define OPL4_STATUS_BUSY 0x01
#define OPL4_STATUS_LOAD 0x02
#endif /* __OPL4_DEFINES_H */

View File

@@ -107,6 +107,7 @@ extern int infocus;
extern char emu_version[200]; /* version ID string */
extern int rctrl_is_lalt;
extern int update_icons;
extern int status_icons_fullscreen;
extern int kbd_req_capture;
extern int hide_status_bar;

View File

@@ -68,6 +68,8 @@ typedef struct scsi_disk_t {
extern scsi_disk_t *scsi_disk[HDD_NUM];
extern void scsi_disk_reset(scsi_common_t *sc);
extern void scsi_disk_hard_reset(void);
extern void scsi_disk_close(void);

View File

@@ -42,6 +42,7 @@ extern const device_t fdc37c935_device;
extern const device_t fdc37m60x_device;
extern const device_t fdc37m60x_370_device;
extern const device_t it8661f_device;
extern const device_t it8671f_device;
extern const device_t i82091aa_device;
extern const device_t i82091aa_398_device;
extern const device_t i82091aa_ide_pri_device;
@@ -79,6 +80,8 @@ extern const device_t ps1_m2133_sio;
extern const device_t sio_detect_device;
#endif
extern const device_t um8669f_device;
extern const device_t um8669f_ide_device;
extern const device_t um8669f_ide_sec_device;
extern const device_t via_vt82c686_sio_device;
extern const device_t w83627hf_device;
extern const device_t w83627hf_no_hwm_device;

View File

@@ -38,6 +38,7 @@ typedef struct fm_drv_t {
void (*reset_buffer)(void *priv);
void (*set_do_cycles)(void *priv, int8_t do_cycles);
void *priv;
void (*generate)(void *priv, int32_t *data, uint32_t num_samples); /* daughterboard only. */
} fm_drv_t;
extern uint8_t fm_driver_get(int chip_id, fm_drv_t *drv);

View File

@@ -41,7 +41,7 @@ typedef struct ibm8514_t {
int type;
int local;
int bpp;
int on;
int on[2];
int accel_bpp;
uint32_t vram_size;
@@ -64,7 +64,7 @@ typedef struct ibm8514_t {
struct {
uint16_t subsys_cntl;
uint16_t setup_md;
uint8_t advfunc_cntl;
uint16_t advfunc_cntl;
uint8_t ext_advfunc_cntl;
uint16_t cur_y;
uint16_t cur_y_bitres;

View File

@@ -22,12 +22,12 @@
#define EMU_NAME "86Box"
#define EMU_NAME_W LSTR(EMU_NAME)
#define EMU_VERSION "4.0.2"
#define EMU_VERSION "4.1"
#define EMU_VERSION_W LSTR(EMU_VERSION)
#define EMU_VERSION_EX "3.50" /* frozen due to IDE re-detection behavior on Windows */
#define EMU_VERSION_MAJ 4
#define EMU_VERSION_MIN 0
#define EMU_VERSION_PATCH 2
#define EMU_VERSION_MIN 1
#define EMU_VERSION_PATCH 0
#define EMU_BUILD_NUM 0
@@ -42,7 +42,7 @@
#define EMU_ROMS_URL "https://github.com/86Box/roms/releases/latest"
#define EMU_ROMS_URL_W LSTR(EMU_ROMS_URL)
#ifdef RELEASE_BUILD
# define EMU_DOCS_URL "https://86box.readthedocs.io/en/v4.0/"
# define EMU_DOCS_URL "https://86box.readthedocs.io/en/v4.1/"
#else
# define EMU_DOCS_URL "https://86box.readthedocs.io"
#endif

View File

@@ -348,6 +348,29 @@ machine_at_gw286ct_init(const machine_t *model)
return ret;
}
int
machine_at_super286c_init(const machine_t *model)
{
int ret;
ret = bios_load_linear("roms/machines/super286c/hyundai_award286.bin",
0x000f0000, 65536, 0);
if (bios_only || !ret)
return ret;
machine_at_common_init(model);
device_add(&keyboard_at_ami_device);
if (fdc_type == FDC_INTERNAL)
device_add(&fdc_at_device);
device_add(&neat_device);
return ret;
}
int
machine_at_super286tr_init(const machine_t *model)
{

View File

@@ -173,9 +173,8 @@ machine_at_p6bat_init(const machine_t *model)
device_add(&sst_flash_39sf020_device);
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
if (sound_card_current[0] == SOUND_INTERNAL) {
if (sound_card_current[0] == SOUND_INTERNAL)
device_add(&cmi8738_onboard_device);
}
return ret;
}
@@ -248,6 +247,46 @@ machine_at_atc7020bxii_init(const machine_t *model)
return ret;
}
int
machine_at_m773_init(const machine_t *model)
{
int ret;
ret = bios_load_linear("roms/machines/m773/010504s.rom",
0x000c0000, 262144, 0);
if (bios_only || !ret)
return ret;
machine_at_common_init_ex(model, 2);
pci_init(PCI_CONFIG_TYPE_1);
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4);
pci_register_slot(0x0C, PCI_CARD_SOUND, 4, 3, 0, 0);
pci_register_slot(0x09, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x0A, PCI_CARD_NORMAL, 2, 3, 4, 1);
pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2);
pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3);
pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4);
device_add(&i440bx_device);
device_add(&slc90e66_device);
device_add(&keyboard_ps2_ami_pci_device);
device_add(&it8671f_device);
device_add(&sst_flash_39sf020_device);
spd_register(SPD_TYPE_SDRAM, 0x3, 256);
device_add(&gl520sm_2d_device); /* fans: CPU, Chassis; temperature: System */
hwm_values.temperatures[0] += 2; /* System offset */
hwm_values.temperatures[1] += 2; /* CPU offset */
hwm_values.voltages[0] = 3300; /* Vcore and 3.3V are swapped */
hwm_values.voltages[2] = hwm_get_vcore();
if (sound_card_current[0] == SOUND_INTERNAL)
device_add(&cmi8738_onboard_device);
return ret;
}
int
machine_at_ambx133_init(const machine_t *model)
{

View File

@@ -59,6 +59,25 @@ machine_at_plato_init(const machine_t *model)
return ret;
}
int
machine_at_dellplato_init(const machine_t *model)
{
int ret;
ret = bios_load_linear_combined("roms/machines/dellplato/1016AX1J.bio",
"roms/machines/dellplato/1016AX1J.bi1",
0x1d000, 128);
if (bios_only || !ret)
return ret;
machine_at_premiere_common_init(model, PCI_CAN_SWITCH_TYPE);
device_add(&i430nx_device);
return ret;
}
int
machine_at_ambradp90_init(const machine_t *model)
{

View File

@@ -1197,3 +1197,33 @@ machine_at_ms5164_init(const machine_t *model)
return ret;
}
int
machine_at_thunderbolt_init(const machine_t *model)
{
int ret;
ret = bios_load_linear("roms/machines/thunderbolt/tbolt-01.rom",
0x000c0000, 262144, 0);
if (bios_only || !ret)
return ret;
machine_at_common_init_ex(model, 2);
pci_init(PCI_CONFIG_TYPE_1);
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 1, 2, 3); /* PIIX4 */
pci_register_slot(0x11, PCI_CARD_NORMAL, 0, 1, 2, 3);
pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 0);
pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 0, 1);
pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 0, 1, 2);
device_add(&i430tx_device);
device_add(&piix4_device);
device_add(&keyboard_ps2_ami_pci_device);
device_add(&fdc37c935_device);
device_add(&intel_flash_bxt_device);
spd_register(SPD_TYPE_SDRAM, 0x3, 128);
return ret;
}

View File

@@ -195,6 +195,40 @@ machine_at_vs440fx_init(const machine_t *model)
return ret;
}
int
machine_at_gw2kvenus_init(const machine_t *model)
{
int ret;
ret = bios_load_linear_combined2("roms/machines/gw2kvenus/1011CS1T.BIO",
"roms/machines/gw2kvenus/1011CS1T.BI1",
"roms/machines/gw2kvenus/1011CS1T.BI2",
"roms/machines/gw2kvenus/1011CS1T.BI3",
"roms/machines/gw2kvenus/1011CS1T.RCV",
0x3a000, 128);
if (bios_only || !ret)
return ret;
machine_at_common_init(model);
pci_init(PCI_CONFIG_TYPE_1);
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3);
pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2);
pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1);
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0);
device_add(&i440fx_device);
device_add(&piix3_device);
device_add(&keyboard_ps2_intel_ami_pci_device);
device_add(&pc87307_device);
device_add(&intel_flash_bxt_ami_device);
return ret;
}
int
machine_at_ap440fx_init(const machine_t *model)
{

View File

@@ -493,6 +493,14 @@ machine_xt_vendex_init(const machine_t *model)
return ret;
}
static void
machine_xt_hyundai_common_init(const machine_t *model)
{
device_add(&keyboard_xt_hyundai_device);
machine_xt_common_init(model);
}
int
machine_xt_super16t_init(const machine_t *model)
{
@@ -504,7 +512,7 @@ machine_xt_super16t_init(const machine_t *model)
if (bios_only || !ret)
return ret;
machine_xt_clone_init(model);
machine_xt_hyundai_common_init(model);
/* On-board FDC cannot be disabled */
device_add(&fdc_xt_device);
@@ -523,7 +531,7 @@ machine_xt_super16te_init(const machine_t *model)
if (bios_only || !ret)
return ret;
machine_xt_clone_init(model);
machine_xt_hyundai_common_init(model);
/* On-board FDC cannot be disabled */
device_add(&fdc_xt_device);

View File

@@ -112,12 +112,8 @@ static const device_t zenith_scratchpad_device = {
void
machine_zenith_init(const machine_t *model)
{
machine_common_init(model);
if (fdc_type == FDC_INTERNAL)
device_add(&fdc_xt_device);
device_add(&zenith_scratchpad_device);
pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt);
@@ -144,6 +140,9 @@ machine_xt_z184_init(const machine_t *model)
machine_zenith_init(model);
if (fdc_type == FDC_INTERNAL)
device_add(&fdc_xt_device);
lpt1_remove(); /* only one parallel port */
lpt2_remove();
lpt1_init(0x278);
@@ -171,6 +170,9 @@ machine_xt_z151_init(const machine_t *model)
machine_zenith_init(model);
if (fdc_type == FDC_INTERNAL)
device_add(&fdc_xt_tandy_device);
return ret;
}
@@ -191,6 +193,9 @@ machine_xt_z159_init(const machine_t *model)
machine_zenith_init(model);
if (fdc_type == FDC_INTERNAL)
device_add(&fdc_xt_tandy_device);
/* parallel port is on the memory board */
lpt1_remove(); /* only one parallel port */
lpt2_remove();

View File

@@ -168,13 +168,15 @@ pit_irq0_timer(int new_out, int old_out)
void
machine_common_init(UNUSED(const machine_t *model))
{
uint8_t cpu_requires_fast_pit = is486 || (is8086 && (cpu_s->rspeed >= 8000000));
/* System devices first. */
pic_init();
dma_init();
int pit_type = IS_AT(machine) ? PIT_8254 : PIT_8253;
/* Select fast PIT if needed */
if (((pit_mode == -1) && is486) || (pit_mode == 1))
if (((pit_mode == -1) && cpu_requires_fast_pit) || (pit_mode == 1))
pit_type += 2;
pit_common_init(pit_type, pit_irq0_timer, NULL);

View File

@@ -164,7 +164,6 @@ const machine_filter_t machine_chipsets[] = {
};
/* Machines to add before machine freeze:
- PCChips M773 (440BX + SMSC with AMI BIOS);
- TMC Mycomp PCI54ST;
- Zeos Quadtel 486.
@@ -1085,7 +1084,7 @@ const machine_t machines[] = {
.ram = {
.min = 256,
.max = 640,
.step = 256
.step = 128
},
.nvrmask = 0,
.kbc_device = &keyboard_xt_olivetti_device,
@@ -1163,7 +1162,7 @@ const machine_t machines[] = {
.ram = {
.min = 256,
.max = 640,
.step = 256
.step = 128
},
.nvrmask = 0,
.kbc_device = &keyboard_xtclone_device,
@@ -1319,7 +1318,7 @@ const machine_t machines[] = {
.ram = {
.min = 256,
.max = 640,
.step = 256
.step = 128
},
.nvrmask = 0,
.kbc_device = &keyboard_xtclone_device,
@@ -3240,6 +3239,46 @@ const machine_t machines[] = {
.snd_device = NULL,
.net_device = NULL
},
/* has an Award-branded KBC controller */
{
.name = "[NEAT] Hyundai Super-286C",
.internal_name = "super286c",
.type = MACHINE_TYPE_286,
.chipset = MACHINE_CHIPSET_NEAT,
.init = machine_at_super286c_init,
.p1_handler = NULL,
.gpio_handler = NULL,
.available_flag = MACHINE_AVAILABLE,
.gpio_acpi_handler = NULL,
.cpu = {
.package = CPU_PKG_286,
.block = CPU_BLOCK_NONE,
.min_bus = 0,
.max_bus = 0,
.min_voltage = 0,
.max_voltage = 0,
.min_multi = 0,
.max_multi = 0
},
.bus_flags = MACHINE_AT,
.flags = MACHINE_FLAGS_NONE,
.ram = {
.min = 512,
.max = 1024,
.step = 128
},
.nvrmask = 127,
.kbc_device = NULL,
.kbc_p1 = 0xff,
.gpio = 0xffffffff,
.gpio_acpi = 0xffffffff,
.device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = NULL,
.snd_device = NULL,
.net_device = NULL
},
/* Has IBM AT KBC firmware. */
{
.name = "[NEAT] NCR 3302",
@@ -8294,6 +8333,46 @@ const machine_t machines[] = {
.snd_device = NULL,
.net_device = NULL
},
/* Same as Intel Premiere PCI/II, but with a Dell OEM BIOS */
{
.name = "[i430NX] Dell Dimension XPS Pxxx",
.internal_name = "dellplato",
.type = MACHINE_TYPE_SOCKET5,
.chipset = MACHINE_CHIPSET_INTEL_430NX,
.init = machine_at_dellplato_init,
.p1_handler = NULL,
.gpio_handler = NULL,
.available_flag = MACHINE_AVAILABLE,
.gpio_acpi_handler = NULL,
.cpu = {
.package = CPU_PKG_SOCKET5_7,
.block = CPU_BLOCK_NONE,
.min_bus = 50000000,
.max_bus = 66666667,
.min_voltage = 3520,
.max_voltage = 3520,
.min_multi = 1.5,
.max_multi = 1.5
},
.bus_flags = MACHINE_PS2_PCI,
.flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI,
.ram = {
.min = 2048,
.max = 131072,
.step = 2048
},
.nvrmask = 127,
.kbc_device = NULL,
.kbc_p1 = 0xff,
.gpio = 0xffffffff,
.gpio_acpi = 0xffffffff,
.device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = NULL,
.snd_device = NULL,
.net_device = NULL
},
/* This has the Phoenix MultiKey KBC firmware.
This is basically an Intel Premiere/PCI II with a fancier POST screen. */
{
@@ -10629,6 +10708,46 @@ const machine_t machines[] = {
.vid_device = NULL,
.snd_device = NULL,
.net_device = NULL
},
/* PhoenixBIOS 4.0 Rel 6.0 for 430TX, most likely has AMI KBC of some sort. Also has onboard Yamaha YMF701 which can't be emulated yet. */
{
.name = "[i430TX] Micronics Thunderbolt",
.internal_name = "thunderbolt",
.type = MACHINE_TYPE_SOCKET7,
.chipset = MACHINE_CHIPSET_INTEL_430TX,
.init = machine_at_thunderbolt_init,
.p1_handler = NULL,
.gpio_handler = NULL,
.available_flag = MACHINE_AVAILABLE,
.gpio_acpi_handler = NULL,
.cpu = {
.package = CPU_PKG_SOCKET5_7,
.block = CPU_BLOCK(CPU_WINCHIP, CPU_WINCHIP2),
.min_bus = 50000000,
.max_bus = 66666667,
.min_voltage = 2500,
.max_voltage = 3520,
.min_multi = 1.5,
.max_multi = 3.0
},
.bus_flags = MACHINE_PS2_PCI,
.flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI,
.ram = {
.min = 8192,
.max = 262144,
.step = 8192
},
.nvrmask = 255,
.kbc_device = NULL,
.kbc_p1 = 0xff,
.gpio = 0xffffffff,
.gpio_acpi = 0xffffffff,
.device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = NULL,
.snd_device = NULL,
.net_device = NULL
},
/* The BIOS sends KBC command BB and expects it to output a byte, which is AMI KBC behavior. */
{
@@ -11619,6 +11738,46 @@ const machine_t machines[] = {
.snd_device = NULL,
.net_device = NULL
},
/* It's a Intel VS440FX with a Gateway 2000 OEM BIOS */
{
.name = "[i440FX] Gateway 2000 Venus",
.internal_name = "gw2kvenus",
.type = MACHINE_TYPE_SOCKET8,
.chipset = MACHINE_CHIPSET_INTEL_440FX,
.init = machine_at_gw2kvenus_init,
.p1_handler = NULL,
.gpio_handler = NULL,
.available_flag = MACHINE_AVAILABLE,
.gpio_acpi_handler = NULL,
.cpu = {
.package = CPU_PKG_SOCKET8,
.block = CPU_BLOCK_NONE,
.min_bus = 60000000,
.max_bus = 66666667,
.min_voltage = 2100,
.max_voltage = 3500,
.min_multi = 2.0,
.max_multi = 3.5
},
.bus_flags = MACHINE_PS2_PCI,
.flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI,
.ram = {
.min = 8192,
.max = 524288,
.step = 8192
},
.nvrmask = 127,
.kbc_device = NULL,
.kbc_p1 = 0xff,
.gpio = 0xffffffff,
.gpio_acpi = 0xffffffff,
.device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = NULL,
.snd_device = NULL,
.net_device = NULL
},
/* Has the SMC FDC73C935's on-chip KBC with Phoenix MultiKey firmware. */
{
.name = "[i440FX] Micronics M6Mi",
@@ -13047,6 +13206,47 @@ const machine_t machines[] = {
.snd_device = NULL,
.net_device = NULL
},
/* Has an ITE IT8671F Super I/O chip with on-chip KBC with AMIKey-2 KBC
firmware. */
{
.name = "[SMSC VictoryBX-66] PC Chips M773",
.internal_name = "m773",
.type = MACHINE_TYPE_SOCKET370,
.chipset = MACHINE_CHIPSET_SMSC_VICTORYBX_66,
.init = machine_at_m773_init,
.p1_handler = NULL,
.gpio_handler = NULL,
.available_flag = MACHINE_AVAILABLE,
.gpio_acpi_handler = NULL,
.cpu = {
.package = CPU_PKG_SOCKET370,
.block = CPU_BLOCK_NONE,
.min_bus = 66666667,
.max_bus = 133333333,
.min_voltage = 1300,
.max_voltage = 3500,
.min_multi = 1.5,
.max_multi = 8.0
},
.bus_flags = MACHINE_PS2_AGP,
.flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_ACPI,
.ram = {
.min = 8192,
.max = 524288,
.step = 8192
},
.nvrmask = 255,
.kbc_device = NULL,
.kbc_p1 = 0xff,
.gpio = 0xffffffff,
.gpio_acpi = 0xffffffff,
.device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = NULL,
.snd_device = &cmi8738_onboard_device,
.net_device = NULL
},
/* VIA Apollo Pro */
/* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA

View File

@@ -14,7 +14,8 @@
#
set(net_sources)
list(APPEND net_sources network.c net_pcap.c net_slirp.c net_dp8390.c net_3c501.c
net_3c503.c net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c net_event.c net_null.c)
net_3c503.c net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c net_event.c net_null.c
net_eeprom_nmc93cxx.c net_tulip.c net_rtl8139.c net_l80225.c)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SLIRP REQUIRED IMPORTED_TARGET slirp)

View File

@@ -0,0 +1,289 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Emulation of National Semiconductors NMC93Cxx EEPROMs.
*
*
* Authors: Cacodemon345
*
* Copyright 2023 Cacodemon345
*/
/* Ported over from QEMU */
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/nvr.h>
#include <86box/net_eeprom_nmc93cxx.h>
#include <86box/plat_unused.h>
struct nmc93cxx_eeprom_t {
uint8_t tick;
uint8_t address;
uint8_t command;
uint8_t writable;
uint8_t eecs;
uint8_t eesk;
uint8_t eedo;
uint8_t addrbits;
uint16_t size;
uint16_t data;
char filename[1024];
uint16_t contents[];
};
typedef struct nmc93cxx_eeprom_t nmc93cxx_eeprom_t;
#ifdef ENABLE_NMC93CXX_EEPROM_LOG
int nmc93cxx_eeprom_do_log = ENABLE_NMC93CXX_EEPROM_LOG;
static void
nmc93cxx_eeprom_log(int lvl, const char *fmt, ...)
{
va_list ap;
if (nmc93cxx_eeprom_do_log >= lvl) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define nmc93cxx_eeprom_log(lvl, fmt, ...)
#endif
static void *
nmc93cxx_eeprom_init_params(UNUSED(const device_t *info), void *params)
{
uint16_t nwords = 64;
uint8_t addrbits = 6;
uint8_t filldefault = 1;
nmc93cxx_eeprom_params_t *params_details = (nmc93cxx_eeprom_params_t *) params;
nmc93cxx_eeprom_t *eeprom = NULL;
if (!params)
return NULL;
nwords = params_details->nwords;
switch (nwords) {
case 16:
case 64:
addrbits = 6;
break;
case 128:
case 256:
addrbits = 8;
break;
default:
nwords = 64;
addrbits = 6;
break;
}
eeprom = calloc(1, sizeof(nmc93cxx_eeprom_t) + ((nwords + 1) * 2));
if (!eeprom)
return NULL;
eeprom->size = nwords;
eeprom->addrbits = addrbits;
/* Output DO is tristate, read results in 1. */
eeprom->eedo = 1;
if (params_details->filename) {
FILE *fp = nvr_fopen(params_details->filename, "rb");
strncpy(eeprom->filename, params_details->filename, sizeof(eeprom->filename) - 1);
if (fp) {
filldefault = !fread(eeprom->contents, sizeof(uint16_t), nwords, fp);
fclose(fp);
}
}
if (filldefault) {
memcpy(eeprom->contents, params_details->default_content, nwords * sizeof(uint16_t));
}
return eeprom;
}
void
nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi)
{
uint8_t tick = eeprom->tick;
uint8_t eedo = eeprom->eedo;
uint16_t address = eeprom->address;
uint8_t command = eeprom->command;
nmc93cxx_eeprom_log(1, "CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
eecs, eesk, eedi, eedo, tick);
if (!eeprom->eecs && eecs) {
/* Start chip select cycle. */
nmc93cxx_eeprom_log(1, "Cycle start, waiting for 1st start bit (0)\n");
tick = 0;
command = 0x0;
address = 0x0;
} else if (eeprom->eecs && !eecs) {
/* End chip select cycle. This triggers write / erase. */
if (eeprom->writable) {
uint8_t subcommand = address >> (eeprom->addrbits - 2);
if (command == 0 && subcommand == 2) {
/* Erase all. */
for (address = 0; address < eeprom->size; address++) {
eeprom->contents[address] = 0xffff;
}
} else if (command == 3) {
/* Erase word. */
eeprom->contents[address] = 0xffff;
} else if (tick >= 2 + 2 + eeprom->addrbits + 16) {
if (command == 1) {
/* Write word. */
eeprom->contents[address] &= eeprom->data;
} else if (command == 0 && subcommand == 1) {
/* Write all. */
for (address = 0; address < eeprom->size; address++) {
eeprom->contents[address] &= eeprom->data;
}
}
}
}
/* Output DO is tristate, read results in 1. */
eedo = 1;
} else if (eecs && !eeprom->eesk && eesk) {
/* Raising edge of clock shifts data in. */
if (tick == 0) {
/* Wait for 1st start bit. */
if (eedi == 0) {
nmc93cxx_eeprom_log(1, "Got correct 1st start bit, waiting for 2nd start bit (1)\n");
tick++;
} else {
nmc93cxx_eeprom_log(1, "wrong 1st start bit (is 1, should be 0)\n");
tick = 2;
#if 0
~ assert(!"wrong start bit");
#endif
}
} else if (tick == 1) {
/* Wait for 2nd start bit. */
if (eedi != 0) {
nmc93cxx_eeprom_log(1, "Got correct 2nd start bit, getting command + address\n");
tick++;
} else {
nmc93cxx_eeprom_log(1, "1st start bit is longer than needed\n");
}
} else if (tick < 2 + 2) {
/* Got 2 start bits, transfer 2 opcode bits. */
tick++;
command <<= 1;
if (eedi) {
command += 1;
}
} else if (tick < 2 + 2 + eeprom->addrbits) {
/* Got 2 start bits and 2 opcode bits, transfer all address bits. */
tick++;
address = ((address << 1) | eedi);
if (tick == 2 + 2 + eeprom->addrbits) {
nmc93cxx_eeprom_log(1, "%s command, address = 0x%02x (value 0x%04x)\n",
opstring[command], address, eeprom->contents[address]);
if (command == 2) {
eedo = 0;
}
address = address % eeprom->size;
if (command == 0) {
/* Command code in upper 2 bits of address. */
switch (address >> (eeprom->addrbits - 2)) {
case 0:
nmc93cxx_eeprom_log(1, "write disable command\n");
eeprom->writable = 0;
break;
case 1:
nmc93cxx_eeprom_log(1, "write all command\n");
break;
case 2:
nmc93cxx_eeprom_log(1, "erase all command\n");
break;
case 3:
nmc93cxx_eeprom_log(1, "write enable command\n");
eeprom->writable = 1;
break;
default:
break;
}
} else {
/* Read, write or erase word. */
eeprom->data = eeprom->contents[address];
}
}
} else if (tick < 2 + 2 + eeprom->addrbits + 16) {
/* Transfer 16 data bits. */
tick++;
if (command == 2) {
/* Read word. */
eedo = ((eeprom->data & 0x8000) != 0);
}
eeprom->data <<= 1;
eeprom->data += eedi;
} else {
nmc93cxx_eeprom_log(1, "additional unneeded tick, not processed\n");
}
}
/* Save status of EEPROM. */
eeprom->tick = tick;
eeprom->eecs = eecs;
eeprom->eesk = eesk;
eeprom->eedo = eedo;
eeprom->address = address;
eeprom->command = command;
}
uint16_t
nmc93cxx_eeprom_read(nmc93cxx_eeprom_t *eeprom)
{
/* Return status of pin DO (0 or 1). */
return eeprom->eedo;
}
static void
nmc93cxx_eeprom_close(void *priv)
{
nmc93cxx_eeprom_t *eeprom = (nmc93cxx_eeprom_t *) priv;
FILE *fp = nvr_fopen(eeprom->filename, "wb");
if (fp) {
fwrite(eeprom->contents, 2, eeprom->size, fp);
fclose(fp);
}
free(priv);
}
uint16_t *
nmc93cxx_eeprom_data(nmc93cxx_eeprom_t *eeprom)
{
/* Get EEPROM data array. */
return &eeprom->contents[0];
}
const device_t nmc93cxx_device = {
.name = "National Semiconductor NMC93Cxx",
.internal_name = "nmc93cxx",
.flags = DEVICE_EXTPARAMS,
.local = 0,
.init_ext = nmc93cxx_eeprom_init_params,
.close = nmc93cxx_eeprom_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

41
src/network/net_l80225.c Normal file
View File

@@ -0,0 +1,41 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <86box/86box.h>
#include <86box/timer.h>
#include <86box/pci.h>
#include <86box/io.h>
#include <86box/mem.h>
#include <86box/dma.h>
#include <86box/device.h>
#include <86box/thread.h>
#include <86box/network.h>
uint16_t
l80225_mii_readw(uint16_t *regs, uint16_t addr)
{
switch (addr) {
case 0x1:
return 0x782D;
case 0x2:
return 0b10110;
case 0x3:
return 0xF830;
case 0x5:
return 0x41E1;
case 0x18:
return 0xC0;
default:
return regs[addr];
}
return 0;
}
void
l80225_mii_writew(uint16_t *regs, uint16_t addr, uint16_t val)
{
regs[addr] = val;
}

3411
src/network/net_rtl8139.c Normal file

File diff suppressed because it is too large Load Diff

1529
src/network/net_tulip.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -73,6 +73,8 @@
#include <86box/net_pcnet.h>
#include <86box/net_plip.h>
#include <86box/net_wd8003.h>
#include <86box/net_tulip.h>
#include <86box/net_rtl8139.h>
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
@@ -129,7 +131,11 @@ static const device_t *net_cards[] = {
&wd8013epa_device,
&pcnet_am79c973_device,
&pcnet_am79c970a_device,
&dec_tulip_device,
&rtl8029as_device,
&rtl8139c_plus_device,
&dec_tulip_21140_device,
&dec_tulip_21140_vpc_device,
&pcnet_am79c960_vlb_device,
NULL
};

View File

@@ -404,6 +404,8 @@ pitf_write(uint16_t addr, uint8_t val, void *priv)
pit_log("[%04X:%08X] pit_write(%04X, %02X, %08X)\n", CS, cpu_state.pc, addr, val, priv);
cycles -= ISA_CYCLES(8);
switch (addr & 3) {
case 3: /* control */
t = val >> 6;
@@ -541,6 +543,8 @@ pitf_read(uint16_t addr, void *priv)
int t = (addr & 3);
ctrf_t *ctr;
cycles -= ISA_CYCLES(8);
switch (addr & 3) {
case 3: /* Control. */
/* This is 8254-only, 8253 returns 0x00. */

View File

@@ -37,6 +37,7 @@
#include <86box/video.h>
#include <86box/port_6x.h>
#include <86box/plat_unused.h>
#include <86box/random.h>
#define PS2_REFRESH_TIME (16 * TIMER_USEC)
@@ -45,6 +46,8 @@
#define PORT_6X_MIRROR 4
#define PORT_6X_SWA 8
static int cycles_sub = 0;
static void
port_6x_write(uint16_t port, uint8_t val, void *priv)
{
@@ -52,6 +55,8 @@ port_6x_write(uint16_t port, uint8_t val, void *priv)
port &= 3;
cycles -= cycles_sub;
if ((port == 3) && (dev->flags & PORT_6X_MIRROR))
port = 1;
@@ -80,6 +85,8 @@ port_61_read_simple(UNUSED(uint16_t port), UNUSED(void *priv))
{
uint8_t ret = ppi.pb & 0x1f;
cycles -= cycles_sub;
if (ppispeakon)
ret |= 0x20;
@@ -92,6 +99,8 @@ port_61_read(UNUSED(uint16_t port), void *priv)
const port_6x_t *dev = (port_6x_t *) priv;
uint8_t ret = 0xff;
cycles -= cycles_sub;
if (dev->flags & PORT_6X_EXT_REF) {
ret = ppi.pb & 0x0f;
@@ -190,6 +199,8 @@ port_6x_init(const device_t *info)
if (dev->flags & PORT_6X_SWA)
io_sethandler(0x0062, 1, port_62_read, NULL, NULL, NULL, NULL, NULL, dev);
cycles_sub = is486 ? ISA_CYCLES(8) : 0;
return dev;
}

View File

@@ -653,7 +653,7 @@ msgid "ZIP images"
msgstr "ZIP 映像"
msgid "86Box could not find any usable ROM images.\n\nPlease <a href=\"https://github.com/86Box/roms/releases/latest\">download</a> a ROM set and extract it into the \"roms\" directory."
msgstr "86Box 找不到任何可用的 ROM 映像。\n\n请<a href=\"https://github.com/86Box/roms/releases/latest\">下载</a>ROM 包并将其解压到 \"roms\" 文件夹中。"
msgstr "86Box 找不到任何可用的 ROM 映像。\n\n请<a href=\"https://github.com/86Box/roms/releases/latest\">下载</a> ROM 包并将其解压到 \"roms\" 文件夹中。"
msgid "(empty)"
msgstr "(空)"

View File

@@ -136,6 +136,22 @@ HardwareRenderer::initializeGL()
m_context->swapBuffers(this);
}
void
HardwareRenderer::paintOverGL()
{
/* Context switching is needed to make use of QPainter to draw status bar icons in fullscreen.
Especially since it seems to be impossible to use QPainter on externally-created OpenGL contexts. */
if (video_fullscreen && status_icons_fullscreen) {
m_context->makeCurrent(nullptr);
makeCurrent();
QPainter painter(this);
drawStatusBarIcons(&painter);
painter.end();
doneCurrent();
m_context->makeCurrent(this);
}
}
void
HardwareRenderer::paintGL()
{

View File

@@ -53,6 +53,7 @@ public:
{
onResize(size().width(), size().height());
}
void paintOverGL() override;
std::vector<std::tuple<uint8_t *, std::atomic_flag *>> getBuffers() override;
HardwareRenderer(QWidget *parent = nullptr, RenderType rtype = RenderType::OpenGL)
: QOpenGLWindow(QOpenGLWindow::NoPartialUpdate, parent->windowHandle())

View File

@@ -429,11 +429,12 @@ MachineStatus::refresh(QStatusBar *sbar)
bool has_xta = machine_has_flags(machine, MACHINE_XTA) > 0;
bool has_esdi = machine_has_flags(machine, MACHINE_ESDI) > 0;
int c_mfm = hdd_count(HDD_BUS_MFM);
int c_esdi = hdd_count(HDD_BUS_ESDI);
int c_xta = hdd_count(HDD_BUS_XTA);
int c_ide = hdd_count(HDD_BUS_IDE);
int c_scsi = hdd_count(HDD_BUS_SCSI);
int c_mfm = hdd_count(HDD_BUS_MFM);
int c_esdi = hdd_count(HDD_BUS_ESDI);
int c_xta = hdd_count(HDD_BUS_XTA);
int c_ide = hdd_count(HDD_BUS_IDE);
int c_atapi = hdd_count(HDD_BUS_ATAPI);
int c_scsi = hdd_count(HDD_BUS_SCSI);
sbar->removeWidget(d->cassette.label.get());
for (int i = 0; i < 2; ++i) {
@@ -597,12 +598,21 @@ MachineStatus::refresh(QStatusBar *sbar)
d->hdds[HDD_BUS_XTA].label->setToolTip(tr("Hard disk (%s)").replace("%s", "XTA"));
sbar->addWidget(d->hdds[HDD_BUS_XTA].label.get());
}
if ((hasIDE() || hdc_name.left(5) == QStringLiteral("xtide") || hdc_name.left(3) == QStringLiteral("ide")) && c_ide > 0) {
d->hdds[HDD_BUS_IDE].label = std::make_unique<QLabel>();
d->hdds[HDD_BUS_IDE].setActive(false);
d->hdds[HDD_BUS_IDE].refresh();
d->hdds[HDD_BUS_IDE].label->setToolTip(tr("Hard disk (%s)").replace("%s", "IDE"));
sbar->addWidget(d->hdds[HDD_BUS_IDE].label.get());
if (hasIDE() || hdc_name.left(5) == QStringLiteral("xtide") || hdc_name.left(3) == QStringLiteral("ide")) {
if (c_ide > 0) {
d->hdds[HDD_BUS_IDE].label = std::make_unique<QLabel>();
d->hdds[HDD_BUS_IDE].setActive(false);
d->hdds[HDD_BUS_IDE].refresh();
d->hdds[HDD_BUS_IDE].label->setToolTip(tr("Hard disk (%s)").replace("%s", "IDE"));
sbar->addWidget(d->hdds[HDD_BUS_IDE].label.get());
}
if (c_atapi > 0) {
d->hdds[HDD_BUS_ATAPI].label = std::make_unique<QLabel>();
d->hdds[HDD_BUS_ATAPI].setActive(false);
d->hdds[HDD_BUS_ATAPI].refresh();
d->hdds[HDD_BUS_ATAPI].label->setToolTip(tr("Hard disk (%s)").replace("%s", "ATAPI"));
sbar->addWidget(d->hdds[HDD_BUS_ATAPI].label.get());
}
}
if ((hasSCSI() || (scsi_card_current[0] != 0) || (scsi_card_current[1] != 0) || (scsi_card_current[2] != 0) || (scsi_card_current[3] != 0)) && c_scsi > 0) {
d->hdds[HDD_BUS_SCSI].label = std::make_unique<QLabel>();

View File

@@ -208,6 +208,18 @@ main(int argc, char *argv[])
return 0;
}
/* Warn the user about unsupported configs */
if (cpu_override) {
QMessageBox warningbox(QMessageBox::Icon::Warning, QObject::tr("You are loading an unsupported configuration"),
QObject::tr("CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid."),
QMessageBox::NoButton);
warningbox.addButton(QObject::tr("Continue"), QMessageBox::AcceptRole);
warningbox.addButton(QObject::tr("Exit"), QMessageBox::RejectRole);
warningbox.exec();
if (warningbox.result() == QDialog::Accepted)
return 0;
}
#ifdef DISCORD
discord_load();
#endif
@@ -279,20 +291,6 @@ main(int argc, char *argv[])
socket.connectToServer(qgetenv("86BOX_MANAGER_SOCKET"));
}
/* Warn the user about unsupported configs */
if (cpu_override) {
QMessageBox warningbox(QMessageBox::Icon::Warning, QObject::tr("You are loading an unsupported configuration"),
QObject::tr("CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid."),
QMessageBox::NoButton, main_window);
warningbox.addButton(QObject::tr("Continue"), QMessageBox::AcceptRole);
warningbox.addButton(QObject::tr("Exit"), QMessageBox::RejectRole);
warningbox.exec();
if (warningbox.result() == QDialog::Accepted) {
confirm_exit_cmdl = 0; /* skip the confirmation prompt without touching the config */
emit main_window->close();
}
}
// pc_reset_hard_init();
/* Set the PAUSE mode depending on the renderer. */

View File

@@ -346,6 +346,7 @@ MainWindow::MainWindow(QWidget *parent)
ui->actionUpdate_status_bar_icons->setChecked(update_icons);
ui->actionEnable_Discord_integration->setChecked(enable_discord);
ui->actionApply_fullscreen_stretch_mode_when_maximized->setChecked(video_fullscreen_scale_maximized);
ui->actionShow_status_icons_in_fullscreen->setChecked(status_icons_fullscreen);
#ifndef DISCORD
ui->actionEnable_Discord_integration->setVisible(false);
@@ -614,6 +615,15 @@ MainWindow::MainWindow(QWidget *parent)
if (!vnc_enabled)
video_setblit(qt_blit);
if (start_in_fullscreen) {
connect(ui->stackedWidget, &RendererStack::blit, this, [this] () {
if (start_in_fullscreen) {
QTimer::singleShot(100, ui->actionFullscreen, &QAction::trigger);
start_in_fullscreen = 0;
}
});
}
#ifdef MTR_ENABLED
{
ui->actionBegin_trace->setVisible(true);
@@ -840,10 +850,6 @@ MainWindow::showEvent(QShowEvent *event)
QApplication::processEvents();
this->adjustSize();
}
if (start_in_fullscreen) {
start_in_fullscreen = 0;
QTimer::singleShot(0, ui->actionFullscreen, &QAction::trigger);
}
}
void
@@ -2027,3 +2033,11 @@ void MainWindow::on_actionACPI_Shutdown_triggered()
{
acpi_pwrbut_pressed = 1;
}
void MainWindow::on_actionShow_status_icons_in_fullscreen_triggered()
{
status_icons_fullscreen = !status_icons_fullscreen;
ui->actionShow_status_icons_in_fullscreen->setChecked(status_icons_fullscreen);
config_save();
}

View File

@@ -144,6 +144,7 @@ private slots:
void on_actionCursor_Puck_triggered();
void on_actionACPI_Shutdown_triggered();
void on_actionShow_status_icons_in_fullscreen_triggered();
private slots:
void on_actionShow_non_primary_monitors_triggered();

View File

@@ -180,6 +180,7 @@
</widget>
<addaction name="actionHide_tool_bar"/>
<addaction name="actionHide_status_bar"/>
<addaction name="actionShow_status_icons_in_fullscreen"/>
<addaction name="separator"/>
<addaction name="actionShow_non_primary_monitors"/>
<addaction name="actionResizable_window"/>
@@ -881,6 +882,14 @@
<string>Cursor/Puck</string>
</property>
</action>
<action name="actionShow_status_icons_in_fullscreen">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Show status icons in fullscreen</string>
</property>
</action>
<action name="actionPen">
<property name="checkable">
<bool>true</bool>

View File

@@ -17,11 +17,15 @@
#include "qt_renderercommon.hpp"
#include "qt_mainwindow.hpp"
#include "qt_machinestatus.hpp"
#include <QPainter>
#include <QWidget>
#include <QEvent>
#include <QApplication>
#include <QFontMetrics>
#include <QStatusBar>
#include <QLayout>
#include <cmath>
@@ -29,6 +33,8 @@ extern "C" {
#include <86box/86box.h>
#include <86box/plat.h>
#include <86box/video.h>
int status_icons_fullscreen = 0;
}
RendererCommon::RendererCommon() = default;
@@ -131,6 +137,52 @@ RendererCommon::onResize(int width, int height)
monitors[r_monitor_index].mon_res_y = (double) destination.height();
}
void RendererCommon::drawStatusBarIcons(QPainter* painter)
{
uint32_t x = 0;
auto prevcompositionMode = painter->compositionMode();
painter->setCompositionMode(QPainter::CompositionMode::CompositionMode_SourceOver);
for (int i = 0; i < main_window->statusBar()->children().count(); i++) {
QLabel* label = qobject_cast<QLabel*>(main_window->statusBar()->children()[i]);
if (label) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
const QPixmap pixmap = label->pixmap();
#elif QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
const QPixmap pixmap = label->pixmap(Qt::ReturnByValue);
#else
const QPixmap pixmap = (label->pixmap() ? *label->pixmap() : QPixmap());
#endif
if (!pixmap.isNull()) {
painter->setBrush(QColor::fromRgbF(0, 0, 0, 1.));
painter->fillRect(x, painter->device()->height() - pixmap.height() - 5,
pixmap.width(), pixmap.height() + 5, QColor::fromRgbF(0, 0, 0, .5));
painter->drawPixmap(x + main_window->statusBar()->layout()->spacing() / 2,
painter->device()->height() - pixmap.height() - 3, pixmap);
x += pixmap.width();
if (i <= main_window->statusBar()->children().count() - 3) {
painter->fillRect(x, painter->device()->height() - pixmap.height() - 5,
main_window->statusBar()->layout()->spacing(), pixmap.height() + 5,
QColor::fromRgbF(0, 0, 0, .5));
x += main_window->statusBar()->layout()->spacing();
} else
painter->fillRect(x, painter->device()->height() - pixmap.height() - 4, 4,
pixmap.height() + 4, QColor::fromRgbF(0, 0, 0, .5));
}
}
}
if (main_window->status->getMessage().isEmpty() == false) {
auto curStatusMsg = main_window->status->getMessage();
auto textSize = painter->fontMetrics().size(Qt::TextSingleLine, QChar(' ') + curStatusMsg + QChar(' '));
painter->setPen(QColor(0, 0, 0, 127));
painter->fillRect(painter->device()->width() - textSize.width(), painter->device()->height() - textSize.height(),
textSize.width(), textSize.height(), QColor(0, 0, 0, 127));
painter->setPen(QColor(255, 255, 255, 255));
painter->drawText(QRectF(painter->device()->width() - textSize.width(), painter->device()->height() - textSize.height(),
textSize.width(), textSize.height()), Qt::TextSingleLine, QChar(' ') + curStatusMsg + QChar(' '));
}
painter->setCompositionMode(prevcompositionMode);
}
bool
RendererCommon::eventDelegate(QEvent *event, bool &result)
{

View File

@@ -42,6 +42,7 @@ public:
protected:
bool eventDelegate(QEvent *event, bool &result);
void drawStatusBarIcons(QPainter* painter);
QRect source { 0, 0, 0, 0 };
QRect destination;

View File

@@ -144,7 +144,10 @@ int ignoreNextMouseEvent = 1;
void
RendererStack::mouseReleaseEvent(QMouseEvent *event)
{
if (this->geometry().contains(event->pos()) && (event->button() == Qt::LeftButton) && !mouse_capture && (isMouseDown & 1) && (kbd_req_capture || (mouse_get_buttons() != 0)) && (mouse_input_mode == 0)) {
if (!dopause && this->geometry().contains(event->pos()) &&
(event->button() == Qt::LeftButton) && !mouse_capture &&
(isMouseDown & 1) && (kbd_req_capture || (mouse_get_buttons() != 0)) &&
(mouse_input_mode == 0)) {
plat_mouse_capture(1);
this->setCursor(Qt::BlankCursor);
if (!ignoreNextMouseEvent)

View File

@@ -627,7 +627,7 @@ sdl_main()
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
if ((event.button.button == SDL_BUTTON_LEFT)
if (!dopause && (event.button.button == SDL_BUTTON_LEFT)
&& !(mouse_capture || video_fullscreen)
&& event.button.state == SDL_RELEASED
&& mouse_inside) {

View File

@@ -24,6 +24,7 @@
extern "C" {
#include <86box/86box.h>
#include <86box/plat.h>
#include <86box/video.h>
}
@@ -113,6 +114,7 @@ SoftwareRenderer::onPaint(QPaintDevice *device)
#endif
painter.setCompositionMode(QPainter::CompositionMode_Plus);
painter.drawImage(destination, *images[cur_image], source);
if (video_fullscreen && status_icons_fullscreen) drawStatusBarIcons(&painter);
}
std::vector<std::tuple<uint8_t *, std::atomic_flag *>>

View File

@@ -1997,7 +1997,7 @@ begin:
case CDROM_TYPE_NEC_211_100:
case CDROM_TYPE_NEC_464_105: /*GPCMD_READ_DISC_INFORMATION_NEC*/
scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN);
scsi_cdrom_buf_alloc(dev, 22); /*NEC manual claims 4 bytes, but the Android source code (namely sr_vendor.c) actually states otherwise.*/
scsi_cdrom_buf_alloc(dev, 22); /* NEC manual claims 4 bytes, but the Linux kernel (namely sr_vendor.c) actually states otherwise. */
if (!dev->drv->ops) {
scsi_cdrom_not_ready(dev);

View File

@@ -128,7 +128,6 @@ static void scsi_disk_command_complete(scsi_disk_t *dev);
static void scsi_disk_mode_sense_load(scsi_disk_t *dev);
static void scsi_disk_init(scsi_disk_t *dev);
static void scsi_disk_reset(scsi_common_t *sc);
#ifdef ENABLE_SCSI_DISK_LOG
int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG;
@@ -787,7 +786,7 @@ scsi_disk_rezero(scsi_disk_t *dev)
scsi_disk_seek(dev, 0);
}
static void
void
scsi_disk_reset(scsi_common_t *sc)
{
scsi_disk_t *dev = (scsi_disk_t *) sc;

View File

@@ -16,7 +16,7 @@
add_library(sio OBJECT sio_acc3221.c sio_ali5123.c sio_f82c710.c sio_82091aa.c
sio_fdc37c6xx.c sio_fdc37c67x.c sio_fdc37c669.c sio_fdc37c93x.c sio_fdc37m60x.c
sio_nsc366.c
sio_it8661f.c
sio_it86x1f.c
sio_it8702.c
sio_pc87306.c sio_pc87307.c sio_pc87309.c sio_pc87310.c sio_pc87311.c sio_pc87332.c
sio_prime3b.c sio_prime3c.c

View File

@@ -1,353 +0,0 @@
/*
* 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 ITE IT8661F chipset.
*
* Note: This Super I/O is partially incomplete and intended only for having the intended machine to function
*
* Authors: Tiseno100
*
* Copyright 2021 Tiseno100
*
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/fdd_common.h>
#include <86box/sio.h>
#include <86box/plat_unused.h>
#define LDN dev->regs[7]
typedef struct it8661f_t {
fdc_t *fdc_controller;
serial_t *uart[2];
uint8_t index;
uint8_t regs[256];
uint8_t device_regs[6][256];
int unlocked;
int enumerator;
} it8661f_t;
static uint8_t mb_pnp_key[32] = { 0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, 0x0d, 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1, 0xe8, 0x74, 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 };
static void it8661f_reset(void *priv);
#ifdef ENABLE_IT8661_LOG
int it8661_do_log = ENABLE_IT8661_LOG;
void
it8661_log(const char *fmt, ...)
{
va_list ap;
if (it8661_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define it8661_log(fmt, ...)
#endif
static void
it8661_fdc(uint16_t addr, uint8_t val, it8661f_t *dev)
{
fdc_remove(dev->fdc_controller);
if (((addr == 0x30) && (val & 1)) || (dev->device_regs[0][0x30] & 1)) {
switch (addr) {
case 0x30:
dev->device_regs[0][addr] = val & 1;
break;
case 0x31:
dev->device_regs[0][addr] = val & 3;
if (val & 1)
dev->device_regs[0][addr] |= 0x55;
break;
case 0x60:
case 0x61:
dev->device_regs[0][addr] = val & ((addr == 0x61) ? 0xff : 0xf8);
break;
case 0x70:
dev->device_regs[0][addr] = val & 0x0f;
break;
case 0x74:
dev->device_regs[0][addr] = val & 7;
break;
case 0xf0:
dev->device_regs[0][addr] = val & 0x0f;
break;
default:
break;
}
fdc_set_base(dev->fdc_controller, (dev->device_regs[0][0x60] << 8) | (dev->device_regs[0][0x61]));
fdc_set_irq(dev->fdc_controller, dev->device_regs[0][0x70] & 0x0f);
fdc_set_dma_ch(dev->fdc_controller, dev->device_regs[0][0x74] & 7);
if (dev->device_regs[0][0xf0] & 1)
fdc_writeprotect(dev->fdc_controller);
it8661_log("ITE 8661-FDC: BASE %04x IRQ %02x\n", (dev->device_regs[0][0x60] << 8) | (dev->device_regs[0][0x61]),
dev->device_regs[0][0x70] & 0x0f);
}
}
static void
it8661_serial(int uart, uint16_t addr, uint8_t val, it8661f_t *dev)
{
serial_remove(dev->uart[uart]);
if (((addr == 0x30) && (val & 1)) || (dev->device_regs[1 + uart][0x30] & 1)) {
switch (addr) {
case 0x30:
dev->device_regs[1 + uart][addr] = val & 1;
break;
case 0x60:
case 0x61:
dev->device_regs[1 + uart][addr] = val & ((addr == 0x61) ? 0xff : 0xf8);
break;
case 0x70:
dev->device_regs[1 + uart][addr] = val & 0x0f;
break;
case 0x74:
dev->device_regs[1 + uart][addr] = val & 7;
break;
case 0xf0:
dev->device_regs[1 + uart][addr] = val & 3;
break;
default:
break;
}
serial_setup(dev->uart[uart], (dev->device_regs[1 + uart][0x60] << 8) | (dev->device_regs[1 + uart][0x61]), dev->device_regs[1 + uart][0x70] & 0x0f);
it8661_log("ITE 8661-UART%01x: BASE %04x IRQ %02x\n", 1 + (LDN % 1),
(dev->device_regs[1 + uart][0x60] << 8) | (dev->device_regs[1 + uart][0x61]),
dev->device_regs[1 + uart][0x70] & 0x0f);
}
}
void
it8661_lpt(uint16_t addr, uint8_t val, it8661f_t *dev)
{
lpt1_remove();
if (((addr == 0x30) && (val & 1)) || (dev->device_regs[3][0x30] & 1)) {
switch (addr) {
case 0x30:
dev->device_regs[3][addr] = val & 1;
break;
case 0x60:
case 0x61:
dev->device_regs[3][addr] = val & ((addr == 0x61) ? 0xff : 0xf8);
break;
case 0x70:
dev->device_regs[3][addr] = val & 0x0f;
break;
case 0x74:
dev->device_regs[3][addr] = val & 7;
break;
case 0xf0:
dev->device_regs[3][addr] = val & 3;
break;
default:
break;
}
lpt1_init((dev->device_regs[3][0x60] << 8) | (dev->device_regs[3][0x61]));
lpt1_irq(dev->device_regs[3][0x70] & 0x0f);
it8661_log("ITE 8661-LPT: BASE %04x IRQ %02x\n", (dev->device_regs[3][0x60] << 8) | (dev->device_regs[3][0x61]),
dev->device_regs[3][0x70] & 0x0f);
}
}
void
it8661_ldn(uint16_t addr, uint8_t val, it8661f_t *dev)
{
switch (LDN) {
case 0:
it8661_fdc(addr, val, dev);
break;
case 1:
case 2:
it8661_serial((LDN & 2) - 1, addr, val, dev);
break;
case 3:
it8661_lpt(addr, val, dev);
break;
default:
break;
}
}
static void
it8661f_write(uint16_t addr, uint8_t val, void *priv)
{
it8661f_t *dev = (it8661f_t *) priv;
switch (addr) {
case FDC_SECONDARY_ADDR:
if (!dev->unlocked) {
(val == mb_pnp_key[dev->enumerator]) ? dev->enumerator++ : (dev->enumerator = 0);
if (dev->enumerator == 31) {
dev->unlocked = 1;
it8661_log("ITE8661F: Unlocked!\n");
}
} else
dev->index = val;
break;
case 0x371:
if (dev->unlocked) {
switch (dev->index) {
case 0x02:
dev->regs[dev->index] = val;
if (val & 1)
it8661f_reset(dev);
if (val & 2)
dev->unlocked = 0;
break;
case 0x07:
dev->regs[dev->index] = val;
break;
case 0x22:
dev->regs[dev->index] = val & 0x30;
break;
case 0x23:
dev->regs[dev->index] = val & 0x1f;
break;
default:
it8661_ldn(dev->index, val, dev);
break;
}
}
break;
default:
break;
}
return;
}
static uint8_t
it8661f_read(uint16_t addr, void *priv)
{
const it8661f_t *dev = (it8661f_t *) priv;
it8661_log("IT8661F:\n", addr, dev->regs[dev->index]);
return (addr == 0xa79) ? dev->regs[dev->index] : 0xff;
}
static void
it8661f_reset(void *priv)
{
it8661f_t *dev = (it8661f_t *) priv;
dev->regs[0x20] = 0x86;
dev->regs[0x21] = 0x61;
dev->device_regs[0][0x60] = 3;
dev->device_regs[0][0x61] = 0xf0;
dev->device_regs[0][0x70] = 6;
dev->device_regs[0][0x71] = 2;
dev->device_regs[0][0x74] = 2;
dev->device_regs[1][0x60] = 3;
dev->device_regs[1][0x61] = 0xf8;
dev->device_regs[1][0x70] = 4;
dev->device_regs[1][0x71] = 2;
dev->device_regs[2][0x60] = 2;
dev->device_regs[2][0x61] = 0xf8;
dev->device_regs[2][0x70] = 3;
dev->device_regs[2][0x71] = 2;
dev->device_regs[3][0x60] = 3;
dev->device_regs[3][0x61] = 0x78;
dev->device_regs[3][0x70] = 7;
dev->device_regs[3][0x71] = 2;
dev->device_regs[3][0x74] = 3;
dev->device_regs[3][0xf0] = 3;
}
static void
it8661f_close(void *priv)
{
it8661f_t *dev = (it8661f_t *) priv;
free(dev);
}
static void *
it8661f_init(UNUSED(const device_t *info))
{
it8661f_t *dev = (it8661f_t *) malloc(sizeof(it8661f_t));
memset(dev, 0, sizeof(it8661f_t));
dev->fdc_controller = device_add(&fdc_at_smc_device);
fdc_reset(dev->fdc_controller);
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
io_sethandler(FDC_SECONDARY_ADDR, 0x0002, it8661f_read, NULL, NULL, it8661f_write, NULL, NULL, dev);
dev->enumerator = 0;
dev->unlocked = 0;
it8661f_reset(dev);
return dev;
}
const device_t it8661f_device = {
.name = "ITE IT8661F",
.internal_name = "it8661f",
.flags = 0,
.local = 0,
.init = it8661f_init,
.close = it8661f_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

862
src/sio/sio_it86x1f.c Normal file
View File

@@ -0,0 +1,862 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Emulation of the ITE IT86x1F Super I/O chips.
*
*
*
* Authors: RichardG, <richardg867@gmail.com>
*
* Copyright 2023 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/pci.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/gameport.h>
#include <86box/sio.h>
#include <86box/isapnp.h>
#include <86box/plat_fallthrough.h>
#include <86box/plat_unused.h>
enum {
ITE_IT8661F = 0x8661,
ITE_IT8671F = 0x8681
};
#define CHIP_ID *((uint16_t *) &dev->global_regs[0])
static void it8671f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv);
static void it8661f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv);
static const struct {
uint16_t chip_id;
uint16_t unlock_id;
uint8_t gpio_ldn;
/* Fake ROMs to delegate all the logical device register handling over to the ISAPnP subsystem.
The actual ROMs/IDs used by real chips when those are set to ISAPnP mode remain to be seen. */
uint8_t *pnp_rom;
const isapnp_device_config_t *pnp_defaults;
void (*pnp_config_changed)(uint8_t ld, isapnp_device_config_t *config, void *priv);
} it86x1f_models[] = {
{
.chip_id = ITE_IT8661F,
.unlock_id = 0x8661,
.gpio_ldn = 0x05,
.pnp_rom = (uint8_t[]) {
0x26, 0x85, 0x86, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, /* ITE8661, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
0x15, 0x41, 0xd0, 0x07, 0x00, 0x01, /* logical device PNP0700, can participate in boot */
0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */
0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x15, 0x41, 0xd0, 0x05, 0x01, 0x01, /* logical device PNP0501, can participate in boot */
0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x15, 0x41, 0xd0, 0x05, 0x01, 0x01, /* logical device PNP0501, can participate in boot */
0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x15, 0x41, 0xd0, 0x04, 0x00, 0x01, /* logical device PNP0400, can participate in boot */
0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */
0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x47, 0x01, 0x00, 0x01, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x100-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */
0x15, 0x41, 0xd0, 0x05, 0x10, 0x01, /* logical device PNP0510, can participate in boot */
0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */
0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */
0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
},
.pnp_defaults = (const isapnp_device_config_t[]) {
{
.activate = 0,
.io = { { .base = FDC_PRIMARY_ADDR }, },
.irq = { { .irq = FDC_PRIMARY_IRQ }, },
.dma = { { .dma = FDC_PRIMARY_DMA }, }
}, {
.activate = 0,
.io = { { .base = COM1_ADDR }, },
.irq = { { .irq = COM1_IRQ }, }
}, {
.activate = 0,
.io = { { .base = COM2_ADDR }, },
.irq = { { .irq = COM2_IRQ }, }
}, {
.activate = 0,
.io = { { .base = LPT1_ADDR }, { .base = 0x778 }, },
.irq = { { .irq = LPT1_IRQ }, },
.dma = { { .dma = 3 }, }
}, {
.activate = 0,
.io = { { .base = COM4_ADDR }, { .base = 0x300 }, },
.irq = { { .irq = 10 }, { .irq = 11 }, },
.dma = { { .dma = 1 }, { .dma = 0 }, }
}, {
.activate = -1
}
},
.pnp_config_changed = it8661f_pnp_config_changed
}, {
.chip_id = ITE_IT8671F,
.unlock_id = 0x8680,
.gpio_ldn = 0x07,
.pnp_rom = (uint8_t[]) {
0x26, 0x85, 0x86, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, /* ITE8671, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
0x15, 0x41, 0xd0, 0x07, 0x00, 0x01, /* logical device PNP0700, can participate in boot */
0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */
0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x15, 0x41, 0xd0, 0x05, 0x01, 0x01, /* logical device PNP0501, can participate in boot */
0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x15, 0x41, 0xd0, 0x05, 0x10, 0x01, /* logical device PNP0510, can participate in boot */
0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */
0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */
0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x15, 0x41, 0xd0, 0x04, 0x00, 0x01, /* logical device PNP0400, can participate in boot */
0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */
0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x47, 0x01, 0x00, 0x01, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x100-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */
0x15, 0x41, 0xd0, 0xff, 0xff, 0x00, /* logical device PNPFFFF (dummy to create APC gap in LDNs) */
0x15, 0x41, 0xd0, 0x03, 0x03, 0x01, /* logical device PNP0303, can participate in boot */
0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */
0x47, 0x01, 0x00, 0x00, 0xff, 0x0f, 0x01, 0x01, /* I/O 0x0-0xFFF, decodes 16-bit, 1-byte alignment, 1 address */
0x47, 0x01, 0x00, 0x00, 0xff, 0x0f, 0x01, 0x01, /* I/O 0x0-0xFFF, decodes 16-bit, 1-byte alignment, 1 address */
0x15, 0x41, 0xd0, 0x0f, 0x13, 0x01, /* logical device PNP0F13, can participate in boot */
0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
},
.pnp_defaults = (const isapnp_device_config_t[]) {
{
.activate = 0,
.io = { { .base = FDC_PRIMARY_ADDR }, },
.irq = { { .irq = FDC_PRIMARY_IRQ }, },
.dma = { { .dma = FDC_PRIMARY_DMA }, }
}, {
.activate = 0,
.io = { { .base = COM1_ADDR }, },
.irq = { { .irq = COM1_IRQ }, }
}, {
.activate = 0,
.io = { { .base = COM2_ADDR }, { .base = 0x300 }, },
.irq = { { .irq = COM2_IRQ }, { .irq = 10 }, },
.dma = { { .dma = 0 }, { .dma = 1 }, }
}, {
.activate = 0,
.io = { { .base = LPT1_ADDR }, { .base = 0x778 }, },
.irq = { { .irq = LPT1_IRQ }, },
.dma = { { .dma = 3 }, }
}, {
.activate = 0
}, {
.activate = 1,
.io = { { .base = 0x60 }, { .base = 0x64 }, },
.irq = { { .irq = 1 }, }
}, {
.activate = 0,
.irq = { { .irq = 12 }, }
}, {
.activate = -1
}
},
.pnp_config_changed = it8671f_pnp_config_changed
}
};
#ifdef ENABLE_IT86X1F_LOG
int it86x1f_do_log = ENABLE_IT86X1F_LOG;
static void
it86x1f_log(const char *fmt, ...)
{
va_list ap;
if (it86x1f_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define it86x1f_log(fmt, ...)
#endif
typedef struct it86x1f_t {
uint8_t instance;
uint8_t locked;
uint8_t cur_ldn;
uint8_t cur_reg;
void *pnp_card;
uint8_t global_regs[16]; /* [0x20:0x2f] */
uint8_t ldn_regs[8][16]; /* [0xf0:0xff] */
uint8_t gpio_regs[36]; /* [0x60:0x7f] then [0xe0:0xe3] */
uint8_t gpio_ldn;
uint16_t unlock_id;
uint16_t addr_port;
uint16_t data_port;
uint8_t unlock_val;
uint8_t unlock_pos : 2;
uint8_t key_pos : 5;
fdc_t *fdc;
serial_t *uart[2];
void *gameport;
} it86x1f_t;
static void it86x1f_remap(it86x1f_t *dev, uint16_t addr_port, uint16_t data_port);
static void
it8661f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv)
{
if (ld > 5) {
it86x1f_log("IT86x1F: Unknown logical device %d\n", ld);
return;
}
it86x1f_t *dev = (it86x1f_t *) priv;
switch (ld) {
case 0:
fdc_remove(dev->fdc);
if (config->activate) {
it86x1f_log("IT86x1F: FDC enabled at port %04X IRQ %d DMA %d\n", config->io[0].base, config->irq[0].irq, (config->dma[0].dma == ISAPNP_DMA_DISABLED) ? -1 : config->dma[0].dma);
if (config->io[0].base != ISAPNP_IO_DISABLED)
fdc_set_base(dev->fdc, config->io[0].base);
fdc_set_irq(dev->fdc, config->irq[0].irq);
fdc_set_dma_ch(dev->fdc, (config->dma[0].dma == ISAPNP_DMA_DISABLED) ? -1 : config->dma[0].dma);
} else {
it86x1f_log("IT86x1F: FDC disabled\n");
}
break;
case 1:
case 2:
serial_remove(dev->uart[ld - 1]);
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) {
it86x1f_log("IT86x1F: UART %d enabled at port %04X IRQ %d\n", ld - 1, config->io[0].base, config->irq[0].irq);
serial_setup(dev->uart[ld - 1], config->io[0].base, config->irq[0].irq);
} else {
it86x1f_log("IT86x1F: UART %d disabled\n", ld - 1);
}
break;
case 3:
lpt1_remove();
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) {
it86x1f_log("IT86x1F: LPT enabled at port %04X IRQ %d\n", config->io[0].base, config->irq[0].irq);
lpt1_init(config->io[0].base);
} else {
it86x1f_log("IT86x1F: LPT disabled\n");
}
break;
case 4:
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) {
it86x1f_log("IT86x1F: IR enabled at ports %04X %04X IRQs %d %d DMAs %d %d\n", config->io[0].base, config->io[1].base, config->irq[0].irq, config->irq[1].irq, (config->dma[0].dma == ISAPNP_DMA_DISABLED) ? -1 : config->dma[0].dma, (config->dma[1].dma == ISAPNP_DMA_DISABLED) ? -1 : config->dma[1].dma);
} else {
it86x1f_log("IT86x1F: IR disabled\n");
}
break;
default:
break;
}
}
static void
it8671f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv)
{
it86x1f_t *dev = (it86x1f_t *) priv;
switch (ld) {
case 2:
it8661f_pnp_config_changed(4, config, dev); /* just for logging, should change if IR UART is implemented */
fallthrough;
case 0 ... 1:
case 3:
it8661f_pnp_config_changed(ld, config, dev);
break;
case 5:
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED) && (config->io[1].base != ISAPNP_IO_DISABLED)) {
it86x1f_log("IT86x1F: KBC enabled at ports %04X %04X IRQ %d\n", config->io[0].base, config->io[1].base, config->irq[0].irq);
} else {
it86x1f_log("IT86x1F: KBC disabled\n");
}
break;
case 6:
if (config->activate) {
it86x1f_log("IT86x1F: KBC mouse enabled at IRQ %d\n", config->irq[0].irq);
} else {
it86x1f_log("IT86x1F: KBC mouse disabled\n");
}
break;
default:
break;
}
}
static uint8_t
it86x1f_pnp_read_vendor_reg(uint8_t ld, uint8_t reg, void *priv)
{
it86x1f_t *dev = (it86x1f_t *) priv;
uint8_t ret = 0xff;
switch (reg) {
case 0x20 ... 0x2f:
ret = dev->global_regs[reg & 0x0f];
break;
case 0x60 ... 0x7f:
if (ld != dev->gpio_ldn)
break;
ret = dev->gpio_regs[reg & 0x1f];
break;
case 0xe0 ... 0xe3:
if (ld != dev->gpio_ldn)
break;
ret = dev->gpio_regs[0x20 | (reg & 0x03)];
break;
case 0xf0 ... 0xff:
if (ld > dev->gpio_ldn)
break;
ret = dev->ldn_regs[ld][reg & 0x0f];
break;
default:
break;
}
it86x1f_log("IT86x1F: read_vendor_reg(%X, %02X) = %02X\n", ld, reg, ret);
return ret;
}
static void
it86x1f_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv)
{
it86x1f_t *dev = (it86x1f_t *) priv;
uint8_t effective_ldn;
it86x1f_log("IT86x1F: write_vendor_reg(%X, %02X, %02X)\n", ld, reg, val);
switch (reg) {
case 0x22:
if (CHIP_ID == ITE_IT8661F) {
dev->global_regs[reg & 0x0f] = (val & 0x30) | (dev->global_regs[reg & 0x0f] & ~0x30);
uint8_t mcc = (val & 0x30) >> 4;
if (mcc != dev->instance) {
it86x1f_log("IT86x1F: Instance %d unmapping as ID %d was written\n", dev->instance, mcc);
it86x1f_remap(dev, 0, 0);
}
}
break;
case 0x23:
val &= (1 << dev->gpio_ldn) - 1;
dev->global_regs[reg & 0x0f] = val;
if (val)
pclog("IT86x1F: Warning: ISAPnP mode enabled.\n");
break;
case 0x24:
dev->global_regs[reg & 0x0f] = val & ((CHIP_ID == ITE_IT8661F) ? 0x03 : 0x5f);
break;
case 0x25:
val &= (CHIP_ID == ITE_IT8661F) ? 0x1f : 0xf0;
fallthrough;
case 0x26:
if (ld == dev->gpio_ldn)
dev->global_regs[reg & 0x0f] = val;
break;
case 0x2e ... 0x2f:
if ((CHIP_ID == ITE_IT8671F) && (ld == 0xf4))
dev->global_regs[reg & 0x0f] = val;
break;
case 0x60 ... 0x7f:
if (ld != dev->gpio_ldn)
break;
dev->gpio_regs[reg & 0x1f] = val;
break;
case 0xe0 ... 0xe3:
if (ld != dev->gpio_ldn)
break;
dev->gpio_regs[0x20 | (reg & 0x0f)] = val;
break;
case 0xf0 ... 0xff:
/* Translate GPIO LDN to 7 for the switch block. */
if (ld == dev->gpio_ldn)
effective_ldn = 7;
else if (ld == 7)
effective_ldn = 8; /* dummy */
else
effective_ldn = ld;
switch ((effective_ldn << 8) | reg) {
case 0x0f0:
dev->ldn_regs[ld][reg & 0x0f] = val & 0x0f;
fdc_set_swwp(dev->fdc, !!(val & 0x01));
fdc_set_swap(dev->fdc, !!(val & 0x04));
break;
case 0x1f0:
dev->ldn_regs[ld][reg & 0x0f] = val & 0x03;
break;
case 0x2f0:
dev->ldn_regs[ld][reg & 0x0f] = val & ((CHIP_ID == ITE_IT8661F) ? 0x03 : 0xf3);
break;
case 0x2f1:
if (CHIP_ID == ITE_IT8671F)
dev->ldn_regs[ld][reg & 0x0f] = val & 0xb7;
break;
case 0x3f0:
dev->ldn_regs[ld][reg & 0x0f] = val & 0x07;
break;
case 0x4f0:
if (CHIP_ID == ITE_IT8661F)
val &= 0x3f;
dev->ldn_regs[ld][reg & 0x0f] = val;
break;
case 0x4f1:
if (CHIP_ID == ITE_IT8671F)
dev->ldn_regs[ld][reg & 0x0f] = val & 0x7f;
break;
case 0x4f2:
case 0x4f6:
if (CHIP_ID == ITE_IT8671F)
dev->ldn_regs[ld][reg & 0x0f] = val;
break;
case 0x4f7:
if (CHIP_ID == ITE_IT8671F)
dev->ldn_regs[ld][reg & 0x0f] = val & 0x7f;
break;
case 0x4f8:
if (CHIP_ID == ITE_IT8671F)
dev->ldn_regs[ld][reg & 0x0f] = val & 0x07;
break;
case 0x5f0:
dev->ldn_regs[ld][reg & 0x0f] = val & 0x1f;
break;
case 0x6f0:
if (CHIP_ID == ITE_IT8671F)
dev->ldn_regs[ld][reg & 0x0f] = val & 0x03;
break;
case 0x760:
case 0x762:
case 0x764:
case 0x766:
dev->gpio_regs[reg & 0x1f] = val & 0x0f;
break;
case 0x772:
if (CHIP_ID != ITE_IT8671F)
break;
fallthrough;
case 0x761:
case 0x763:
case 0x765:
case 0x767:
case 0x770:
dev->gpio_regs[reg & 0x1f] = val;
case 0x771:
if (CHIP_ID == ITE_IT8671F)
dev->gpio_regs[reg & 0x1f] = val & 0xde;
break;
case 0x7e0:
if (CHIP_ID == ITE_IT8671F)
dev->gpio_regs[0x20 | (reg & 0x03)] = val & 0xef;
break;
case 0x7e1:
if (CHIP_ID == ITE_IT8671F)
dev->gpio_regs[0x20 | (reg & 0x03)] = val & 0x7f;
break;
case 0x7e3:
if ((CHIP_ID == ITE_IT8671F) && (val & 0x80))
*((uint16_t *) &dev->gpio_regs[0x22]) = 0x0000;
break;
case 0x7fb:
if (CHIP_ID == ITE_IT8671F)
val &= 0x7f;
fallthrough;
case 0x7f0 ... 0x7f5:
dev->ldn_regs[ld][reg & 0x0f] = val;
break;
case 0x7f6:
dev->ldn_regs[ld][reg & 0x0f] = val & ((CHIP_ID == ITE_IT8661F) ? 0x3f : 0xcf);
break;
case 0x7f7:
dev->ldn_regs[ld][reg & 0x0f] = val & ((CHIP_ID == ITE_IT8661F) ? 0x9f : 0xdf);
break;
case 0x7f8 ... 0x7fa:
dev->ldn_regs[ld][reg & 0x0f] = val & ((CHIP_ID == ITE_IT8661F) ? 0x1f : 0x0f);
break;
case 0x7fc:
if (CHIP_ID == ITE_IT8661F)
dev->ldn_regs[ld][reg & 0x0f] = val;
break;
case 0x7ff:
if (CHIP_ID == ITE_IT8671F)
dev->ldn_regs[ld][reg & 0x0f] = val & 0x2f;
break;
default:
break;
}
break;
default:
break;
}
}
static void
it86x1f_write_addr(uint16_t port, uint8_t val, void *priv)
{
it86x1f_t *dev = (it86x1f_t *) priv;
it86x1f_log("IT86x1F: write_addr(%04X, %02X)\n", port, val);
if (dev->locked) {
if (val == isapnp_init_key[dev->key_pos]) {
if (++dev->key_pos == 0) {
it86x1f_log("IT86x1F: Unlocked\n");
dev->locked = 0;
}
} else {
dev->key_pos = 0;
}
} else {
dev->cur_reg = val;
}
}
static void
it86x1f_write_data(uint16_t port, uint8_t val, void *priv)
{
it86x1f_t *dev = (it86x1f_t *) priv;
it86x1f_log("IT86x1F: write_data(%04X, %02X)\n", port, val);
if (dev->locked)
return;
switch (dev->cur_reg) {
case 0x00 ... 0x01:
case 0x03 ... 0x06:
case 0x31:
case 0x71:
case 0x73:
break; /* ISAPnP-only */
case 0x07:
dev->cur_ldn = val;
break;
case 0x02:
if (val & 0x02) {
it86x1f_log("IT86x1F: Locked => ");
dev->locked = 1;
it86x1f_remap(dev, 0, 0);
}
fallthrough;
default:
isapnp_write_reg(dev->pnp_card, dev->cur_ldn, dev->cur_reg, val);
break;
}
}
static uint8_t
it86x1f_read_addr(uint16_t port, void *priv)
{
it86x1f_t *dev = (it86x1f_t *) priv;
uint8_t ret = dev->locked ? 0xff : dev->cur_reg;
it86x1f_log("IT86x1F: read_addr(%04X) = %02X\n", port, ret);
return ret;
}
static uint8_t
it86x1f_read_data(uint16_t port, void *priv)
{
it86x1f_t *dev = (it86x1f_t *) priv;
uint8_t ret = 0xff;
switch (dev->cur_reg) {
case 0x00 ... 0x01:
case 0x03 ... 0x06:
case 0x31:
case 0x71:
case 0x73:
break; /* ISAPnP-only */
case 0x07:
ret = dev->cur_ldn;
break;
default:
ret = isapnp_read_reg(dev->pnp_card, dev->cur_ldn, dev->cur_reg);
break;
}
it86x1f_log("IT86x1F: read_data(%04X) = %02X\n", port, ret);
return ret;
}
static void
it86x1f_remap(it86x1f_t *dev, uint16_t addr_port, uint16_t data_port)
{
if (dev->addr_port)
io_removehandler(dev->addr_port, 1, it86x1f_read_addr, NULL, NULL, it86x1f_write_addr, NULL, NULL, dev);
if (dev->data_port)
io_removehandler(dev->data_port, 1, it86x1f_read_data, NULL, NULL, it86x1f_write_data, NULL, NULL, dev);
it86x1f_log("IT86x1F: remap(%04X, %04X)\n", addr_port, data_port);
dev->addr_port = addr_port;
dev->data_port = data_port;
if (dev->addr_port)
io_sethandler(dev->addr_port, 1, it86x1f_read_addr, NULL, NULL, it86x1f_write_addr, NULL, NULL, dev);
if (dev->data_port)
io_sethandler(dev->data_port, 1, it86x1f_read_data, NULL, NULL, it86x1f_write_data, NULL, NULL, dev);
}
static void
it86x1f_write_unlock(UNUSED(uint16_t port), uint8_t val, void *priv)
{
it86x1f_t *dev = (it86x1f_t *) priv;
it86x1f_log("IT86x1F: write_unlock(%04X, %02X)\n", port, val);
if (!dev->locked)
dev->unlock_pos = 0;
switch (dev->unlock_pos++) {
case 0:
if (val != (dev->unlock_id >> 8))
dev->unlock_pos = 0;
break;
case 1:
if (val != (dev->unlock_id & 0xff))
dev->unlock_pos = 0;
break;
case 2:
if ((val != 0x55) && (val != 0xaa))
dev->unlock_pos = 0;
else
dev->unlock_val = val;
break;
case 3:
switch ((dev->unlock_val << 8) | val) {
case 0x5555:
it86x1f_remap(dev, 0x3f0, 0x3f1);
break;
case 0x55aa:
it86x1f_remap(dev, 0x3bd, 0x3bf);
break;
case 0xaa55:
it86x1f_remap(dev, 0x370, 0x371);
break;
default:
it86x1f_remap(dev, 0, 0);
break;
}
dev->unlock_pos = 0;
break;
}
}
void
it86x1f_reset(it86x1f_t *dev)
{
it86x1f_log("IT86x1F: reset()\n");
fdc_reset(dev->fdc);
serial_remove(dev->uart[0]);
serial_remove(dev->uart[1]);
lpt1_remove();
isapnp_enable_card(dev->pnp_card, ISAPNP_CARD_DISABLE);
dev->locked = 1;
isapnp_reset_card(dev->pnp_card);
}
static void
it86x1f_close(void *priv)
{
it86x1f_t *dev = (it86x1f_t *) priv;
it86x1f_log("IT86x1F: close()\n");
free(dev);
}
static void *
it86x1f_init(UNUSED(const device_t *info))
{
it86x1f_t *dev = (it86x1f_t *) malloc(sizeof(it86x1f_t));
memset(dev, 0, sizeof(it86x1f_t));
uint8_t i;
for (i = 0; i < (sizeof(it86x1f_models) / sizeof(it86x1f_models[0])); i++) {
if (it86x1f_models[i].chip_id == info->local)
break;
}
if (i >= (sizeof(it86x1f_models) / sizeof(it86x1f_models[0]))) {
fatal("IT86x1F: Unknown type %04X selected\n", info->local);
return NULL;
}
it86x1f_log("IT86x1F: init(%04X)\n", info->local);
/* Let the resource data parser figure out the ROM size. */
dev->pnp_card = isapnp_add_card(it86x1f_models[i].pnp_rom, -1, it86x1f_models[i].pnp_config_changed, NULL, it86x1f_pnp_read_vendor_reg, it86x1f_pnp_write_vendor_reg, dev);
for (uint8_t j = 0; it86x1f_models[i].pnp_defaults[j].activate != (uint8_t) -1; j++)
isapnp_set_device_defaults(dev->pnp_card, j, &it86x1f_models[i].pnp_defaults[j]);
dev->fdc = device_add(&fdc_at_smc_device);
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->gameport = gameport_add(&gameport_sio_device);
dev->instance = device_get_instance();
dev->gpio_ldn = it86x1f_models[i].gpio_ldn;
CHIP_ID = it86x1f_models[i].chip_id;
dev->unlock_id = it86x1f_models[i].unlock_id;
io_sethandler(0x279, 1, NULL, NULL, NULL, it86x1f_write_unlock, NULL, NULL, dev);
it86x1f_reset(dev);
return dev;
}
const device_t it8661f_device = {
.name = "ITE IT8661F Super I/O",
.internal_name = "it8661f",
.flags = 0,
.local = ITE_IT8661F,
.init = it86x1f_init,
.close = it86x1f_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t it8671f_device = {
.name = "ITE IT8671F Super I/O",
.internal_name = "it8671f",
.flags = 0,
.local = ITE_IT8671F,
.init = it86x1f_init,
.close = it86x1f_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -439,6 +439,7 @@ pc87306_reset_common(void *priv)
fdc_reset(dev->fdc);
pc87306_gpio_init(dev);
nvr_lock_set(0x00, 256, 0, dev->nvr);
nvr_at_handler(0, 0x0070, dev->nvr);
nvr_at_handler(1, 0x0070, dev->nvr);
nvr_bank_set(0, 0, dev->nvr);
nvr_wp_set(0, 0, dev->nvr);

View File

@@ -18,6 +18,35 @@
* Copyright 2016-2021 Miran Grca.
* Copyright 2021 RichardG.
*/
/*
UMC UM8669F non-PnP register definitions
C0:
[7] Infrared half duplex
[4:3] LPT mode:
00 SPP
01 EPP
10 ECP
11 ECP + EPP
C1:
[7] Enable PnP access
[6:0] Always set regardless of PnP access enabled/disabled
C2:
[6:5] Potentially pin muxing mode: (names from AMI "IR group" setup option)
00 Reserved
01 A (no IDE)
10 B (no IDE)
11 C
[4:3] Infrared mode:
00 Reserved
01 HPSIR
10 ASKIR
11 Disabled
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
@@ -35,8 +64,10 @@
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/gameport.h>
#include <86box/sio.h>
#include <86box/hdc.h>
#include <86box/isapnp.h>
#include <86box/hdc_ide.h>
#include <86box/sio.h>
#include <86box/plat_unused.h>
/* Real chips don't have a PnP ROM and instead rely on the BIOS going in blind.
@@ -63,7 +94,9 @@ static uint8_t um8669f_pnp_rom[] = {
0x22, 0xfa, 0x1f, /* IRQ 1/3/4/5/6/7/8/9/10/11/12 */
0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */
0x15, 0x41, 0xd0, 0xff, 0xff, 0x00, /* logical device PNPFFFF (dummy to create a gap in LDNs) */
0x15, 0x41, 0xd0, 0x06, 0x00, 0x01, /* logical device PNP0600, can participate in boot */
0x22, 0xfa, 0x1f, /* IRQ 1/3/4/5/6/7/8/9/10/11/12 */
0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */
0x15, 0x41, 0xd0, 0xb0, 0x2f, 0x01, /* logical device PNPB02F, can participate in boot */
0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */
@@ -89,7 +122,9 @@ static const isapnp_device_config_t um8669f_pnp_defaults[] = {
.io = { { .base = LPT1_ADDR }, },
.irq = { { .irq = LPT1_IRQ }, }
}, {
.activate = 0
.activate = 0,
.io = { { .base = 0x1f0 }, },
.irq = { { .irq = 14 }, }
}, {
.activate = 0,
.io = { { .base = 0x200 }, }
@@ -116,13 +151,13 @@ um8669f_log(const char *fmt, ...)
typedef struct um8669f_t {
uint8_t locked;
uint8_t cur_reg_108;
uint8_t cur_reg;
void *pnp_card;
uint8_t regs_108[256];
uint8_t regs[3];
fdc_t *fdc;
serial_t *uart[2];
uint8_t ide;
void *gameport;
} um8669f_t;
@@ -179,6 +214,18 @@ um8669f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pri
break;
case 4:
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED))
um8669f_log("UM8669F: IDE enabled at port %04X IRQ %d\n", config->io[0].base, config->irq[0].irq);
else
um8669f_log("UM8669F: IDE disabled\n");
if (dev->ide < IDE_BUS_MAX) {
config->io[1].base = config->io[0].base + 0x206; /* status port apparently fixed */
ide_pnp_config_changed(0, config, (void *) (int) dev->ide);
}
break;
case 5:
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) {
um8669f_log("UM8669F: Game port enabled at port %04X\n", config->io[0].base);
@@ -209,11 +256,11 @@ um8669f_write(uint16_t port, uint8_t val, void *priv)
if (val == 0x55)
dev->locked = 1;
else
dev->cur_reg_108 = val;
} else {
dev->regs_108[dev->cur_reg_108] = val;
dev->cur_reg = val;
} else if ((dev->cur_reg >= 0xc0) && (dev->cur_reg <= 0xc2)) {
dev->regs[dev->cur_reg & 3] = val;
if (dev->cur_reg_108 == 0xc1) {
if (dev->cur_reg == 0xc1) {
um8669f_log("UM8669F: ISAPnP %sabled\n", (val & 0x80) ? "en" : "dis");
isapnp_enable_card(dev->pnp_card, (val & 0x80) ? ISAPNP_CARD_FORCE_CONFIG : ISAPNP_CARD_DISABLE);
}
@@ -229,9 +276,9 @@ um8669f_read(uint16_t port, void *priv)
if (!dev->locked) {
if (port == 0x108)
ret = dev->cur_reg_108; /* ??? */
else
ret = dev->regs_108[dev->cur_reg_108];
ret = dev->cur_reg; /* ??? */
else if ((dev->cur_reg >= 0xc0) && (dev->cur_reg <= 0xc2))
ret = dev->regs[dev->cur_reg & 3];
}
um8669f_log("UM8669F: read(%04X) = %02X\n", port, ret);
@@ -252,6 +299,9 @@ um8669f_reset(um8669f_t *dev)
lpt1_remove();
if (dev->ide < IDE_BUS_MAX)
ide_remove_handlers(dev->ide);
isapnp_enable_card(dev->pnp_card, ISAPNP_CARD_DISABLE);
dev->locked = 1;
@@ -270,9 +320,9 @@ um8669f_close(void *priv)
}
static void *
um8669f_init(UNUSED(const device_t *info))
um8669f_init(const device_t *info)
{
um8669f_log("UM8669F: init()\n");
um8669f_log("UM8669F: init(%02X)\n", info->local);
um8669f_t *dev = (um8669f_t *) malloc(sizeof(um8669f_t));
memset(dev, 0, sizeof(um8669f_t));
@@ -286,6 +336,10 @@ um8669f_init(UNUSED(const device_t *info))
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->ide = info->local;
if (dev->ide < IDE_BUS_MAX)
device_add(&ide_isa_device);
dev->gameport = gameport_add(&gameport_sio_device);
io_sethandler(0x0108, 0x0002,
@@ -300,6 +354,20 @@ const device_t um8669f_device = {
.name = "UMC UM8669F Super I/O",
.internal_name = "um8669f",
.flags = 0,
.local = 0xff,
.init = um8669f_init,
.close = um8669f_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t um8669f_ide_device = {
.name = "UMC UM8669F Super I/O (With IDE)",
.internal_name = "um8669f_ide",
.flags = 0,
.local = 0,
.init = um8669f_init,
.close = um8669f_close,
@@ -309,3 +377,17 @@ const device_t um8669f_device = {
.force_redraw = NULL,
.config = NULL
};
const device_t um8669f_ide_sec_device = {
.name = "UMC UM8669F Super I/O (With Secondary IDE)",
.internal_name = "um8669f_ide_sec",
.flags = 0,
.local = 1,
.init = um8669f_init,
.close = um8669f_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -18,7 +18,7 @@ add_library(snd OBJECT sound.c snd_opl.c snd_opl_nuked.c snd_opl_ymfm.cpp snd_re
snd_lpt_dss.c snd_ps1.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c
snd_azt2316a.c snd_cms.c snd_cmi8x38.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c
snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c
snd_optimc.c)
snd_optimc.c midi_opl4.c midi_opl4_yrw801.c)
if(OPENAL)
if(VCPKG_TOOLCHAIN)

View File

@@ -100,6 +100,7 @@ static const MIDI_OUT_DEVICE devices[] = {
#ifdef USE_RTMIDI
{ &rtmidi_output_device },
#endif
{ &opl4_midi_device },
{ NULL }
// clang-format on
};

View File

@@ -1,32 +1,31 @@
/* some code borrowed from scummvm */
#ifdef USE_FLUIDSYNTH
# include <stdint.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <wchar.h>
# ifdef __unix__
# include <unistd.h>
# endif
# define FLUIDSYNTH_NOT_A_DLL
# include <fluidsynth.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#ifdef __unix__
# include <unistd.h>
#endif
#define FLUIDSYNTH_NOT_A_DLL
#include <fluidsynth.h>
# include <86box/86box.h>
# include <86box/config.h>
# include <86box/device.h>
# include <86box/midi.h>
# include <86box/thread.h>
# include <86box/sound.h>
# include <86box/plat_unused.h>
#include <86box/86box.h>
#include <86box/config.h>
#include <86box/device.h>
#include <86box/midi.h>
#include <86box/thread.h>
#include <86box/sound.h>
#include <86box/plat_unused.h>
# define RENDER_RATE 100
# define BUFFER_SEGMENTS 10
#define RENDER_RATE 100
#define BUFFER_SEGMENTS 10
/* Check the FluidSynth version to determine wheteher to use the older reverb/chorus
control functions that were deprecated in 2.2.0, or their newer replacements */
# if (FLUIDSYNTH_VERSION_MAJOR < 2) || ((FLUIDSYNTH_VERSION_MAJOR == 2) && (FLUIDSYNTH_VERSION_MINOR < 2))
# define USE_OLD_FLUIDSYNTH_API
# endif
#if (FLUIDSYNTH_VERSION_MAJOR < 2) || ((FLUIDSYNTH_VERSION_MAJOR == 2) && (FLUIDSYNTH_VERSION_MINOR < 2))
# define USE_OLD_FLUIDSYNTH_API
#endif
extern void givealbuffer_midi(void *buf, uint32_t size);
extern void al_set_midi(int freq, int buf_size);
@@ -167,19 +166,19 @@ fluidsynth_init(UNUSED(const device_t *info))
data->synth = new_fluid_synth(data->settings);
const char *sound_font = device_get_config_string("sound_font");
# ifdef __unix__
#ifdef __unix__
if (!sound_font || sound_font[0] == 0)
sound_font = (access("/usr/share/sounds/sf2/FluidR3_GM.sf2", F_OK) == 0 ? "/usr/share/sounds/sf2/FluidR3_GM.sf2" :
(access("/usr/share/soundfonts/default.sf2", F_OK) == 0 ? "/usr/share/soundfonts/default.sf2" : ""));
# endif
#endif
data->sound_font = fluid_synth_sfload(data->synth, sound_font, 1);
if (device_get_config_int("chorus")) {
# ifndef USE_OLD_FLUIDSYNTH_API
#ifndef USE_OLD_FLUIDSYNTH_API
fluid_synth_chorus_on(data->synth, -1, 1);
# else
#else
fluid_synth_set_chorus_on(data->synth, 1);
# endif
#endif
int chorus_voices = device_get_config_int("chorus_voices");
double chorus_level = device_get_config_int("chorus_level") / 100.0;
@@ -192,48 +191,48 @@ fluidsynth_init(UNUSED(const device_t *info))
else
chorus_waveform = FLUID_CHORUS_MOD_TRIANGLE;
# ifndef USE_OLD_FLUIDSYNTH_API
#ifndef USE_OLD_FLUIDSYNTH_API
fluid_synth_set_chorus_group_nr(data->synth, -1, chorus_voices);
fluid_synth_set_chorus_group_level(data->synth, -1, chorus_level);
fluid_synth_set_chorus_group_speed(data->synth, -1, chorus_speed);
fluid_synth_set_chorus_group_depth(data->synth, -1, chorus_depth);
fluid_synth_set_chorus_group_type(data->synth, -1, chorus_waveform);
# else
#else
fluid_synth_set_chorus(data->synth, chorus_voices, chorus_level, chorus_speed, chorus_depth, chorus_waveform);
# endif
#endif
} else
# ifndef USE_OLD_FLUIDSYNTH_API
#ifndef USE_OLD_FLUIDSYNTH_API
fluid_synth_chorus_on(data->synth, -1, 0);
# else
#else
fluid_synth_set_chorus_on(data->synth, 0);
# endif
#endif
if (device_get_config_int("reverb")) {
# ifndef USE_OLD_FLUIDSYNTH_API
#ifndef USE_OLD_FLUIDSYNTH_API
fluid_synth_reverb_on(data->synth, -1, 1);
# else
#else
fluid_synth_set_reverb_on(data->synth, 1);
# endif
#endif
double reverb_room_size = device_get_config_int("reverb_room_size") / 100.0;
double reverb_damping = device_get_config_int("reverb_damping") / 100.0;
double reverb_width = device_get_config_int("reverb_width") / 10.0;
double reverb_level = device_get_config_int("reverb_level") / 100.0;
# ifndef USE_OLD_FLUIDSYNTH_API
#ifndef USE_OLD_FLUIDSYNTH_API
fluid_synth_set_reverb_group_roomsize(data->synth, -1, reverb_room_size);
fluid_synth_set_reverb_group_damp(data->synth, -1, reverb_damping);
fluid_synth_set_reverb_group_width(data->synth, -1, reverb_width);
fluid_synth_set_reverb_group_level(data->synth, -1, reverb_level);
# else
#else
fluid_synth_set_reverb(data->synth, reverb_room_size, reverb_damping, reverb_width, reverb_level);
# endif
#endif
} else
# ifndef USE_OLD_FLUIDSYNTH_API
#ifndef USE_OLD_FLUIDSYNTH_API
fluid_synth_reverb_on(data->synth, -1, 0);
# else
#else
fluid_synth_set_reverb_on(data->synth, 0);
# endif
#endif
int interpolation = device_get_config_int("interpolation");
int fs_interpolation = FLUID_INTERP_4THORDER;
@@ -499,4 +498,3 @@ const device_t fluidsynth_device = {
.config = fluidsynth_config
};
#endif /*USE_FLUIDSYNTH*/

731
src/sound/midi_opl4.c Normal file
View File

@@ -0,0 +1,731 @@
// Based off ROBOPLAY's OPL4 MID player code, with some fixes and modifications to make it work well.
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/midi.h>
#include <86box/plat.h>
#include <86box/thread.h>
#include <86box/rom.h>
#include <86box/sound.h>
#include <86box/ui.h>
#include <86box/snd_opl.h>
#include <86box/opl4_defines.h>
#include "yrw801.h"
#define NR_OF_MIDI_CHANNELS 16
#define NR_OF_WAVE_CHANNELS 24
#define DRUM_CHANNEL 9
typedef struct
{
uint8_t instrument;
uint8_t panpot;
uint8_t vibrato;
bool drum_channel;
} MIDI_CHANNEL_DATA;
typedef struct
{
bool is_active;
uint64_t activated;
uint8_t number;
MIDI_CHANNEL_DATA *midi_channel;
uint8_t note;
uint8_t velocity;
const YRW801_WAVE_DATA *wave_data;
uint8_t level_direct;
uint8_t reg_f_number;
uint8_t reg_misc;
uint8_t reg_lfo_vibrato;
} VOICE_DATA;
static const int16_t g_wave_pitch_map[0x600] = {
0x000, 0x000, 0x001, 0x001, 0x002, 0x002, 0x003, 0x003,
0x004, 0x004, 0x005, 0x005, 0x006, 0x006, 0x006, 0x007,
0x007, 0x008, 0x008, 0x009, 0x009, 0x00a, 0x00a, 0x00b,
0x00b, 0x00c, 0x00c, 0x00d, 0x00d, 0x00d, 0x00e, 0x00e,
0x00f, 0x00f, 0x010, 0x010, 0x011, 0x011, 0x012, 0x012,
0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x015, 0x016,
0x016, 0x017, 0x017, 0x018, 0x018, 0x019, 0x019, 0x01a,
0x01a, 0x01b, 0x01b, 0x01c, 0x01c, 0x01d, 0x01d, 0x01e,
0x01e, 0x01e, 0x01f, 0x01f, 0x020, 0x020, 0x021, 0x021,
0x022, 0x022, 0x023, 0x023, 0x024, 0x024, 0x025, 0x025,
0x026, 0x026, 0x027, 0x027, 0x028, 0x028, 0x029, 0x029,
0x029, 0x02a, 0x02a, 0x02b, 0x02b, 0x02c, 0x02c, 0x02d,
0x02d, 0x02e, 0x02e, 0x02f, 0x02f, 0x030, 0x030, 0x031,
0x031, 0x032, 0x032, 0x033, 0x033, 0x034, 0x034, 0x035,
0x035, 0x036, 0x036, 0x037, 0x037, 0x038, 0x038, 0x038,
0x039, 0x039, 0x03a, 0x03a, 0x03b, 0x03b, 0x03c, 0x03c,
0x03d, 0x03d, 0x03e, 0x03e, 0x03f, 0x03f, 0x040, 0x040,
0x041, 0x041, 0x042, 0x042, 0x043, 0x043, 0x044, 0x044,
0x045, 0x045, 0x046, 0x046, 0x047, 0x047, 0x048, 0x048,
0x049, 0x049, 0x04a, 0x04a, 0x04b, 0x04b, 0x04c, 0x04c,
0x04d, 0x04d, 0x04e, 0x04e, 0x04f, 0x04f, 0x050, 0x050,
0x051, 0x051, 0x052, 0x052, 0x053, 0x053, 0x054, 0x054,
0x055, 0x055, 0x056, 0x056, 0x057, 0x057, 0x058, 0x058,
0x059, 0x059, 0x05a, 0x05a, 0x05b, 0x05b, 0x05c, 0x05c,
0x05d, 0x05d, 0x05e, 0x05e, 0x05f, 0x05f, 0x060, 0x060,
0x061, 0x061, 0x062, 0x062, 0x063, 0x063, 0x064, 0x064,
0x065, 0x065, 0x066, 0x066, 0x067, 0x067, 0x068, 0x068,
0x069, 0x069, 0x06a, 0x06a, 0x06b, 0x06b, 0x06c, 0x06c,
0x06d, 0x06d, 0x06e, 0x06e, 0x06f, 0x06f, 0x070, 0x071,
0x071, 0x072, 0x072, 0x073, 0x073, 0x074, 0x074, 0x075,
0x075, 0x076, 0x076, 0x077, 0x077, 0x078, 0x078, 0x079,
0x079, 0x07a, 0x07a, 0x07b, 0x07b, 0x07c, 0x07c, 0x07d,
0x07d, 0x07e, 0x07e, 0x07f, 0x07f, 0x080, 0x081, 0x081,
0x082, 0x082, 0x083, 0x083, 0x084, 0x084, 0x085, 0x085,
0x086, 0x086, 0x087, 0x087, 0x088, 0x088, 0x089, 0x089,
0x08a, 0x08a, 0x08b, 0x08b, 0x08c, 0x08d, 0x08d, 0x08e,
0x08e, 0x08f, 0x08f, 0x090, 0x090, 0x091, 0x091, 0x092,
0x092, 0x093, 0x093, 0x094, 0x094, 0x095, 0x096, 0x096,
0x097, 0x097, 0x098, 0x098, 0x099, 0x099, 0x09a, 0x09a,
0x09b, 0x09b, 0x09c, 0x09c, 0x09d, 0x09d, 0x09e, 0x09f,
0x09f, 0x0a0, 0x0a0, 0x0a1, 0x0a1, 0x0a2, 0x0a2, 0x0a3,
0x0a3, 0x0a4, 0x0a4, 0x0a5, 0x0a6, 0x0a6, 0x0a7, 0x0a7,
0x0a8, 0x0a8, 0x0a9, 0x0a9, 0x0aa, 0x0aa, 0x0ab, 0x0ab,
0x0ac, 0x0ad, 0x0ad, 0x0ae, 0x0ae, 0x0af, 0x0af, 0x0b0,
0x0b0, 0x0b1, 0x0b1, 0x0b2, 0x0b2, 0x0b3, 0x0b4, 0x0b4,
0x0b5, 0x0b5, 0x0b6, 0x0b6, 0x0b7, 0x0b7, 0x0b8, 0x0b8,
0x0b9, 0x0ba, 0x0ba, 0x0bb, 0x0bb, 0x0bc, 0x0bc, 0x0bd,
0x0bd, 0x0be, 0x0be, 0x0bf, 0x0c0, 0x0c0, 0x0c1, 0x0c1,
0x0c2, 0x0c2, 0x0c3, 0x0c3, 0x0c4, 0x0c4, 0x0c5, 0x0c6,
0x0c6, 0x0c7, 0x0c7, 0x0c8, 0x0c8, 0x0c9, 0x0c9, 0x0ca,
0x0cb, 0x0cb, 0x0cc, 0x0cc, 0x0cd, 0x0cd, 0x0ce, 0x0ce,
0x0cf, 0x0d0, 0x0d0, 0x0d1, 0x0d1, 0x0d2, 0x0d2, 0x0d3,
0x0d3, 0x0d4, 0x0d5, 0x0d5, 0x0d6, 0x0d6, 0x0d7, 0x0d7,
0x0d8, 0x0d8, 0x0d9, 0x0da, 0x0da, 0x0db, 0x0db, 0x0dc,
0x0dc, 0x0dd, 0x0de, 0x0de, 0x0df, 0x0df, 0x0e0, 0x0e0,
0x0e1, 0x0e1, 0x0e2, 0x0e3, 0x0e3, 0x0e4, 0x0e4, 0x0e5,
0x0e5, 0x0e6, 0x0e7, 0x0e7, 0x0e8, 0x0e8, 0x0e9, 0x0e9,
0x0ea, 0x0eb, 0x0eb, 0x0ec, 0x0ec, 0x0ed, 0x0ed, 0x0ee,
0x0ef, 0x0ef, 0x0f0, 0x0f0, 0x0f1, 0x0f1, 0x0f2, 0x0f3,
0x0f3, 0x0f4, 0x0f4, 0x0f5, 0x0f5, 0x0f6, 0x0f7, 0x0f7,
0x0f8, 0x0f8, 0x0f9, 0x0f9, 0x0fa, 0x0fb, 0x0fb, 0x0fc,
0x0fc, 0x0fd, 0x0fd, 0x0fe, 0x0ff, 0x0ff, 0x100, 0x100,
0x101, 0x101, 0x102, 0x103, 0x103, 0x104, 0x104, 0x105,
0x106, 0x106, 0x107, 0x107, 0x108, 0x108, 0x109, 0x10a,
0x10a, 0x10b, 0x10b, 0x10c, 0x10c, 0x10d, 0x10e, 0x10e,
0x10f, 0x10f, 0x110, 0x111, 0x111, 0x112, 0x112, 0x113,
0x114, 0x114, 0x115, 0x115, 0x116, 0x116, 0x117, 0x118,
0x118, 0x119, 0x119, 0x11a, 0x11b, 0x11b, 0x11c, 0x11c,
0x11d, 0x11e, 0x11e, 0x11f, 0x11f, 0x120, 0x120, 0x121,
0x122, 0x122, 0x123, 0x123, 0x124, 0x125, 0x125, 0x126,
0x126, 0x127, 0x128, 0x128, 0x129, 0x129, 0x12a, 0x12b,
0x12b, 0x12c, 0x12c, 0x12d, 0x12e, 0x12e, 0x12f, 0x12f,
0x130, 0x131, 0x131, 0x132, 0x132, 0x133, 0x134, 0x134,
0x135, 0x135, 0x136, 0x137, 0x137, 0x138, 0x138, 0x139,
0x13a, 0x13a, 0x13b, 0x13b, 0x13c, 0x13d, 0x13d, 0x13e,
0x13e, 0x13f, 0x140, 0x140, 0x141, 0x141, 0x142, 0x143,
0x143, 0x144, 0x144, 0x145, 0x146, 0x146, 0x147, 0x148,
0x148, 0x149, 0x149, 0x14a, 0x14b, 0x14b, 0x14c, 0x14c,
0x14d, 0x14e, 0x14e, 0x14f, 0x14f, 0x150, 0x151, 0x151,
0x152, 0x153, 0x153, 0x154, 0x154, 0x155, 0x156, 0x156,
0x157, 0x157, 0x158, 0x159, 0x159, 0x15a, 0x15b, 0x15b,
0x15c, 0x15c, 0x15d, 0x15e, 0x15e, 0x15f, 0x160, 0x160,
0x161, 0x161, 0x162, 0x163, 0x163, 0x164, 0x165, 0x165,
0x166, 0x166, 0x167, 0x168, 0x168, 0x169, 0x16a, 0x16a,
0x16b, 0x16b, 0x16c, 0x16d, 0x16d, 0x16e, 0x16f, 0x16f,
0x170, 0x170, 0x171, 0x172, 0x172, 0x173, 0x174, 0x174,
0x175, 0x175, 0x176, 0x177, 0x177, 0x178, 0x179, 0x179,
0x17a, 0x17a, 0x17b, 0x17c, 0x17c, 0x17d, 0x17e, 0x17e,
0x17f, 0x180, 0x180, 0x181, 0x181, 0x182, 0x183, 0x183,
0x184, 0x185, 0x185, 0x186, 0x187, 0x187, 0x188, 0x188,
0x189, 0x18a, 0x18a, 0x18b, 0x18c, 0x18c, 0x18d, 0x18e,
0x18e, 0x18f, 0x190, 0x190, 0x191, 0x191, 0x192, 0x193,
0x193, 0x194, 0x195, 0x195, 0x196, 0x197, 0x197, 0x198,
0x199, 0x199, 0x19a, 0x19a, 0x19b, 0x19c, 0x19c, 0x19d,
0x19e, 0x19e, 0x19f, 0x1a0, 0x1a0, 0x1a1, 0x1a2, 0x1a2,
0x1a3, 0x1a4, 0x1a4, 0x1a5, 0x1a6, 0x1a6, 0x1a7, 0x1a8,
0x1a8, 0x1a9, 0x1a9, 0x1aa, 0x1ab, 0x1ab, 0x1ac, 0x1ad,
0x1ad, 0x1ae, 0x1af, 0x1af, 0x1b0, 0x1b1, 0x1b1, 0x1b2,
0x1b3, 0x1b3, 0x1b4, 0x1b5, 0x1b5, 0x1b6, 0x1b7, 0x1b7,
0x1b8, 0x1b9, 0x1b9, 0x1ba, 0x1bb, 0x1bb, 0x1bc, 0x1bd,
0x1bd, 0x1be, 0x1bf, 0x1bf, 0x1c0, 0x1c1, 0x1c1, 0x1c2,
0x1c3, 0x1c3, 0x1c4, 0x1c5, 0x1c5, 0x1c6, 0x1c7, 0x1c7,
0x1c8, 0x1c9, 0x1c9, 0x1ca, 0x1cb, 0x1cb, 0x1cc, 0x1cd,
0x1cd, 0x1ce, 0x1cf, 0x1cf, 0x1d0, 0x1d1, 0x1d1, 0x1d2,
0x1d3, 0x1d3, 0x1d4, 0x1d5, 0x1d5, 0x1d6, 0x1d7, 0x1d7,
0x1d8, 0x1d9, 0x1d9, 0x1da, 0x1db, 0x1db, 0x1dc, 0x1dd,
0x1dd, 0x1de, 0x1df, 0x1df, 0x1e0, 0x1e1, 0x1e1, 0x1e2,
0x1e3, 0x1e4, 0x1e4, 0x1e5, 0x1e6, 0x1e6, 0x1e7, 0x1e8,
0x1e8, 0x1e9, 0x1ea, 0x1ea, 0x1eb, 0x1ec, 0x1ec, 0x1ed,
0x1ee, 0x1ee, 0x1ef, 0x1f0, 0x1f0, 0x1f1, 0x1f2, 0x1f3,
0x1f3, 0x1f4, 0x1f5, 0x1f5, 0x1f6, 0x1f7, 0x1f7, 0x1f8,
0x1f9, 0x1f9, 0x1fa, 0x1fb, 0x1fb, 0x1fc, 0x1fd, 0x1fe,
0x1fe, 0x1ff, 0x200, 0x200, 0x201, 0x202, 0x202, 0x203,
0x204, 0x205, 0x205, 0x206, 0x207, 0x207, 0x208, 0x209,
0x209, 0x20a, 0x20b, 0x20b, 0x20c, 0x20d, 0x20e, 0x20e,
0x20f, 0x210, 0x210, 0x211, 0x212, 0x212, 0x213, 0x214,
0x215, 0x215, 0x216, 0x217, 0x217, 0x218, 0x219, 0x21a,
0x21a, 0x21b, 0x21c, 0x21c, 0x21d, 0x21e, 0x21e, 0x21f,
0x220, 0x221, 0x221, 0x222, 0x223, 0x223, 0x224, 0x225,
0x226, 0x226, 0x227, 0x228, 0x228, 0x229, 0x22a, 0x22b,
0x22b, 0x22c, 0x22d, 0x22d, 0x22e, 0x22f, 0x230, 0x230,
0x231, 0x232, 0x232, 0x233, 0x234, 0x235, 0x235, 0x236,
0x237, 0x237, 0x238, 0x239, 0x23a, 0x23a, 0x23b, 0x23c,
0x23c, 0x23d, 0x23e, 0x23f, 0x23f, 0x240, 0x241, 0x241,
0x242, 0x243, 0x244, 0x244, 0x245, 0x246, 0x247, 0x247,
0x248, 0x249, 0x249, 0x24a, 0x24b, 0x24c, 0x24c, 0x24d,
0x24e, 0x24f, 0x24f, 0x250, 0x251, 0x251, 0x252, 0x253,
0x254, 0x254, 0x255, 0x256, 0x257, 0x257, 0x258, 0x259,
0x259, 0x25a, 0x25b, 0x25c, 0x25c, 0x25d, 0x25e, 0x25f,
0x25f, 0x260, 0x261, 0x262, 0x262, 0x263, 0x264, 0x265,
0x265, 0x266, 0x267, 0x267, 0x268, 0x269, 0x26a, 0x26a,
0x26b, 0x26c, 0x26d, 0x26d, 0x26e, 0x26f, 0x270, 0x270,
0x271, 0x272, 0x273, 0x273, 0x274, 0x275, 0x276, 0x276,
0x277, 0x278, 0x279, 0x279, 0x27a, 0x27b, 0x27c, 0x27c,
0x27d, 0x27e, 0x27f, 0x27f, 0x280, 0x281, 0x282, 0x282,
0x283, 0x284, 0x285, 0x285, 0x286, 0x287, 0x288, 0x288,
0x289, 0x28a, 0x28b, 0x28b, 0x28c, 0x28d, 0x28e, 0x28e,
0x28f, 0x290, 0x291, 0x291, 0x292, 0x293, 0x294, 0x294,
0x295, 0x296, 0x297, 0x298, 0x298, 0x299, 0x29a, 0x29b,
0x29b, 0x29c, 0x29d, 0x29e, 0x29e, 0x29f, 0x2a0, 0x2a1,
0x2a1, 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a5, 0x2a6, 0x2a7,
0x2a8, 0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ab, 0x2ac, 0x2ad,
0x2ae, 0x2af, 0x2af, 0x2b0, 0x2b1, 0x2b2, 0x2b2, 0x2b3,
0x2b4, 0x2b5, 0x2b5, 0x2b6, 0x2b7, 0x2b8, 0x2b9, 0x2b9,
0x2ba, 0x2bb, 0x2bc, 0x2bc, 0x2bd, 0x2be, 0x2bf, 0x2c0,
0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c4, 0x2c5, 0x2c6,
0x2c7, 0x2c7, 0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cb, 0x2cc,
0x2cd, 0x2ce, 0x2ce, 0x2cf, 0x2d0, 0x2d1, 0x2d2, 0x2d2,
0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d6, 0x2d7, 0x2d8, 0x2d9,
0x2da, 0x2da, 0x2db, 0x2dc, 0x2dd, 0x2dd, 0x2de, 0x2df,
0x2e0, 0x2e1, 0x2e1, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e5,
0x2e6, 0x2e7, 0x2e8, 0x2e9, 0x2e9, 0x2ea, 0x2eb, 0x2ec,
0x2ed, 0x2ed, 0x2ee, 0x2ef, 0x2f0, 0x2f1, 0x2f1, 0x2f2,
0x2f3, 0x2f4, 0x2f5, 0x2f5, 0x2f6, 0x2f7, 0x2f8, 0x2f9,
0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fd, 0x2fd, 0x2fe, 0x2ff,
0x300, 0x301, 0x302, 0x302, 0x303, 0x304, 0x305, 0x306,
0x306, 0x307, 0x308, 0x309, 0x30a, 0x30a, 0x30b, 0x30c,
0x30d, 0x30e, 0x30f, 0x30f, 0x310, 0x311, 0x312, 0x313,
0x313, 0x314, 0x315, 0x316, 0x317, 0x318, 0x318, 0x319,
0x31a, 0x31b, 0x31c, 0x31c, 0x31d, 0x31e, 0x31f, 0x320,
0x321, 0x321, 0x322, 0x323, 0x324, 0x325, 0x326, 0x326,
0x327, 0x328, 0x329, 0x32a, 0x32a, 0x32b, 0x32c, 0x32d,
0x32e, 0x32f, 0x32f, 0x330, 0x331, 0x332, 0x333, 0x334,
0x334, 0x335, 0x336, 0x337, 0x338, 0x339, 0x339, 0x33a,
0x33b, 0x33c, 0x33d, 0x33e, 0x33e, 0x33f, 0x340, 0x341,
0x342, 0x343, 0x343, 0x344, 0x345, 0x346, 0x347, 0x348,
0x349, 0x349, 0x34a, 0x34b, 0x34c, 0x34d, 0x34e, 0x34e,
0x34f, 0x350, 0x351, 0x352, 0x353, 0x353, 0x354, 0x355,
0x356, 0x357, 0x358, 0x359, 0x359, 0x35a, 0x35b, 0x35c,
0x35d, 0x35e, 0x35f, 0x35f, 0x360, 0x361, 0x362, 0x363,
0x364, 0x364, 0x365, 0x366, 0x367, 0x368, 0x369, 0x36a,
0x36a, 0x36b, 0x36c, 0x36d, 0x36e, 0x36f, 0x370, 0x370,
0x371, 0x372, 0x373, 0x374, 0x375, 0x376, 0x377, 0x377,
0x378, 0x379, 0x37a, 0x37b, 0x37c, 0x37d, 0x37d, 0x37e,
0x37f, 0x380, 0x381, 0x382, 0x383, 0x383, 0x384, 0x385,
0x386, 0x387, 0x388, 0x389, 0x38a, 0x38a, 0x38b, 0x38c,
0x38d, 0x38e, 0x38f, 0x390, 0x391, 0x391, 0x392, 0x393,
0x394, 0x395, 0x396, 0x397, 0x398, 0x398, 0x399, 0x39a,
0x39b, 0x39c, 0x39d, 0x39e, 0x39f, 0x39f, 0x3a0, 0x3a1,
0x3a2, 0x3a3, 0x3a4, 0x3a5, 0x3a6, 0x3a7, 0x3a7, 0x3a8,
0x3a9, 0x3aa, 0x3ab, 0x3ac, 0x3ad, 0x3ae, 0x3ae, 0x3af,
0x3b0, 0x3b1, 0x3b2, 0x3b3, 0x3b4, 0x3b5, 0x3b6, 0x3b6,
0x3b7, 0x3b8, 0x3b9, 0x3ba, 0x3bb, 0x3bc, 0x3bd, 0x3be,
0x3bf, 0x3bf, 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4, 0x3c5,
0x3c6, 0x3c7, 0x3c7, 0x3c8, 0x3c9, 0x3ca, 0x3cb, 0x3cc,
0x3cd, 0x3ce, 0x3cf, 0x3d0, 0x3d1, 0x3d1, 0x3d2, 0x3d3,
0x3d4, 0x3d5, 0x3d6, 0x3d7, 0x3d8, 0x3d9, 0x3da, 0x3da,
0x3db, 0x3dc, 0x3dd, 0x3de, 0x3df, 0x3e0, 0x3e1, 0x3e2,
0x3e3, 0x3e4, 0x3e4, 0x3e5, 0x3e6, 0x3e7, 0x3e8, 0x3e9,
0x3ea, 0x3eb, 0x3ec, 0x3ed, 0x3ee, 0x3ef, 0x3ef, 0x3f0,
0x3f1, 0x3f2, 0x3f3, 0x3f4, 0x3f5, 0x3f6, 0x3f7, 0x3f8,
0x3f9, 0x3fa, 0x3fa, 0x3fb, 0x3fc, 0x3fd, 0x3fe, 0x3ff
};
/*
* Attenuation according to GM recommendations, in -0.375 dB units.
* table[v] = 40 * log(v / 127) / -0.375
*/
static const uint8_t g_volume_table[128] = {
255, 224, 192, 173, 160, 150, 141, 134,
128, 122, 117, 113, 109, 105, 102, 99,
96, 93, 90, 88, 85, 83, 81, 79,
77, 75, 73, 71, 70, 68, 67, 65,
64, 62, 61, 59, 58, 57, 56, 54,
53, 52, 51, 50, 49, 48, 47, 46,
45, 44, 43, 42, 41, 40, 39, 39,
38, 37, 36, 35, 34, 34, 33, 32,
31, 31, 30, 29, 29, 28, 27, 27,
26, 25, 25, 24, 24, 23, 22, 22,
21, 21, 20, 19, 19, 18, 18, 17,
17, 16, 16, 15, 15, 14, 14, 13,
13, 12, 12, 11, 11, 10, 10, 9,
9, 9, 8, 8, 7, 7, 6, 6,
6, 5, 5, 4, 4, 4, 3, 3,
2, 2, 2, 1, 1, 0, 0, 0
};
#define BUFFER_SEGMENTS 10
#define RENDER_RATE (48000 / 100)
typedef struct opl4_midi {
fm_drv_t opl4;
MIDI_CHANNEL_DATA midi_channel_data[16];
VOICE_DATA voice_data[24];
int16_t buffer[(48000 / 100) * 2 * BUFFER_SEGMENTS];
float buffer_float[(48000 / 100) * 2 * BUFFER_SEGMENTS];
uint32_t midi_pos;
bool on;
atomic_bool gen_in_progress;
thread_t *thread;
event_t *wait_event;
} opl4_midi_t;
static opl4_midi_t *opl4_midi_cur;
static void
opl4_write_wave_register(const uint8_t reg, const uint8_t value, opl4_midi_t *opl4_midi)
{
opl4_midi->opl4.write(0x380, reg, opl4_midi->opl4.priv);
opl4_midi->opl4.write(0x381, value, opl4_midi->opl4.priv);
}
VOICE_DATA *
get_voice(const YRW801_WAVE_DATA *wave_data, opl4_midi_t *opl4_midi)
{
VOICE_DATA *free_voice = &opl4_midi->voice_data[0];
VOICE_DATA *oldest_voice = &opl4_midi->voice_data[0];
for (uint8_t voice = 0; voice < 24; voice++) {
if (opl4_midi_cur->voice_data[voice].is_active) {
if (opl4_midi_cur->voice_data[voice].activated < oldest_voice->activated)
oldest_voice = &opl4_midi_cur->voice_data[voice];
} else {
if (opl4_midi_cur->voice_data[voice].wave_data == wave_data) {
free_voice = &opl4_midi_cur->voice_data[voice];
break;
}
if (opl4_midi_cur->voice_data[voice].activated < free_voice->activated) {
free_voice = &opl4_midi_cur->voice_data[voice];
break;
}
}
}
/* If no free voice is found, look for one with the same instrument */
if (free_voice->is_active) {
for (uint8_t voice = 0; voice < 24; voice++) {
if (opl4_midi_cur->voice_data[voice].is_active
&& opl4_midi_cur->voice_data[voice].wave_data == wave_data) {
free_voice = &opl4_midi_cur->voice_data[voice];
free_voice->is_active = 0;
free_voice->activated = 0;
free_voice->reg_misc &= ~OPL4_KEY_ON_BIT;
opl4_write_wave_register(OPL4_REG_MISC + free_voice->number, free_voice->reg_misc, opl4_midi);
return free_voice;
}
}
}
/* If still no free voice found, deactivate the 'oldest' */
if (free_voice->is_active) {
free_voice = oldest_voice;
free_voice->is_active = 0;
free_voice->activated = 0;
free_voice->reg_misc &= ~OPL4_KEY_ON_BIT;
opl4_write_wave_register(OPL4_REG_MISC + free_voice->number, free_voice->reg_misc, opl4_midi);
}
return free_voice;
}
static void
update_pan(VOICE_DATA *voice, opl4_midi_t *opl4_midi)
{
int8_t pan = voice->wave_data->panpot;
if (!voice->midi_channel->drum_channel)
pan += voice->midi_channel->panpot;
if (pan < -7)
pan = -7;
else if (pan > 7)
pan = 7;
voice->reg_misc = (voice->reg_misc & ~OPL4_PAN_POT_MASK) | (pan & OPL4_PAN_POT_MASK);
opl4_write_wave_register(OPL4_REG_MISC + voice->number, voice->reg_misc, opl4_midi);
}
void
update_pitch(VOICE_DATA *voice, uint16_t pitch_bend, opl4_midi_t *opl4_midi)
{
int32_t pitch = voice->midi_channel->drum_channel ? 0 : (voice->note - 60) * 128;
pitch = pitch * (int) voice->wave_data->key_scaling / 100;
pitch = pitch + 7680;
pitch += voice->wave_data->pitch_offset;
pitch += pitch_bend * 256 / 0x2000;
if (pitch < 0)
pitch = 0;
else if (pitch > 0x5FFF)
pitch = 0x5FFF;
int8_t octave = pitch / 0x600 - 8;
uint16_t fnumber = g_wave_pitch_map[pitch % 0x600];
opl4_write_wave_register(OPL4_REG_OCTAVE + voice->number, (octave << 4) | ((fnumber >> 7) & 0x07), opl4_midi);
voice->reg_f_number = (voice->reg_f_number & OPL4_TONE_NUMBER_BIT8) | ((fnumber << 1) & OPL4_F_NUMBER_LOW_MASK);
opl4_write_wave_register(OPL4_REG_F_NUMBER + voice->number, voice->reg_f_number, opl4_midi);
}
void
update_volume(VOICE_DATA *voice, opl4_midi_t *opl4_midi)
{
int16_t att = voice->wave_data->tone_attenuate;
att += g_volume_table[voice->velocity];
att = 0x7F - (0x7F - att) * (voice->wave_data->volume_factor) / 0xFE;
att -= 16;
if (att < 0)
att = 0;
else if (att > 0x7E)
att = 0x7E;
opl4_write_wave_register(OPL4_REG_LEVEL + voice->number, (att << 1) | voice->level_direct, opl4_midi);
voice->level_direct = 0;
}
void
note_off(uint8_t note, uint8_t velocity, MIDI_CHANNEL_DATA *midi_channel, opl4_midi_t *opl4_midi)
{
/* Velocity not used */
(void) velocity;
while (opl4_midi->gen_in_progress) { }
for (uint8_t i = 0; i < 24; i++) {
VOICE_DATA *voice = &opl4_midi->voice_data[i];
if (voice->is_active && voice->midi_channel == midi_channel && voice->note == note) {
voice->is_active = false;
voice->activated = 0;
voice->reg_misc &= ~OPL4_KEY_ON_BIT;
opl4_write_wave_register(OPL4_REG_MISC + voice->number, voice->reg_misc, opl4_midi);
}
}
}
void
update_vibrato_depth(VOICE_DATA *voice, opl4_midi_t *opl4_midi)
{
uint16_t depth;
depth = (7 - voice->wave_data->vibrato) * (voice->midi_channel->vibrato & 0x7F);
depth = (depth >> 7) + voice->wave_data->vibrato;
voice->reg_lfo_vibrato &= ~OPL4_VIBRATO_DEPTH_MASK;
voice->reg_lfo_vibrato |= depth & OPL4_VIBRATO_DEPTH_MASK;
opl4_write_wave_register(OPL4_REG_LFO_VIBRATO + voice->number, voice->reg_lfo_vibrato, opl4_midi);
}
void
note_on(uint8_t note, uint8_t velocity, MIDI_CHANNEL_DATA *midi_channel, opl4_midi_t *opl4_midi)
{
const YRW801_REGION_DATA_PTR *region_ptr = &snd_yrw801_regions[0];
const YRW801_WAVE_DATA *wave_data[2];
VOICE_DATA *voice[2];
uint8_t i = 0, voices = 0;
while (opl4_midi->gen_in_progress) { }
if (midi_channel->drum_channel)
wave_data[voices++] = &region_ptr[0x80].regions[note - 0x1A].wave_data;
else {
/* Determine the number of voices and voice parameters */
const YRW801_REGION_DATA *region = region_ptr[midi_channel->instrument & 0x7F].regions;
while (i < region_ptr[midi_channel->instrument & 0x7F].count) {
if (note >= region[i].key_min && note <= region[i].key_max) {
wave_data[voices] = &region[i].wave_data;
if (++voices >= 2)
break;
}
i++;
}
}
/* Allocate and initialize needed voices */
for (i = 0; i < voices; i++) {
voice[i] = get_voice(wave_data[i], opl4_midi);
voice[i]->is_active = true;
voice[i]->activated = plat_get_ticks();
voice[i]->midi_channel = midi_channel;
voice[i]->note = note;
voice[i]->velocity = velocity & 0x7F;
}
for (i = 0; i < voices; i++) {
voice[i]->reg_f_number = (wave_data[i]->tone >> 8) & OPL4_TONE_NUMBER_BIT8;
opl4_write_wave_register(OPL4_REG_F_NUMBER + voice[i]->number, voice[i]->reg_f_number, opl4_midi);
bool new_wave = (voice[i]->wave_data != wave_data[i]);
/* Set tone number (triggers header loading) */
if (new_wave) {
opl4_write_wave_register(OPL4_REG_TONE_NUMBER + voice[i]->number, wave_data[i]->tone & 0xFF, opl4_midi);
voice[i]->wave_data = wave_data[i];
}
voice[i]->reg_misc = OPL4_LFO_RESET_BIT;
update_pan(voice[i], opl4_midi);
update_pitch(voice[i], 0, opl4_midi);
voice[i]->level_direct = OPL4_LEVEL_DIRECT_BIT;
update_volume(voice[i], opl4_midi);
if (new_wave) {
/* Set remaining parameters */
opl4_write_wave_register(OPL4_REG_ATTACK_DECAY1 + voice[i]->number, voice[i]->wave_data->reg_attack_decay1, opl4_midi);
opl4_write_wave_register(OPL4_REG_LEVEL_DECAY2 + voice[i]->number, voice[i]->wave_data->reg_level_decay2, opl4_midi);
opl4_write_wave_register(OPL4_REG_RELEASE_CORRECTION + voice[i]->number, voice[i]->wave_data->reg_release_correction, opl4_midi);
opl4_write_wave_register(OPL4_REG_TREMOLO + voice[i]->number, voice[i]->wave_data->reg_tremolo, opl4_midi);
voice[i]->reg_lfo_vibrato = voice[i]->wave_data->reg_lfo_vibrato;
if (!midi_channel->drum_channel)
update_vibrato_depth(voice[i], opl4_midi);
}
}
/* Finally, switch on all voices */
for (i = 0; i < voices; i++) {
voice[i]->reg_misc = (voice[i]->reg_misc & 0x1F) | OPL4_KEY_ON_BIT;
opl4_write_wave_register(OPL4_REG_MISC + voice[i]->number, voice[i]->reg_misc, opl4_midi);
}
}
void
control_change(uint8_t midi_channel, uint8_t id, uint8_t value, opl4_midi_t *opl4_midi)
{
int i = 0;
switch (id) {
case 10:
/* Change stereo panning */
if (midi_channel != DRUM_CHANNEL) {
opl4_midi->midi_channel_data[midi_channel].panpot = (value - 0x40) >> 3;
for (i = 0; i < NR_OF_WAVE_CHANNELS; i++) {
if (opl4_midi->voice_data[i].is_active && opl4_midi->voice_data[i].midi_channel == &opl4_midi->midi_channel_data[midi_channel]) {
update_pan(&opl4_midi->voice_data[i], opl4_midi);
}
}
}
break;
}
}
void
pitch_wheel(uint8_t midi_channel, uint16_t value, opl4_midi_t *opl4_midi)
{
int i = 0;
for (i = 0; i < 24; i++) {
if (opl4_midi->voice_data[i].is_active && opl4_midi->voice_data[i].midi_channel == &opl4_midi->midi_channel_data[midi_channel]) {
update_pitch(&opl4_midi->voice_data[i], value, opl4_midi);
}
}
}
void
channel_pressure(uint8_t midi_channel, uint8_t pressure)
{
(void) midi_channel;
(void) pressure;
}
void
key_pressure(uint8_t midi_channel, uint8_t note, uint8_t pressure)
{
(void) midi_channel;
(void) note;
(void) pressure;
}
void
program_change(uint8_t midi_channel, uint8_t program, opl4_midi_t *opl4_midi)
{
opl4_midi->midi_channel_data[midi_channel].instrument = program;
}
static void
opl4_midi_thread(void *arg)
{
opl4_midi_t *opl4_midi = opl4_midi_cur;
uint32_t i = 0;
uint32_t buf_size = RENDER_RATE * 2;
uint32_t buf_size_segments = buf_size * BUFFER_SEGMENTS;
uint32_t buf_pos = 0;
int32_t buffer[RENDER_RATE * 2];
extern void givealbuffer_midi(void *buf, uint32_t size);
while (opl4_midi->on) {
thread_wait_event(opl4_midi->wait_event, -1);
thread_reset_event(opl4_midi->wait_event);
if (!opl4_midi->on)
break;
atomic_store(&opl4_midi->gen_in_progress, true);
opl4_midi->opl4.generate(opl4_midi->opl4.priv, buffer, RENDER_RATE);
atomic_store(&opl4_midi->gen_in_progress, false);
if (sound_is_float) {
for (i = 0; i < (buf_size / 2); i++) {
opl4_midi->buffer_float[(i + buf_pos) * 2] = buffer[i * 2] / 32768.0;
opl4_midi->buffer_float[((i + buf_pos) * 2) + 1] = buffer[(i * 2) + 1] / 32768.0;
}
buf_pos += buf_size / 2;
if (buf_pos >= (buf_size_segments / 2)) {
givealbuffer_midi(opl4_midi->buffer_float, buf_size_segments);
buf_pos = 0;
}
} else {
for (i = 0; i < (buf_size / 2); i++) {
opl4_midi->buffer[(i + buf_pos) * 2] = buffer[i * 2] & 0xFFFF; /* Outputs are clamped beforehand. */
opl4_midi->buffer[((i + buf_pos) * 2) + 1] = buffer[(i * 2) + 1] & 0xFFFF; /* Outputs are clamped beforehand. */
}
buf_pos += buf_size / 2;
if (buf_pos >= (buf_size_segments / 2)) {
givealbuffer_midi(opl4_midi->buffer, buf_size_segments);
buf_pos = 0;
}
}
}
}
static void
opl4_midi_poll(void)
{
opl4_midi_t *opl4_midi = opl4_midi_cur;
opl4_midi->midi_pos++;
if (opl4_midi->midi_pos == RENDER_RATE) {
opl4_midi->midi_pos = 0;
thread_set_event(opl4_midi->wait_event);
}
}
void
opl4_midi_msg(uint8_t *val)
{
opl4_midi_t *opl4_midi = opl4_midi_cur;
uint32_t msg = *(uint32_t *) (val);
uint8_t data_byte_1 = msg & 0xFF;
uint8_t data_byte_2 = (msg >> 8) & 0xFF;
uint8_t data_byte_3 = (msg >> 16) & 0xFF;
uint8_t midi_channel = data_byte_1 & 0x0F;
uint8_t midi_command = data_byte_1 >> 4;
switch (midi_command) {
case 0x8: // Note OFF
note_off(data_byte_2 & 0x7F, data_byte_3, &opl4_midi->midi_channel_data[midi_channel], opl4_midi);
break;
case 0x9: // Note ON
note_on(data_byte_2 & 0x7F, data_byte_3, &opl4_midi->midi_channel_data[midi_channel], opl4_midi);
break;
case 0xA: // Key after-touch
break;
case 0xB: // Control change
control_change(midi_channel, data_byte_2, data_byte_3, opl4_midi);
break;
case 0xC: // Program change
program_change(midi_channel, data_byte_2 & 0x7F, opl4_midi);
break;
case 0xD: // Channel after-touch
break;
case 0xE: // Pitch wheel
pitch_wheel(midi_channel, ((data_byte_3 <<= 7) | data_byte_2), opl4_midi);
break;
}
}
void
opl4_midi_sysex(uint8_t *data, unsigned int len)
{
}
void *
opl4_init(const device_t *info)
{
midi_device_t *dev;
extern void al_set_midi(int freq, int buf_size);
dev = malloc(sizeof(midi_device_t));
memset(dev, 0, sizeof(midi_device_t));
dev->play_msg = opl4_midi_msg;
dev->play_sysex = opl4_midi_sysex;
dev->poll = opl4_midi_poll;
al_set_midi(48000, 4800);
opl4_midi_cur = calloc(1, sizeof(opl4_midi_t));
fm_driver_get(FM_YMF278B, &opl4_midi_cur->opl4);
opl4_midi_cur->opl4.write(0x38A, 0x05, opl4_midi_cur->opl4.priv);
opl4_midi_cur->opl4.write(0x389, 0x3, opl4_midi_cur->opl4.priv);
midi_out_init(dev);
opl4_midi_cur->on = true;
opl4_midi_cur->midi_channel_data[9].drum_channel = true;
atomic_init(&opl4_midi_cur->gen_in_progress, 0);
for (uint8_t voice = 0; voice < NR_OF_WAVE_CHANNELS; voice++) {
opl4_midi_cur->voice_data[voice].number = voice;
opl4_midi_cur->voice_data[voice].is_active = false;
opl4_midi_cur->voice_data[voice].activated = 0;
opl4_midi_cur->voice_data[voice].midi_channel = NULL;
opl4_midi_cur->voice_data[voice].note = 0;
opl4_midi_cur->voice_data[voice].velocity = 0;
opl4_midi_cur->voice_data[voice].wave_data = NULL;
opl4_midi_cur->voice_data[voice].level_direct = 0;
opl4_midi_cur->voice_data[voice].reg_f_number = 0;
opl4_midi_cur->voice_data[voice].reg_misc = 0;
opl4_midi_cur->voice_data[voice].reg_lfo_vibrato = 0;
}
opl4_midi_cur->wait_event = thread_create_event();
opl4_midi_cur->thread = thread_create(opl4_midi_thread, NULL);
return dev;
}
void
opl4_close(void *p)
{
if (!p)
return;
opl4_midi_cur->on = false;
thread_set_event(opl4_midi_cur->wait_event);
thread_wait(opl4_midi_cur->thread);
free(opl4_midi_cur);
opl4_midi_cur = NULL;
}
static int
opl4_midi_available(void)
{
return rom_present("roms/sound/yamaha/yrw801.rom");
}
const device_t opl4_midi_device = {
.name = "OPL4-ML Daughterboard",
.internal_name = "opl4-ml",
.flags = 0,
.local = 0,
.init = opl4_init,
.close = opl4_close,
.reset = NULL,
{ .available = opl4_midi_available },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

1042
src/sound/midi_opl4_yrw801.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1657,4 +1657,5 @@ const fm_drv_t nuked_opl_drv = {
&nuked_drv_reset_buffer,
&nuked_drv_set_do_cycles,
NULL,
NULL,
};

View File

@@ -399,6 +399,13 @@ ymfm_drv_set_do_cycles(void *priv, int8_t do_cycles)
drv->set_do_cycles(do_cycles);
}
static void
ymfm_drv_generate(void *priv, int32_t *data, uint32_t num_samples)
{
YMFMChipBase *drv = (YMFMChipBase *) priv;
drv->generate_resampled(data, num_samples);
}
const device_t ym3812_ymfm_device = {
.name = "Yamaha YM3812 OPL2 (YMFM)",
.internal_name = "ym3812_ymfm",
@@ -462,6 +469,7 @@ const fm_drv_t ymfm_drv {
&ymfm_drv_reset_buffer,
&ymfm_drv_set_do_cycles,
NULL,
ymfm_drv_generate,
};
#ifdef __clang__

View File

@@ -945,7 +945,7 @@ sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *priv)
break;
case 0xff:
if (sb->dsp.sb_type >= SB16) {
if (sb->dsp.sb_type > SBAWE32) {
/*
Bit 5: High DMA channel enabled (0 = yes, 1 = no);
Bit 2: ????;
@@ -1173,7 +1173,7 @@ sb_ct1745_mixer_read(uint16_t addr, void *priv)
- Register FF = FF: Volume playback normal.
- Register FF = Not FF: Volume playback low unless
bit 6 of 82h is set. */
if (sb->dsp.sb_type >= SB16)
if (sb->dsp.sb_type > SBAWE32)
ret = mixer->regs[mixer->index];
break;
@@ -1599,8 +1599,14 @@ sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv)
sb_dsp_setdma8(&sb->dsp, val);
val = config->dma[1].dma;
if (val != ISAPNP_DMA_DISABLED)
sb_dsp_setdma16(&sb->dsp, val);
sb_dsp_setdma16_enabled(&sb->dsp, val != ISAPNP_DMA_DISABLED);
sb_dsp_setdma16_translate(&sb->dsp, val < ISAPNP_DMA_DISABLED);
if (val != ISAPNP_DMA_DISABLED) {
if (sb->dsp.sb_16_dma_supported)
sb_dsp_setdma16(&sb->dsp, val);
else
sb_dsp_setdma16_8(&sb->dsp, val);
}
}
break;
@@ -1630,95 +1636,11 @@ static void
sb_vibra16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv)
{
sb_t *sb = (sb_t *) priv;
uint16_t addr = sb->dsp.sb_addr;
uint8_t val;
switch (ld) {
case 0: /* Audio */
io_removehandler(addr, 0x0004,
sb->opl.read, NULL, NULL,
sb->opl.write, NULL, NULL,
sb->opl.priv);
io_removehandler(addr + 8, 0x0002,
sb->opl.read, NULL, NULL,
sb->opl.write, NULL, NULL,
sb->opl.priv);
io_removehandler(addr + 4, 0x0002,
sb_ct1745_mixer_read, NULL, NULL,
sb_ct1745_mixer_write, NULL, NULL,
sb);
addr = sb->opl_pnp_addr;
if (addr) {
sb->opl_pnp_addr = 0;
io_removehandler(addr, 0x0004,
sb->opl.read, NULL, NULL,
sb->opl.write, NULL, NULL,
sb->opl.priv);
}
sb_dsp_setaddr(&sb->dsp, 0);
sb_dsp_setirq(&sb->dsp, 0);
sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED);
sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED);
mpu401_change_addr(sb->mpu, 0);
if (config->activate) {
addr = config->io[0].base;
if (addr != ISAPNP_IO_DISABLED) {
io_sethandler(addr, 0x0004,
sb->opl.read, NULL, NULL,
sb->opl.write, NULL, NULL,
sb->opl.priv);
io_sethandler(addr + 8, 0x0002,
sb->opl.read, NULL, NULL,
sb->opl.write, NULL, NULL,
sb->opl.priv);
io_sethandler(addr + 4, 0x0002,
sb_ct1745_mixer_read, NULL, NULL,
sb_ct1745_mixer_write, NULL, NULL,
sb);
sb_dsp_setaddr(&sb->dsp, addr);
}
addr = config->io[1].base;
if (addr != ISAPNP_IO_DISABLED)
mpu401_change_addr(sb->mpu, addr);
addr = config->io[2].base;
if (addr != ISAPNP_IO_DISABLED) {
sb->opl_pnp_addr = addr;
io_sethandler(addr, 0x0004,
sb->opl.read, NULL, NULL,
sb->opl.write, NULL, NULL,
sb->opl.priv);
}
val = config->irq[0].irq;
if (val != ISAPNP_IRQ_DISABLED)
sb_dsp_setirq(&sb->dsp, val);
val = config->dma[0].dma;
if (val != ISAPNP_DMA_DISABLED)
sb_dsp_setdma8(&sb->dsp, val);
val = config->dma[1].dma;
sb_dsp_setdma16_enabled(&sb->dsp, val != ISAPNP_DMA_DISABLED);
sb_dsp_setdma16_translate(&sb->dsp, val < ISAPNP_DMA_DISABLED);
if (val != ISAPNP_DMA_DISABLED) {
if (sb->dsp.sb_16_dma_supported)
sb_dsp_setdma16(&sb->dsp, val);
else
sb_dsp_setdma16_8(&sb->dsp, val);
}
}
break;
case 1: /* Game */
gameport_remap(sb->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
sb_16_pnp_config_changed(ld * 3, config, sb);
break;
default:
@@ -2179,6 +2101,7 @@ sb_16_init(UNUSED(const device_t *info))
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16"));
sb_dsp_setdma16_supported(&sb->dsp, 1);
sb_dsp_setdma16_enabled(&sb->dsp, 1);
sb_ct1745_mixer_reset(sb);
if (sb->opl_enabled) {
@@ -2233,6 +2156,7 @@ sb_16_reply_mca_init(UNUSED(const device_t *info))
sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_setdma16_supported(&sb->dsp, 1);
sb_dsp_setdma16_enabled(&sb->dsp, 1);
sb_ct1745_mixer_reset(sb);
sb->mixer_enabled = 1;
@@ -2304,7 +2228,7 @@ sb_16_pnp_init(UNUSED(const device_t *info))
sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED);
mpu401_change_addr(sb->mpu, 0);
ide_remove_handlers(2);
ide_remove_handlers(3);
sb->gameport_addr = 0;
gameport_remap(sb->gameport, 0);
@@ -2415,6 +2339,7 @@ sb_16_compat_init(const device_t *info)
sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_setdma16_supported(&sb->dsp, 1);
sb_dsp_setdma16_enabled(&sb->dsp, 1);
sb_ct1745_mixer_reset(sb);
sb->mixer_enabled = 1;
@@ -2488,6 +2413,7 @@ sb_awe32_init(UNUSED(const device_t *info))
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16"));
sb_dsp_setdma16_supported(&sb->dsp, 1);
sb_dsp_setdma16_enabled(&sb->dsp, 1);
sb_ct1745_mixer_reset(sb);
if (sb->opl_enabled) {
@@ -2631,7 +2557,8 @@ sb_awe32_pnp_init(const device_t *info)
sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED);
mpu401_change_addr(sb->mpu, 0);
ide_remove_handlers(2);
if ((info->local != 2) && (info->local != 3) && (info->local != 4))
ide_remove_handlers(3);
emu8k_change_addr(&sb->emu8k, 0);

45
src/sound/yrw801.h Normal file
View File

@@ -0,0 +1,45 @@
/*
* RoboPlay for MSX
* Copyright (C) 2022 by RoboSoft Inc.
*
* yrw801.h
*/
/* Cacodemon345: Added pointer structs from Linux */
#pragma once
#include <stdint.h>
typedef struct
{
uint16_t tone;
int16_t pitch_offset;
uint8_t key_scaling;
int8_t panpot;
uint8_t vibrato;
uint8_t tone_attenuate;
uint8_t volume_factor;
uint8_t reg_lfo_vibrato;
uint8_t reg_attack_decay1;
uint8_t reg_level_decay2;
uint8_t reg_release_correction;
uint8_t reg_tremolo;
} YRW801_WAVE_DATA;
typedef struct
{
uint8_t key_min;
uint8_t key_max;
YRW801_WAVE_DATA wave_data;
} YRW801_REGION_DATA;
typedef struct
{
int count;
const YRW801_REGION_DATA* regions;
} YRW801_REGION_DATA_PTR;
extern const YRW801_REGION_DATA_PTR snd_yrw801_regions[0x81];

View File

@@ -12,10 +12,10 @@
# After a successful build, you can install the RPMs as follows:
# sudo dnf install RPMS/$(uname -m)/86Box-3* RPMS/noarch/86Box-roms*
%global romver 4.0.1
%global romver 4.1
Name: 86Box
Version: 4.0.2
Version: 4.1
Release: 1%{?dist}
Summary: Classic PC emulator
License: GPLv2+
@@ -121,5 +121,5 @@ popd
%{_datadir}/%{name}/roms
%changelog
* Mon Oct 16 2023 Robert de Rooy <robert.de.rooy[AT]gmail.com> 4.0.2-1
* Mon Oct 16 2023 Robert de Rooy <robert.de.rooy[AT]gmail.com> 4.1-1
- Bump release

View File

@@ -10,7 +10,7 @@
</categories>
<launchable type="desktop-id">net.86box.86Box.desktop</launchable>
<releases>
<release version="4.0.2" date="2023-10-16"/>
<release version="4.1" date="2023-10-16"/>
</releases>
<content_rating type="oars-1.1" />
<description>

View File

@@ -60,6 +60,7 @@ extern wchar_t sdl_win_title[512];
plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS];
joystick_t joystick_state[MAX_JOYSTICKS];
int joysticks_present;
int status_icons_fullscreen = 0; /* unused. */
SDL_mutex *blitmtx;
SDL_threadID eventthread;
static int exit_event = 0;

View File

@@ -964,8 +964,8 @@ ibm8514_accel_out(uint16_t port, uint32_t val, svga_t *svga, int len)
if (!val)
break;
dev->accel.advfunc_cntl = val & 0x0f;
dev->on = val & 0x01;
vga_on = !dev->on;
dev->on[0] = val & 0x01;
vga_on = !dev->on[0];
ibm8514_log("IBM 8514/A: VGA ON = %i, val = %02x\n", vga_on, val);
svga_recalctimings(svga);
break;
@@ -1200,17 +1200,16 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat
if (cpu_input) {
if ((dev->accel.cmd & 2) || (pixcntl == 2)) {
if ((frgd_mix == 2) || (bkgd_mix == 2)) {
if ((frgd_mix == 2) || (bkgd_mix == 2))
count >>= 3;
} else if (pixcntl == 2) {
if (dev->accel.cmd & 2) {
else if (pixcntl == 2) {
if (dev->accel.cmd & 2)
count >>= 1;
} else
else
count >>= 3;
}
} else {
} else
count >>= 3;
}
if (dev->bpp) {
if ((dev->accel.cmd & 0x200) && (count == 2))
@@ -1299,7 +1298,8 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat
/*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled.
When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on
the NOP command)*/
ibm8514_log("CMD8514: CMD=%d, full=%04x, pixcntl=%x, count=%d, frgdmix = %02x, bkgdmix = %02x, polygon=%x.\n", cmd, dev->accel.cmd, pixcntl, count, frgd_mix, bkgd_mix, dev->accel.multifunc[0x0a] & 6);
if (dev->accel.cmd == 0x53b1 && !cpu_dat)
ibm8514_log("CMD8514: CMD=%d, full=%04x, pixcntl=%x, count=%d, frgdmix = %02x, bkgdmix = %02x, polygon=%x, cpu=%08x, frgdmix=%02x, bkgdmix=%02x.\n", cmd, dev->accel.cmd, pixcntl, count, frgd_mix, bkgd_mix, dev->accel.multifunc[0x0a] & 6, cpu_dat, dev->accel.frgd_mix, dev->accel.bkgd_mix);
switch (cmd) {
case 0: /*NOP (Short Stroke Vectors)*/
@@ -4243,7 +4243,7 @@ ibm8514_recalctimings(svga_t *svga)
{
ibm8514_t *dev = (ibm8514_t *) svga->dev8514;
if (dev->on) {
if (dev->on[0]) {
dev->h_disp = (dev->hdisp + 1) << 3;
dev->pitch = (dev->accel.advfunc_cntl & 4) ? 1024 : 640;
dev->h_total = (dev->htotal + 1);

View File

@@ -73,16 +73,16 @@ ati68860_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga)
switch (addr) {
case 0:
svga_out((dev && dev->on) ? 0x2ec : 0x3c8, val, svga);
svga_out((dev && (dev->on[0] || dev->on[1])) ? 0x2ec : 0x3c8, val, svga);
break;
case 1:
svga_out((dev && dev->on) ? 0x2ed : 0x3c9, val, svga);
svga_out((dev && (dev->on[0] || dev->on[1])) ? 0x2ed : 0x3c9, val, svga);
break;
case 2:
svga_out((dev && dev->on) ? 0x2ea : 0x3c6, val, svga);
svga_out((dev && (dev->on[0] || dev->on[1])) ? 0x2ea : 0x3c6, val, svga);
break;
case 3:
svga_out((dev && dev->on) ? 0x2eb : 0x3c7, val, svga);
svga_out((dev && (dev->on[0] || dev->on[1])) ? 0x2eb : 0x3c7, val, svga);
break;
default:
ramdac->regs[addr & 0xf] = val;
@@ -178,16 +178,16 @@ ati68860_ramdac_in(uint16_t addr, void *priv, svga_t *svga)
switch (addr) {
case 0:
temp = svga_in((dev && dev->on) ? 0x2ec : 0x3c8, svga);
temp = svga_in((dev && (dev->on[0] || dev->on[1])) ? 0x2ec : 0x3c8, svga);
break;
case 1:
temp = svga_in((dev && dev->on) ? 0x2ed : 0x3c9, svga);
temp = svga_in((dev && (dev->on[0] || dev->on[1])) ? 0x2ed : 0x3c9, svga);
break;
case 2:
temp = svga_in((dev && dev->on) ? 0x2ea : 0x3c6, svga);
temp = svga_in((dev && (dev->on[0] || dev->on[1])) ? 0x2ea : 0x3c6, svga);
break;
case 3:
temp = svga_in((dev && dev->on) ? 0x2eb : 0x3c7, svga);
temp = svga_in((dev && (dev->on[0] || dev->on[1])) ? 0x2eb : 0x3c7, svga);
break;
case 4:
case 8:

View File

@@ -100,8 +100,8 @@ typedef struct mach_t {
uint8_t bank_w;
uint8_t bank_r;
uint16_t shadow_set;
int ext_on;
int ati_mode;
int ext_on[2];
int ati_mode[2];
struct {
uint8_t line_idx;
@@ -1140,9 +1140,9 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3
mix = 1;
break;
case 1:
if (mach->accel.mono_pattern_enable) {
if (mach->accel.mono_pattern_enable)
mix = mach->accel.mono_pattern[dev->accel.dy & 7][dev->accel.dx & 7];
} else {
else {
if ((dev->accel_bpp == 24) && (frgd_sel == 5) && (mach->accel.patt_len_reg & 0x4000))
mix = 1;
else {
@@ -1205,18 +1205,16 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3
src_dat = cpu_dat;
else {
READ(dev->accel.src + (dev->accel.cx), src_dat);
if (mono_src == 3) {
if (mono_src == 3)
src_dat = (src_dat & rd_mask) == rd_mask;
}
}
break;
case 5:
if (mix) {
if (dev->bpp) {
if (dev->bpp)
src_dat = mach->accel.color_pattern_word[mach->accel.color_pattern_idx];
} else {
else
src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx];
}
} else
src_dat = 0;
break;
@@ -1318,9 +1316,9 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3
mach->accel.color_pattern_idx++;
if (mach->accel.color_pattern_idx == 3)
mach->accel.color_pattern_idx = 0;
} else {
} else
mach->accel.color_pattern_idx = (mach->accel.color_pattern_idx + mach->accel.stepx) & mach->accel.patt_len;
}
} else if ((dev->accel_bpp == 24) && (mach->accel.patt_len_reg & 0x4000) && (frgd_sel == 5)) {
mach->accel.color_pattern_idx++;
if (mach->accel.color_pattern_idx == 3)
@@ -1346,9 +1344,9 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3
if (dev->bpp)
dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * (dev->pitch));
else {
else
dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * (dev->pitch));
}
if ((mono_src == 1) && (dev->accel_bpp == 24) && (frgd_sel == 5))
mach->accel.color_pattern_idx = 0;
else
@@ -2347,7 +2345,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv)
mach->bank_r |= ((mach->regs[0xae] & 0x0c) << 2);
mach->bank_w |= ((mach->regs[0xae] & 3) << 4);
}
if (dev->on)
if (dev->on[0] || dev->on[1])
mach_log("Separate B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]);
} else { /* Single bank mode */
mach->bank_w = ((mach->regs[0xb2] & 0x1e) >> 1);
@@ -2355,7 +2353,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv)
mach->bank_w |= ((mach->regs[0xae] & 3) << 4);
}
mach->bank_r = mach->bank_w;
if (dev->on)
if (dev->on[0] || dev->on[1])
mach_log("Single B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]);
}
svga->read_bank = mach->bank_r << 16;
@@ -2590,7 +2588,7 @@ mach_recalctimings(svga_t *svga)
if (mach->regs[0xb0] & 0x20)
svga->gdcreg[5] |= 0x40;
if (dev->on) {
if (dev->on[0] || dev->on[1]) {
mach_log("8514/A ON.\n");
if (dev->local >= 2) {
dev->h_disp = (dev->hdisp + 1) << 3;
@@ -3686,19 +3684,16 @@ mach_accel_out(uint16_t port, uint8_t val, mach_t *mach)
case 0x4ae8:
case 0x4ae9:
if (!(port & 1)) {
if (dev->local < 2)
dev->ext_crt_pitch = 128;
if (dev->local < 2)
dev->ext_crt_pitch = 128;
dev->accel.advfunc_cntl = val & 0x0f;
} else {
dev->on = (dev->accel.advfunc_cntl & 0x01);
vga_on = !dev->on;
mach->ext_on = dev->on;
mach_log("ATI 8514/A: (0x4ae9) val = %04x, ext = %d.\n", dev->accel.advfunc_cntl & 0x01, mach->ext_on);
mach32_updatemapping(mach);
}
mach->ati_mode = 0;
WRITE8(port, dev->accel.advfunc_cntl, val);
dev->on[port & 1] = (dev->accel.advfunc_cntl & 0x01);
mach_log("%04x: ON=%d.\n", port, dev->on[port & 1]);
vga_on = !dev->on[port & 1];
mach->ext_on[port & 1] = dev->on[port & 1];
mach32_updatemapping(mach);
mach->ati_mode[port & 1] = 0;
svga_recalctimings(svga);
break;
@@ -3806,29 +3801,22 @@ mach_accel_out(uint16_t port, uint8_t val, mach_t *mach)
break;
case 0x42ee:
mach->accel.test2[0] = val;
break;
case 0x42ef:
mach->accel.test2[1] = val;
mach->accel.test2[port & 1] = val;
break;
case 0x46ee:
mach->accel.test3[0] = val;
break;
case 0x46ef:
mach->accel.test3[1] = val;
mach->accel.test3[port & 1] = val;
break;
case 0x4aee:
case 0x4aef:
WRITE8(port, mach->accel.clock_sel, val);
if (port & 1) {
dev->on = mach->accel.clock_sel & 0x01;
mach->ext_on = dev->on;
vga_on = !dev->on;
mach_log("ATI 8514/A: (0x4aef) val = %04x, ext = %d.\n", mach->accel.clock_sel & 0x01, mach->ext_on);
}
mach->ati_mode = 1;
dev->on[port & 1] = mach->accel.clock_sel & 0x01;
mach->ext_on[port & 1] = dev->on[port & 1];
vga_on = !dev->on[port & 1];
mach->ati_mode[port & 1] = 1;
svga_recalctimings(svga);
break;
@@ -3836,16 +3824,14 @@ mach_accel_out(uint16_t port, uint8_t val, mach_t *mach)
case 0x52ef:
mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val);
WRITE8(port, mach->accel.scratch0, val);
if (port & 1)
mach->ext_on = 1;
mach->ext_on[port & 1] = 1;
break;
case 0x56ee:
case 0x56ef:
mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val);
WRITE8(port, mach->accel.scratch1, val);
if (port & 1)
mach->ext_on = 1;
mach->ext_on[port & 1] = 1;
break;
case 0x5aee:
@@ -3926,11 +3912,8 @@ mach_accel_out(uint16_t port, uint8_t val, mach_t *mach)
break;
}
svga_set_ramdac_type(svga, !!(mach->accel.ext_ge_config & 0x4000));
if (port & 1) {
mach->ati_mode = 1;
mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val);
mach32_updatemapping(mach);
}
mach->ati_mode[port & 1] = 1;
mach32_updatemapping(mach);
}
svga_recalctimings(svga);
break;
@@ -5115,10 +5098,12 @@ mach32_updatemapping(mach_t *mach)
mach->ap_size = 4;
mem_mapping_disable(&mach->mmio_linear_mapping);
}
if (mach->ext_on && (dev->local >= 2) && mach->ati_mode) {
if ((mach->ext_on[0] || mach->ext_on[1]) && (dev->local >= 2) && (mach->ati_mode[0] || mach->ati_mode[1])) {
mach_log("ExtON.\n");
mem_mapping_set_handler(&svga->mapping, mach32_read, mach32_readw, mach32_readl, mach32_write, mach32_writew, mach32_writel);
mem_mapping_set_p(&svga->mapping, mach);
} else {
mach_log("ExtOFF.\n");
mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel);
mem_mapping_set_p(&svga->mapping, svga);
}
@@ -5456,7 +5441,8 @@ mach_mca_reset(void *priv)
mem_mapping_disable(&mach->bios_rom.mapping);
mem_mapping_disable(&mach->bios_rom2.mapping);
mach_log("MCA reset.\n");
dev->on = 0;
dev->on[0] = 0;
dev->on[1] = 0;
vga_on = 1;
mach_mca_write(0x102, 0, mach);
}
@@ -5564,12 +5550,10 @@ mach32_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv)
case 0x12:
mach->linear_base = (mach->linear_base & 0xff000000) | ((val & 0xc0) << 16);
mach->ati_mode = 1;
mach32_updatemapping(mach);
break;
case 0x13:
mach->linear_base = (mach->linear_base & 0xc00000) | (val << 24);
mach->ati_mode = 1;
mach32_updatemapping(mach);
break;
@@ -5722,7 +5706,8 @@ mach8_init(const device_t *info)
dev->bpp = 0;
svga->getclock = ics2494_getclock;
dev->on = 0;
dev->on[0] = 0;
dev->on[1] = 0;
dev->ext_pitch = 1024;
dev->ext_crt_pitch = 0x80;
dev->accel_bpp = 8;

View File

@@ -212,10 +212,12 @@ svga_out(uint16_t addr, uint8_t val, void *priv)
svga_recalctimings(svga);
break;
case 0x3c3:
if (xga_active)
if (xga_active && xga)
xga->on = (val & 0x01) ? 0 : 1;
if (ibm8514_active)
dev->on = (val & 0x01) ? 0 : 1;
if (ibm8514_active && dev) {
dev->on[0] = (val & 0x01) ? 0 : 1;
dev->on[1] = dev->on[0];
}
svga_log("3C3: XGA ON = %d.\n", xga->on);
vga_on = val & 0x01;
@@ -527,7 +529,7 @@ svga_set_ramdac_type(svga_t *svga, int type)
svga->ramdac_type = type;
for (int c = 0; c < 256; c++) {
if (ibm8514_active) {
if (ibm8514_active && dev) {
if (svga->ramdac_type == RAMDAC_8BIT)
dev->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b);
else
@@ -535,7 +537,7 @@ svga_set_ramdac_type(svga_t *svga, int type)
(svga->vgapal[c].g & 0x3f) * 4,
(svga->vgapal[c].b & 0x3f) * 4);
}
if (xga_active) {
if (xga_active && xga) {
if (svga->ramdac_type == RAMDAC_8BIT)
xga->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b);
else
@@ -834,11 +836,11 @@ svga_poll(void *priv)
int old_ma;
if (!svga->override) {
if (ibm8514_active && dev->on) {
if (ibm8514_active && dev && (dev->on[0] || dev->on[1])) {
ibm8514_poll(dev, svga);
return;
}
if (xga_active && xga->on) {
if (xga_active && xga && xga->on) {
if ((xga->disp_cntl_2 & 7) >= 2) {
xga_poll(xga, svga);
return;
@@ -1253,7 +1255,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *priv)
cycles -= svga->monitor->mon_video_timing_write_b;
if (!linear) {
if (xga_active) {
if (xga_active && xga) {
if (((xga->op_mode & 7) >= 4) && (xga->aperture_cntl >= 1)) {
if (val == 0xa5) { /*Memory size test of XGA*/
xga->test = val;
@@ -1474,7 +1476,7 @@ svga_read_common(uint32_t addr, uint8_t linear, void *priv)
cycles -= svga->monitor->mon_video_timing_read_b;
if (!linear) {
if (xga_active) {
if (xga_active && xga) {
if (((xga->op_mode & 7) >= 4) && (xga->aperture_cntl >= 1)) {
if (xga->test == 0xa5) { /*Memory size test of XGA*/
if (addr == 0xa0001) {

View File

@@ -1462,7 +1462,7 @@ tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui)
}
}
/*See this: https://android.googlesource.com/kernel/tegra/+/android-tegra-flounder-3.10-lollipop-release/drivers/video/tridentfb.c for the pitch*/
/* See Linux kernel drivers/video/tridentfb.c for the pitch */
tgui->accel.pitch = svga->rowoffset;
switch (svga->bpp) {

View File

@@ -637,7 +637,7 @@ DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm
SIOOBJ := sio_acc3221.o sio_ali5123.o \
sio_f82c710.o sio_82091aa.o sio_fdc37c6xx.o \
sio_fdc37c67x.o sio_fdc37c669.o sio_fdc37c93x.o sio_fdc37m60x.o \
sio_it8661f.o \
sio_it86x1f.o \
sio_it8702.o \
sio_pc87306.o sio_pc87307.o sio_pc87309.o sio_pc87310.o sio_pc87311.o sio_pc87332.o \
sio_prime3b.o sio_prime3c.o \
@@ -692,7 +692,11 @@ NETOBJ := network.o \
net_3c503.o net_ne2000.o \
net_pcnet.o net_wd8003.o \
net_plip.o net_event.o \
net_null.o
net_null.o \
net_eeprom_nmc93cxx.o \
net_tulip.o \
net_rtl8139.o \
net_l80225.o
PRINTOBJ := png.o prt_cpmap.o \
prt_escp.o prt_text.o prt_ps.o
@@ -708,6 +712,8 @@ SNDOBJ := sound.o \
wave8580__ST.o wave8580_P_T.o wave8580_PS_.o \
wave8580_PST.o wave.o \
midi.o \
midi_opl4.o \
midi_opl4_yrw801.o \
snd_speaker.o \
snd_pssj.o \
snd_ps1.o \

View File

@@ -76,6 +76,8 @@ int hide_status_bar = 0;
int hide_tool_bar = 0;
int dpi = 96;
int status_icons_fullscreen = 0; /* unused. */
extern char openfilestring[512];
extern WCHAR wopenfilestring[512];

View File

@@ -1,6 +1,6 @@
{
"name": "86box",
"version-string": "4.0.2",
"version-string": "4.1",
"homepage": "https://86box.net/",
"documentation": "https://86box.readthedocs.io/",
"license": "GPL-2.0-or-later",