mirror of
https://github.com/86Box/86Box.git
synced 2026-02-22 09:35:32 -07:00
Merge pull request #3823 from 86Box/version/4.1
Merge Version/4.1 into master since we have decided to just go straight for 4.1
This commit is contained in:
@@ -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
2
debian/changelog
vendored
@@ -1,4 +1,4 @@
|
||||
86box (4.0.2) UNRELEASED; urgency=medium
|
||||
86box (4.1) UNRELEASED; urgency=medium
|
||||
|
||||
* Bump release.
|
||||
|
||||
|
||||
@@ -1625,7 +1625,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)
|
||||
|
||||
@@ -2370,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;
|
||||
@@ -2388,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;
|
||||
@@ -2406,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;
|
||||
|
||||
@@ -2764,6 +2764,7 @@ const cpu_legacy_machine_t cpu_legacy_table[] = {
|
||||
{ "award286", cputables_286 },
|
||||
{ "gw286ct", cputables_286 },
|
||||
{ "gdc212m", cputables_286 },
|
||||
{ "super286c", cputables_286 },
|
||||
{ "super286tr", cputables_286 },
|
||||
{ "spc4200p", cputables_286 },
|
||||
{ "spc4216p", cputables_286 },
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -68,6 +68,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;
|
||||
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -446,6 +446,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 *);
|
||||
@@ -599,6 +600,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 *);
|
||||
|
||||
@@ -672,6 +674,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 *);
|
||||
@@ -704,6 +707,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 *);
|
||||
@@ -752,6 +756,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 *);
|
||||
|
||||
@@ -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
|
||||
|
||||
19
src/include/86box/net_eeprom_nmc93cxx.h
Normal file
19
src/include/86box/net_eeprom_nmc93cxx.h
Normal 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;
|
||||
1
src/include/86box/net_rtl8139.h
Normal file
1
src/include/86box/net_rtl8139.h
Normal file
@@ -0,0 +1 @@
|
||||
extern const device_t rtl8139c_plus_device;
|
||||
2
src/include/86box/net_tulip.h
Normal file
2
src/include/86box/net_tulip.h
Normal file
@@ -0,0 +1,2 @@
|
||||
extern const device_t dec_tulip_device;
|
||||
extern const device_t dec_tulip_21140_device;
|
||||
101
src/include/86box/opl4_defines.h
Normal file
101
src/include/86box/opl4_defines.h
Normal 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 */
|
||||
@@ -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;
|
||||
@@ -71,6 +72,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 w83787f_88h_device;
|
||||
extern const device_t w83787f_device;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_init(model);
|
||||
|
||||
device_add(&neat_device);
|
||||
|
||||
if (fdc_type == FDC_INTERNAL)
|
||||
device_add(&fdc_at_device);
|
||||
|
||||
device_add(&keyboard_at_ami_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
machine_at_super286tr_init(const machine_t *model)
|
||||
{
|
||||
|
||||
@@ -247,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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -163,7 +163,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.
|
||||
|
||||
@@ -3239,6 +3238,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",
|
||||
@@ -8293,6 +8332,45 @@ 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 = 0,
|
||||
.gpio = 0,
|
||||
.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. */
|
||||
{
|
||||
@@ -10628,6 +10706,45 @@ 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 = 0,
|
||||
.gpio = 0,
|
||||
.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. */
|
||||
{
|
||||
@@ -11618,6 +11735,45 @@ 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 = 0,
|
||||
.gpio = 0,
|
||||
.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",
|
||||
@@ -13046,6 +13202,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
293
src/network/net_eeprom_nmc93cxx.c
Normal file
293
src/network/net_eeprom_nmc93cxx.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* 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 const char *opstring[] = {
|
||||
"extended", "write", "read", "erase"
|
||||
};
|
||||
|
||||
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, 1024);
|
||||
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
41
src/network/net_l80225.c
Normal 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;
|
||||
}
|
||||
3387
src/network/net_rtl8139.c
Normal file
3387
src/network/net_rtl8139.c
Normal file
File diff suppressed because it is too large
Load Diff
1637
src/network/net_tulip.c
Normal file
1637
src/network/net_tulip.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -131,6 +133,9 @@ static const device_t *net_cards[] = {
|
||||
&pcnet_am79c970a_device,
|
||||
&rtl8029as_device,
|
||||
&pcnet_am79c960_vlb_device,
|
||||
&dec_tulip_device,
|
||||
&rtl8139c_plus_device,
|
||||
&dec_tulip_21140_device,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,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_it8661f.c
|
||||
sio_it86x1f.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
|
||||
sio_w83787f.c sio_w83877f.c sio_w83977f.c sio_um8669f.c
|
||||
|
||||
@@ -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
862
src/sio/sio_it86x1f.c
Normal 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;
|
||||
|
||||
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. */
|
||||
uint8_t effective_ldn;
|
||||
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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -100,6 +100,7 @@ static const MIDI_OUT_DEVICE devices[] = {
|
||||
#ifdef USE_RTMIDI
|
||||
{ &rtmidi_output_device },
|
||||
#endif
|
||||
{ &opl4_midi_device },
|
||||
{ NULL }
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
732
src/sound/midi_opl4.c
Normal file
732
src/sound/midi_opl4.c
Normal file
@@ -0,0 +1,732 @@
|
||||
// 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;
|
||||
uint32_t j = 0;
|
||||
|
||||
while (opl4_midi->gen_in_progress) { }
|
||||
|
||||
if (midi_channel->drum_channel)
|
||||
wave_data[voices++] = ®ion_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] = ®ion[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
1042
src/sound/midi_opl4_yrw801.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1657,4 +1657,5 @@ const fm_drv_t nuked_opl_drv = {
|
||||
&nuked_drv_reset_buffer,
|
||||
&nuked_drv_set_do_cycles,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
@@ -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__
|
||||
|
||||
45
src/sound/yrw801.h
Normal file
45
src/sound/yrw801.h
Normal 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];
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -633,7 +633,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_pc87306.o sio_pc87307.o sio_pc87309.o sio_pc87310.o sio_pc87311.o sio_pc87332.o \
|
||||
sio_prime3b.o sio_prime3c.o \
|
||||
sio_w83787f.o \
|
||||
@@ -686,7 +686,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
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user