Applied all the mainline PCem commits, this also fixes the annoying buzzing on the AWE32.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
#
|
||||
# Modified Makefile for Win32 (MinGW32) environment.
|
||||
#
|
||||
# Version: @(#)Makefile.mingw 1.0.40 2017/08/27
|
||||
# Version: @(#)Makefile.mingw 1.0.41 2017/09/01
|
||||
#
|
||||
# Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
# Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
@@ -207,15 +207,15 @@ SYSOBJ = model.o \
|
||||
ali1429.o \
|
||||
opti495.o \
|
||||
scat.o \
|
||||
sis496.o \
|
||||
sis85c471.o sis496.o \
|
||||
wd76c10.o \
|
||||
acer386sx.o amstrad.o \
|
||||
compaq.o laserxt.o jim.o \
|
||||
olivetti_m24.o ps1.o ps2.o ps2_mca.o \
|
||||
tandy_eeprom.o tandy_rom.o
|
||||
DEVOBJ = bugger.o lpt.o $(SERIAL) \
|
||||
DEVOBJ = bugger.o lpt.o $(SERIAL) cbm_io.o \
|
||||
fdc37c665.o fdc37c669.o fdc37c932fr.o \
|
||||
pc87306.o sis85c471.o w83877f.o um8669f.o \
|
||||
pc87306.o w83877f.o um8669f.o \
|
||||
keyboard.o \
|
||||
keyboard_xt.o keyboard_at.o keyboard_pcjr.o \
|
||||
keyboard_amstrad.o keyboard_olim24.o \
|
||||
@@ -388,6 +388,8 @@ amstrad.o: ibm.h cpu/cpu.h io.h device.h model.h keyboard.h lpt.h mouse.h
|
||||
|
||||
bugger.o: ibm.h io.h bugger.h
|
||||
|
||||
cmb_io.o: ibm.h io.h lpt.h serial.h
|
||||
|
||||
cdrom.o: 86box.h cdrom.h ibm.h hdd/hdd_ide_at.h piix.h scsi/scsi.h timer.h \
|
||||
win/plat_iodev.h
|
||||
|
||||
|
37
src/cbm_io.c
Normal file
37
src/cbm_io.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "ibm.h"
|
||||
|
||||
#include "io.h"
|
||||
#include "lpt.h"
|
||||
#include "serial.h"
|
||||
|
||||
static void cbm_io_write(uint16_t port, uint8_t val, void *p)
|
||||
{
|
||||
lpt1_remove();
|
||||
lpt2_remove();
|
||||
switch (val & 3)
|
||||
{
|
||||
case 1:
|
||||
lpt1_init(0x3bc);
|
||||
break;
|
||||
case 2:
|
||||
lpt1_init(0x378);
|
||||
break;
|
||||
case 3:
|
||||
lpt1_init(0x278);
|
||||
break;
|
||||
}
|
||||
switch (val & 0xc)
|
||||
{
|
||||
case 0x4:
|
||||
serial_setup(1, 0x2f8, 3);
|
||||
break;
|
||||
case 0x8:
|
||||
serial_setup(1, 0x3f8, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cbm_io_init()
|
||||
{
|
||||
io_sethandler(0x0230, 0x0001, NULL,NULL,NULL, cbm_io_write,NULL,NULL, NULL);
|
||||
}
|
1
src/cbm_io.h
Normal file
1
src/cbm_io.h
Normal file
@@ -0,0 +1 @@
|
||||
void cbm_io_init();
|
@@ -702,7 +702,7 @@ int dma_channel_write(int channel, uint16_t val)
|
||||
{
|
||||
if (dma16.mode[channel] & 0x10) /*Auto-init*/
|
||||
{
|
||||
dma16.cc[channel] = dma16.cb[channel] + 1;
|
||||
dma16.cc[channel] = dma16.cb[channel];
|
||||
dma16.ac[channel] = dma16.ab[channel];
|
||||
}
|
||||
else
|
||||
|
26
src/model.c
26
src/model.c
@@ -27,6 +27,7 @@
|
||||
#include "mouse.h"
|
||||
#include "cdrom.h"
|
||||
|
||||
#include "cbm_io.h"
|
||||
#include "disc.h"
|
||||
#include "dma.h"
|
||||
#include "fdc.h"
|
||||
@@ -58,6 +59,9 @@
|
||||
#include "pit.h"
|
||||
#include "ps2_mca.h"
|
||||
#include "serial.h"
|
||||
#if 0
|
||||
#include "sis50x.h"
|
||||
#endif
|
||||
#include "sis85c471.h"
|
||||
#include "sio.h"
|
||||
#include "sound/snd_ps1.h"
|
||||
@@ -493,6 +497,7 @@ static void cmdpc30_init(void)
|
||||
{
|
||||
at_ide_init();
|
||||
mem_remap_top_384k();
|
||||
cbm_io_init();
|
||||
}
|
||||
|
||||
|
||||
@@ -761,18 +766,27 @@ static void at_batman_init(void)
|
||||
|
||||
|
||||
#if 0
|
||||
/* Slots present: 00 01 02 (special) */
|
||||
/* Slots not present: 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 */
|
||||
#define SIO_SLOT 0x07
|
||||
static void at_586mc1_init(void)
|
||||
{
|
||||
at_ide_init();
|
||||
memregs_init();
|
||||
pci_init(PCI_CONFIG_TYPE_2);
|
||||
i430lx_init();
|
||||
pci_slot(0xc);
|
||||
pci_slot(0xe);
|
||||
pci_slot(0x6);
|
||||
sio_init(2);
|
||||
pci_init(PCI_CONFIG_TYPE_1);
|
||||
pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0);
|
||||
pci_register_slot(0x19, PCI_CARD_NORMAL, 1, 2, 3, 4);
|
||||
pci_register_slot(0x1A, PCI_CARD_NORMAL, 2, 3, 4, 1);
|
||||
pci_register_slot(0x1B, PCI_CARD_NORMAL, 3, 4, 1, 2);
|
||||
pci_register_slot(0x1C, PCI_CARD_NORMAL, 4, 1, 2, 3);
|
||||
pci_register_slot(SIO_SLOT, PCI_CARD_SPECIAL, 0, 0, 0, 0);
|
||||
fdc37c665_init();
|
||||
intel_batman_init();
|
||||
device_add(&intel_flash_bxt_device);
|
||||
secondary_ide_check();
|
||||
sis501_init();
|
||||
sis503_init(SIO_SLOT);
|
||||
sis50x_isa_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
349
src/sis50x.c
349
src/sis50x.c
@@ -26,19 +26,25 @@ typedef struct sis501_t
|
||||
uint8_t turbo_reg;
|
||||
} sis501_t;
|
||||
|
||||
sis501_t sis501;
|
||||
|
||||
typedef struct sis503_t
|
||||
{
|
||||
uint8_t pci_conf[256];
|
||||
} sis503_t;
|
||||
|
||||
sis503_t sis503;
|
||||
|
||||
typedef struct sis50x_t
|
||||
{
|
||||
uint8_t isa_conf[12];
|
||||
uint8_t reg;
|
||||
} sis50x_t;
|
||||
} sis50x_isa_t;
|
||||
|
||||
sis50x_isa_t sis50x_isa;
|
||||
|
||||
|
||||
static void sis501_recalcmapping(sis501_t *sis501)
|
||||
static void sis501_recalcmapping(void)
|
||||
{
|
||||
int c, d;
|
||||
|
||||
@@ -46,11 +52,10 @@ static void sis501_recalcmapping(sis501_t *sis501)
|
||||
{
|
||||
for (d = 0; d < 4; d++)
|
||||
{
|
||||
// uint32_t base = (((2 - c) << 16) + 0xc0000) + (d << 14);
|
||||
uint32_t base = 0xe0000 + (d << 14);
|
||||
if (sis501->pci_conf[0x54 + c] & (1 << (d + 4)))
|
||||
if (sis501.pci_conf[0x54 + c] & (1 << (d + 4)))
|
||||
{
|
||||
switch (sis501->pci_conf[0x53] & 0x60)
|
||||
switch (sis501.pci_conf[0x53] & 0x60)
|
||||
{
|
||||
case 0x00:
|
||||
mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
|
||||
@@ -78,240 +83,244 @@ static void sis501_recalcmapping(sis501_t *sis501)
|
||||
|
||||
static void sis501_write(int func, int addr, uint8_t val, void *p)
|
||||
{
|
||||
sis501_t *sis501 = (sis501_t *)p;
|
||||
//pclog("sis501_write : addr=%02x val=%02x\n", addr, val);
|
||||
/* pclog("sis501_write : addr=%02x val=%02x\n", addr, val); */
|
||||
if (func)
|
||||
return;
|
||||
|
||||
if ((addr >= 0x10) && (addr < 0x4f))
|
||||
return;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x00: case 0x01: case 0x02: case 0x03:
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
||||
case 0x0c: case 0x0e:
|
||||
return;
|
||||
|
||||
case 0x04: /*Command register*/
|
||||
val &= 0x42;
|
||||
val |= 0x04;
|
||||
break;
|
||||
case 0x05:
|
||||
val &= 0x01;
|
||||
break;
|
||||
|
||||
case 0x06: /*Status*/
|
||||
val = 0;
|
||||
break;
|
||||
case 0x07:
|
||||
val = 0x02;
|
||||
break;
|
||||
|
||||
case 0x54: /*Shadow configure*/
|
||||
if ((sis501->pci_conf[0x54] & val) ^ 0xf0)
|
||||
if ((sis501.pci_conf[0x54] & val) ^ 0xf0)
|
||||
{
|
||||
sis501->pci_conf[0x54] = val;
|
||||
sis501_recalcmapping(sis501);
|
||||
sis501.pci_conf[0x54] = val;
|
||||
sis501_recalcmapping();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((addr >= 4 && addr < 8) || addr >= 0x40)
|
||||
sis501->pci_conf[addr] = val;
|
||||
}
|
||||
|
||||
|
||||
static void sis501_turbo_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
sis501_t *sis501 = (sis501_t *)priv;
|
||||
|
||||
uint8_t valxor = val ^ sis501->turbo_reg;
|
||||
|
||||
sis501->turbo_reg = val;
|
||||
|
||||
if ((val & 4) && (valxor & 4))
|
||||
{
|
||||
if (sis501->turbo_reg & 2)
|
||||
resetpchard();
|
||||
else
|
||||
softresetx86();
|
||||
}
|
||||
sis501.pci_conf[addr] = val;
|
||||
}
|
||||
|
||||
|
||||
static void sis503_write(int func, int addr, uint8_t val, void *p)
|
||||
{
|
||||
sis503_t *sis503 = (sis503_t *)p;
|
||||
//pclog("sis503_write : addr=%02x val=%02x\n", addr, val);
|
||||
/* pclog("sis503_write : addr=%02x val=%02x\n", addr, val); */
|
||||
|
||||
if ((addr >= 4 && addr < 8) || addr >= 0x0f)
|
||||
sis503->pci_conf[addr] = val;
|
||||
if (func > 0)
|
||||
return;
|
||||
|
||||
if (addr >= 0x0f && addr < 0x41)
|
||||
return;
|
||||
|
||||
switch(addr)
|
||||
{
|
||||
case 0x00: case 0x01: case 0x02: case 0x03:
|
||||
case 0x08: case 0x09: case 0x0a: case 0x0b:
|
||||
case 0x0e:
|
||||
return;
|
||||
|
||||
case 0x04: /*Command register*/
|
||||
val &= 0x08;
|
||||
val |= 0x07;
|
||||
break;
|
||||
case 0x05:
|
||||
val = 0;
|
||||
break;
|
||||
|
||||
case 0x06: /*Status*/
|
||||
val = 0;
|
||||
break;
|
||||
case 0x07:
|
||||
val = 0x02;
|
||||
break;
|
||||
|
||||
case 0x41:
|
||||
pclog("Set IRQ routing: INT A -> %02X\n", val);
|
||||
if (val & 0x80)
|
||||
pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED);
|
||||
else
|
||||
pci_set_irq_routing(PCI_INTA, val & 0xf);
|
||||
break;
|
||||
case 0x42:
|
||||
pclog("Set IRQ routing: INT B -> %02X\n", val);
|
||||
if (val & 0x80)
|
||||
pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED);
|
||||
else
|
||||
pci_set_irq_routing(PCI_INTC, val & 0xf);
|
||||
break;
|
||||
case 0x43:
|
||||
pclog("Set IRQ routing: INT C -> %02X\n", val);
|
||||
if (val & 0x80)
|
||||
pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED);
|
||||
else
|
||||
pci_set_irq_routing(PCI_INTB, val & 0xf);
|
||||
break;
|
||||
case 0x44:
|
||||
pclog("Set IRQ routing: INT D -> %02X\n", val);
|
||||
if (val & 0x80)
|
||||
pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED);
|
||||
else
|
||||
pci_set_irq_routing(PCI_INTD, val & 0xf);
|
||||
break;
|
||||
}
|
||||
|
||||
sis503.pci_conf[addr] = val;
|
||||
}
|
||||
|
||||
|
||||
static void sis50x_write(uint16_t port, uint8_t val, void *priv)
|
||||
static void sis50x_isa_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
sis50x_t *sis50x = (sis50x_t *)priv;
|
||||
|
||||
if (port & 1)
|
||||
{
|
||||
if (sis50x->reg <= 0xB) sis50x->isa_conf[sis50x->reg] = val;
|
||||
if (sis50x_isa.reg <= 0xB) sis50x_isa.isa_conf[sis50x_isa.reg] = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
sis50x->reg = val;
|
||||
sis50x_isa.reg = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t sis501_read(int func, int addr, void *p)
|
||||
{
|
||||
sis501_t *sis501 = (sis501_t *)p;
|
||||
|
||||
return sis501->pci_conf[addr];
|
||||
if (func)
|
||||
return 0xff;
|
||||
|
||||
return sis501.pci_conf[addr];
|
||||
}
|
||||
|
||||
|
||||
static uint8_t sis501_turbo_read(uint16_t port, void *priv)
|
||||
{
|
||||
sis501_t *sis501 = (sis501_t *)priv;
|
||||
|
||||
return sis501->turbo_reg;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t sis503_read(int func, int addr, void *p)
|
||||
{
|
||||
sis503_t *sis503 = (sis503_t *)p;
|
||||
|
||||
return sis503->pci_conf[addr];
|
||||
if (func > 0)
|
||||
return 0xff;
|
||||
|
||||
return sis503.pci_conf[addr];
|
||||
}
|
||||
|
||||
|
||||
static uint8_t sis50x_read(uint16_t port, void *priv)
|
||||
static uint8_t sis50x_isa_read(uint16_t port, void *priv)
|
||||
{
|
||||
sis50x_t *sis50x = (sis50x_t *)priv;
|
||||
|
||||
if (port & 1)
|
||||
{
|
||||
if (sis50x->reg <= 0xB)
|
||||
return sis50x->isa_conf[sis50x->reg];
|
||||
if (sis50x_isa.reg <= 0xB)
|
||||
return sis50x_isa.isa_conf[sis50x_isa.reg];
|
||||
else
|
||||
return 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
return sis50x->reg;
|
||||
return sis50x_isa.reg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *sis501_init(void)
|
||||
static void sis501_reset(void)
|
||||
{
|
||||
sis501_t *sis501 = malloc(sizeof(sis501_t));
|
||||
memset(sis501, 0, sizeof(sis501_t));
|
||||
memset(&sis501, 0, sizeof(sis501_t));
|
||||
sis501.pci_conf[0x00] = 0x39; /*SiS*/
|
||||
sis501.pci_conf[0x01] = 0x10;
|
||||
sis501.pci_conf[0x02] = 0x06; /*501/502*/
|
||||
sis501.pci_conf[0x03] = 0x04;
|
||||
|
||||
// io_sethandler(0x0cf9, 0x0001, sis501_turbo_read, NULL, NULL, sis501_turbo_write, NULL, NULL, sis501);
|
||||
|
||||
// pci_add_specific(5, sis501_read, sis501_write, sis501);
|
||||
pci_add_specific(0, sis501_read, sis501_write, sis501);
|
||||
|
||||
sis501->pci_conf[0x00] = 0x39; /*SiS*/
|
||||
sis501->pci_conf[0x01] = 0x10;
|
||||
sis501->pci_conf[0x02] = 0x06; /*501/502*/
|
||||
sis501->pci_conf[0x03] = 0x04;
|
||||
sis501.pci_conf[0x04] = 7;
|
||||
sis501.pci_conf[0x05] = 0;
|
||||
|
||||
sis501->pci_conf[0x04] = 7;
|
||||
sis501->pci_conf[0x05] = 0;
|
||||
|
||||
sis501->pci_conf[0x06] = 0x80;
|
||||
sis501->pci_conf[0x07] = 0x02;
|
||||
sis501.pci_conf[0x06] = 0x80;
|
||||
sis501.pci_conf[0x07] = 0x02;
|
||||
|
||||
sis501->pci_conf[0x08] = 0; /*Device revision*/
|
||||
sis501.pci_conf[0x08] = 0; /*Device revision*/
|
||||
|
||||
sis501->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/
|
||||
sis501->pci_conf[0x0a] = 0x00;
|
||||
sis501->pci_conf[0x0b] = 0x06;
|
||||
sis501.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/
|
||||
sis501.pci_conf[0x0a] = 0x00;
|
||||
sis501.pci_conf[0x0b] = 0x06;
|
||||
|
||||
sis501->pci_conf[0x0e] = 0x00; /*Single function device*/
|
||||
sis501.pci_conf[0x0e] = 0x00; /*Single function device*/
|
||||
|
||||
sis501.pci_conf[0x50] = 0xbc;
|
||||
sis501.pci_conf[0x51] = 0xfb;
|
||||
sis501.pci_conf[0x52] = 0xad;
|
||||
sis501.pci_conf[0x53] = 0xfe;
|
||||
|
||||
shadowbios = 1;
|
||||
|
||||
return sis501;
|
||||
}
|
||||
|
||||
|
||||
static void *sis503_init(void)
|
||||
void sis501_init(void)
|
||||
{
|
||||
sis503_t *sis503 = malloc(sizeof(sis503_t));
|
||||
memset(sis503, 0, sizeof(sis503_t));
|
||||
pci_add_card(0, sis501_read, sis501_write, NULL);
|
||||
|
||||
// pci_add_specific(6, sis503_read, sis503_write, sis503);
|
||||
pci_add_specific(1, sis503_read, sis503_write, sis503);
|
||||
sis501_reset();
|
||||
|
||||
pci_reset_handler.pci_master_reset = NULL;
|
||||
}
|
||||
|
||||
void sis503_reset(void)
|
||||
{
|
||||
memset(&sis503, 0, sizeof(sis503_t));
|
||||
sis503.pci_conf[0x00] = 0x39; /*SiS*/
|
||||
sis503.pci_conf[0x01] = 0x10;
|
||||
sis503.pci_conf[0x02] = 0x08; /*503*/
|
||||
sis503.pci_conf[0x03] = 0x00;
|
||||
|
||||
sis503.pci_conf[0x04] = 7;
|
||||
sis503.pci_conf[0x05] = 0;
|
||||
|
||||
sis503.pci_conf[0x06] = 0x80;
|
||||
sis503.pci_conf[0x07] = 0x02;
|
||||
|
||||
sis503->pci_conf[0x00] = 0x39; /*SiS*/
|
||||
sis503->pci_conf[0x01] = 0x10;
|
||||
sis503->pci_conf[0x02] = 0x08; /*503*/
|
||||
sis503->pci_conf[0x03] = 0x00;
|
||||
sis503.pci_conf[0x08] = 0; /*Device revision*/
|
||||
|
||||
sis503->pci_conf[0x04] = 7;
|
||||
sis503->pci_conf[0x05] = 0;
|
||||
|
||||
sis503->pci_conf[0x06] = 0x80;
|
||||
sis503->pci_conf[0x07] = 0x02;
|
||||
sis503.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/
|
||||
sis503.pci_conf[0x0a] = 0x01;
|
||||
sis503.pci_conf[0x0b] = 0x06;
|
||||
|
||||
sis503->pci_conf[0x08] = 0; /*Device revision*/
|
||||
sis503.pci_conf[0x0e] = 0x00; /*Single function device*/
|
||||
|
||||
sis503->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/
|
||||
sis503->pci_conf[0x0a] = 0x01;
|
||||
sis503->pci_conf[0x0b] = 0x06;
|
||||
sis503.pci_conf[0x41] = sis503.pci_conf[0x42] = sis503.pci_conf[0x43] = sis503.pci_conf[0x44] = 0x80;
|
||||
}
|
||||
|
||||
void sis503_init(int card)
|
||||
{
|
||||
|
||||
sis503->pci_conf[0x0e] = 0x00; /*Single function device*/
|
||||
pci_add_card(card, sis503_read, sis503_write, NULL);
|
||||
|
||||
return sis503;
|
||||
sis503_reset();
|
||||
|
||||
trc_init();
|
||||
|
||||
port_92_reset();
|
||||
|
||||
port_92_add();
|
||||
|
||||
pci_reset_handler.pci_set_reset = sis503_reset;
|
||||
}
|
||||
|
||||
|
||||
static void *sis50x_init(void)
|
||||
void sis50x_isa_init(void)
|
||||
{
|
||||
sis50x_t *sis50x = malloc(sizeof(sis50x_t));
|
||||
memset(sis50x, 0, sizeof(sis50x_t));
|
||||
memset(&sis50x_isa, 0, sizeof(sis50x_isa_t));
|
||||
|
||||
io_sethandler(0x22, 0x0002, sis50x_read, NULL, NULL, sis50x_write, NULL, NULL, sis50x);
|
||||
io_sethandler(0x22, 0x0002, sis50x_isa_read, NULL, NULL, sis50x_isa_write, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void sis501_close(void *p)
|
||||
{
|
||||
sis501_t *sis501 = (sis501_t *)p;
|
||||
|
||||
free(sis501);
|
||||
}
|
||||
|
||||
|
||||
static void sis503_close(void *p)
|
||||
{
|
||||
sis503_t *sis503 = (sis503_t *)p;
|
||||
|
||||
free(sis503);
|
||||
}
|
||||
|
||||
|
||||
static void sis50x_close(void *p)
|
||||
{
|
||||
sis50x_t *sis50x = (sis50x_t *)p;
|
||||
|
||||
free(sis50x);
|
||||
}
|
||||
|
||||
|
||||
device_t sis501_device =
|
||||
{
|
||||
"SiS 501/502",
|
||||
0,
|
||||
sis501_init,
|
||||
sis501_close,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
device_t sis503_device =
|
||||
{
|
||||
"SiS 503",
|
||||
0,
|
||||
sis503_init,
|
||||
sis503_close,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
device_t sis50x_device =
|
||||
{
|
||||
"SiS 50x ISA",
|
||||
0,
|
||||
sis50x_init,
|
||||
sis50x_close,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
@@ -12,6 +12,6 @@
|
||||
* Copyright 2017 Miran Grca.
|
||||
*/
|
||||
|
||||
extern device_t sis501_device;
|
||||
extern device_t sis503_device;
|
||||
extern device_t sis50x_device;
|
||||
void sis501_init(void);
|
||||
void sis503_init(int card);
|
||||
void sis50x_isa_init(void);
|
||||
|
@@ -1,123 +1,81 @@
|
||||
/*12log2(r) * 4096
|
||||
|
||||
freq = 2^((in - 0xe000) / 4096)*/
|
||||
/*LFO - lowest (0.042 Hz) = 2^20 steps = 1048576
|
||||
highest (10.72 Hz) = 2^12 steps = 4096*/
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "../ibm.h"
|
||||
#include "../device.h"
|
||||
#include "../io.h"
|
||||
#include "../mem.h"
|
||||
#include "../rom.h"
|
||||
#include "../timer.h"
|
||||
#include "../device.h"
|
||||
#include "sound.h"
|
||||
#include "snd_emu8k.h"
|
||||
#include "../timer.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
#if !defined FILTER_INITIAL && !defined FILTER_MOOG && !defined FILTER_CONSTANT
|
||||
/* #define FILTER_INITIAL */
|
||||
#define FILTER_MOOG
|
||||
/* #define FILTER_CONSTANT */
|
||||
#endif
|
||||
|
||||
#if !defined RESAMPLER_LINEAR && !defined RESAMPLER_CUBIC
|
||||
/* #define RESAMPLER_LINEAR */
|
||||
#define RESAMPLER_CUBIC
|
||||
#endif
|
||||
|
||||
/* #define EMU8K_DEBUG_REGISTERS */
|
||||
|
||||
char *PORT_NAMES[][8]={
|
||||
/* Data 0 ( 0x620/0x622) */
|
||||
{ /* Register 0 */
|
||||
"AWE_CPF",
|
||||
/* Register 1 */
|
||||
"AWE_PTRX",
|
||||
/* Register 2 */
|
||||
"AWE_CVCF",
|
||||
/* Register 3 */
|
||||
"AWE_VTFT",
|
||||
/* Register 4 */
|
||||
"Unk-620-4",
|
||||
/* Register 5 */
|
||||
"Unk-620-5",
|
||||
/* Register 6 */
|
||||
"AWE_PSST",
|
||||
/* Register 7 */
|
||||
"AWE_CSL",
|
||||
},
|
||||
/* Data 1 0xA20 */
|
||||
{ /* Register 0 */
|
||||
"AWE_CCCA",
|
||||
/* Register 1 */
|
||||
0,
|
||||
/*
|
||||
*
|
||||
"AWE_HWCF4"
|
||||
"AWE_HWCF5"
|
||||
"AWE_HWCF6"
|
||||
"AWE_HWCF7"
|
||||
"AWE_SMALR"
|
||||
"AWE_SMARR"
|
||||
"AWE_SMALW"
|
||||
"AWE_SMARW"
|
||||
"AWE_SMLD"
|
||||
"AWE_SMRD"
|
||||
"AWE_WC"
|
||||
"AWE_HWCF1"
|
||||
"AWE_HWCF2"
|
||||
"AWE_HWCF3"
|
||||
*/
|
||||
/* Register 2 */
|
||||
0, /* "AWE_INIT1", */
|
||||
/* Register 3 */
|
||||
0, /* "AWE_INIT3", */
|
||||
/* Register 4 */
|
||||
"AWE_ENVVOL",
|
||||
/* Register 5 */
|
||||
"AWE_DCYSUSV",
|
||||
/* Register 6 */
|
||||
"AWE_ENVVAL",
|
||||
/* Register 7 */
|
||||
"AWE_DCYSUS",
|
||||
},
|
||||
/* Data 2 0xA22 */
|
||||
{ /* Register 0 */
|
||||
"AWE_CCCA",
|
||||
/* Register 1 */
|
||||
0,
|
||||
/* Register 2 */
|
||||
0, /* "AWE_INIT2", */
|
||||
/* Register 3 */
|
||||
0, /* "AWE_INIT4", */
|
||||
/* Register 4 */
|
||||
"AWE_ATKHLDV",
|
||||
/* Register 5 */
|
||||
"AWE_LFO1VAL",
|
||||
/* Register 6 */
|
||||
"AWE_ATKHLD",
|
||||
/* Register 7 */
|
||||
"AWE_LFO2VAL",
|
||||
},
|
||||
/* Data 3 0xE20 */
|
||||
{ /* Register 0 */
|
||||
"AWE_IP",
|
||||
/* Register 1 */
|
||||
"AWE_IFATN",
|
||||
/* Register 2 */
|
||||
"AWE_PEFE",
|
||||
/* Register 3 */
|
||||
"AWE_FMMOD",
|
||||
/* Register 4 */
|
||||
"AWE_TREMFRQ",
|
||||
/* Register 5 */
|
||||
"AWE_FM2FRQ2",
|
||||
/* Register 6 */
|
||||
0,
|
||||
/* Register 7 */
|
||||
0,
|
||||
},
|
||||
char *PORT_NAMES[][8] =
|
||||
{
|
||||
/* Data 0 ( 0x620/0x622) */
|
||||
{ "AWE_CPF",
|
||||
"AWE_PTRX",
|
||||
"AWE_CVCF",
|
||||
"AWE_VTFT",
|
||||
"Unk-620-4",
|
||||
"Unk-620-5",
|
||||
"AWE_PSST",
|
||||
"AWE_CSL",
|
||||
},
|
||||
/* Data 1 0xA20 */
|
||||
{ "AWE_CCCA",
|
||||
0,
|
||||
/*
|
||||
"AWE_HWCF4"
|
||||
"AWE_HWCF5"
|
||||
"AWE_HWCF6"
|
||||
"AWE_HWCF7"
|
||||
"AWE_SMALR"
|
||||
"AWE_SMARR"
|
||||
"AWE_SMALW"
|
||||
"AWE_SMARW"
|
||||
"AWE_SMLD"
|
||||
"AWE_SMRD"
|
||||
"AWE_WC"
|
||||
"AWE_HWCF1"
|
||||
"AWE_HWCF2"
|
||||
"AWE_HWCF3"
|
||||
*/
|
||||
0,
|
||||
0,
|
||||
"AWE_ENVVOL",
|
||||
"AWE_DCYSUSV",
|
||||
"AWE_ENVVAL",
|
||||
"AWE_DCYSUS",
|
||||
},
|
||||
/* Data 2 0xA22 */
|
||||
{ "AWE_CCCA",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"AWE_ATKHLDV",
|
||||
"AWE_LFO1VAL",
|
||||
"AWE_ATKHLD",
|
||||
"AWE_LFO2VAL",
|
||||
},
|
||||
/* Data 3 0xE20 */
|
||||
{ "AWE_IP",
|
||||
"AWE_IFATN",
|
||||
"AWE_PEFE",
|
||||
"AWE_FMMOD",
|
||||
"AWE_TREMFRQ",
|
||||
"AWE_FM2FRQ2",
|
||||
0,
|
||||
0,
|
||||
},
|
||||
};
|
||||
|
||||
enum
|
||||
@@ -126,9 +84,7 @@ enum
|
||||
ENV_DELAY = 1,
|
||||
ENV_ATTACK = 2,
|
||||
ENV_HOLD = 3,
|
||||
/* ENV_DECAY = 4, */
|
||||
ENV_SUSTAIN = 5,
|
||||
/* ENV_RELEASE = 6, */
|
||||
ENV_RAMP_DOWN = 7,
|
||||
ENV_RAMP_UP = 8
|
||||
};
|
||||
@@ -149,24 +105,27 @@ static float cubic_table[CUBIC_RESOLUTION*4];
|
||||
static int64_t freqtable[65536];
|
||||
/* Conversion from initial attenuation to 16 bit unsigned lineal amplitude (currently only a way to update volume target register) */
|
||||
static int32_t attentable[256];
|
||||
/* Conversion from envelope dbs (once rigth shifted) (0 = 0dBFS, 65535 = -96dbFS and silence ) to 16 bit unsigned lineal amplitude, to convert to current volume. (0 to 65536) */
|
||||
/* Conversion from envelope dbs (once rigth shifted) (0 = 0dBFS, 65535 = -96dbFS and silence ) to 16 bit unsigned lineal amplitude,
|
||||
* to convert to current volume. (0 to 65536) */
|
||||
static int32_t env_vol_db_to_vol_target[65537];
|
||||
/* Same as above, but to convert amplitude (once rigth shifted) (0 to 65536) to db (0 = 0dBFS, 65535 = -96dbFS and silence ). it is needed so that the delay, attack and hold phase can be added to initial attenuation and tremolo */
|
||||
/* Same as above, but to convert amplitude (once rigth shifted) (0 to 65536) to db (0 = 0dBFS, 65535 = -96dbFS and silence ).
|
||||
* it is needed so that the delay, attack and hold phase can be added to initial attenuation and tremolo */
|
||||
static int32_t env_vol_amplitude_to_db[65537];
|
||||
/* Conversion from envelope herts (once right shifted) to octave . it is needed so that the delay, attack and hold phase can be added to initial pitch ,lfos pitch , initial filter and lfo filter */
|
||||
/* Conversion from envelope herts (once right shifted) to octave . it is needed so that the delay, attack and hold phase can be
|
||||
* added to initial pitch ,lfos pitch , initial filter and lfo filter */
|
||||
static int32_t env_mod_hertz_to_octave[65537];
|
||||
/* Conversion from envelope amount to time in samples. */
|
||||
static int32_t env_attack_to_samples[128];
|
||||
/* This table has been generated using the following formula:
|
||||
Get the amount of dBs that have to be added each sample to reach 96dBs in the amount
|
||||
of time determined by the encoded value "i".
|
||||
float d = 1.0/((env_decay_to_millis[i]/96.0)*44.1);
|
||||
int result = round(d*21845);
|
||||
The multiplication by 21845 gives a minimum value of 1, and a maximum accumulated value of 1<<21
|
||||
The accumulated value has to be converted to amplitude, and that can be done with the
|
||||
env_vol_to_amplitude and shifting by 8
|
||||
In other words, the unit of the table is the 1/21845th of a dB per sample frame, to be added or
|
||||
substracted to the accumulating value_db of the envelope. */
|
||||
* Get the amount of dBs that have to be added each sample to reach 96dBs in the amount
|
||||
* of time determined by the encoded value "i".
|
||||
* float d = 1.0/((env_decay_to_millis[i]/96.0)*44.1);
|
||||
* int result = round(d*21845);
|
||||
* The multiplication by 21845 gives a minimum value of 1, and a maximum accumulated value of 1<<21
|
||||
* The accumulated value has to be converted to amplitude, and that can be done with the
|
||||
* env_vol_db_to_vol_target and shifting by 8
|
||||
* In other words, the unit of the table is the 1/21845th of a dB per sample frame, to be added or
|
||||
* substracted to the accumulating value_db of the envelope. */
|
||||
static int32_t env_decay_to_dbs_or_oct[128] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
@@ -179,10 +138,10 @@ static int32_t env_decay_to_dbs_or_oct[128] =
|
||||
1106, 1160, 1219, 1285, 1321, 1399, 1441, 1534, 1585, 1640, 1698, 1829, 1902, 1981, 2068, 2162
|
||||
};
|
||||
/* The table "env_decay_to_millis" is based on the table "decay_time_tbl" found in the freebsd/linux
|
||||
AWE32 driver.
|
||||
I tried calculating it using the instructions in awe32p10 from Judge Dredd, but the formula there
|
||||
is wrong. */
|
||||
/*
|
||||
* AWE32 driver.
|
||||
* I tried calculating it using the instructions in awe32p10 from Judge Dredd, but the formula there
|
||||
* is wrong.
|
||||
*
|
||||
static int32_t env_decay_to_millis[128] = {
|
||||
0, 45120, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082,
|
||||
2828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507,
|
||||
@@ -206,45 +165,44 @@ static double chortable[65536];
|
||||
static const int REV_BUFSIZE_STEP=242;
|
||||
|
||||
|
||||
/* these lines come from the awe32faq, describing the NRPN control for the initial filter
|
||||
where it describes a linear increment filter instead of an octave-incremented one.
|
||||
NRPN LSB 21 (Initial Filter Cutoff)
|
||||
Range : [0, 127]
|
||||
Unit : 62Hz
|
||||
Filter cutoff from 100Hz to 8000Hz */
|
||||
/* These lines come from the awe32faq, describing the NRPN control for the initial filter
|
||||
* where it describes a linear increment filter instead of an octave-incremented one.
|
||||
* NRPN LSB 21 (Initial Filter Cutoff)
|
||||
* Range : [0, 127]
|
||||
* Unit : 62Hz
|
||||
* Filter cutoff from 100Hz to 8000Hz
|
||||
|
||||
/* This table comes from the awe32faq, describing the NRPN control for the filter Q.
|
||||
I don't know if is meant to be interpreted as the actual measured output of the
|
||||
filter or what. Especially, I don't understand the "low" and "high" ranges.
|
||||
What is otherwise documented is that the Q ranges from 0dB to 24dB and the attenuation
|
||||
is half of the Q ( i.e. for 12dB Q, attenuate the input signal with -6dB) */
|
||||
/*InitialFilterCutoff = RegisterValue*31.25Hz+100Hz */
|
||||
/*Coeff Low Fc(Hz)Low Q(dB)High Fc(kHz)High Q(dB)DC Attenuation(dB)
|
||||
0 92 5 Flat Flat -0.0
|
||||
1 93 6 8.5 0.5 -0.5
|
||||
2 94 8 8.3 1 -1.2
|
||||
3 95 10 8.2 2 -1.8
|
||||
4 96 11 8.1 3 -2.5
|
||||
5 97 13 8.0 4 -3.3
|
||||
6 98 14 7.9 5 -4.1
|
||||
7 99 16 7.8 6 -5.5
|
||||
8 100 17 7.7 7 -6.0
|
||||
9 100 19 7.5 9 -6.6
|
||||
10 100 20 7.4 10 -7.2
|
||||
11 100 22 7.3 11 -7.9
|
||||
12 100 23 7.2 13 -8.5
|
||||
13 100 25 7.1 15 -9.3
|
||||
14 100 26 7.1 16 -10.1
|
||||
15 100 28 7.0 18 -11.0
|
||||
*/
|
||||
/* Attenuation as above, codified in amplitude, and Q as in High Q. */
|
||||
* This table comes from the awe32faq, describing the NRPN control for the filter Q.
|
||||
* I don't know if is meant to be interpreted as the actual measured output of the
|
||||
* filter or what. Especially, I don't understand the "low" and "high" ranges.
|
||||
* What is otherwise documented is that the Q ranges from 0dB to 24dB and the attenuation
|
||||
* is half of the Q ( i.e. for 12dB Q, attenuate the input signal with -6dB)
|
||||
Coeff Low Fc(Hz)Low Q(dB)High Fc(kHz)High Q(dB)DC Attenuation(dB)
|
||||
* 0 92 5 Flat Flat -0.0
|
||||
* 1 93 6 8.5 0.5 -0.5
|
||||
* 2 94 8 8.3 1 -1.2
|
||||
* 3 95 10 8.2 2 -1.8
|
||||
* 4 96 11 8.1 3 -2.5
|
||||
* 5 97 13 8.0 4 -3.3
|
||||
* 6 98 14 7.9 5 -4.1
|
||||
* 7 99 16 7.8 6 -5.5
|
||||
* 8 100 17 7.7 7 -6.0
|
||||
* 9 100 19 7.5 9 -6.6
|
||||
* 10 100 20 7.4 10 -7.2
|
||||
* 11 100 22 7.3 11 -7.9
|
||||
* 12 100 23 7.2 13 -8.5
|
||||
* 13 100 25 7.1 15 -9.3
|
||||
* 14 100 26 7.1 16 -10.1
|
||||
* 15 100 28 7.0 18 -11.0
|
||||
*
|
||||
* Attenuation as above, codified in amplitude.*/
|
||||
static int32_t filter_atten[16] =
|
||||
{
|
||||
65536, 61869, 57079, 53269, 49145, 44820, 40877, 34792, 32845, 30653, 28607,
|
||||
26392, 24630, 22463, 20487, 18470
|
||||
};
|
||||
|
||||
|
||||
/*Coefficients for the filters for a defined Q and cutoff.*/
|
||||
static int32_t filt_coeffs[16][256][3];
|
||||
|
||||
#define READ16_SWITCH(addr, var) switch ((addr) & 2) \
|
||||
@@ -267,9 +225,10 @@ uint32_t rep_count_r = 0;
|
||||
uint32_t rep_count_w = 0;
|
||||
|
||||
# define READ16(addr, var) READ16_SWITCH(addr, var) \
|
||||
if ((addr) & 2) { \
|
||||
{ \
|
||||
const char *name=0; \
|
||||
switch(addr) { \
|
||||
switch(addr) \
|
||||
{ \
|
||||
case 0x620: case 0x622: \
|
||||
name = PORT_NAMES[0][emu8k->cur_reg]; \
|
||||
break; \
|
||||
@@ -280,16 +239,20 @@ uint32_t rep_count_w = 0;
|
||||
name = PORT_NAMES[2][emu8k->cur_reg]; \
|
||||
break; \
|
||||
} \
|
||||
if (name == 0) { \
|
||||
if (name == 0) \
|
||||
{ \
|
||||
/*pclog("EMU8K READ %04X-%02X(%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_voice,ret);*/ \
|
||||
} else { \
|
||||
/*pclog("EMU8K READ %s (%d): %04X\n",name,emu8k->cur_voice, ret);*/ \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
pclog("EMU8K READ %s(%d) (%d): %04X\n",name, (addr&0x2), emu8k->cur_voice, ret); \
|
||||
}\
|
||||
}
|
||||
# define WRITE16(addr, var, val) WRITE16_SWITCH(addr, var, val) \
|
||||
if ((addr) & 2) { \
|
||||
{ \
|
||||
const char *name=0; \
|
||||
switch(addr) { \
|
||||
switch(addr) \
|
||||
{ \
|
||||
case 0x620: case 0x622: \
|
||||
name = PORT_NAMES[0][emu8k->cur_reg]; \
|
||||
break; \
|
||||
@@ -300,17 +263,20 @@ uint32_t rep_count_w = 0;
|
||||
name = PORT_NAMES[2][emu8k->cur_reg]; \
|
||||
break; \
|
||||
} \
|
||||
if (name == 0) { \
|
||||
if (name == 0) \
|
||||
{ \
|
||||
/*pclog("EMU8K WRITE %04X-%02X(%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_voice, val);*/ \
|
||||
} else { \
|
||||
pclog("EMU8K WRITE %s (%d): %04X\n",name,emu8k->cur_voice, val); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
pclog("EMU8K WRITE %s(%d) (%d): %04X\n",name, (addr&0x2), emu8k->cur_voice,val); \
|
||||
}\
|
||||
}
|
||||
|
||||
#else
|
||||
# define READ16(addr, var) READ16_SWITCH(addr, var)
|
||||
# define WRITE16(addr, var, val) WRITE16_SWITCH(addr, var, val)
|
||||
#endif /* EMU8K_DEBUG_REGISTERS */
|
||||
#endif /* EMU8K_DEBUG_REGISTERS */
|
||||
|
||||
|
||||
static inline int16_t EMU8K_READ(emu8k_t *emu8k, uint32_t addr)
|
||||
@@ -319,22 +285,20 @@ static inline int16_t EMU8K_READ(emu8k_t *emu8k, uint32_t addr)
|
||||
return emu8k->ram_pointers[addrmem.hb_address][addrmem.lw_address];
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline int16_t EMU8K_READ_INTERP_LINEAR(emu8k_t *emu8k, uint32_t int_addr, uint16_t fract)
|
||||
{
|
||||
/* The interpolation in AWE32 used a so-called patented 3-point interpolation
|
||||
( I guess some sort of spline having one point before and one point after).
|
||||
Also, it has the consequence that the playback is delayed by one sample.
|
||||
I simulate the "one sample later" than the address with addr+1 and addr+2
|
||||
instead of +0 and +1 */
|
||||
* ( I guess some sort of spline having one point before and one point after).
|
||||
* Also, it has the consequence that the playback is delayed by one sample.
|
||||
* I simulate the "one sample later" than the address with addr+1 and addr+2
|
||||
* instead of +0 and +1 */
|
||||
int16_t dat1 = EMU8K_READ(emu8k, int_addr+1);
|
||||
int32_t dat2 = EMU8K_READ(emu8k, int_addr+2);
|
||||
dat1 += ((dat2-(int32_t)dat1)* fract) >> 16;
|
||||
return dat1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int16_t EMU8K_READ_INTERP_CUBIC(emu8k_t *emu8k, uint32_t int_addr, uint16_t fract)
|
||||
static inline int32_t EMU8K_READ_INTERP_CUBIC(emu8k_t *emu8k, uint32_t int_addr, uint16_t fract)
|
||||
{
|
||||
/*Since there are four floats in the table for each fraction, the position is 16byte aligned. */
|
||||
fract >>= 16-CUBIC_RESOLUTION_LOG;
|
||||
@@ -369,11 +333,11 @@ static inline void EMU8K_WRITE(emu8k_t *emu8k, uint32_t addr, uint16_t val)
|
||||
return;
|
||||
|
||||
/* It looks like if an application writes to a memory part outside of the available
|
||||
amount on the card, it wraps, and opencubicplayer uses that to detect the amount
|
||||
of memory, as opposed to simply check at the address that it has just tried to write. */
|
||||
while (addr >= emu8k->ram_end_addr) {
|
||||
* amount on the card, it wraps, and opencubicplayer uses that to detect the amount
|
||||
* of memory, as opposed to simply check at the address that it has just tried to write. */
|
||||
while (addr >= emu8k->ram_end_addr)
|
||||
addr -= emu8k->ram_end_addr - EMU8K_RAM_MEM_START;
|
||||
}
|
||||
|
||||
emu8k->ram[addr - EMU8K_RAM_MEM_START] = val;
|
||||
}
|
||||
|
||||
@@ -381,7 +345,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p)
|
||||
{
|
||||
emu8k_t *emu8k = (emu8k_t *)p;
|
||||
uint16_t ret = 0xffff;
|
||||
|
||||
|
||||
#ifdef EMU8K_DEBUG_REGISTERS
|
||||
if (addr == 0xE22)
|
||||
{
|
||||
@@ -421,6 +385,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p)
|
||||
last_read=tmpz;
|
||||
pclog("EMU8K READ RAM I/O or configuration or clock \n");
|
||||
}
|
||||
/* pclog("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); */
|
||||
}
|
||||
else if ((addr&0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3))
|
||||
{
|
||||
@@ -435,6 +400,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p)
|
||||
last_read=tmpz;
|
||||
pclog("EMU8K READ INIT \n");
|
||||
}
|
||||
/* pclog("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); */
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -454,7 +420,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p)
|
||||
case 5: val = emu8k->voice[emu8k->cur_voice].dcysusv; break;
|
||||
case 6: val = emu8k->voice[emu8k->cur_voice].envval; break;
|
||||
case 7: val = emu8k->voice[emu8k->cur_voice].dcysus; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (addr == 0xA22)
|
||||
{
|
||||
@@ -507,7 +473,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p)
|
||||
|
||||
switch (addr & 0xF02)
|
||||
{
|
||||
case 0x600: case 0x602: /*Data0*/ /* also known as BLASTER+0x400 and EMU+0x000 */
|
||||
case 0x600: case 0x602: /*Data0. also known as BLASTER+0x400 and EMU+0x000 */
|
||||
switch (emu8k->cur_reg)
|
||||
{
|
||||
case 0:
|
||||
@@ -544,7 +510,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA00: /*Data1*/ /* also known as BLASTER+0x800 and EMU+0x400 */
|
||||
case 0xA00: /*Data1. also known as BLASTER+0x800 and EMU+0x400 */
|
||||
switch (emu8k->cur_reg)
|
||||
{
|
||||
case 0:
|
||||
@@ -560,7 +526,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p)
|
||||
case 10:
|
||||
READ16(addr, emu8k->hwcf5);
|
||||
return ret;
|
||||
/* Actually, these two might be command words rather than registers, or some LFO position/buffer reset. */
|
||||
/* Actually, these two might be command words rather than registers, or some LFO position/buffer reset.*/
|
||||
case 13:
|
||||
READ16(addr, emu8k->hwcf6);
|
||||
return ret;
|
||||
@@ -620,7 +586,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA02: /*Data2*/ /* also known as BLASTER+0x802 and EMU+0x402 */
|
||||
case 0xA02: /*Data2. also known as BLASTER+0x802 and EMU+0x402 */
|
||||
switch (emu8k->cur_reg)
|
||||
{
|
||||
case 0:
|
||||
@@ -652,17 +618,17 @@ uint16_t emu8k_inw(uint16_t addr, void *p)
|
||||
return ret;
|
||||
case 21:
|
||||
READ16(addr, emu8k->smarr|dmareadbit);
|
||||
/* xor with itself to set to zero faster. */
|
||||
/* xor with itself to set to zero faster.*/
|
||||
dmareadbit^=dmareadbit;
|
||||
return ret;
|
||||
case 22:
|
||||
READ16(addr, emu8k->smalw|dmawritebit);
|
||||
/* xor with itself to set to zero faster. */
|
||||
/*xor with itself to set to zero faster.*/
|
||||
dmawritebit^=dmawritebit;
|
||||
return ret;
|
||||
case 23:
|
||||
READ16(addr, emu8k->smarw|dmawritebit);
|
||||
/* xor with itself to set to zero faster. */
|
||||
/*xor with itself to set to zero faster.*/
|
||||
dmawritebit^=dmawritebit;
|
||||
return ret;
|
||||
|
||||
@@ -701,7 +667,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE00: /*Data3*/ /* also known as BLASTER+0xC00 and EMU+0x800 */
|
||||
case 0xE00: /*Data3. also known as BLASTER+0xC00 and EMU+0x800 */
|
||||
switch (emu8k->cur_reg)
|
||||
{
|
||||
case 0:
|
||||
@@ -730,12 +696,12 @@ uint16_t emu8k_inw(uint16_t addr, void *p)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE02: /* Pointer */ /* also known as BLASTER+0xC02 and EMU+0x802 */
|
||||
case 0xE02: /* Pointer. also known as BLASTER+0xC02 and EMU+0x802 */
|
||||
/* LS five bits = channel number, next 3 bits = register number
|
||||
and MS 8 bits = VLSI test register.
|
||||
Impulse tracker tests the non variability of the LS byte that it has set, and the variability
|
||||
of the MS byte to determine that it really is an AWE32.
|
||||
cubic player has a similar code, where it waits until value & 0x1000 is nonzero, and then waits again until it changes to zero. */
|
||||
* and MS 8 bits = VLSI test register.
|
||||
* Impulse tracker tests the non variability of the LS byte that it has set, and the variability
|
||||
* of the MS byte to determine that it really is an AWE32.
|
||||
* cubic player has a similar code, where it waits until value & 0x1000 is nonzero, and then waits again until it changes to zero.*/
|
||||
random_helper = (random_helper + 1) & 0x1F;
|
||||
return ((0x80 | random_helper) << 8) | (emu8k->cur_reg << 5) | emu8k->cur_voice;
|
||||
}
|
||||
@@ -747,8 +713,8 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
{
|
||||
emu8k_t *emu8k = (emu8k_t *)p;
|
||||
|
||||
/* TODO: I would like to not call this here, but i found it was needed or else cubic player would not finish opening (take a looot more of time than usual).
|
||||
Basically, being here means that the audio is generated in the emulation thread, instead of the audio thread. */
|
||||
/*TODO: I would like to not call this here, but i found it was needed or else cubic player would not finish opening (take a looot more of time than usual).
|
||||
* Basically, being here means that the audio is generated in the emulation thread, instead of the audio thread.*/
|
||||
emu8k_update(emu8k);
|
||||
|
||||
#ifdef EMU8K_DEBUG_REGISTERS
|
||||
@@ -789,9 +755,10 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
last_write=tmpz;
|
||||
pclog("EMU8K WRITE RAM I/O or configuration \n");
|
||||
}
|
||||
/* pclog("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); */
|
||||
}
|
||||
else if ((addr&0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3))
|
||||
{
|
||||
{
|
||||
uint32_t tmpz = ((addr&0xF00) << 16);
|
||||
if (tmpz != last_write)
|
||||
{
|
||||
@@ -803,6 +770,7 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
last_write=tmpz;
|
||||
pclog("EMU8K WRITE INIT \n");
|
||||
}
|
||||
/* pclog("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); */
|
||||
}
|
||||
else if (addr != 0xE22)
|
||||
{
|
||||
@@ -847,12 +815,12 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
|
||||
switch (addr & 0xF02)
|
||||
{
|
||||
case 0x600: case 0x602: /*Data0*/
|
||||
case 0x600: case 0x602: /*Data0. also known as BLASTER+0x400 and EMU+0x000 */
|
||||
switch (emu8k->cur_reg)
|
||||
{
|
||||
case 0:
|
||||
WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val);
|
||||
/* The docs says that this value is constantly updating, and it should have no actual effect. Actions should be done over ptrx */
|
||||
WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val);
|
||||
return;
|
||||
|
||||
case 1:
|
||||
@@ -898,7 +866,7 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA00: /*Data1*/
|
||||
case 0xA00: /*Data1. also known as BLASTER+0x800 and EMU+0x400 */
|
||||
switch (emu8k->cur_reg)
|
||||
{
|
||||
case 0:
|
||||
@@ -1031,14 +999,15 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
emu8k->voice[emu8k->cur_voice].env_engine_on = DCYSUSV_GENERATOR_ENGINE_ON(val);
|
||||
|
||||
if (emu8k->voice[emu8k->cur_voice].env_engine_on &&
|
||||
old_on != emu8k->voice[emu8k->cur_voice].env_engine_on) {
|
||||
old_on != emu8k->voice[emu8k->cur_voice].env_engine_on)
|
||||
{
|
||||
if (emu8k->hwcf3 != 0x04 && emu8k->cur_voice == 31)
|
||||
{
|
||||
/* This is a hack for some programs like Doom or cubic player 1.7 that don't initialize
|
||||
the hwcfg and init registers (doom does not init the card at all. only tests the cfg registers) */
|
||||
emu8k->hwcf3 = 0x04;
|
||||
}
|
||||
|
||||
|
||||
/* reset lfos. */
|
||||
emu8k->voice[emu8k->cur_voice].lfo1_count.addr = 0;
|
||||
emu8k->voice[emu8k->cur_voice].lfo2_count.addr = 0;
|
||||
@@ -1065,7 +1034,6 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
vol_env->state = ENV_HOLD;
|
||||
}*/
|
||||
}
|
||||
pclog("triggering: %d\n", vol_env->state);
|
||||
}
|
||||
|
||||
if (ATKHLD_TRIGGER(emu8k->voice[emu8k->cur_voice].atkhld))
|
||||
@@ -1117,7 +1085,7 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
emu8k->voice[emu8k->cur_voice].envval = val;
|
||||
emu8k->voice[emu8k->cur_voice].mod_envelope.delay_samples = ENVVAL_TO_EMU_SAMPLES(val);
|
||||
return;
|
||||
|
||||
|
||||
case 7:
|
||||
{
|
||||
/* TODO: Look for a bug on delay (first trigger it works, next trigger it doesn't) */
|
||||
@@ -1142,7 +1110,7 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA02: /*Data2*/
|
||||
case 0xA02: /*Data2. also known as BLASTER+0x802 and EMU+0x402 */
|
||||
switch (emu8k->cur_reg)
|
||||
{
|
||||
case 0:
|
||||
@@ -1175,20 +1143,15 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
{
|
||||
/* The scale of this value is unknown. I've taken it as milliHz.
|
||||
* Another interpretation could be periods. (and so, Hz = 1/period)*/
|
||||
double osc_speed = emu8k->hwcf5; /* *1.316; */
|
||||
#if 1 /* milliHz */
|
||||
double osc_speed = emu8k->hwcf5;/* *1.316; */
|
||||
/*milliHz to lfotable samples.*/
|
||||
osc_speed *= 65.536/44100.0;
|
||||
#elif 0 /* periods */
|
||||
/* 44.1Khz ticks to lfotable samples.*/
|
||||
osc_speed = 65.536/osc_speed;
|
||||
#endif
|
||||
/*left shift 32bits for 32.32 fixed.point*/
|
||||
osc_speed *= 65536.0*65536.0;
|
||||
emu8k->chorus_engine.lfo_inc.addr = (uint64_t)osc_speed;
|
||||
}
|
||||
return;
|
||||
/* Actually, these two might be command words rather than registers, or some LFO position/buffer reset. */
|
||||
/* Actually, these two might be command words rather than registers, or some LFO position/buffer reset.*/
|
||||
case 13:
|
||||
WRITE16(addr, emu8k->hwcf6, val);
|
||||
return;
|
||||
@@ -1196,18 +1159,18 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
WRITE16(addr, emu8k->hwcf7, val);
|
||||
return;
|
||||
|
||||
case 20: /* Top 8 bits are for Empty (MT) bit or non-addressable. */
|
||||
case 20: /*Top 8 bits are for Empty (MT) bit or non-addressable.*/
|
||||
WRITE16(addr, emu8k->smalr, val&0xFF);
|
||||
dmareadbit=0x8000;
|
||||
return;
|
||||
case 21: /* Top 8 bits are for Empty (MT) bit or non-addressable. */
|
||||
case 21: /*Top 8 bits are for Empty (MT) bit or non-addressable.*/
|
||||
WRITE16(addr, emu8k->smarr, val&0xFF);
|
||||
dmareadbit=0x8000;
|
||||
return;
|
||||
case 22: /* Top 8 bits are for full bit or non-addressable. */
|
||||
case 22: /*Top 8 bits are for full bit or non-addressable.*/
|
||||
WRITE16(addr, emu8k->smalw, val&0xFF);
|
||||
return;
|
||||
case 23: /* Top 8 bits are for full bit or non-addressable. */
|
||||
case 23: /*Top 8 bits are for full bit or non-addressable.*/
|
||||
WRITE16(addr, emu8k->smarw, val&0xFF);
|
||||
return;
|
||||
|
||||
@@ -1219,7 +1182,6 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
}
|
||||
break;
|
||||
|
||||
/* TODO: Read Reverb, Chorus and equalizer setups */
|
||||
case 2:
|
||||
emu8k->init2[emu8k->cur_voice] = val;
|
||||
/* Skip if in first/second initialization step */
|
||||
@@ -1346,7 +1308,6 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
vol_env->state = ENV_HOLD;
|
||||
}*/
|
||||
}
|
||||
pclog("triggering: %d\n", vol_env->state);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -1407,7 +1368,7 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE00: /*Data3*/
|
||||
case 0xE00: /*Data3. also known as BLASTER+0xC00 and EMU+0x800 */
|
||||
switch (emu8k->cur_reg)
|
||||
{
|
||||
case 0:
|
||||
@@ -1495,19 +1456,20 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE02: /*Pointer*/
|
||||
case 0xE02: /* Pointer. also known as BLASTER+0xC02 and EMU+0x802 */
|
||||
emu8k->cur_voice = (val & 31);
|
||||
emu8k->cur_reg = ((val >> 5) & 7);
|
||||
return;
|
||||
}
|
||||
pclog("EMU8K WRITE: Unknown register write: %04X-%02X(%d/%d): %04X \n", addr, (emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg,emu8k->cur_voice, val);
|
||||
pclog("EMU8K WRITE: Unknown register write: %04X-%02X(%d/%d): %04X \n", addr, (emu8k->cur_reg)<<5|emu8k->cur_voice,
|
||||
emu8k->cur_reg,emu8k->cur_voice, val);
|
||||
|
||||
}
|
||||
|
||||
uint8_t emu8k_inb(uint16_t addr, void *p)
|
||||
{
|
||||
/* Reading a single byte is a feature that at least Impulse tracker uses,
|
||||
but only on detection code and not for odd addresses. */
|
||||
* but only on detection code and not for odd addresses.*/
|
||||
if (addr & 1)
|
||||
return emu8k_inw(addr & ~1, p) >> 1;
|
||||
return emu8k_inw(addr, p) & 0xff;
|
||||
@@ -1515,8 +1477,8 @@ uint8_t emu8k_inb(uint16_t addr, void *p)
|
||||
|
||||
void emu8k_outb(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
/* FIXME: AWE32 docs says that you cannot write in bytes, but if
|
||||
an app were to use this, the content of the LSByte would be lost. */
|
||||
/* TODO: AWE32 docs says that you cannot write in bytes, but if
|
||||
* an app were to use this implementation, the content of the LS Byte would be lost.*/
|
||||
if (addr & 1)
|
||||
emu8k_outw(addr & ~1, val << 8, p);
|
||||
else
|
||||
@@ -1532,13 +1494,15 @@ void emu8k_work_chorus(int32_t *inbuf, int32_t *outbuf, emu8k_chorus_eng_t *engi
|
||||
double lfo_inter1 = chortable[engine->lfo_pos.int_address];
|
||||
/* double lfo_inter2 = chortable[(engine->lfo_pos.int_address+1)&0xFFFF]; */
|
||||
|
||||
double offset_lfo =lfo_inter1; /* = lfo_inter1 + ((lfo_inter2-lfo_inter1)*engine->lfo_pos.fract_address/65536.0); */
|
||||
double offset_lfo =lfo_inter1; //= lfo_inter1 + ((lfo_inter2-lfo_inter1)*engine->lfo_pos.fract_address/65536.0);
|
||||
offset_lfo *= engine->lfodepth_multip;
|
||||
|
||||
/* Work left */
|
||||
double readdouble = (double)engine->write - (double)engine->delay_samples_central - offset_lfo;
|
||||
int read = (int32_t)floor(readdouble);
|
||||
int fraction_part = (readdouble - (double)read)*65536.0;
|
||||
if (read < 0)
|
||||
read = 0;
|
||||
int next_value = read + 1;
|
||||
if(read < 0)
|
||||
{
|
||||
@@ -1560,6 +1524,8 @@ void emu8k_work_chorus(int32_t *inbuf, int32_t *outbuf, emu8k_chorus_eng_t *engi
|
||||
/* Work right */
|
||||
readdouble = (double)engine->write - (double)engine->delay_samples_central - engine->delay_offset_samples_right - offset_lfo;
|
||||
read = (int32_t)floor(readdouble);
|
||||
if (read < 0)
|
||||
read = 0;
|
||||
next_value = read + 1;
|
||||
if(read < 0)
|
||||
{
|
||||
@@ -1625,7 +1591,7 @@ int32_t emu8k_reverb_diffuser_work(emu8k_reverb_combfilter_t* comb, int32_t in)
|
||||
int32_t emu8k_reverb_tail_work(emu8k_reverb_combfilter_t* comb, emu8k_reverb_combfilter_t* allpasses, int32_t in)
|
||||
{
|
||||
int32_t output = comb->reflection[comb->read_pos];
|
||||
/* store new value in delayed buffer */
|
||||
/* store new value in delayed buffer */
|
||||
comb->reflection[comb->read_pos] = in;
|
||||
|
||||
/* output = emu8k_reverb_allpass_work(&allpasses[0],output); */
|
||||
@@ -1698,18 +1664,21 @@ void emu8k_work_eq(int32_t *inoutbuf, int count)
|
||||
}
|
||||
|
||||
|
||||
int32_t emu8k_vol_slide(emu8k_slide_t* slide, int32_t target) {
|
||||
if (slide->last < target) {
|
||||
int32_t emu8k_vol_slide(emu8k_slide_t* slide, int32_t target)
|
||||
{
|
||||
if (slide->last < target)
|
||||
{
|
||||
slide->last+=0x400;
|
||||
if (slide->last > target) slide->last = target;
|
||||
} else if (slide->last > target){
|
||||
}
|
||||
else if (slide->last > target)
|
||||
{
|
||||
slide->last-=0x400;
|
||||
if (slide->last < target) slide->last = target;
|
||||
}
|
||||
return slide->last;
|
||||
}
|
||||
|
||||
int32_t older[32]={0};
|
||||
void emu8k_update(emu8k_t *emu8k)
|
||||
{
|
||||
int new_pos = (sound_pos_global * 44100) / 48000;
|
||||
@@ -2059,7 +2028,7 @@ I've recopilated these sentences to get an idea of how to loop
|
||||
|
||||
-Setting the PlayPosition greater than the Loop End Offset, will cause the oscillator to play in reverse, back to the Loop End Offset.
|
||||
It's pretty neat, but appears to be uncontrollable (the rate at which the samples are played in reverse).
|
||||
|
||||
|
||||
-Note that due to interpolator offset, the actual loop point is one greater than the start address
|
||||
-Note that due to interpolator offset, the actual loop point will end at an address one greater than the loop address
|
||||
-Note that the actual audio location is the point 1 word higher than this value due to interpolation offset
|
||||
@@ -2082,19 +2051,14 @@ I've recopilated these sentences to get an idea of how to loop
|
||||
/* Update EMU voice registers. */
|
||||
emu_voice->ccca = (((uint32_t)emu_voice->ccca_qcontrol) << 24) | emu_voice->addr.int_address;
|
||||
emu_voice->cpf_curr_frac_addr = emu_voice->addr.fract_address;
|
||||
|
||||
if ( emu_voice->cvcf_curr_volume != older[c]) {
|
||||
pclog("EMUVOL (%d):%d\n", c, emu_voice->cvcf_curr_volume);
|
||||
older[c]=emu_voice->cvcf_curr_volume;
|
||||
}
|
||||
/* pclog("EMUFILT :%d\n", emu_voice->cvcf_curr_filt_ctoff); */
|
||||
}
|
||||
|
||||
|
||||
buf = &emu8k->buffer[emu8k->pos*2];
|
||||
emu8k_work_reverb(&emu8k->reverb_in_buffer[emu8k->pos], buf, &emu8k->reverb_engine, new_pos-emu8k->pos);
|
||||
emu8k_work_chorus(&emu8k->chorus_in_buffer[emu8k->pos], buf, &emu8k->chorus_engine, new_pos-emu8k->pos);
|
||||
emu8k_work_eq(buf, new_pos-emu8k->pos);
|
||||
|
||||
|
||||
/* Clip signal */
|
||||
for (pos = emu8k->pos; pos < new_pos; pos++)
|
||||
{
|
||||
@@ -2154,7 +2118,7 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram)
|
||||
|
||||
if (onboard_ram)
|
||||
{
|
||||
/* Clip to 28MB, since that's the max that we can address. */
|
||||
/*Clip to 28MB, since that's the max that we can address. */
|
||||
if (onboard_ram > 0x7000) onboard_ram = 0x7000;
|
||||
emu8k->ram = malloc(onboard_ram * 1024);
|
||||
memset(emu8k->ram, 0, onboard_ram * 1024);
|
||||
@@ -2192,7 +2156,7 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram)
|
||||
freqtable[c] = (uint64_t)(exp2((double)(c - 0xe000) / 4096.0) * 65536.0 * 65536.0);
|
||||
}
|
||||
/* Shortcut: minimum pitch equals stopped. I don't really know if this is true, but it's better
|
||||
since some programs set the pitch to 0 for unused channels. */
|
||||
* since some programs set the pitch to 0 for unused channels. */
|
||||
freqtable[0] = 0;
|
||||
|
||||
/* starting at 65535 because it is used for "volume target" register conversion. */
|
||||
@@ -2206,7 +2170,7 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram)
|
||||
attentable[255]=0;
|
||||
|
||||
/* Note: these two tables have "db" inverted: 0 dB is max volume, 65535 "db" (-96.32dBFS) is silence.
|
||||
Important: Using 65535 as max output value because this is intended to be used with the volume target register! */
|
||||
* Important: Using 65535 as max output value because this is intended to be used with the volume target register! */
|
||||
out = 65535.0;
|
||||
for (c = 0; c < 0x10000; c++)
|
||||
{
|
||||
@@ -2216,49 +2180,49 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram)
|
||||
}
|
||||
/* Shortcut: max attenuation is silent, not -96dB. */
|
||||
env_vol_db_to_vol_target[0x10000-1]=0;
|
||||
/* One more position to forget about max value being 65536. */
|
||||
/* One more position to accept max value being 65536. */
|
||||
env_vol_db_to_vol_target[0x10000]=0;
|
||||
|
||||
for (c = 1; c < 0x10000; c++)
|
||||
{
|
||||
out = -680.32142884264* 20.0 * log10(c/65535.0);
|
||||
out = -680.32142884264* 20.0 * log10(((double)c)/65535.0);
|
||||
env_vol_amplitude_to_db[c] = (int32_t)out;
|
||||
}
|
||||
/* Shortcut: max attenuation is silent, not -96dB. */
|
||||
/*Shortcut: max attenuation is silent, not -96dB.*/
|
||||
env_vol_amplitude_to_db[0]=65535;
|
||||
/* One more position to forget about max value being 65536. */
|
||||
/* One more position to accept max value being 65536. */
|
||||
env_vol_amplitude_to_db[0x10000]=0;
|
||||
|
||||
|
||||
for (c = 1; c < 0x10000; c++)
|
||||
{
|
||||
out = log2((c/0x10000)+1.0) *65536.0;
|
||||
out = log2((((double)c)/0x10000)+1.0) *65536.0;
|
||||
env_mod_hertz_to_octave[c] = (int32_t)out;
|
||||
}
|
||||
/* No hertz change, no octave change. */
|
||||
/*No hertz change, no octave change. */
|
||||
env_mod_hertz_to_octave[0]=0;
|
||||
/* One more position to forget about max value being 65536. */
|
||||
/* One more position to accept max value being 65536. */
|
||||
env_mod_hertz_to_octave[0x10000]=65536;
|
||||
|
||||
|
||||
/* This formula comes from vince vu/judge dredd's awe32p10 and corresponds to what the freebsd/linux AWE32 driver has. */
|
||||
float millis;
|
||||
for (c=0;c<128;c++) {
|
||||
if (c==0) {
|
||||
/* This means never attack. */
|
||||
millis = 0;
|
||||
}
|
||||
else if (c < 32) {
|
||||
millis = 11878.0/c;
|
||||
} else {
|
||||
millis = 360*exp((c - 32) / (16.0/log(1.0/2.0)));
|
||||
}
|
||||
env_attack_to_samples[c] = 44.1*millis;
|
||||
/* This is an alternate formula with linear increments, but probably incorrect: (256+4096*(0x7F-c)) */
|
||||
for (c=0;c<128;c++)
|
||||
{
|
||||
if (c==0)
|
||||
millis = 0; /* This means never attack. */
|
||||
else if (c < 32)
|
||||
millis = 11878.0/c;
|
||||
else
|
||||
millis = 360*exp((c - 32) / (16.0/log(1.0/2.0)));
|
||||
|
||||
env_attack_to_samples[c] = 44.1*millis;
|
||||
/* This is an alternate formula with linear increments, but probably incorrect:
|
||||
* millis = (256+4096*(0x7F-c)) */
|
||||
}
|
||||
|
||||
/* The LFOs use a triangular waveform starting at zero and going 1/-1/1/-1.
|
||||
This table is stored in signed 16bits precision, with a period of 65536 samples */
|
||||
* This table is stored in signed 16bits precision, with a period of 65536 samples */
|
||||
for (c = 0; c < 65536; c++)
|
||||
{
|
||||
int d = (c + 16384) & 65535;
|
||||
@@ -2275,7 +2239,6 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram)
|
||||
out += 0.042;
|
||||
}
|
||||
|
||||
|
||||
for (c = 0; c < 65536; c++)
|
||||
{
|
||||
chortable[c] = sin(c*M_PI/32768.0);
|
||||
@@ -2319,6 +2282,9 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram)
|
||||
#endif /* FILTER_TYPE */
|
||||
/* 42.66 divisions per octave (the doc says quarter seminotes which is 48, but then it would be almost an octave less) */
|
||||
out *= 1.016378315;
|
||||
/* 42 divisions. This moves the max frequency to 8.5Khz.*/
|
||||
/* out *= 1.0166404394; */
|
||||
/* This is a linear increment method, that corresponds to the NRPN table, but contradicts the EMU8KPRM doc: */
|
||||
}
|
||||
}
|
||||
/* NOTE! read_pos and buffer content is implicitly initialized to zero by the sb_t structure memset on sb_awe32_init() */
|
||||
@@ -2337,17 +2303,19 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram)
|
||||
emu8k->reverb_engine.allpass[7-c].feedback=0.5;
|
||||
emu8k->reverb_engine.allpass[7-c].bufsize=(4*c)*REV_BUFSIZE_STEP+55;
|
||||
}
|
||||
|
||||
|
||||
/* Cubic Resampling ( 4point cubic spline) { */
|
||||
|
||||
/* Cubic Resampling ( 4point cubic spline) */
|
||||
double const resdouble = 1.0/(double)CUBIC_RESOLUTION;
|
||||
for(int i = 0; i < CUBIC_RESOLUTION; ++i)
|
||||
for (c = 0; c < CUBIC_RESOLUTION; c++)
|
||||
{
|
||||
double x = (double)i * resdouble;
|
||||
double x = (double)c * resdouble;
|
||||
/* Cubic resolution is made of four table, but I've put them all in one table to optimize memory access. */
|
||||
cubic_table[i*4] = (-0.5 * x * x * x + x * x - 0.5 * x) ;
|
||||
cubic_table[i*4+1] = ( 1.5 * x * x * x - 2.5 * x * x + 1.0) ;
|
||||
cubic_table[i*4+2] = (-1.5 * x * x * x + 2.0 * x * x + 0.5 * x) ;
|
||||
cubic_table[i*4+3] = ( 0.5 * x * x * x - 0.5 * x * x) ;
|
||||
cubic_table[c*4] = (-0.5 * x * x * x + x * x - 0.5 * x) ;
|
||||
cubic_table[c*4+1] = ( 1.5 * x * x * x - 2.5 * x * x + 1.0) ;
|
||||
cubic_table[c*4+2] = (-1.5 * x * x * x + 2.0 * x * x + 0.5 * x) ;
|
||||
cubic_table[c*4+3] = ( 0.5 * x * x * x - 0.5 * x * x) ;
|
||||
}
|
||||
/* If this is not set here, AWE card is not detected on Windows with Aweman driver. It's weird that the EMU8k says that this
|
||||
* has to be set by applications, and the AWE driver does not set it. */
|
||||
|
@@ -62,6 +62,13 @@ typedef struct sb_t
|
||||
uint8_t pos_regs[8];
|
||||
} sb_t;
|
||||
|
||||
/* 0 to 7 -> -14dB to 0dB i 2dB steps. 8 to 15 -> 0 to +14dB in 2dB steps.
|
||||
Note that for positive dB values, this is not amplitude, it is amplitude-1. */
|
||||
const float sb_bass_treble_4bits[]= {
|
||||
0.199526231, 0.25, 0.316227766, 0.398107170, 0.5, 0.63095734, 0.794328234, 1,
|
||||
0, 0.25892541, 0.584893192, 1, 1.511886431, 2.16227766, 3, 4.011872336
|
||||
};
|
||||
|
||||
static int sb_att[]=
|
||||
{
|
||||
50,65,82,103,130,164,207,260,328,413,520,655,825,1038,1307,
|
||||
@@ -101,14 +108,15 @@ static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p)
|
||||
|
||||
if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8)
|
||||
{
|
||||
if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5;
|
||||
if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5;
|
||||
if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5;
|
||||
if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5;
|
||||
if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5;
|
||||
if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5;
|
||||
if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5;
|
||||
if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5;
|
||||
/* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */
|
||||
if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]);
|
||||
if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]);
|
||||
if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]);
|
||||
if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]);
|
||||
if (mixer->bass_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->bass_l]));
|
||||
if (mixer->bass_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->bass_r]));
|
||||
if (mixer->treble_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->treble_l]));
|
||||
if (mixer->treble_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->treble_r]));
|
||||
}
|
||||
|
||||
buffer[c] += out_l;
|
||||
@@ -152,14 +160,15 @@ static void sb_get_buffer_opl3(int32_t *buffer, int len, void *p)
|
||||
|
||||
if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8)
|
||||
{
|
||||
if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5;
|
||||
if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5;
|
||||
if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5;
|
||||
if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5;
|
||||
if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5;
|
||||
if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5;
|
||||
if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5;
|
||||
if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5;
|
||||
/* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */
|
||||
if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]);
|
||||
if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]);
|
||||
if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]);
|
||||
if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]);
|
||||
if (mixer->bass_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->bass_l]));
|
||||
if (mixer->bass_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->bass_r]));
|
||||
if (mixer->treble_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->treble_l]));
|
||||
if (mixer->treble_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->treble_r]));
|
||||
}
|
||||
|
||||
buffer[c] += out_l;
|
||||
@@ -209,14 +218,15 @@ static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p)
|
||||
|
||||
if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8)
|
||||
{
|
||||
if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5;
|
||||
if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5;
|
||||
if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5;
|
||||
if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5;
|
||||
if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5;
|
||||
if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5;
|
||||
if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5;
|
||||
if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5;
|
||||
/* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */
|
||||
if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]);
|
||||
if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]);
|
||||
if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]);
|
||||
if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]);
|
||||
if (mixer->bass_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->bass_l]));
|
||||
if (mixer->bass_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->bass_r]));
|
||||
if (mixer->treble_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->treble_l]));
|
||||
if (mixer->treble_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->treble_r]));
|
||||
}
|
||||
|
||||
buffer[c] += out_l;
|
||||
|
@@ -961,18 +961,18 @@ uint8_t ega_read(uint32_t addr, void *p)
|
||||
ega->ld = ega->vram[addr | 0x3];
|
||||
if (ega->readmode)
|
||||
{
|
||||
temp = (ega->colournocare & 1) ? 0xff : 0;
|
||||
temp &= ega->la;
|
||||
temp = ega->la;
|
||||
temp ^= (ega->colourcompare & 1) ? 0xff : 0;
|
||||
temp2 = (ega->colournocare & 2) ? 0xff : 0;
|
||||
temp2 &= ega->lb;
|
||||
temp &= (ega->colournocare & 1) ? 0xff : 0;
|
||||
temp2 = ega->lb;
|
||||
temp2 ^= (ega->colourcompare & 2) ? 0xff : 0;
|
||||
temp3 = (ega->colournocare & 4) ? 0xff : 0;
|
||||
temp3 &= ega->lc;
|
||||
temp2 &= (ega->colournocare & 2) ? 0xff : 0;
|
||||
temp3 = ega->lc;
|
||||
temp3 ^= (ega->colourcompare & 4) ? 0xff : 0;
|
||||
temp4 = (ega->colournocare & 8) ? 0xff : 0;
|
||||
temp4 &= ega->ld;
|
||||
temp3 &= (ega->colournocare & 4) ? 0xff : 0;
|
||||
temp4 = ega->ld;
|
||||
temp4 ^= (ega->colourcompare & 8) ? 0xff : 0;
|
||||
temp4 &= (ega->colournocare & 8) ? 0xff : 0;
|
||||
return ~(temp | temp2 | temp3 | temp4);
|
||||
}
|
||||
return ega->vram[addr | readplane];
|
||||
|
@@ -1306,18 +1306,18 @@ uint8_t svga_read(uint32_t addr, void *p)
|
||||
|
||||
if (svga->readmode)
|
||||
{
|
||||
temp = (svga->colournocare & 1) ? 0xff : 0;
|
||||
temp &= svga->la;
|
||||
temp = svga->la;
|
||||
temp ^= (svga->colourcompare & 1) ? 0xff : 0;
|
||||
temp2 = (svga->colournocare & 2) ? 0xff : 0;
|
||||
temp2 &= svga->lb;
|
||||
temp &= (svga->colournocare & 1) ? 0xff : 0;
|
||||
temp2 = svga->lb;
|
||||
temp2 ^= (svga->colourcompare & 2) ? 0xff : 0;
|
||||
temp3 = (svga->colournocare & 4) ? 0xff : 0;
|
||||
temp3 &= svga->lc;
|
||||
temp2 &= (svga->colournocare & 2) ? 0xff : 0;
|
||||
temp3 = svga->lc;
|
||||
temp3 ^= (svga->colourcompare & 4) ? 0xff : 0;
|
||||
temp4 = (svga->colournocare & 8) ? 0xff : 0;
|
||||
temp4 &= svga->ld;
|
||||
temp3 &= (svga->colournocare & 4) ? 0xff : 0;
|
||||
temp4 = svga->ld;
|
||||
temp4 ^= (svga->colourcompare & 8) ? 0xff : 0;
|
||||
temp4 &= (svga->colournocare & 8) ? 0xff : 0;
|
||||
return ~(temp | temp2 | temp3 | temp4);
|
||||
}
|
||||
return svga->vram[addr | readplane];
|
||||
@@ -1572,18 +1572,18 @@ uint8_t svga_read_linear(uint32_t addr, void *p)
|
||||
svga->ld = svga->vram[addr | 0x3];
|
||||
if (svga->readmode)
|
||||
{
|
||||
temp = (svga->colournocare & 1) ? 0xff : 0;
|
||||
temp &= svga->la;
|
||||
temp = svga->la;
|
||||
temp ^= (svga->colourcompare & 1) ? 0xff : 0;
|
||||
temp2 = (svga->colournocare & 2) ? 0xff : 0;
|
||||
temp2 &= svga->lb;
|
||||
temp &= (svga->colournocare & 1) ? 0xff : 0;
|
||||
temp2 = svga->lb;
|
||||
temp2 ^= (svga->colourcompare & 2) ? 0xff : 0;
|
||||
temp3 = (svga->colournocare & 4) ? 0xff : 0;
|
||||
temp3 &= svga->lc;
|
||||
temp2 &= (svga->colournocare & 2) ? 0xff : 0;
|
||||
temp3 = svga->lc;
|
||||
temp3 ^= (svga->colourcompare & 4) ? 0xff : 0;
|
||||
temp4 = (svga->colournocare & 8) ? 0xff : 0;
|
||||
temp4 &= svga->ld;
|
||||
temp3 &= (svga->colournocare & 4) ? 0xff : 0;
|
||||
temp4 = svga->ld;
|
||||
temp4 ^= (svga->colourcompare & 8) ? 0xff : 0;
|
||||
temp4 &= (svga->colournocare & 8) ? 0xff : 0;
|
||||
return ~(temp | temp2 | temp3 | temp4);
|
||||
}
|
||||
return svga->vram[addr | readplane];
|
||||
|
Reference in New Issue
Block a user