mirror of
https://github.com/86Box/86Box.git
synced 2026-02-24 02:18:20 -07:00
Merge branch '86Box:master' into master
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
#include <86box/pit.h>
|
||||
#include <86box/apm.h>
|
||||
#include <86box/acpi.h>
|
||||
#include <86box/dma.h>
|
||||
#include <86box/machine.h>
|
||||
#include <86box/i2c.h>
|
||||
#include <86box/video.h>
|
||||
@@ -1025,8 +1026,13 @@ acpi_reg_write_common_regs(UNUSED(int size), uint16_t addr, uint8_t val, void *p
|
||||
nvr_reg_write(0x000f, 0xff, dev->nvr);
|
||||
}
|
||||
|
||||
if (sus_typ & SUS_RESET_PCI)
|
||||
if (sus_typ & SUS_RESET_PCI) {
|
||||
/* DMA is part of the southbridge so it responds to PCI reset. */
|
||||
dma_reset();
|
||||
dma_set_at(1);
|
||||
|
||||
device_reset_all(DEVICE_PCI);
|
||||
}
|
||||
|
||||
if (sus_typ & SUS_RESET_CPU)
|
||||
cpu_alt_reset = 0;
|
||||
|
||||
@@ -155,6 +155,7 @@ piix_ide_handlers(piix_t *dev, int bus)
|
||||
uint16_t side;
|
||||
|
||||
if (bus & 0x01) {
|
||||
piix_log("Disabling primary IDE...\n");
|
||||
ide_pri_disable();
|
||||
|
||||
if (dev->type == 5) {
|
||||
@@ -170,11 +171,14 @@ piix_ide_handlers(piix_t *dev, int bus)
|
||||
ide_set_side(0, side);
|
||||
}
|
||||
|
||||
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x41] & 0x80))
|
||||
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x41] & 0x80)) {
|
||||
piix_log("Enabling primary IDE...\n");
|
||||
ide_pri_enable();
|
||||
}
|
||||
}
|
||||
|
||||
if (bus & 0x02) {
|
||||
piix_log("Disabling secondary IDE...\n");
|
||||
ide_sec_disable();
|
||||
|
||||
if (dev->type == 5) {
|
||||
@@ -190,8 +194,10 @@ piix_ide_handlers(piix_t *dev, int bus)
|
||||
ide_set_side(1, side);
|
||||
}
|
||||
|
||||
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x43] & 0x80))
|
||||
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x43] & 0x80)) {
|
||||
piix_log("Enabling secondary IDE...\n");
|
||||
ide_sec_enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,6 +471,13 @@ piix_write(int func, int addr, uint8_t val, void *priv)
|
||||
uint8_t *fregs;
|
||||
uint16_t base;
|
||||
|
||||
/* Dell OptiPlex Gn+ shows that register 02:FF is aliased in 01:FF. */
|
||||
if ((dev->type == 4) && (func == 1) && (addr == 0xff))
|
||||
func = 2;
|
||||
|
||||
if ((func == 1) || (addr == 0xf8) || (addr == 0xf9))
|
||||
piix_log("[W] %02X:%02X = %02X\n", func, addr, val);
|
||||
|
||||
/* Return on unsupported function. */
|
||||
if (dev->max_func > 0) {
|
||||
if (func > dev->max_func)
|
||||
@@ -736,6 +749,8 @@ piix_write(int func, int addr, uint8_t val, void *priv)
|
||||
fregs[addr] = val;
|
||||
break;
|
||||
case 0xb0:
|
||||
if (val & 0x10)
|
||||
warning("Write %02X to B0\n", val);
|
||||
if (dev->type == 4)
|
||||
fregs[addr] = (fregs[addr] & 0x8c) | (val & 0x73);
|
||||
else if (dev->type == 5)
|
||||
@@ -745,6 +760,8 @@ piix_write(int func, int addr, uint8_t val, void *priv)
|
||||
alt_access = !!(val & 0x20);
|
||||
break;
|
||||
case 0xb1:
|
||||
if (val & 0x18)
|
||||
warning("Write %02X to B1\n", val);
|
||||
if (dev->type > 3)
|
||||
fregs[addr] = val & 0xdf;
|
||||
break;
|
||||
@@ -923,6 +940,12 @@ piix_write(int func, int addr, uint8_t val, void *priv)
|
||||
if (dev->type > 4)
|
||||
fregs[addr] = val;
|
||||
break;
|
||||
case 0xf8:
|
||||
case 0xf9:
|
||||
/* Undocumented! */
|
||||
if (dev->type == 4)
|
||||
fregs[addr] = val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1169,6 +1192,10 @@ piix_read(int func, int addr, void *priv)
|
||||
uint8_t ret = 0xff;
|
||||
const uint8_t *fregs;
|
||||
|
||||
/* Dell OptiPlex Gn+ shows that register 02:FF is aliased in 01:FF. */
|
||||
if ((dev->type == 4) && (func == 1) && (addr == 0xff))
|
||||
func = 2;
|
||||
|
||||
if ((dev->type == 3) && (func == 2) && (dev->max_func == 1) && (addr >= 0x40))
|
||||
ret = 0x00;
|
||||
|
||||
@@ -1199,7 +1226,7 @@ piix_reset_hard(piix_t *dev)
|
||||
|
||||
sff_set_slot(dev->bm[1], dev->pci_slot);
|
||||
sff_set_irq_pin(dev->bm[1], PCI_INTA);
|
||||
sff_set_irq_line(dev->bm[1], 14);
|
||||
sff_set_irq_line(dev->bm[1], 15);
|
||||
sff_set_irq_mode(dev->bm[1], IRQ_MODE_LEGACY);
|
||||
}
|
||||
|
||||
@@ -1315,6 +1342,10 @@ piix_reset_hard(piix_t *dev)
|
||||
fregs[0x45] = 0x55;
|
||||
fregs[0x46] = 0x01;
|
||||
}
|
||||
if (dev->type == 4) {
|
||||
fregs[0xf8] = 0x30;
|
||||
fregs[0xf9] = 0x0f;
|
||||
}
|
||||
if ((dev->type == 1) && (dev->rev == 2))
|
||||
dev->max_func = 0; /* It starts with IDE disabled, then enables it. */
|
||||
else
|
||||
@@ -1678,7 +1709,7 @@ const device_t piix4_device = {
|
||||
.name = "Intel 82371AB/EB (PIIX4/PIIX4E)",
|
||||
.internal_name = "piix4",
|
||||
.flags = DEVICE_PCI,
|
||||
.local = 0x71100004,
|
||||
.local = 0x71100014,
|
||||
.init = piix_init,
|
||||
.close = piix_close,
|
||||
.reset = piix_reset,
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*
|
||||
* Copyright 2019-2020 Miran Grca.
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -631,6 +632,41 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv)
|
||||
sis_85c4xx_recalcremap(dev);
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
if (dev->reg_base == 0x50) {
|
||||
double bus_clk;
|
||||
|
||||
switch (val & 0xe0) {
|
||||
default:
|
||||
case 0x00:
|
||||
bus_clk = 7159091.0;
|
||||
break;
|
||||
case 0x02:
|
||||
bus_clk = cpu_busspeed / 10.0;
|
||||
break;
|
||||
case 0x04:
|
||||
bus_clk = cpu_busspeed / 8.0;
|
||||
break;
|
||||
case 0x06:
|
||||
bus_clk = cpu_busspeed / 6.0;
|
||||
break;
|
||||
case 0x80:
|
||||
bus_clk = cpu_busspeed / 5.0;
|
||||
break;
|
||||
case 0xa0:
|
||||
bus_clk = cpu_busspeed / 4.0;
|
||||
break;
|
||||
case 0xc0:
|
||||
bus_clk = cpu_busspeed / 3.0;
|
||||
break;
|
||||
case 0xe0:
|
||||
bus_clk = cpu_busspeed / 2.0;
|
||||
break;
|
||||
}
|
||||
cpu_set_isa_speed((int) round(bus_clk));
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x13:
|
||||
if (dev->is_471 && (valxor & 0xf0)) {
|
||||
smram_disable(dev->smram);
|
||||
@@ -813,6 +849,9 @@ sis_85c4xx_reset(void *priv)
|
||||
|
||||
dev->force_flush = 1;
|
||||
sis_85c4xx_recalcmapping(dev);
|
||||
|
||||
if (dev->reg_base == 0x50)
|
||||
cpu_set_isa_speed((int) round(7159091.0));
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -132,7 +132,8 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv)
|
||||
break;
|
||||
case 0x02: case 0x03:
|
||||
dev->regs[dev->idx] = val;
|
||||
if (!strcmp(machine_get_internal_name(), "martin"))
|
||||
if (!strcmp(machine_get_internal_name(), "martin") ||
|
||||
!strcmp(machine_get_internal_name(), "prolineamt"))
|
||||
vl82c480_recalc_banks(dev);
|
||||
break;
|
||||
case 0x04:
|
||||
@@ -140,8 +141,6 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv)
|
||||
dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x08) | (val & 0xf7);
|
||||
else
|
||||
dev->regs[dev->idx] = val;
|
||||
if (!strcmp(machine_get_internal_name(), "martin"))
|
||||
dev->regs[dev->idx] &= 0x1f;
|
||||
break;
|
||||
case 0x05:
|
||||
dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x10) | (val & 0xef);
|
||||
@@ -221,6 +220,9 @@ vl82c480_init(const device_t *info)
|
||||
vl82c480_t *dev = (vl82c480_t *) calloc(1, sizeof(vl82c480_t));
|
||||
uint32_t sizes[8] = { 0, 0, 1024, 2048, 4096, 8192, 16384, 32768 };
|
||||
uint32_t ms = mem_size;
|
||||
uint8_t min_i = !strcmp(machine_get_internal_name(), "prolineamt") ? 1 : 0;
|
||||
uint8_t min_j = !strcmp(machine_get_internal_name(), "prolineamt") ? 4 : 2;
|
||||
uint8_t max_j = !strcmp(machine_get_internal_name(), "prolineamt") ? 8 : 7;
|
||||
|
||||
dev->regs[0x00] = info->local;
|
||||
dev->regs[0x01] = 0xff;
|
||||
@@ -231,8 +233,16 @@ vl82c480_init(const device_t *info)
|
||||
dev->regs[0x07] = 0x21;
|
||||
dev->regs[0x08] = 0x38;
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
for (uint8_t j = 2; j < 7; j++) {
|
||||
if (!strcmp(machine_get_internal_name(), "prolineamt")) {
|
||||
dev->banks[0] = 4096;
|
||||
|
||||
/* Bank 0 is ignored if 64 MB is installed. */
|
||||
if (ms != 65536)
|
||||
ms -= 4096;
|
||||
}
|
||||
|
||||
if (ms > 0) for (uint8_t i = min_i; i < 4; i++) {
|
||||
for (uint8_t j = min_j; j < max_j; j++) {
|
||||
if (ms >= sizes[j])
|
||||
dev->banks[i] = sizes[j];
|
||||
else
|
||||
|
||||
@@ -818,6 +818,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
|
||||
int over = 0;
|
||||
int pc_off = 0;
|
||||
int test_modrm = 1;
|
||||
int in_lock = 0;
|
||||
int c;
|
||||
uint32_t op87 = 0x00000000;
|
||||
|
||||
@@ -956,6 +957,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
|
||||
break;
|
||||
|
||||
case 0xf0: /*LOCK*/
|
||||
in_lock = 0;
|
||||
break;
|
||||
|
||||
case 0xf2: /*REPNE*/
|
||||
@@ -1013,6 +1015,9 @@ generate_call:
|
||||
STORE_IMM_ADDR_L((uintptr_t) &x87_op, op87);
|
||||
}
|
||||
|
||||
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
|
||||
goto codegen_skip;
|
||||
|
||||
if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) {
|
||||
uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block);
|
||||
if (new_pc) {
|
||||
@@ -1040,7 +1045,13 @@ generate_call:
|
||||
}
|
||||
}
|
||||
|
||||
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
|
||||
codegen_skip:
|
||||
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
|
||||
/* This is always ILLEGAL. */
|
||||
op = x86_dynarec_opcodes_3DNOW[0xff];
|
||||
else
|
||||
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
|
||||
|
||||
if (op_ssegs != last_ssegs) {
|
||||
last_ssegs = op_ssegs;
|
||||
addbyte(0xC6); /*MOVB $0,(ssegs)*/
|
||||
|
||||
@@ -1857,6 +1857,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
|
||||
int over = 0;
|
||||
int pc_off = 0;
|
||||
int test_modrm = 1;
|
||||
int in_lock = 0;
|
||||
int c;
|
||||
uint32_t op87 = 0x00000000;
|
||||
|
||||
@@ -1996,6 +1997,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
|
||||
break;
|
||||
|
||||
case 0xf0: /*LOCK*/
|
||||
in_lock = 1;
|
||||
break;
|
||||
|
||||
case 0xf2: /*REPNE*/
|
||||
@@ -2054,6 +2056,9 @@ generate_call:
|
||||
STORE_IMM_ADDR_L((uintptr_t) &x87_op, op87);
|
||||
}
|
||||
|
||||
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
|
||||
goto codegen_skip;
|
||||
|
||||
if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) {
|
||||
uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block);
|
||||
if (new_pc) {
|
||||
@@ -2080,7 +2085,13 @@ generate_call:
|
||||
}
|
||||
}
|
||||
|
||||
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
|
||||
codegen_skip:
|
||||
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
|
||||
/* This is always ILLEGAL. */
|
||||
op = x86_dynarec_opcodes_3DNOW[0xff];
|
||||
else
|
||||
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
|
||||
|
||||
if (op_ssegs != last_ssegs) {
|
||||
last_ssegs = op_ssegs;
|
||||
|
||||
|
||||
@@ -395,6 +395,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
|
||||
int over = 0;
|
||||
int test_modrm = 1;
|
||||
int pc_off = 0;
|
||||
int in_lock = 0;
|
||||
uint32_t next_pc = 0;
|
||||
uint16_t op87 = 0x0000;
|
||||
#ifdef DEBUG_EXTRA
|
||||
@@ -556,6 +557,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
|
||||
break;
|
||||
|
||||
case 0xf0: /*LOCK*/
|
||||
in_lock = 1;
|
||||
break;
|
||||
|
||||
case 0xf2: /*REPNE*/
|
||||
@@ -675,6 +677,9 @@ generate_call:
|
||||
goto codegen_skip;
|
||||
#endif
|
||||
|
||||
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
|
||||
goto codegen_skip;
|
||||
|
||||
if (recomp_op_table && recomp_op_table[(opcode | op_32) & recomp_opcode_mask]) {
|
||||
uint32_t new_pc = recomp_op_table[(opcode | op_32) & recomp_opcode_mask](block, ir, opcode, fetchdat, op_32, op_pc);
|
||||
if (new_pc) {
|
||||
@@ -692,13 +697,17 @@ generate_call:
|
||||
}
|
||||
}
|
||||
|
||||
// codegen_skip:
|
||||
codegen_skip:
|
||||
if ((op_table == x86_dynarec_opcodes_REPNE || op_table == x86_dynarec_opcodes_REPE) && !op_table[opcode | op_32]) {
|
||||
op_table = x86_dynarec_opcodes;
|
||||
recomp_op_table = recomp_opcodes;
|
||||
}
|
||||
|
||||
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
|
||||
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
|
||||
/* This is always ILLEGAL. */
|
||||
op = x86_dynarec_opcodes_3DNOW[0xff];
|
||||
else
|
||||
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
|
||||
|
||||
if (!test_modrm || (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]) || (op_table == x86_dynarec_opcodes_3DNOW)) {
|
||||
int stack_offset = 0;
|
||||
|
||||
@@ -781,14 +781,9 @@ host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p)
|
||||
codegen_addbyte4(block, 0x41, 0x8b, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, ram_offset[R12]*/
|
||||
codegen_addlong(block, ram_offset);
|
||||
} else if ((ram_offset < -2147483648LL) || (ram_offset > 2147483647LL) || !(block->flags & CODEBLOCK_NO_IMMEDIATES)) {
|
||||
// fatal("host_x86_MOV32_REG_ABS - out of range\n");
|
||||
// void *q = p;
|
||||
//uint32_t *r = NULL;
|
||||
// *r = 5; /* Crash deliberately. */
|
||||
codegen_alloc_bytes(block, 8);
|
||||
codegen_alloc_bytes(block, 13);
|
||||
codegen_addbyte2(block, 0x49, 0xb9); /*MOV r9,(uintptr_t) p*/
|
||||
codegen_addquad(block, (uintptr_t) p);
|
||||
codegen_alloc_bytes(block, 3);
|
||||
codegen_addbyte3(block, 0x41, 0x8b, 0x01 | ((dst_reg & 7) << 3)); /*MOV dst_reg, [R9]*/
|
||||
} else {
|
||||
fatal("host_x86_MOV32_REG_ABS - RAM offset = %016" PRIX64 " (p - ram = %016" PRIX64 ")\n", ram_offset, (uintptr_t) p - (uintptr_t) ram);
|
||||
|
||||
@@ -753,7 +753,7 @@ opLOCK(uint32_t fetchdat)
|
||||
return 0;
|
||||
cpu_state.pc++;
|
||||
|
||||
ILLEGAL_ON((fetchdat & 0xff) == 0x90);
|
||||
ILLEGAL_ON(((fetchdat & 0xff) == 0x90) || ((fetchdat & 0xff) == 0xec));
|
||||
|
||||
CLOCK_CYCLES(4);
|
||||
PREFETCH_PREFIX();
|
||||
|
||||
@@ -145,6 +145,11 @@ typedef struct atkbc_t {
|
||||
/* Internal FIFO for the purpose of commands with multi-byte output. */
|
||||
uint8_t key_ctrl_queue[64];
|
||||
|
||||
uint8_t handler_enable[2];
|
||||
|
||||
uint16_t base_addr[2];
|
||||
uint16_t irq[2];
|
||||
|
||||
uint32_t flags;
|
||||
|
||||
/* Main timers. */
|
||||
@@ -157,8 +162,13 @@ typedef struct atkbc_t {
|
||||
/* Local copies of the pointers to both ports for easier swapping (AMI '5' MegaKey). */
|
||||
kbc_at_port_t *ports[2];
|
||||
|
||||
uint8_t (*write60_ven)(void *priv, uint8_t val);
|
||||
uint8_t (*write64_ven)(void *priv, uint8_t val);
|
||||
struct {
|
||||
uint8_t (*read)(uint16_t port, void *priv);
|
||||
void (*write)(uint16_t port, uint8_t val, void *priv);
|
||||
} handlers[2];
|
||||
|
||||
uint8_t (*write_cmd_data_ven)(void *priv, uint8_t val);
|
||||
uint8_t (*write_cmd_ven)(void *priv, uint8_t val);
|
||||
} atkbc_t;
|
||||
|
||||
/* Keyboard controller ports. */
|
||||
@@ -167,8 +177,6 @@ kbc_at_port_t *kbc_at_ports[2] = { NULL, NULL };
|
||||
static uint8_t kbc_ami_revision = '8';
|
||||
static uint8_t kbc_award_revision = 0x42;
|
||||
|
||||
static uint8_t kbc_handler_set = 0;
|
||||
|
||||
static void (*kbc_at_do_poll)(atkbc_t *dev);
|
||||
|
||||
/* Non-translated to translated scan codes. */
|
||||
@@ -362,12 +370,19 @@ kbc_do_irq(atkbc_t *dev)
|
||||
if (dev->do_irq) {
|
||||
/* WARNING: On PS/2, all IRQ's are level-triggered, but the IBM PS/2 KBC firmware is explicitly
|
||||
written to pulse its P2 IRQ bits, so they should be kept as as edge-triggered here. */
|
||||
picint_common(1 << 1, 0, 0, NULL);
|
||||
picint_common(1 << 12, 0, 0, NULL);
|
||||
if (dev->channel >= 2)
|
||||
picint_common(1 << 12, 0, 1, NULL);
|
||||
else
|
||||
picint_common(1 << 1, 0, 1, NULL);
|
||||
if (dev->irq[0] != 0xffff)
|
||||
picint_common(1 << dev->irq[0], 0, 0, NULL);
|
||||
|
||||
if (dev->irq[1] != 0xffff)
|
||||
picint_common(1 << dev->irq[1], 0, 0, NULL);
|
||||
|
||||
if (dev->channel >= 2) {
|
||||
if (dev->irq[1] != 0xffff)
|
||||
picint_common(1 << dev->irq[1], 0, 1, NULL);
|
||||
} else {
|
||||
if (dev->irq[0] != 0xffff)
|
||||
picint_common(1 << dev->irq[0], 0, 1, NULL);
|
||||
}
|
||||
|
||||
dev->do_irq = 0;
|
||||
}
|
||||
@@ -404,7 +419,9 @@ kbc_send_to_ob(atkbc_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi)
|
||||
} else if (dev->mem[0x20] & 0x01)
|
||||
kbc_set_do_irq(dev, channel);
|
||||
} else if (dev->mem[0x20] & 0x01)
|
||||
picintlevel(1 << 1, &dev->irq_state); /* AT KBC: IRQ 1 is level-triggered because it is tied to OBF. */
|
||||
/* AT KBC: IRQ 1 is level-triggered because it is tied to OBF. */
|
||||
if (dev->irq[0] != 0xffff)
|
||||
picintlevel(1 << dev->irq[0], &dev->irq_state);
|
||||
|
||||
#ifdef WRONG_CONDITION
|
||||
if ((dev->channel > 0) || dev->is_asic || (kbc_ven == KBC_VEN_IBM_PS1) || (kbc_ven == KBC_VEN_IBM))
|
||||
@@ -784,10 +801,12 @@ write_p2(atkbc_t *dev, uint8_t val)
|
||||
/* PS/2: Handle IRQ's. */
|
||||
if (dev->misc_flags & FLAG_PS2) {
|
||||
/* IRQ 12 */
|
||||
picint_common(1 << 12, 0, val & 0x20, NULL);
|
||||
if (dev->irq[1] != 0xffff)
|
||||
picint_common(1 << dev->irq[1], 0, val & 0x20, NULL);
|
||||
|
||||
/* IRQ 1 */
|
||||
picint_common(1 << 1, 0, val & 0x10, NULL);
|
||||
if (dev->irq[0] != 0xffff)
|
||||
picint_common(1 << dev->irq[0], 0, val & 0x10, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -932,7 +951,7 @@ pulse_poll(void *priv)
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
write64_generic(void *priv, uint8_t val)
|
||||
write_cmd_generic(void *priv, uint8_t val)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
uint8_t current_drive;
|
||||
@@ -1088,12 +1107,41 @@ write64_generic(void *priv, uint8_t val)
|
||||
/* (B0 or F0) | (0x04 or 0x0c) */
|
||||
kbc_delay_to_ob(dev, dev->p1 | fixed_bits, 0, 0x00);
|
||||
} else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_GREEN)) {
|
||||
/* (B0 or F0) | (0x08 or 0x0c) */
|
||||
uint8_t p1_out = ((dev->p1 | fixed_bits) & 0xf0) |
|
||||
(((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c);
|
||||
if (!strcmp(machine_get_internal_name(), "alfredo"))
|
||||
p1_out &= 0xef;
|
||||
kbc_delay_to_ob(dev, p1_out, 0, 0x00);
|
||||
if (!strcmp(machine_get_internal_name(), "dell466np")) {
|
||||
/*
|
||||
Dell 466/NP:
|
||||
- Bit 2: Keyboard fuse (must be set);
|
||||
- Bit 4: Password disable jumper (must be clear);
|
||||
- Bit 5: Manufacturing jumper (must be set);
|
||||
*/
|
||||
uint8_t p1 = 0x24;
|
||||
kbc_delay_to_ob(dev, p1, 0, 0x00);
|
||||
} else if (!strcmp(machine_get_internal_name(), "optiplex_gxl")) {
|
||||
/*
|
||||
Dell OptiPlex GXL/GXM:
|
||||
- Bit 3: Password disable jumper (must be clear);
|
||||
- Bit 4: Keyboard fuse (must be set);
|
||||
- Bit 5: Manufacturing jumper (must be set);
|
||||
*/
|
||||
uint8_t p1 = 0x30;
|
||||
kbc_delay_to_ob(dev, p1, 0, 0x00);
|
||||
} else if (!strcmp(machine_get_internal_name(), "dellplato") || !strcmp(machine_get_internal_name(), "dellhannibalp")) {
|
||||
/*
|
||||
Dell Dimension XPS Pxxx & Pxxxa/Mxxxa:
|
||||
- Bit 3: Password disable jumper (must be clear);
|
||||
- Bit 4: Clear CMOS jumper (must be set);
|
||||
*/
|
||||
uint8_t p1 = 0x10;
|
||||
kbc_delay_to_ob(dev, p1, 0, 0x00);
|
||||
} else {
|
||||
/* (B0 or F0) | (0x08 or 0x0c) */
|
||||
uint8_t p1_out = ((dev->p1 | fixed_bits) & 0xf0) |
|
||||
(((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c);
|
||||
if (!strcmp(machine_get_internal_name(), "alfredo"))
|
||||
p1_out &= 0xef;
|
||||
|
||||
kbc_delay_to_ob(dev, p1_out, 0, 0x00);
|
||||
}
|
||||
} else if (kbc_ven == KBC_VEN_COMPAQ)
|
||||
kbc_delay_to_ob(dev, dev->p1 | (hasfpu ? 0x00 : 0x04), 0, 0x00);
|
||||
else
|
||||
@@ -1149,7 +1197,7 @@ write64_generic(void *priv, uint8_t val)
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
write60_ami(void *priv, uint8_t val)
|
||||
write_cmd_data_ami(void *priv, uint8_t val)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
|
||||
@@ -1219,7 +1267,7 @@ kbc_at_set_ps2(void *priv, const uint8_t ps2)
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
write64_ami(void *priv, uint8_t val)
|
||||
write_cmd_ami(void *priv, uint8_t val)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
|
||||
@@ -1424,11 +1472,11 @@ write64_ami(void *priv, uint8_t val)
|
||||
break;
|
||||
}
|
||||
|
||||
return write64_generic(dev, val);
|
||||
return write_cmd_generic(dev, val);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
write60_phoenix(void *priv, uint8_t val)
|
||||
write_cmd_data_phoenix(void *priv, uint8_t val)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
|
||||
@@ -1501,7 +1549,7 @@ write60_phoenix(void *priv, uint8_t val)
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
write64_phoenix(void *priv, uint8_t val)
|
||||
write_cmd_phoenix(void *priv, uint8_t val)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
|
||||
@@ -1647,11 +1695,11 @@ write64_phoenix(void *priv, uint8_t val)
|
||||
break;
|
||||
}
|
||||
|
||||
return write64_generic(dev, val);
|
||||
return write_cmd_generic(dev, val);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
write64_siemens(void *priv, uint8_t val)
|
||||
write_cmd_siemens(void *priv, uint8_t val)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
|
||||
@@ -1680,11 +1728,11 @@ write64_siemens(void *priv, uint8_t val)
|
||||
break;
|
||||
}
|
||||
|
||||
return write64_ami(dev, val);
|
||||
return write_cmd_ami(dev, val);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
write60_quadtel(void *priv, UNUSED(uint8_t val))
|
||||
write_cmd_data_quadtel(void *priv, UNUSED(uint8_t val))
|
||||
{
|
||||
const atkbc_t *dev = (atkbc_t *) priv;
|
||||
|
||||
@@ -1701,7 +1749,7 @@ write60_quadtel(void *priv, UNUSED(uint8_t val))
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
write64_olivetti(void *priv, uint8_t val)
|
||||
write_cmd_olivetti(void *priv, uint8_t val)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
|
||||
@@ -1722,11 +1770,11 @@ write64_olivetti(void *priv, uint8_t val)
|
||||
break;
|
||||
}
|
||||
|
||||
return write64_generic(dev, val);
|
||||
return write_cmd_generic(dev, val);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
write64_quadtel(void *priv, uint8_t val)
|
||||
write_cmd_quadtel(void *priv, uint8_t val)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
|
||||
@@ -1745,11 +1793,11 @@ write64_quadtel(void *priv, uint8_t val)
|
||||
break;
|
||||
}
|
||||
|
||||
return write64_generic(dev, val);
|
||||
return write_cmd_generic(dev, val);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
write60_toshiba(void *priv, uint8_t val)
|
||||
write_cmd_data_toshiba(void *priv, uint8_t val)
|
||||
{
|
||||
const atkbc_t *dev = (atkbc_t *) priv;
|
||||
|
||||
@@ -1767,7 +1815,7 @@ write60_toshiba(void *priv, uint8_t val)
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
write64_toshiba(void *priv, uint8_t val)
|
||||
write_cmd_toshiba(void *priv, uint8_t val)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
|
||||
@@ -1856,7 +1904,7 @@ write64_toshiba(void *priv, uint8_t val)
|
||||
break;
|
||||
}
|
||||
|
||||
return write64_generic(dev, val);
|
||||
return write_cmd_generic(dev, val);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1900,8 +1948,10 @@ kbc_at_process_cmd(void *priv)
|
||||
/* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */
|
||||
dev->p1 = dev->p1 & 0xff;
|
||||
write_p2(dev, 0x4b);
|
||||
picintc(0x1000);
|
||||
picintc(0x0002);
|
||||
if (dev->irq[1] != 0xffff)
|
||||
picintc(1 << dev->irq[1]);
|
||||
if (dev->irq[0] != 0xffff)
|
||||
picintc(1 << dev->irq[0]);
|
||||
}
|
||||
|
||||
dev->status = (dev->status & 0x0f) | 0x60;
|
||||
@@ -1920,7 +1970,8 @@ kbc_at_process_cmd(void *priv)
|
||||
/* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */
|
||||
dev->p1 = dev->p1 & 0xff;
|
||||
write_p2(dev, 0xcf);
|
||||
picintclevel(0x0002, &dev->irq_state);
|
||||
if (dev->irq[0] != 0xffff)
|
||||
picintclevel(1 << dev->irq[0], &dev->irq_state);
|
||||
dev->irq_state = 0;
|
||||
}
|
||||
|
||||
@@ -2035,8 +2086,8 @@ kbc_at_process_cmd(void *priv)
|
||||
* that. Otherwise, or if that handler fails,
|
||||
* log a bad command.
|
||||
*/
|
||||
if (dev->write64_ven)
|
||||
bad = dev->write64_ven(dev, dev->ib);
|
||||
if (dev->write_cmd_ven)
|
||||
bad = dev->write_cmd_ven(dev, dev->ib);
|
||||
|
||||
kbc_at_log(bad ? "ATkbc: bad controller command %02X\n" : "", dev->ib);
|
||||
}
|
||||
@@ -2122,8 +2173,8 @@ kbc_at_process_cmd(void *priv)
|
||||
* it returns an error, log a bad
|
||||
* controller command.
|
||||
*/
|
||||
if (dev->write60_ven)
|
||||
bad = dev->write60_ven(dev, dev->ib);
|
||||
if (dev->write_cmd_data_ven)
|
||||
bad = dev->write_cmd_data_ven(dev, dev->ib);
|
||||
|
||||
if (bad) {
|
||||
kbc_at_log("ATkbc: bad controller command %02x data %02x\n", dev->command, dev->ib);
|
||||
@@ -2133,7 +2184,7 @@ kbc_at_process_cmd(void *priv)
|
||||
}
|
||||
|
||||
static void
|
||||
kbc_at_write(uint16_t port, uint8_t val, void *priv)
|
||||
kbc_at_port_1_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
|
||||
@@ -2141,83 +2192,89 @@ kbc_at_write(uint16_t port, uint8_t val, void *priv)
|
||||
|
||||
kbc_at_log("ATkbc: [%04X:%08X] write(%04X) = %02X\n", CS, cpu_state.pc, port, val);
|
||||
|
||||
switch (port) {
|
||||
case 0x60:
|
||||
dev->status &= ~STAT_CD;
|
||||
if (fast_a20 && dev->wantdata && (dev->command == 0xd1)) {
|
||||
kbc_at_log("ATkbc: write P2\n");
|
||||
dev->status &= ~STAT_CD;
|
||||
|
||||
/* Fast A20 - ignore all other bits. */
|
||||
write_p2_fast_a20(dev, (dev->p2 & 0xfd) | (val & 0x02));
|
||||
if (fast_a20 && dev->wantdata && (dev->command == 0xd1)) {
|
||||
kbc_at_log("ATkbc: write P2\n");
|
||||
|
||||
dev->wantdata = 0;
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
/* Fast A20 - ignore all other bits. */
|
||||
write_p2_fast_a20(dev, (dev->p2 & 0xfd) | (val & 0x02));
|
||||
|
||||
/*
|
||||
Explicitly clear IBF so that any preceding
|
||||
command is not executed.
|
||||
*/
|
||||
dev->status &= ~STAT_IFULL;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
dev->wantdata = 0;
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
|
||||
case 0x64:
|
||||
dev->status |= STAT_CD;
|
||||
if (fast_a20 && (val == 0xd1)) {
|
||||
kbc_at_log("ATkbc: write P2\n");
|
||||
dev->wantdata = 1;
|
||||
dev->state = STATE_KBC_PARAM;
|
||||
dev->command = 0xd1;
|
||||
/*
|
||||
Explicitly clear IBF so that any preceding
|
||||
command is not executed.
|
||||
*/
|
||||
dev->status &= ~STAT_IFULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Explicitly clear IBF so that any preceding
|
||||
command is not executed.
|
||||
*/
|
||||
dev->status &= ~STAT_IFULL;
|
||||
return;
|
||||
} else if (fast_reset && ((val & 0xf0) == 0xf0)) {
|
||||
pulse_output(dev, val & 0x0f);
|
||||
dev->ib = val;
|
||||
dev->status |= STAT_IFULL;
|
||||
}
|
||||
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
static void
|
||||
kbc_at_port_2_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
|
||||
uint8_t fast_a20 = (kbc_ven != KBC_VEN_SIEMENS);
|
||||
|
||||
/*
|
||||
Explicitly clear IBF so that any preceding
|
||||
command is not executed.
|
||||
*/
|
||||
dev->status &= ~STAT_IFULL;
|
||||
return;
|
||||
} else if (val == 0xad) {
|
||||
/* Fast track it because of the Bochs BIOS. */
|
||||
kbc_at_log("ATkbc: disable keyboard\n");
|
||||
set_enable_kbd(dev, 0);
|
||||
kbc_at_log("ATkbc: [%04X:%08X] write(%04X) = %02X\n", CS, cpu_state.pc, port, val);
|
||||
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
dev->status |= STAT_CD;
|
||||
|
||||
/*
|
||||
Explicitly clear IBF so that any preceding
|
||||
command is not executed.
|
||||
*/
|
||||
dev->status &= ~STAT_IFULL;
|
||||
return;
|
||||
} else if (val == 0xae) {
|
||||
/* Fast track it because of the LG MultiNet. */
|
||||
kbc_at_log("ATkbc: enable keyboard\n");
|
||||
set_enable_kbd(dev, 1);
|
||||
if (fast_a20 && (val == 0xd1)) {
|
||||
kbc_at_log("ATkbc: write P2\n");
|
||||
dev->wantdata = 1;
|
||||
dev->state = STATE_KBC_PARAM;
|
||||
dev->command = 0xd1;
|
||||
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
/*
|
||||
Explicitly clear IBF so that any preceding
|
||||
command is not executed.
|
||||
*/
|
||||
dev->status &= ~STAT_IFULL;
|
||||
return;
|
||||
} else if (fast_reset && ((val & 0xf0) == 0xf0)) {
|
||||
pulse_output(dev, val & 0x0f);
|
||||
|
||||
/*
|
||||
Explicitly clear IBF so that any preceding
|
||||
command is not executed.
|
||||
*/
|
||||
dev->status &= ~STAT_IFULL;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
|
||||
default:
|
||||
break;
|
||||
/*
|
||||
Explicitly clear IBF so that any preceding
|
||||
command is not executed.
|
||||
*/
|
||||
dev->status &= ~STAT_IFULL;
|
||||
return;
|
||||
} else if (val == 0xad) {
|
||||
/* Fast track it because of the Bochs BIOS. */
|
||||
kbc_at_log("ATkbc: disable keyboard\n");
|
||||
set_enable_kbd(dev, 0);
|
||||
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
|
||||
/*
|
||||
Explicitly clear IBF so that any preceding
|
||||
command is not executed.
|
||||
*/
|
||||
dev->status &= ~STAT_IFULL;
|
||||
return;
|
||||
} else if (val == 0xae) {
|
||||
/* Fast track it because of the LG MultiNet. */
|
||||
kbc_at_log("ATkbc: enable keyboard\n");
|
||||
set_enable_kbd(dev, 1);
|
||||
|
||||
dev->state = STATE_MAIN_IBF;
|
||||
|
||||
/*
|
||||
Explicitly clear IBF so that any preceding
|
||||
command is not executed.
|
||||
*/
|
||||
dev->status &= ~STAT_IFULL;
|
||||
return;
|
||||
}
|
||||
|
||||
dev->ib = val;
|
||||
@@ -2225,7 +2282,7 @@ kbc_at_write(uint16_t port, uint8_t val, void *priv)
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
kbc_at_read(uint16_t port, void *priv)
|
||||
kbc_at_port_1_read(uint16_t port, void *priv)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
@@ -2233,26 +2290,32 @@ kbc_at_read(uint16_t port, void *priv)
|
||||
if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
switch (port) {
|
||||
case 0x60:
|
||||
ret = dev->ob;
|
||||
dev->status &= ~STAT_OFULL;
|
||||
/* TODO: IRQ is only tied to OBF on the AT KBC, on the PS/2 KBC, it is controlled by a P2 bit.
|
||||
This also means that in AT mode, the IRQ is level-triggered. */
|
||||
if (!(dev->misc_flags & FLAG_PS2))
|
||||
picintclevel(1 << 1, &dev->irq_state);
|
||||
if ((strstr(machine_get_internal_name(), "pb41") != NULL) && (cpu_override_dynarec == 1))
|
||||
cpu_override_dynarec = 0;
|
||||
break;
|
||||
ret = dev->ob;
|
||||
dev->status &= ~STAT_OFULL;
|
||||
/*
|
||||
TODO: IRQ is only tied to OBF on the AT KBC, on the PS/2 KBC, it is controlled by a P2 bit.
|
||||
This also means that in AT mode, the IRQ is level-triggered.
|
||||
*/
|
||||
if (!(dev->misc_flags & FLAG_PS2) && (dev->irq[0] != 0xffff))
|
||||
picintclevel(1 << dev->irq[0], &dev->irq_state);
|
||||
if ((strstr(machine_get_internal_name(), "pb41") != NULL) && (cpu_override_dynarec == 1))
|
||||
cpu_override_dynarec = 0;
|
||||
|
||||
case 0x64:
|
||||
ret = dev->status;
|
||||
break;
|
||||
kbc_at_log("ATkbc: [%04X:%08X] read (%04X) = %02X\n", CS, cpu_state.pc, port, ret);
|
||||
|
||||
default:
|
||||
kbc_at_log("ATkbc: read(%04x) invalid!\n",port);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
kbc_at_port_2_read(uint16_t port, void *priv)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
ret = dev->status;
|
||||
|
||||
kbc_at_log("ATkbc: [%04X:%08X] read (%04X) = %02X\n", CS, cpu_state.pc, port, ret);
|
||||
|
||||
@@ -2291,11 +2354,14 @@ kbc_at_reset(void *priv)
|
||||
if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) {
|
||||
dev->misc_flags |= FLAG_PS2;
|
||||
kbc_at_do_poll = kbc_at_poll_ps2;
|
||||
picintc(0x1000);
|
||||
picintc(0x0002);
|
||||
if (dev->irq[1] != 0xffff)
|
||||
picintc(1 << dev->irq[1]);
|
||||
if (dev->irq[0] != 0xffff)
|
||||
picintc(1 << dev->irq[0]);
|
||||
} else {
|
||||
kbc_at_do_poll = kbc_at_poll_at;
|
||||
picintclevel(0x0002, &dev->irq_state);
|
||||
if (dev->irq[0] != 0xffff)
|
||||
picintclevel(1 << dev->irq[0], &dev->irq_state);
|
||||
dev->irq_state = 0;
|
||||
}
|
||||
|
||||
@@ -2338,19 +2404,44 @@ kbc_at_close(void *priv)
|
||||
}
|
||||
|
||||
void
|
||||
kbc_at_handler(int set, void *priv)
|
||||
kbc_at_port_handler(int num, int set, uint16_t port, void *priv)
|
||||
{
|
||||
if (kbc_handler_set) {
|
||||
io_removehandler(0x0060, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv);
|
||||
io_removehandler(0x0064, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv);
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
|
||||
if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000))
|
||||
io_removehandler(dev->base_addr[num], 1,
|
||||
dev->handlers[num].read, NULL, NULL,
|
||||
dev->handlers[num].write, NULL, NULL, priv);
|
||||
|
||||
dev->handler_enable[num] = set;
|
||||
dev->base_addr[num] = port;
|
||||
|
||||
if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000))
|
||||
io_sethandler(dev->base_addr[num], 1,
|
||||
dev->handlers[num].read, NULL, NULL,
|
||||
dev->handlers[num].write, NULL, NULL, priv);
|
||||
}
|
||||
|
||||
void
|
||||
kbc_at_handler(int set, uint16_t port, void *priv)
|
||||
{
|
||||
kbc_at_port_handler(0, set, port, priv);
|
||||
kbc_at_port_handler(1, set, port + 0x0004, priv);
|
||||
}
|
||||
|
||||
void
|
||||
kbc_at_set_irq(int num, uint16_t irq, void *priv)
|
||||
{
|
||||
atkbc_t *dev = (atkbc_t *) priv;
|
||||
|
||||
if (dev->irq[num] != 0xffff) {
|
||||
if ((num == 0) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1))
|
||||
picintclevel(1 << dev->irq[num], &dev->irq_state);
|
||||
else
|
||||
picintc(1 << dev->irq[num]);
|
||||
}
|
||||
|
||||
kbc_handler_set = set;
|
||||
|
||||
if (kbc_handler_set) {
|
||||
io_sethandler(0x0060, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv);
|
||||
io_sethandler(0x0064, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv);
|
||||
}
|
||||
dev->irq[num] = irq;
|
||||
}
|
||||
|
||||
static void *
|
||||
@@ -2371,16 +2462,21 @@ kbc_at_init(const device_t *info)
|
||||
if (info->flags & DEVICE_PCI)
|
||||
dev->misc_flags |= FLAG_PCI;
|
||||
|
||||
kbc_handler_set = 0;
|
||||
kbc_at_handler(1, dev);
|
||||
dev->handlers[0].read = kbc_at_port_1_read;
|
||||
dev->handlers[0].write = kbc_at_port_1_write;
|
||||
dev->handlers[1].read = kbc_at_port_2_read;
|
||||
dev->handlers[1].write = kbc_at_port_2_write;
|
||||
|
||||
dev->irq[0] = 1;
|
||||
dev->irq[1] = 12;
|
||||
|
||||
timer_add(&dev->kbc_poll_timer, kbc_at_poll, dev, 1);
|
||||
timer_add(&dev->pulse_cb, pulse_poll, dev, 0);
|
||||
|
||||
timer_add(&dev->kbc_dev_poll_timer, kbc_at_dev_poll, dev, 1);
|
||||
|
||||
dev->write60_ven = NULL;
|
||||
dev->write64_ven = NULL;
|
||||
dev->write_cmd_data_ven = NULL;
|
||||
dev->write_cmd_ven = NULL;
|
||||
|
||||
kbc_ami_revision = '8';
|
||||
kbc_award_revision = 0x42;
|
||||
@@ -2389,8 +2485,8 @@ kbc_at_init(const device_t *info)
|
||||
case KBC_VEN_SIEMENS:
|
||||
kbc_ami_revision = '8';
|
||||
kbc_award_revision = 0x42;
|
||||
dev->write60_ven = write60_ami;
|
||||
dev->write64_ven = write64_siemens;
|
||||
dev->write_cmd_data_ven = write_cmd_data_ami;
|
||||
dev->write_cmd_ven = write_cmd_siemens;
|
||||
break;
|
||||
|
||||
case KBC_VEN_ACER:
|
||||
@@ -2399,24 +2495,24 @@ kbc_at_init(const device_t *info)
|
||||
case KBC_VEN_IBM_PS1:
|
||||
case KBC_VEN_IBM:
|
||||
case KBC_VEN_COMPAQ:
|
||||
dev->write64_ven = write64_generic;
|
||||
dev->write_cmd_ven = write_cmd_generic;
|
||||
break;
|
||||
|
||||
case KBC_VEN_OLIVETTI:
|
||||
dev->write64_ven = write64_olivetti;
|
||||
dev->write_cmd_ven = write_cmd_olivetti;
|
||||
break;
|
||||
|
||||
case KBC_VEN_ALI:
|
||||
kbc_ami_revision = 'F';
|
||||
kbc_award_revision = 0x43;
|
||||
dev->write60_ven = write60_ami;
|
||||
dev->write64_ven = write64_ami;
|
||||
dev->write_cmd_data_ven = write_cmd_data_ami;
|
||||
dev->write_cmd_ven = write_cmd_ami;
|
||||
break;
|
||||
|
||||
case KBC_VEN_TRIGEM_AMI:
|
||||
kbc_ami_revision = 'Z';
|
||||
dev->write60_ven = write60_ami;
|
||||
dev->write64_ven = write64_ami;
|
||||
dev->write_cmd_data_ven = write_cmd_data_ami;
|
||||
dev->write_cmd_ven = write_cmd_ami;
|
||||
break;
|
||||
|
||||
case KBC_VEN_AMI:
|
||||
@@ -2439,23 +2535,23 @@ kbc_at_init(const device_t *info)
|
||||
else
|
||||
kbc_ami_revision = 'F';
|
||||
|
||||
dev->write60_ven = write60_ami;
|
||||
dev->write64_ven = write64_ami;
|
||||
dev->write_cmd_data_ven = write_cmd_data_ami;
|
||||
dev->write_cmd_ven = write_cmd_ami;
|
||||
break;
|
||||
|
||||
case KBC_VEN_PHOENIX:
|
||||
dev->write60_ven = write60_phoenix;
|
||||
dev->write64_ven = write64_phoenix;
|
||||
dev->write_cmd_data_ven = write_cmd_data_phoenix;
|
||||
dev->write_cmd_ven = write_cmd_phoenix;
|
||||
break;
|
||||
|
||||
case KBC_VEN_QUADTEL:
|
||||
dev->write60_ven = write60_quadtel;
|
||||
dev->write64_ven = write64_quadtel;
|
||||
dev->write_cmd_data_ven = write_cmd_data_quadtel;
|
||||
dev->write_cmd_ven = write_cmd_quadtel;
|
||||
break;
|
||||
|
||||
case KBC_VEN_TOSHIBA:
|
||||
dev->write60_ven = write60_toshiba;
|
||||
dev->write64_ven = write64_toshiba;
|
||||
dev->write_cmd_data_ven = write_cmd_data_toshiba;
|
||||
dev->write_cmd_ven = write_cmd_toshiba;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2481,6 +2577,8 @@ kbc_at_init(const device_t *info)
|
||||
|
||||
fast_reset = 0x00;
|
||||
|
||||
kbc_at_handler(1, 0x0060, dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,11 +30,13 @@
|
||||
#include "cpu.h"
|
||||
|
||||
uint8_t postcard_codes[POSTCARDS_NUM];
|
||||
char postcard_diags[5] = { 0 };
|
||||
|
||||
static uint16_t postcard_port;
|
||||
static uint8_t postcard_written[POSTCARDS_NUM];
|
||||
static uint8_t postcard_ports_num = 1;
|
||||
static uint8_t postcard_prev_codes[POSTCARDS_NUM];
|
||||
static char postcard_prev_diags[5] = { 0 };
|
||||
#define UISTR_LEN 32
|
||||
static char postcard_str[UISTR_LEN]; /* UI output string */
|
||||
|
||||
@@ -97,6 +99,22 @@ postcard_setui(void)
|
||||
ps[1][0], ps[1][1], ps[1][2], ps[1][3]);
|
||||
break;
|
||||
}
|
||||
} else if (strstr(machines[machine].name, " Dell ")) {
|
||||
char dell_diags[10] = { 0 };
|
||||
|
||||
if (!postcard_written[1])
|
||||
snprintf(dell_diags, sizeof(dell_diags), "---- ----");
|
||||
else if (postcard_written[1] == 1)
|
||||
snprintf(dell_diags, sizeof(dell_diags), "%s ----", postcard_diags);
|
||||
else
|
||||
snprintf(dell_diags, sizeof(dell_diags), "%s %s", postcard_diags, postcard_prev_diags);
|
||||
|
||||
if (!postcard_written[0])
|
||||
snprintf(postcard_str, sizeof(postcard_str), "POST: -- -- %s", dell_diags);
|
||||
else if (postcard_written[0] == 1)
|
||||
snprintf(postcard_str, sizeof(postcard_str), "POST: %02X -- %s", postcard_codes[0], dell_diags);
|
||||
else
|
||||
snprintf(postcard_str, sizeof(postcard_str), "POST: %02X %02X %s", postcard_codes[0], postcard_prev_codes[0], dell_diags);
|
||||
} else {
|
||||
if (!postcard_written[0])
|
||||
snprintf(postcard_str, sizeof(postcard_str), "POST: -- --");
|
||||
@@ -122,6 +140,9 @@ postcard_reset(void)
|
||||
memset(postcard_codes, 0x00, POSTCARDS_NUM * sizeof(uint8_t));
|
||||
memset(postcard_prev_codes, 0x00, POSTCARDS_NUM * sizeof(uint8_t));
|
||||
|
||||
memset(postcard_diags, 0x00, 5 * sizeof(char));
|
||||
memset(postcard_prev_diags, 0x00, 5 * sizeof(char));
|
||||
|
||||
postcard_setui();
|
||||
}
|
||||
|
||||
@@ -140,6 +161,35 @@ postcard_write(uint16_t port, uint8_t val, UNUSED(void *priv))
|
||||
postcard_setui();
|
||||
}
|
||||
|
||||
static int
|
||||
postcard_cmp_diags(uint32_t val)
|
||||
{
|
||||
int ret = 0;
|
||||
char *pv = (char *) &val;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
ret = ret || (pv[i] != postcard_diags[3 - i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
postcard_writel(uint16_t port, uint32_t val, UNUSED(void *priv))
|
||||
{
|
||||
char *pv = (char *) &val;
|
||||
|
||||
if (postcard_written[1] && !postcard_cmp_diags(val))
|
||||
return;
|
||||
|
||||
*(uint32_t *) postcard_prev_diags = *(uint32_t *) postcard_diags;
|
||||
for (int i = 0; i < 4; i++)
|
||||
postcard_diags[i] = pv[3 - i];
|
||||
if (postcard_written[1] < 2)
|
||||
postcard_written[1]++;
|
||||
|
||||
postcard_setui();
|
||||
}
|
||||
|
||||
static void *
|
||||
postcard_init(UNUSED(const device_t *info))
|
||||
{
|
||||
@@ -173,6 +223,10 @@ postcard_init(UNUSED(const device_t *info))
|
||||
io_sethandler(postcard_port, postcard_ports_num,
|
||||
NULL, NULL, NULL, postcard_write, NULL, NULL, NULL);
|
||||
|
||||
if (strstr(machines[machine].name, " Dell "))
|
||||
io_sethandler(0x00e0, 0x0001,
|
||||
NULL, NULL, NULL, NULL, NULL, postcard_writel, NULL);
|
||||
|
||||
return postcard_write;
|
||||
}
|
||||
|
||||
|
||||
@@ -272,7 +272,10 @@ rz1000_init(const device_t *info)
|
||||
|
||||
dev->channels = ((info->local & 0x60000) >> 17) & 0x03;
|
||||
|
||||
device_add(&ide_pci_2ch_device);
|
||||
if (dev->channels & 0x02)
|
||||
device_add(&ide_pci_2ch_device);
|
||||
else
|
||||
device_add(&ide_pci_device);
|
||||
|
||||
if (info->local & 0x80000)
|
||||
pci_add_card(PCI_ADD_NORMAL, rz1000_pci_read, rz1000_pci_write, dev, &dev->pci_slot);
|
||||
|
||||
@@ -856,7 +856,7 @@ dma16_read(uint16_t addr, UNUSED(void *priv))
|
||||
break;
|
||||
}
|
||||
|
||||
dma_log("dma16_read(%08X) = %02X\n", port, ret);
|
||||
dma_log("dma16_read(%08X) = %02X\n", addr, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -377,6 +377,15 @@ fdc_set_power_down(fdc_t *fdc, uint8_t power_down)
|
||||
fdc->power_down = power_down;
|
||||
}
|
||||
|
||||
void
|
||||
fdc_toggle_flag(fdc_t *fdc, int flag, int on)
|
||||
{
|
||||
if (on)
|
||||
fdc->flags |= flag;
|
||||
else
|
||||
fdc->flags &= ~flag;
|
||||
}
|
||||
|
||||
void
|
||||
fdc_update_max_track(fdc_t *fdc, int max_track)
|
||||
{
|
||||
@@ -469,9 +478,11 @@ fdc_update_drv2en(fdc_t *fdc, int drv2en)
|
||||
void
|
||||
fdc_update_rate(fdc_t *fdc, int drive)
|
||||
{
|
||||
if (((fdc->rwc[drive] == 1) || (fdc->rwc[drive] == 2)) && fdc->enh_mode)
|
||||
if (((fdc->rwc[drive] == 1) || (fdc->rwc[drive] == 2)) &&
|
||||
fdc->enh_mode && !(fdc->flags & FDC_FLAG_SMC661))
|
||||
fdc->bit_rate = 500;
|
||||
else if ((fdc->rwc[drive] == 3) && fdc->enh_mode)
|
||||
else if ((fdc->rwc[drive] == 3) && fdc->enh_mode &&
|
||||
!(fdc->flags & FDC_FLAG_SMC661))
|
||||
fdc->bit_rate = 250;
|
||||
else switch (fdc->rate) {
|
||||
default:
|
||||
@@ -535,7 +546,7 @@ fdc_get_bitcell_period(fdc_t *fdc)
|
||||
static int
|
||||
fdc_get_densel(fdc_t *fdc, int drive)
|
||||
{
|
||||
if (fdc->enh_mode) {
|
||||
if (fdc->enh_mode && !(fdc->flags & FDC_FLAG_SMC661)) {
|
||||
switch (fdc->rwc[drive]) {
|
||||
case 1:
|
||||
case 3:
|
||||
@@ -770,8 +781,13 @@ fdc_write(uint16_t addr, uint8_t val, void *priv)
|
||||
return;
|
||||
case 3: /* TDR */
|
||||
if (fdc->enh_mode) {
|
||||
drive = real_drive(fdc, fdc->dor & 3);
|
||||
fdc_update_rwc(fdc, drive, (val & 0x30) >> 4);
|
||||
if (fdc->flags & FDC_FLAG_SMC661) {
|
||||
fdc_set_swap(fdc, !!(val & 0x20));
|
||||
fdc_update_densel_force(fdc, (val & 0x18) >> 3);
|
||||
} else {
|
||||
drive = real_drive(fdc, fdc->dor & 3);
|
||||
fdc_update_rwc(fdc, drive, (val & 0x30) >> 4);
|
||||
}
|
||||
}
|
||||
/* Bit 2: FIFO test mode (PS/55 5550-S,T only. Undocumented)
|
||||
The Power-on Self Test of PS/55 writes and verifies 8 bytes of FIFO buffer through I/O 3F5h.
|
||||
@@ -1391,6 +1407,8 @@ fdc_read(uint16_t addr, void *priv)
|
||||
/* PS/55 POST throws an error and halt if ret = 1 or 2, somehow. */
|
||||
} else if (!fdc->enh_mode)
|
||||
ret = 0x20;
|
||||
else if (fdc->flags & FDC_FLAG_SMC661)
|
||||
ret = (fdc->densel_force << 3) | ((!!fdc->swap) << 5) | (fdc->media_id << 6);
|
||||
else
|
||||
ret = (fdc->rwc[drive] << 4) | (fdc->media_id << 6);
|
||||
break;
|
||||
@@ -1475,7 +1493,7 @@ fdc_read(uint16_t addr, void *priv)
|
||||
fdc->step = 0;
|
||||
break;
|
||||
default:
|
||||
ret = 0xFF;
|
||||
ret = 0xff;
|
||||
}
|
||||
fdc_log("[%04X:%08X] Read FDC %04X %02X [%i:%02X]\n", CS, cpu_state.pc, addr, ret, drive, fdc->dor & (0x10 << drive));
|
||||
return ret;
|
||||
@@ -2226,9 +2244,13 @@ fdc_set_base(fdc_t *fdc, int base)
|
||||
{
|
||||
int super_io = (fdc->flags & FDC_FLAG_SUPERIO);
|
||||
|
||||
if (base == 0x0000) {
|
||||
fdc->base_address = base;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fdc->flags & FDC_FLAG_NSC) {
|
||||
io_sethandler(base + 2, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
|
||||
io_sethandler(base + 4, 0x0002, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
|
||||
io_sethandler(base + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
|
||||
io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
|
||||
} else {
|
||||
if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) {
|
||||
@@ -2257,10 +2279,12 @@ fdc_remove(fdc_t *fdc)
|
||||
{
|
||||
int super_io = (fdc->flags & FDC_FLAG_SUPERIO);
|
||||
|
||||
if (fdc->base_address == 0x0000)
|
||||
return;
|
||||
|
||||
fdc_log("FDC Removed (%04X)\n", fdc->base_address);
|
||||
if (fdc->flags & FDC_FLAG_NSC) {
|
||||
io_removehandler(fdc->base_address + 2, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
|
||||
io_removehandler(fdc->base_address + 4, 0x0002, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
|
||||
io_removehandler(fdc->base_address + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
|
||||
io_removehandler(fdc->base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
|
||||
} else {
|
||||
if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) {
|
||||
@@ -2644,6 +2668,20 @@ const device_t fdc_at_actlow_device = {
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t fdc_at_smc_661_device = {
|
||||
.name = "PC/AT Floppy Drive Controller (SM(s)C FDC37C661/2)",
|
||||
.internal_name = "fdc_at_smc",
|
||||
.flags = 0,
|
||||
.local = FDC_FLAG_AT | FDC_FLAG_SUPERIO | FDC_FLAG_SMC661,
|
||||
.init = fdc_init,
|
||||
.close = fdc_close,
|
||||
.reset = fdc_reset,
|
||||
.available = NULL,
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t fdc_at_smc_device = {
|
||||
.name = "PC/AT Floppy Drive Controller (SM(s)C FDC37Cxxx)",
|
||||
.internal_name = "fdc_at_smc",
|
||||
|
||||
@@ -38,26 +38,27 @@
|
||||
#define FDC_QUATERNARY_IRQ 6
|
||||
#define FDC_QUATERNARY_DMA 2
|
||||
|
||||
#define FDC_FLAG_PCJR 0x01 /* PCjr */
|
||||
#define FDC_FLAG_DISKCHG_ACTLOW 0x02 /* Amstrad, PS/1, PS/2 ISA */
|
||||
#define FDC_FLAG_AT 0x04 /* AT+, PS/x */
|
||||
#define FDC_FLAG_PS2 0x08 /* PS/1, PS/2 ISA */
|
||||
#define FDC_FLAG_PS2_MCA 0x10 /* PS/2 MCA */
|
||||
#define FDC_FLAG_SUPERIO 0x20 /* Super I/O chips */
|
||||
#define FDC_FLAG_START_RWC_1 0x40 /* W83877F, W83977F */
|
||||
#define FDC_FLAG_MORE_TRACKS 0x80 /* W83877F, W83977F, PC87306, PC87309 */
|
||||
#define FDC_FLAG_NSC 0x100 /* PC87306, PC87309 */
|
||||
#define FDC_FLAG_TOSHIBA 0x200 /* T1000, T1200 */
|
||||
#define FDC_FLAG_AMSTRAD 0x400 /* Non-AT Amstrad machines */
|
||||
#define FDC_FLAG_UMC 0x800 /* UMC UM8398 */
|
||||
#define FDC_FLAG_ALI 0x1000 /* ALi M512x / M1543C */
|
||||
#define FDC_FLAG_NO_DSR_RESET 0x2000 /* Has no DSR reset */
|
||||
#define FDC_FLAG_DENSEL_INVERT 0x4000 /* Invert DENSEL polarity */
|
||||
#define FDC_FLAG_FINTR 0x8000 /* Raise FINTR on data command finish */
|
||||
#define FDC_FLAG_NEC 0x10000 /* Is NEC upd765-compatible */
|
||||
#define FDC_FLAG_SEC 0x20000 /* Is Secondary */
|
||||
#define FDC_FLAG_TER 0x40000 /* Is Tertiary */
|
||||
#define FDC_FLAG_QUA 0x80000 /* Is Quaternary */
|
||||
#define FDC_FLAG_PCJR 0x01 /* PCjr */
|
||||
#define FDC_FLAG_DISKCHG_ACTLOW 0x02 /* Amstrad, PS/1, PS/2 ISA */
|
||||
#define FDC_FLAG_AT 0x04 /* AT+, PS/x */
|
||||
#define FDC_FLAG_PS2 0x08 /* PS/1, PS/2 ISA */
|
||||
#define FDC_FLAG_PS2_MCA 0x10 /* PS/2 MCA */
|
||||
#define FDC_FLAG_SUPERIO 0x20 /* Super I/O chips */
|
||||
#define FDC_FLAG_START_RWC_1 0x40 /* W83877F, W83977F */
|
||||
#define FDC_FLAG_MORE_TRACKS 0x80 /* W83877F, W83977F, PC87306, PC87309 */
|
||||
#define FDC_FLAG_NSC 0x100 /* PC87306, PC87309 */
|
||||
#define FDC_FLAG_TOSHIBA 0x200 /* T1000, T1200 */
|
||||
#define FDC_FLAG_AMSTRAD 0x400 /* Non-AT Amstrad machines */
|
||||
#define FDC_FLAG_UMC 0x800 /* UMC UM8398 */
|
||||
#define FDC_FLAG_ALI 0x1000 /* ALi M512x / M1543C */
|
||||
#define FDC_FLAG_NO_DSR_RESET 0x2000 /* Has no DSR reset */
|
||||
#define FDC_FLAG_DENSEL_INVERT 0x4000 /* Invert DENSEL polarity */
|
||||
#define FDC_FLAG_FINTR 0x8000 /* Raise FINTR on data command finish */
|
||||
#define FDC_FLAG_NEC 0x10000 /* Is NEC upd765-compatible */
|
||||
#define FDC_FLAG_SEC 0x20000 /* Is Secondary */
|
||||
#define FDC_FLAG_TER 0x40000 /* Is Tertiary */
|
||||
#define FDC_FLAG_QUA 0x80000 /* Is Quaternary */
|
||||
#define FDC_FLAG_SMC661 0x100000 /* SM(s)C FDC37C661 - different TDR enhanced mode */
|
||||
|
||||
typedef struct fdc_t {
|
||||
uint8_t dor;
|
||||
@@ -182,6 +183,7 @@ extern uint8_t fdc_get_densel_polarity(fdc_t *fdc);
|
||||
extern void fdc_update_densel_force(fdc_t *fdc, int densel_force);
|
||||
extern void fdc_update_drvrate(fdc_t *fdc, int drive, int drvrate);
|
||||
extern void fdc_update_drv2en(fdc_t *fdc, int drv2en);
|
||||
extern void fdc_toggle_flag(fdc_t *fdc, int flag, int on);
|
||||
|
||||
extern void fdc_noidam(fdc_t *fdc);
|
||||
extern void fdc_nosector(fdc_t *fdc);
|
||||
@@ -260,6 +262,7 @@ extern const device_t fdc_at_sec_device;
|
||||
extern const device_t fdc_at_ter_device;
|
||||
extern const device_t fdc_at_qua_device;
|
||||
extern const device_t fdc_at_actlow_device;
|
||||
extern const device_t fdc_at_smc_661_device;
|
||||
extern const device_t fdc_at_smc_device;
|
||||
extern const device_t fdc_at_ali_device;
|
||||
extern const device_t fdc_at_winbond_device;
|
||||
|
||||
@@ -289,7 +289,9 @@ extern uint8_t kbc_at_read_p(void *priv, uint8_t port, uint8_t mask);
|
||||
extern void kbc_at_write_p(void *priv, uint8_t port, uint8_t mask, uint8_t val);
|
||||
|
||||
extern void kbc_at_set_fast_reset(uint8_t new_fast_reset);
|
||||
extern void kbc_at_handler(int set, void *priv);
|
||||
extern void kbc_at_port_handler(int num, int set, uint16_t port, void *priv);
|
||||
extern void kbc_at_handler(int set, uint16_t port, void *priv);
|
||||
extern void kbc_at_set_irq(int num, uint16_t irq, void *priv);
|
||||
|
||||
extern void kbc_at_dev_queue_reset(atkbc_dev_t *dev, uint8_t reset_main);
|
||||
extern uint8_t kbc_at_dev_queue_pos(atkbc_dev_t *dev, uint8_t main);
|
||||
|
||||
@@ -532,6 +532,8 @@ extern int machine_at_cs4031_init(const machine_t *);
|
||||
extern int machine_at_pb410a_init(const machine_t *);
|
||||
|
||||
extern int machine_at_decpclpv_init(const machine_t *);
|
||||
extern int machine_at_dell466np_init(const machine_t *);
|
||||
|
||||
extern int machine_at_acerv10_init(const machine_t *);
|
||||
|
||||
extern int machine_at_acera1g_init(const machine_t *);
|
||||
@@ -670,6 +672,7 @@ extern int machine_at_tek932_init(const machine_t *);
|
||||
|
||||
extern int machine_at_acerv30_init(const machine_t *);
|
||||
extern int machine_at_apollo_init(const machine_t *);
|
||||
extern int machine_at_optiplex_gxl_init(const machine_t *);
|
||||
extern int machine_at_zappa_init(const machine_t *);
|
||||
extern int machine_at_powermatev_init(const machine_t *);
|
||||
extern int machine_at_hawk_init(const machine_t *);
|
||||
@@ -749,6 +752,7 @@ extern int machine_at_gw2kte_init(const machine_t *);
|
||||
extern int machine_at_ma23c_init(const machine_t *);
|
||||
extern int machine_at_nupro592_init(const machine_t *);
|
||||
extern int machine_at_tx97_init(const machine_t *);
|
||||
extern int machine_at_optiplex_gn_init(const machine_t *);
|
||||
#ifdef USE_AN430TX
|
||||
extern int machine_at_an430tx_init(const machine_t *);
|
||||
#endif /* USE_AN430TX */
|
||||
@@ -818,8 +822,8 @@ extern int machine_at_p65up5_cpknd_init(const machine_t *);
|
||||
extern int machine_at_kn97_init(const machine_t *);
|
||||
|
||||
extern int machine_at_lx6_init(const machine_t *);
|
||||
extern int machine_at_optiplex_gxa_init(const machine_t *);
|
||||
extern int machine_at_spitfire_init(const machine_t *);
|
||||
|
||||
extern int machine_at_ma30d_init(const machine_t *);
|
||||
|
||||
extern int machine_at_p6i440e2_init(const machine_t *);
|
||||
|
||||
@@ -92,13 +92,23 @@ extern const device_t pc87332_398_ide_device;
|
||||
extern const device_t pc87332_398_ide_sec_device;
|
||||
extern const device_t pc87332_398_ide_fdcon_device;
|
||||
|
||||
#define PCX7307_PC87307 0x00c0
|
||||
#define PCX7307_PC97307 0x00cf
|
||||
|
||||
#define PC87309_PC87309 0x00e0
|
||||
|
||||
#define PCX730X_CHIP_ID 0x00ff
|
||||
|
||||
#define PCX730X_AMI 0x0200 /* AMI '5' Megakey KBC firmware. */
|
||||
#define PCX730X_PHOENIX_42 0x0500 /* Phoenix Multikey/42 1.37 KBC firmware. */
|
||||
#define PCX730X_PHOENIX_42I 0x0700 /* Phoenix Multikey/42i 4.16 KBC firmware. */
|
||||
#define PCX730X_KBC 0x0f00
|
||||
|
||||
#define PCX730X_15C 0x2000
|
||||
|
||||
extern const device_t pc87307_device;
|
||||
extern const device_t pc87307_15c_device;
|
||||
extern const device_t pc87307_both_device;
|
||||
extern const device_t pc97307_device;
|
||||
|
||||
extern const device_t pc87309_device;
|
||||
extern const device_t pc87309_15c_device;
|
||||
|
||||
/* LG Prime */
|
||||
extern const device_t prime3b_device;
|
||||
|
||||
@@ -7,20 +7,23 @@
|
||||
#define MASTER_CLOCK 7159090
|
||||
|
||||
typedef struct cms_t {
|
||||
#ifdef SAASOUND_H_INCLUDED
|
||||
SAASND saasound;
|
||||
SAASND saasound2;
|
||||
#else
|
||||
void* saasound;
|
||||
void* saasound2;
|
||||
#endif
|
||||
int addrs[2];
|
||||
uint8_t regs[2][32];
|
||||
uint16_t latch[2][6];
|
||||
int freq[2][6];
|
||||
float count[2][6];
|
||||
int vol[2][6][2];
|
||||
int stat[2][6];
|
||||
uint16_t noise[2][2];
|
||||
uint16_t noisefreq[2][2];
|
||||
int noisecount[2][2];
|
||||
int noisetype[2][2];
|
||||
|
||||
uint8_t latched_data;
|
||||
|
||||
int16_t buffer[WTBUFLEN * 2];
|
||||
int16_t buffer2[WTBUFLEN * 2];
|
||||
int16_t buffer[SOUNDBUFLEN * 2];
|
||||
|
||||
int pos, pos2;
|
||||
int pos;
|
||||
} cms_t;
|
||||
|
||||
extern void cms_update(cms_t *cms);
|
||||
|
||||
@@ -365,6 +365,7 @@ extern const device_t gd5428_boca_isa_device;
|
||||
extern const device_t gd5428_mca_device;
|
||||
extern const device_t gd5426_mca_device;
|
||||
extern const device_t gd5428_onboard_device;
|
||||
extern const device_t gd5428_onboard_vlb_device;
|
||||
extern const device_t gd5429_isa_device;
|
||||
extern const device_t gd5429_vlb_device;
|
||||
extern const device_t gd5430_diamond_speedstar_pro_se_a8_vlb_device;
|
||||
|
||||
4
src/io.c
4
src/io.c
@@ -445,10 +445,10 @@ outb(uint16_t port, uint8_t val)
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (!found || (port == 0x84)) {
|
||||
cycles -= io_delay;
|
||||
#ifdef USE_DYNAREC
|
||||
if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed)))
|
||||
if (cpu_use_dynarec && ((port == 0x84) || (port == 0xeb) || (port == 0xed)))
|
||||
update_tsc();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -229,9 +229,9 @@ void
|
||||
lpt_port_setup(int i, uint16_t port)
|
||||
{
|
||||
if (lpt_ports[i].enabled) {
|
||||
if (lpt_ports[i].addr != 0xffff)
|
||||
if ((lpt_ports[i].addr != 0xffff) && (lpt_ports[i].addr != 0x0000))
|
||||
io_removehandler(lpt_ports[i].addr, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
||||
if (port != 0xffff)
|
||||
if ((port != 0xffff) && (port != 0x0000))
|
||||
io_sethandler(port, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
|
||||
lpt_ports[i].addr = port;
|
||||
} else
|
||||
|
||||
@@ -396,7 +396,7 @@ machine_at_pb410a_init(const machine_t *model)
|
||||
device_add(&phoenix_486_jumper_device);
|
||||
|
||||
if (gfxcard[0] == VID_INTERNAL)
|
||||
device_add(&ht216_32_pb410a_device);
|
||||
device_add(machine_get_vid_device(machine));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -545,16 +545,47 @@ machine_at_decpclpv_init(const machine_t *model)
|
||||
device_add(&sis_85c461_device);
|
||||
|
||||
if (gfxcard[0] == VID_INTERNAL)
|
||||
device_add(&s3_86c805_onboard_vlb_device);
|
||||
device_add(machine_get_vid_device(machine));
|
||||
|
||||
device_add(&keyboard_ps2_phoenix_pci_device);
|
||||
|
||||
/* TODO: Phoenix MultiKey KBC */
|
||||
device_add(&keyboard_ps2_ami_pci_device);
|
||||
device_add(&ide_isa_2ch_device);
|
||||
device_add(&fdc37c663_ide_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
machine_at_dell466np_init(const machine_t *model)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bios_load_linear("roms/machines/dell466np/466np.bin",
|
||||
0x000c0000, 262144, 0);
|
||||
|
||||
if (bios_only || !ret)
|
||||
return ret;
|
||||
|
||||
machine_at_common_init(model);
|
||||
device_add(&sis_85c461_device);
|
||||
|
||||
if (gfxcard[0] == VID_INTERNAL)
|
||||
device_add(machine_get_vid_device(machine));
|
||||
else {
|
||||
for (uint16_t i = 0; i < 32768; i++)
|
||||
rom[i] = mem_readb_phys(0x000c0000 + i);
|
||||
}
|
||||
mem_mapping_set_addr(&bios_mapping, 0x0c0000, 0x40000);
|
||||
mem_mapping_set_exec(&bios_mapping, rom);
|
||||
|
||||
device_add(&keyboard_ps2_phoenix_pci_device);
|
||||
|
||||
device_add(&ide_isa_device);
|
||||
device_add(&fdc37c661_ide_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
machine_at_ali1429_common_init(const machine_t *model, int is_green)
|
||||
{
|
||||
@@ -1696,9 +1727,6 @@ machine_at_sb486pv_init(const machine_t *model)
|
||||
device_context_restore();
|
||||
|
||||
machine_at_common_init(model);
|
||||
// machine_at_common_init_ex(model, 2);
|
||||
|
||||
// device_add(&amstrad_megapc_nvr_device);
|
||||
device_add(&ide_pci_device);
|
||||
|
||||
pci_init(PCI_CONFIG_TYPE_2);
|
||||
|
||||
@@ -150,6 +150,39 @@ machine_at_lx6_init(const machine_t *model)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
machine_at_optiplex_gxa_init(const machine_t *model)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bios_load_linear("roms/machines/optiplex_gxa/DELL.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, 1, 2, 3, 4);
|
||||
pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4);
|
||||
pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 2, 1);
|
||||
pci_register_slot(0x11, PCI_CARD_NETWORK, 4, 0, 0, 0);
|
||||
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4);
|
||||
pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4);
|
||||
|
||||
if (sound_card_current[0] == SOUND_INTERNAL)
|
||||
device_add(machine_get_snd_device(machine));
|
||||
|
||||
device_add(&i440lx_device);
|
||||
device_add(&piix4_device);
|
||||
device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42 | PCX7307_PC87307));
|
||||
device_add(&intel_flash_bxt_device);
|
||||
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
machine_at_spitfire_init(const machine_t *model)
|
||||
{
|
||||
@@ -584,8 +617,7 @@ machine_at_s1846_init(const machine_t *model)
|
||||
pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4);
|
||||
device_add(&i440bx_device);
|
||||
device_add(&piix4e_device);
|
||||
device_add(&pc87309_device);
|
||||
device_add(&keyboard_ps2_ami_pci_device);
|
||||
device_add_params(&pc87309_device, (void *) (PCX730X_AMI | PC87309_PC87309));
|
||||
device_add(&intel_flash_bxt_device);
|
||||
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
|
||||
|
||||
|
||||
@@ -140,8 +140,7 @@ machine_at_fw6400gx_init(const machine_t *model)
|
||||
|
||||
device_add(&i440gx_device);
|
||||
device_add(&piix4e_device);
|
||||
device_add(&keyboard_ps2_ami_pci_device);
|
||||
device_add(&pc87309_15c_device);
|
||||
device_add_params(&pc87309_device, (void *) (PCX730X_15C | PCX730X_AMI | PC87309_PC87309));
|
||||
device_add(ics9xxx_get(ICS9250_08));
|
||||
device_add(&sst_flash_29ee020_device);
|
||||
spd_register(SPD_TYPE_SDRAM, 0xF, 512);
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <86box/sio.h>
|
||||
#include <86box/video.h>
|
||||
#include <86box/machine.h>
|
||||
#include <86box/sound.h>
|
||||
|
||||
int
|
||||
machine_at_plato_init(const machine_t *model)
|
||||
@@ -236,6 +237,42 @@ machine_at_apollo_init(const machine_t *model)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
machine_at_optiplex_gxl_init(const machine_t *model)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bios_load_linear("roms/machines/optiplex_gxl/DELL.ROM",
|
||||
0x000e0000, 131072, 0);
|
||||
|
||||
if (bios_only || !ret)
|
||||
return ret;
|
||||
|
||||
machine_at_common_init_ex(model, 2);
|
||||
device_add(&amstrad_megapc_nvr_device);
|
||||
|
||||
pci_init(PCI_CONFIG_TYPE_1);
|
||||
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4);
|
||||
pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4);
|
||||
pci_register_slot(0x0D, PCI_CARD_NORMAL, 3, 4, 2, 1);
|
||||
pci_register_slot(0x10, PCI_CARD_VIDEO, 0, 0, 0, 0);
|
||||
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0);
|
||||
|
||||
if (gfxcard[0] == VID_INTERNAL)
|
||||
device_add(machine_get_vid_device(machine));
|
||||
|
||||
if (sound_card_current[0] == SOUND_INTERNAL)
|
||||
machine_snd = device_add(machine_get_snd_device(machine));
|
||||
|
||||
device_add(&keyboard_ps2_phoenix_pci_device);
|
||||
device_add(&i430fx_device);
|
||||
device_add(&piix_device);
|
||||
device_add(&pc87332_device);
|
||||
device_add(&intel_flash_bxt_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
machine_at_zappa_gpio_init(void)
|
||||
{
|
||||
|
||||
@@ -969,6 +969,42 @@ machine_at_tx97_init(const machine_t *model)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
machine_at_optiplex_gn_init(const machine_t *model)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bios_load_linear("roms/machines/optiplex_gn/DELL.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, 1, 2, 3, 4);
|
||||
pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 2, 1);
|
||||
pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4);
|
||||
pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Trio64V2/GX, temporarily Trio64V2/DX is given */
|
||||
pci_register_slot(0x11, PCI_CARD_NETWORK, 4, 0, 0, 0); /* 3C905, not yet emulated */
|
||||
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4);
|
||||
|
||||
if (gfxcard[0] == VID_INTERNAL)
|
||||
device_add(machine_get_vid_device(machine));
|
||||
|
||||
if ((sound_card_current[0] == SOUND_INTERNAL) && machine_get_snd_device(machine)->available())
|
||||
machine_snd = device_add(machine_get_snd_device(machine));
|
||||
|
||||
device_add(&i430tx_device);
|
||||
device_add(&piix4_device);
|
||||
device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42 | PCX7307_PC87307));
|
||||
device_add(&intel_flash_bxt_device);
|
||||
spd_register(SPD_TYPE_SDRAM, 0x3, 128);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef USE_AN430TX
|
||||
int
|
||||
machine_at_an430tx_init(const machine_t *model)
|
||||
@@ -1006,8 +1042,7 @@ machine_at_an430tx_init(const machine_t *model)
|
||||
pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3);
|
||||
device_add(&i430tx_device);
|
||||
device_add(&piix4_device);
|
||||
device_add(&keyboard_ps2_ami_pci_device);
|
||||
device_add(&pc87307_both_device);
|
||||
device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42I | PCX7307_PC97307));
|
||||
device_add(&intel_flash_bxt_ami_device);
|
||||
spd_register(SPD_TYPE_SDRAM, 0x3, 128);
|
||||
|
||||
|
||||
@@ -706,17 +706,59 @@ machine_at_gw2kma_init(const machine_t *model)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const device_config_t ap5s_config[] = {
|
||||
// clang-format off
|
||||
{
|
||||
.name = "bios",
|
||||
.description = "BIOS Version",
|
||||
.type = CONFIG_BIOS,
|
||||
.default_string = "ap5s",
|
||||
.default_int = 0,
|
||||
.file_filter = "",
|
||||
.spinner = { 0 },
|
||||
.bios = {
|
||||
{ .name = "04/22/96 1.20 4.50PG", .internal_name = "ap5s_450pg", .bios_type = BIOS_NORMAL,
|
||||
.files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/ap5s/ap5s120.bin", "" } },
|
||||
{ .name = "11/13/96 1.50 4.51PG", .internal_name = "ap5s", .bios_type = BIOS_NORMAL,
|
||||
.files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/ap5s/AP5S150.BIN", "" } },
|
||||
{ .name = "06/25/97 1.60 4.51PG", .internal_name = "ap5s_latest", .bios_type = BIOS_NORMAL,
|
||||
.files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/ap5s/ap5s160.bin", "" } },
|
||||
{ .files_no = 0 }
|
||||
},
|
||||
},
|
||||
{ .name = "", .description = "", .type = CONFIG_END }
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
const device_t ap5s_device = {
|
||||
.name = "AOpen AP5S",
|
||||
.internal_name = "ap5s_device",
|
||||
.flags = 0,
|
||||
.local = 0,
|
||||
.init = NULL,
|
||||
.close = NULL,
|
||||
.reset = NULL,
|
||||
.available = NULL,
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = ap5s_config
|
||||
};
|
||||
|
||||
int
|
||||
machine_at_ap5s_init(const machine_t *model)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
const char* fn;
|
||||
|
||||
ret = bios_load_linear("roms/machines/ap5s/AP5S150.BIN",
|
||||
0x000e0000, 131072, 0);
|
||||
|
||||
if (bios_only || !ret)
|
||||
/* No ROMs available */
|
||||
if (!device_available(model->device))
|
||||
return ret;
|
||||
|
||||
device_context(model->device);
|
||||
fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0);
|
||||
ret = bios_load_linear(fn, 0x000e0000, 131072, 0);
|
||||
device_context_restore();
|
||||
|
||||
machine_at_common_init_ex(model, 2);
|
||||
|
||||
pci_init(PCI_CONFIG_TYPE_1 | FLAG_TRC_CONTROLS_CPURST);
|
||||
|
||||
@@ -250,8 +250,7 @@ machine_at_vs440fx_init(const machine_t *model)
|
||||
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_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC87307));
|
||||
|
||||
device_add(&intel_flash_bxt_ami_device);
|
||||
|
||||
@@ -287,8 +286,7 @@ machine_at_gw2kvenus_init(const machine_t *model)
|
||||
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_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC87307));
|
||||
|
||||
device_add(&intel_flash_bxt_ami_device);
|
||||
|
||||
@@ -324,8 +322,7 @@ machine_at_ap440fx_init(const machine_t *model)
|
||||
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4);
|
||||
device_add(&i440fx_device);
|
||||
device_add(&piix3_device);
|
||||
device_add(&keyboard_ps2_ami_pci_device);
|
||||
device_add(&pc87307_device);
|
||||
device_add_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC87307));
|
||||
device_add(&intel_flash_bxt_ami_device);
|
||||
|
||||
if (sound_card_current[0] == SOUND_INTERNAL)
|
||||
|
||||
@@ -70,6 +70,7 @@ extern const device_t jukopc_device;
|
||||
extern const device_t vendex_device;
|
||||
extern const device_t c5sbm2_device;
|
||||
extern const device_t sb486pv_device;
|
||||
extern const device_t ap5s_device;
|
||||
|
||||
const machine_filter_t machine_types[] = {
|
||||
{ "None", MACHINE_TYPE_NONE },
|
||||
@@ -6646,7 +6647,7 @@ const machine_t machines[] = {
|
||||
.device = NULL,
|
||||
.fdc_device = NULL,
|
||||
.sio_device = NULL,
|
||||
.vid_device = NULL,
|
||||
.vid_device = &ht216_32_pb410a_device,
|
||||
.snd_device = NULL,
|
||||
.net_device = NULL
|
||||
},
|
||||
@@ -6934,6 +6935,46 @@ const machine_t machines[] = {
|
||||
.snd_device = NULL,
|
||||
.net_device = NULL
|
||||
},
|
||||
/* Uses a ???? KBC. */
|
||||
{
|
||||
.name = "[SiS 461] Dell 466/NP",
|
||||
.internal_name = "dell466np",
|
||||
.type = MACHINE_TYPE_486_S2,
|
||||
.chipset = MACHINE_CHIPSET_SIS_461,
|
||||
.init = machine_at_dell466np_init,
|
||||
.p1_handler = NULL,
|
||||
.gpio_handler = NULL,
|
||||
.available_flag = MACHINE_AVAILABLE,
|
||||
.gpio_acpi_handler = NULL,
|
||||
.cpu = {
|
||||
.package = CPU_PKG_SOCKET3,
|
||||
.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_PS2,
|
||||
.flags = MACHINE_IDE | MACHINE_VIDEO | MACHINE_APM,
|
||||
.ram = {
|
||||
.min = 1024,
|
||||
.max = 32768,
|
||||
.step = 1024
|
||||
},
|
||||
.nvrmask = 127,
|
||||
.kbc_device = NULL,
|
||||
.kbc_p1 = 0xff,
|
||||
.gpio = 0xffffffff,
|
||||
.gpio_acpi = 0xffffffff,
|
||||
.device = NULL,
|
||||
.fdc_device = NULL,
|
||||
.sio_device = NULL,
|
||||
.vid_device = &gd5428_onboard_vlb_device,
|
||||
.snd_device = NULL,
|
||||
.net_device = NULL
|
||||
},
|
||||
/* The BIOS does not send any non-standard keyboard controller commands and wants
|
||||
a PS/2 mouse, so it's an IBM PS/2 KBC (Type 1) firmware. */
|
||||
{
|
||||
@@ -7816,10 +7857,10 @@ const machine_t machines[] = {
|
||||
.kbc_p1 = 0xff,
|
||||
.gpio = 0xffffffff,
|
||||
.gpio_acpi = 0xffffffff,
|
||||
.device = &tgui9440_onboard_pci_device,
|
||||
.device = NULL,
|
||||
.fdc_device = NULL,
|
||||
.sio_device = NULL,
|
||||
.vid_device = NULL,
|
||||
.vid_device = &tgui9440_onboard_pci_device,
|
||||
.snd_device = NULL,
|
||||
.net_device = NULL
|
||||
},
|
||||
@@ -10512,6 +10553,46 @@ const machine_t machines[] = {
|
||||
.snd_device = NULL,
|
||||
.net_device = NULL
|
||||
},
|
||||
/* Has a National Semiconductor PC87332VLJ Super I/O with AMIKey 'F' KBC firmware. */
|
||||
{
|
||||
.name = "[i430FX] Dell OptiPlex GXL/GXM",
|
||||
.internal_name = "optiplex_gxl",
|
||||
.type = MACHINE_TYPE_SOCKET5,
|
||||
.chipset = MACHINE_CHIPSET_INTEL_430FX,
|
||||
.init = machine_at_optiplex_gxl_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_Cx6x86),
|
||||
.min_bus = 60000000,
|
||||
.max_bus = 66666667,
|
||||
.min_voltage = 3380,
|
||||
.max_voltage = 3520,
|
||||
.min_multi = 1.5,
|
||||
.max_multi = 3.0
|
||||
},
|
||||
.bus_flags = MACHINE_PS2_PCI,
|
||||
.flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND | MACHINE_APM, /* Video: S3 Trio64V+ (86C765), Sound: Creative ViBRA 16S (CT2504), Network: 3Com ETHERLINK III (3C509B) */
|
||||
.ram = {
|
||||
.min = 8192,
|
||||
.max = 131072,
|
||||
.step = 8192
|
||||
},
|
||||
.nvrmask = 127,
|
||||
.kbc_device = NULL,
|
||||
.kbc_p1 = 0xff,
|
||||
.gpio = 0xffffffff,
|
||||
.gpio_acpi = 0xffffffff,
|
||||
.device = NULL,
|
||||
.fdc_device = NULL,
|
||||
.sio_device = NULL,
|
||||
.vid_device = &s3_phoenix_trio64vplus_onboard_pci_device,
|
||||
.snd_device = &sb_vibra16s_onboard_device,
|
||||
.net_device = NULL /* not yet emulated */
|
||||
},
|
||||
/* According to tests from real hardware: This has AMI MegaKey KBC firmware on the
|
||||
PC87306 Super I/O chip, command 0xA1 returns '5'.
|
||||
Command 0xA0 copyright string: (C)1994 AMI . */
|
||||
@@ -11780,7 +11861,7 @@ const machine_t machines[] = {
|
||||
.kbc_p1 = 0xff,
|
||||
.gpio = 0xffffffff,
|
||||
.gpio_acpi = 0xffffffff,
|
||||
.device = NULL,
|
||||
.device = &ap5s_device,
|
||||
.fdc_device = NULL,
|
||||
.sio_device = NULL,
|
||||
.vid_device = NULL,
|
||||
@@ -13062,6 +13143,56 @@ const machine_t machines[] = {
|
||||
.snd_device = NULL,
|
||||
.net_device = NULL
|
||||
},
|
||||
/*
|
||||
According to Dell specifications, it can have either National Semiconductor
|
||||
PC87307 or PC87309 Super I/O. All known instances have the former, although
|
||||
other similar Dells of the era have pinouts for accompanying either so this
|
||||
likely also does.
|
||||
|
||||
The KBC is either an AMI '5' MegaKey, Phoenix MultiKey/42 1.37, or Phoenix
|
||||
MultiKey/42i 4.16.
|
||||
*/
|
||||
{
|
||||
.name = "[i430TX] Dell OptiPlex GN+",
|
||||
.internal_name = "optiplex_gn",
|
||||
.type = MACHINE_TYPE_SOCKET7,
|
||||
.chipset = MACHINE_CHIPSET_INTEL_430TX,
|
||||
.init = machine_at_optiplex_gn_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 = 2500,
|
||||
.max_voltage = 3520,
|
||||
.min_multi = 1.5,
|
||||
.max_multi = 3.5
|
||||
},
|
||||
.bus_flags = MACHINE_PS2_PCI,
|
||||
/* Video: S3 86C785 (Trio64V2/GX), ethernet: 3C905. */
|
||||
.flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_VIDEO | MACHINE_SOUND,
|
||||
.ram = {
|
||||
.min = 8192,
|
||||
.max = 262144,
|
||||
.step = 8192
|
||||
},
|
||||
.nvrmask = 255,
|
||||
.kbc_device = NULL,
|
||||
.kbc_p1 = 0xff,
|
||||
.gpio = 0xffffffff,
|
||||
.gpio_acpi = 0xffffffff,
|
||||
.device = NULL,
|
||||
.fdc_device = NULL,
|
||||
.sio_device = NULL,
|
||||
/* Stop-gap measure until the Trio64V2/GX is emulated, as both use the same VBIOS. */
|
||||
.vid_device = &s3_trio64v2_dx_onboard_pci_device,
|
||||
.snd_device = &sb_vibra16xv_onboard_device,
|
||||
.net_device = NULL
|
||||
},
|
||||
/* [TEST] Has AMI Megakey '5' KBC firmware on the SM(S)C FDC37C67x Super I/O chip. */
|
||||
{
|
||||
.name = "[i430TX] Gateway E-1000",
|
||||
@@ -15039,6 +15170,47 @@ const machine_t machines[] = {
|
||||
.snd_device = NULL,
|
||||
.net_device = NULL
|
||||
},
|
||||
/* Has a National Semiconductor PC87307 Super I/O with on-chip KBC, which has one of these
|
||||
firmwares: AMI '5' MegaKey, Phoenix MultiKey/42 1.37, or Phoenix MultiKey/42i 4.16. */
|
||||
{
|
||||
.name = "[i440LX] Dell OptiPlex GXa",
|
||||
.internal_name = "optiplex_gxa",
|
||||
.type = MACHINE_TYPE_SLOT1,
|
||||
.chipset = MACHINE_CHIPSET_INTEL_440LX,
|
||||
.init = machine_at_optiplex_gxa_init,
|
||||
.p1_handler = NULL,
|
||||
.gpio_handler = NULL,
|
||||
.available_flag = MACHINE_AVAILABLE,
|
||||
.gpio_acpi_handler = NULL,
|
||||
.cpu = {
|
||||
.package = CPU_PKG_SLOT1,
|
||||
.block = CPU_BLOCK(CPU_PENTIUMPRO, CPU_CYRIX3S),
|
||||
.min_bus = 66666667,
|
||||
.max_bus = 66666667,
|
||||
.min_voltage = 1800,
|
||||
.max_voltage = 3500,
|
||||
.min_multi = 1.5,
|
||||
.max_multi = 5.0
|
||||
},
|
||||
.bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB,
|
||||
.flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, /* Video: ATi 3D Rage Pro, Network: 3Com 3C905, Sound: Crystal CS4236B */
|
||||
.ram = {
|
||||
.min = 8192,
|
||||
.max = 786432,
|
||||
.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, /* not yet emulated */
|
||||
.snd_device = &cs4236b_device,
|
||||
.net_device = NULL /* not yet emulated */
|
||||
},
|
||||
/* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix
|
||||
MultiKey/42 (version 1.38) KBC firmware. */
|
||||
{
|
||||
|
||||
@@ -2549,6 +2549,12 @@ rtl8139_io_writeb(uint32_t addr, uint8_t val, void *priv)
|
||||
|
||||
break;
|
||||
|
||||
case RxConfig:
|
||||
rtl8139_log("RxConfig write(b) val=0x%02x\n", val);
|
||||
rtl8139_RxConfig_write(s,
|
||||
(rtl8139_RxConfig_read(s) & 0xFFFFFF00) | val);
|
||||
break;
|
||||
|
||||
default:
|
||||
rtl8139_log("not implemented write(b) addr=0x%x val=0x%02x\n", addr, val);
|
||||
break;
|
||||
|
||||
@@ -1107,9 +1107,10 @@ nvr_at_init(const device_t *info)
|
||||
case 1: /* standard AT */
|
||||
case 5: /* AMI WinBIOS 1994 */
|
||||
case 6: /* AMI BIOS 1995 */
|
||||
if ((info->local & 0x1f) == 0x11)
|
||||
if ((info->local & 0x1f) == 0x11) {
|
||||
local->flags |= FLAG_PIIX4;
|
||||
else {
|
||||
local->def = 0x00;
|
||||
} else {
|
||||
local->def = 0x00;
|
||||
if ((info->local & 0x1f) == 0x15)
|
||||
local->flags |= FLAG_AMI_1994_HACK;
|
||||
|
||||
@@ -1503,6 +1503,7 @@ OpenGLRenderer::render()
|
||||
|
||||
/* loop through each pass */
|
||||
for (i = 0; i < shader->num_passes; ++i) {
|
||||
bool resetFiltering = false;
|
||||
struct shader_pass *pass = &shader->passes[i];
|
||||
|
||||
memcpy(pass->state.input_size, input->state.output_size, 2 * sizeof(GLfloat));
|
||||
@@ -1524,8 +1525,14 @@ OpenGLRenderer::render()
|
||||
|
||||
glw.glBindFramebuffer(GL_FRAMEBUFFER, pass->fbo.id);
|
||||
glw.glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]);
|
||||
} else
|
||||
} else {
|
||||
resetFiltering = true;
|
||||
glw.glBindTexture(GL_TEXTURE_2D, input->fbo.texture.id);
|
||||
glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST);
|
||||
glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST);
|
||||
glw.glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glw.glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h);
|
||||
}
|
||||
|
||||
glw.glClearColor(0, 0, 0, 1);
|
||||
glw.glClear(GL_COLOR_BUFFER_BIT);
|
||||
@@ -1570,6 +1577,13 @@ OpenGLRenderer::render()
|
||||
glw.glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
if (resetFiltering) {
|
||||
glw.glBindTexture(GL_TEXTURE_2D, input->fbo.texture.id);
|
||||
glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, input->fbo.texture.min_filter);
|
||||
glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, input->fbo.texture.mag_filter);
|
||||
glw.glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
input = pass;
|
||||
}
|
||||
|
||||
@@ -1637,6 +1651,11 @@ OpenGLRenderer::render()
|
||||
pass->state.output_texture_size[j] = next_pow2(pass->state.output_size[j]);
|
||||
}
|
||||
|
||||
glw.glBindTexture(GL_TEXTURE_2D, input->fbo.texture.id);
|
||||
glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST);
|
||||
glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST);
|
||||
glw.glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glw.glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h);
|
||||
|
||||
glw.glClearColor(0, 0, 0, 1);
|
||||
|
||||
@@ -61,6 +61,11 @@ struct mouseinputdata {
|
||||
static mouseinputdata mousedata;
|
||||
|
||||
extern MainWindow *main_window;
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
HWND rw_hwnd;
|
||||
#endif
|
||||
|
||||
RendererStack::RendererStack(QWidget *parent, int monitor_index)
|
||||
: QStackedWidget(parent)
|
||||
, ui(new Ui::RendererStack)
|
||||
@@ -251,7 +256,9 @@ RendererStack::mouseMoveEvent(QMouseEvent *event)
|
||||
leaveEvent((QEvent *) event);
|
||||
ignoreNextMouseEvent--;
|
||||
}
|
||||
#if !defined _WIN32
|
||||
QCursor::setPos(mapToGlobal(QPoint(width() / 2, height() / 2)));
|
||||
#endif
|
||||
ignoreNextMouseEvent = 2;
|
||||
oldPos = event->pos();
|
||||
#endif
|
||||
@@ -405,8 +412,15 @@ RendererStack::createRenderer(Renderer renderer)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (current.get() == nullptr)
|
||||
if (current.get() == nullptr) {
|
||||
#ifdef Q_OS_WINDOWS
|
||||
rw_hwnd = NULL;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
rw_hwnd = (HWND) this->winId();
|
||||
#endif
|
||||
current->setFocusPolicy(Qt::NoFocus);
|
||||
current->setFocusProxy(this);
|
||||
current->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
@@ -649,6 +663,14 @@ RendererStack::setFocusRenderer()
|
||||
void
|
||||
RendererStack::onResize(int width, int height)
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (mouse_capture) {
|
||||
RECT rect;
|
||||
if (GetWindowRect((HWND)this->winId(), &rect)) {
|
||||
ClipCursor(&rect);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (rendererWindow) {
|
||||
rendererWindow->r_monitor_index = m_monitor_index;
|
||||
rendererWindow->onResize(width, height);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <QStatusBar>
|
||||
#include <QApplication>
|
||||
|
||||
#include "qt_mainwindow.hpp"
|
||||
#include "qt_machinestatus.hpp"
|
||||
@@ -122,6 +123,10 @@ plat_resize(int w, int h, int monitor_index)
|
||||
main_window->resizeContents(w, h);
|
||||
}
|
||||
|
||||
#if defined _WIN32
|
||||
extern HWND rw_hwnd;
|
||||
#endif
|
||||
|
||||
void
|
||||
plat_mouse_capture(int on)
|
||||
{
|
||||
@@ -129,6 +134,26 @@ plat_mouse_capture(int on)
|
||||
return;
|
||||
|
||||
main_window->setMouseCapture(on > 0 ? true : false);
|
||||
|
||||
#if defined _WIN32
|
||||
if (on) {
|
||||
QCursor cursor(Qt::BlankCursor);
|
||||
|
||||
QApplication::setOverrideCursor(cursor);
|
||||
QApplication::changeOverrideCursor(cursor);
|
||||
|
||||
RECT rect;
|
||||
|
||||
GetWindowRect(rw_hwnd, &rect);
|
||||
|
||||
ClipCursor(&rect);
|
||||
|
||||
} else {
|
||||
ClipCursor(NULL);
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -395,7 +395,7 @@ WindowsRawInputFilter::mouse_handle(PRAWINPUT raw)
|
||||
|
||||
mouse_scale(delta_x, delta_y);
|
||||
|
||||
HWND wnd = (HWND)window->winId();
|
||||
/* HWND wnd = (HWND)window->winId();
|
||||
|
||||
RECT rect;
|
||||
|
||||
@@ -404,5 +404,5 @@ WindowsRawInputFilter::mouse_handle(PRAWINPUT raw)
|
||||
int left = rect.left + (rect.right - rect.left) / 2;
|
||||
int top = rect.top + (rect.bottom - rect.top) / 2;
|
||||
|
||||
SetCursorPos(left, top);
|
||||
SetCursorPos(left, top); */
|
||||
}
|
||||
|
||||
@@ -314,7 +314,10 @@ fdc37c6xx_init(const device_t *info)
|
||||
{
|
||||
fdc37c6xx_t *dev = (fdc37c6xx_t *) calloc(1, sizeof(fdc37c6xx_t));
|
||||
|
||||
dev->fdc = device_add(&fdc_at_smc_device);
|
||||
if (dev->chip_id >= 0x63)
|
||||
dev->fdc = device_add(&fdc_at_smc_device);
|
||||
else
|
||||
dev->fdc = device_add(&fdc_at_smc_661_device);
|
||||
|
||||
dev->chip_id = info->local & 0xff;
|
||||
dev->has_ide = (info->local >> 8) & 0xff;
|
||||
|
||||
@@ -894,7 +894,7 @@ fdc37c93x_kbc_handler(fdc37c93x_t *dev)
|
||||
dev->kbc_base = local_enable ? 0x0060 : 0x0000;
|
||||
|
||||
if (dev->kbc_base != old_base)
|
||||
kbc_at_handler(local_enable, dev->kbc);
|
||||
kbc_at_handler(local_enable, dev->kbc_base, dev->kbc);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,56 +8,97 @@
|
||||
*
|
||||
* Emulation of the NatSemi PC87309 Super I/O chip.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2020 Miran Grca.
|
||||
* Copyright 2020-2025 Miran Grca.
|
||||
*/
|
||||
#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/io.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/lpt.h>
|
||||
#include <86box/machine.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/nvr.h>
|
||||
#include <86box/pci.h>
|
||||
#include <86box/rom.h>
|
||||
#include <86box/serial.h>
|
||||
#include <86box/hdc.h>
|
||||
#include <86box/hdc_ide.h>
|
||||
#include <86box/fdd.h>
|
||||
#include <86box/fdc.h>
|
||||
#include <86box/keyboard.h>
|
||||
#include <86box/sio.h>
|
||||
#include <86box/plat_fallthrough.h>
|
||||
#include "cpu.h"
|
||||
|
||||
typedef struct pc87309_t {
|
||||
uint8_t id;
|
||||
uint8_t baddr;
|
||||
uint8_t pm_idx;
|
||||
uint8_t regs[48];
|
||||
uint8_t ld_regs[256][208];
|
||||
uint8_t pm[8];
|
||||
uint16_t superio_base;
|
||||
uint16_t pm_base;
|
||||
int cur_reg;
|
||||
void *kbc;
|
||||
fdc_t *fdc;
|
||||
serial_t *uart[2];
|
||||
} pc87309_t;
|
||||
|
||||
static void fdc_handler(pc87309_t *dev);
|
||||
static void lpt1_handler(pc87309_t *dev);
|
||||
static void serial_handler(pc87309_t *dev, int uart);
|
||||
enum {
|
||||
LD_FDC = 0,
|
||||
LD_LPT,
|
||||
LD_UART2,
|
||||
LD_UART1,
|
||||
LD_PM,
|
||||
LD_KBD,
|
||||
LD_MOUSE
|
||||
} pc87309_ld_t;
|
||||
|
||||
#define LD_MIN LD_FDC
|
||||
#define LD_MAX LD_MOUSE
|
||||
|
||||
static void fdc_handler(pc87309_t *dev);
|
||||
static void lpt1_handler(pc87309_t *dev);
|
||||
static void serial_handler(pc87309_t *dev, int uart);
|
||||
static void kbc_handler(pc87309_t *dev);
|
||||
static void pc87309_write(uint16_t port, uint8_t val, void *priv);
|
||||
static uint8_t pc87309_read(uint16_t port, void *priv);
|
||||
|
||||
#ifdef ENABLE_PC87309_LOG
|
||||
int pc87309_do_log = ENABLE_PC87309_LOG;
|
||||
|
||||
static void
|
||||
pc87309_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (pc87309_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define pc87309_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
static void
|
||||
pc87309_pm_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
pc87309_t *dev = (pc87309_t *) priv;
|
||||
|
||||
if (port & 1) {
|
||||
if (port & 1)
|
||||
dev->pm[dev->pm_idx] = val;
|
||||
else {
|
||||
dev->pm_idx = val & 0x07;
|
||||
|
||||
switch (dev->pm_idx) {
|
||||
case 0x00:
|
||||
@@ -70,8 +111,7 @@ pc87309_pm_write(uint16_t port, uint8_t val, void *priv)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
dev->pm_idx = val & 0x07;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t
|
||||
@@ -104,20 +144,49 @@ pc87309_pm_init(pc87309_t *dev, uint16_t addr)
|
||||
pc87309_pm_read, NULL, NULL, pc87309_pm_write, NULL, NULL, dev);
|
||||
}
|
||||
|
||||
static void
|
||||
kbc_handler(pc87309_t *dev)
|
||||
{
|
||||
uint8_t active = (dev->ld_regs[LD_KBD][0x00] & 0x01) &&
|
||||
(dev->pm[0x00] & 0x01);
|
||||
uint8_t active_2 = dev->ld_regs[LD_MOUSE][0x00] & 0x01;
|
||||
uint8_t irq = (dev->ld_regs[LD_KBD][0x40] & 0x0f);
|
||||
uint8_t irq_2 = (dev->ld_regs[LD_MOUSE][0x40] & 0x0f);
|
||||
uint16_t addr = (dev->ld_regs[LD_KBD][0x30] << 8) |
|
||||
dev->ld_regs[LD_KBD][0x31];
|
||||
uint16_t addr_2 = (dev->ld_regs[LD_KBD][0x32] << 8) |
|
||||
dev->ld_regs[LD_KBD][0x33];
|
||||
|
||||
pc87309_log("%02X, %02X, %02X, %02X, %04X, %04X\n",
|
||||
active, active_2, irq, irq_2, addr, addr_2);
|
||||
|
||||
if (addr <= 0xfff8) {
|
||||
pc87309_log("Enabling KBC #1 on %04X...\n", addr);
|
||||
kbc_at_port_handler(0, active, addr, dev->kbc);
|
||||
}
|
||||
|
||||
if (addr_2 <= 0xfff8) {
|
||||
pc87309_log("Enabling KBC #2 on %04X...\n", addr_2);
|
||||
kbc_at_port_handler(1, active, addr_2, dev->kbc);
|
||||
}
|
||||
|
||||
kbc_at_set_irq(0, active ? irq : 0xffff, dev->kbc);
|
||||
kbc_at_set_irq(1, (active && active_2) ? irq_2 : 0xffff, dev->kbc);
|
||||
}
|
||||
|
||||
static void
|
||||
fdc_handler(pc87309_t *dev)
|
||||
{
|
||||
uint8_t irq;
|
||||
uint8_t active;
|
||||
uint16_t addr;
|
||||
|
||||
fdc_remove(dev->fdc);
|
||||
|
||||
active = (dev->ld_regs[0x00][0x00] & 0x01) && (dev->pm[0x00] & 0x08);
|
||||
addr = ((dev->ld_regs[0x00][0x30] << 8) | dev->ld_regs[0x00][0x31]) - 0x0002;
|
||||
irq = (dev->ld_regs[0x00][0x40] & 0x0f);
|
||||
uint8_t active = (dev->ld_regs[LD_FDC][0x00] & 0x01) &&
|
||||
(dev->pm[0x00] & 0x08);
|
||||
uint8_t irq = (dev->ld_regs[LD_FDC][0x40] & 0x0f);
|
||||
uint16_t addr = ((dev->ld_regs[LD_FDC][0x30] << 8) |
|
||||
dev->ld_regs[LD_FDC][0x31]) & 0xfff8;
|
||||
|
||||
if (active) {
|
||||
if (active && (addr <= 0xfff8)) {
|
||||
pc87309_log("Enabling FDC on %04X, IRQ %i...\n", addr, irq);
|
||||
fdc_set_base(dev->fdc, addr);
|
||||
fdc_set_irq(dev->fdc, irq);
|
||||
}
|
||||
@@ -126,221 +195,351 @@ fdc_handler(pc87309_t *dev)
|
||||
static void
|
||||
lpt1_handler(pc87309_t *dev)
|
||||
{
|
||||
uint8_t irq;
|
||||
uint8_t active;
|
||||
uint16_t addr;
|
||||
uint8_t active = (dev->ld_regs[LD_LPT][0x00] & 0x01) &&
|
||||
(dev->pm[0x00] & 0x10);
|
||||
uint8_t irq = (dev->ld_regs[LD_LPT][0x40] & 0x0f);
|
||||
uint16_t addr = (dev->ld_regs[LD_LPT][0x30] << 8) |
|
||||
dev->ld_regs[LD_LPT][0x31];
|
||||
|
||||
lpt1_remove();
|
||||
|
||||
active = (dev->ld_regs[0x01][0x00] & 0x01) && (dev->pm[0x00] & 0x10);
|
||||
addr = (dev->ld_regs[0x01][0x30] << 8) | dev->ld_regs[0x01][0x31];
|
||||
irq = (dev->ld_regs[0x01][0x40] & 0x0f);
|
||||
|
||||
if (active) {
|
||||
if (active && (addr <= 0xfffc)) {
|
||||
pc87309_log("Enabling LPT1 on %04X...\n", addr);
|
||||
lpt1_setup(addr);
|
||||
lpt1_irq(irq);
|
||||
}
|
||||
} else
|
||||
lpt1_setup(0xffff);
|
||||
|
||||
lpt1_irq(irq);
|
||||
}
|
||||
|
||||
static void
|
||||
serial_handler(pc87309_t *dev, int uart)
|
||||
{
|
||||
uint8_t irq;
|
||||
uint8_t active;
|
||||
uint16_t addr;
|
||||
|
||||
serial_remove(dev->uart[uart]);
|
||||
|
||||
active = (dev->ld_regs[0x03 - uart][0x00] & 0x01) && (dev->pm[0x00] & (1 << (6 - uart)));
|
||||
addr = (dev->ld_regs[0x03 - uart][0x30] << 8) | dev->ld_regs[0x03 - uart][0x31];
|
||||
irq = (dev->ld_regs[0x03 - uart][0x40] & 0x0f);
|
||||
uint8_t active = (dev->ld_regs[LD_UART1 - uart][0x00] & 0x01) &&
|
||||
(dev->pm[0x00] & (1 << (6 - uart)));
|
||||
uint8_t irq = (dev->ld_regs[LD_UART1 - uart][0x40] & 0x0f);
|
||||
uint16_t addr = (dev->ld_regs[LD_UART1 - uart][0x30] << 8) |
|
||||
dev->ld_regs[LD_UART1 - uart][0x31];
|
||||
|
||||
if (active)
|
||||
if (active && (addr <= 0xfff8)) {
|
||||
pc87309_log("Enabling COM%i on %04X...\n", uart + 1, addr);
|
||||
serial_setup(dev->uart[uart], addr, irq);
|
||||
} else
|
||||
serial_setup(dev->uart[uart], 0x0000, irq);
|
||||
}
|
||||
|
||||
static void
|
||||
pm_handler(pc87309_t *dev)
|
||||
{
|
||||
uint8_t active;
|
||||
uint16_t addr;
|
||||
|
||||
pc87309_pm_remove(dev);
|
||||
|
||||
active = (dev->ld_regs[0x04][0x00] & 0x01);
|
||||
addr = (dev->ld_regs[0x04][0x30] << 8) | dev->ld_regs[0x04][0x31];
|
||||
uint8_t active = (dev->ld_regs[LD_PM][0x00] & 0x01);
|
||||
uint16_t addr = (dev->ld_regs[LD_PM][0x30] << 8) |
|
||||
dev->ld_regs[LD_PM][0x31];
|
||||
|
||||
if (active)
|
||||
if (active) {
|
||||
pc87309_log("Enabling power management on %04X...\n", addr);
|
||||
pc87309_pm_init(dev, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
superio_handler(pc87309_t *dev)
|
||||
{
|
||||
if (dev->superio_base != 0x0000)
|
||||
io_removehandler(dev->superio_base, 0x0002,
|
||||
pc87309_read, NULL, NULL,
|
||||
pc87309_write, NULL, NULL, dev);
|
||||
|
||||
switch (dev->regs[0x21] & 0x0b) {
|
||||
default:
|
||||
dev->superio_base = 0x0000;
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x08: case 0x0a:
|
||||
dev->superio_base = 0x015c;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x09: case 0x0b:
|
||||
dev->superio_base = 0x002e;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dev->superio_base != 0x0000) {
|
||||
pc87309_log("Enabling Super I/O on %04X...\n", dev->superio_base);
|
||||
io_sethandler(dev->superio_base, 0x0002,
|
||||
pc87309_read, NULL, NULL,
|
||||
pc87309_write, NULL, NULL, dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pc87309_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
pc87309_t *dev = (pc87309_t *) priv;
|
||||
uint8_t index;
|
||||
|
||||
index = (port & 1) ? 0 : 1;
|
||||
pc87309_t *dev = (pc87309_t *) priv;
|
||||
uint8_t ld = dev->regs[0x07];
|
||||
uint8_t reg = dev->cur_reg - 0x30;
|
||||
uint8_t index = (port & 1) ? 0 : 1;
|
||||
uint8_t old = dev->regs[dev->cur_reg];
|
||||
|
||||
if (index) {
|
||||
dev->cur_reg = val;
|
||||
return;
|
||||
} else {
|
||||
#ifdef ENABLE_PC87309_LOG
|
||||
if (dev->cur_reg >= 0x30)
|
||||
pc87309_log("[%04X:%08X] [W] (%04X) %02X:%02X = %02X\n",
|
||||
CS, cpu_state.pc, port, ld, dev->cur_reg, val);
|
||||
else
|
||||
pc87309_log("[%04X:%08X] [W] (%04X) %02X = %02X\n",
|
||||
CS, cpu_state.pc, port, dev->cur_reg, val);
|
||||
#endif
|
||||
switch (dev->cur_reg) {
|
||||
case 0x00:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
case 0x21:
|
||||
case 0x02: case 0x03:
|
||||
case 0x06: case 0x07:
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
break;
|
||||
case 0x21:
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !(val & 0x04));
|
||||
superio_handler(dev);
|
||||
break;
|
||||
case 0x22:
|
||||
dev->regs[dev->cur_reg] = val & 0x7f;
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
break;
|
||||
default:
|
||||
if (dev->cur_reg >= 0x30) {
|
||||
if ((dev->regs[0x07] != 0x06) || !(dev->regs[0x21] & 0x10))
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val;
|
||||
}
|
||||
if (dev->cur_reg >= 0x30)
|
||||
old = dev->ld_regs[ld][reg];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (dev->cur_reg) {
|
||||
case 0x30:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x01;
|
||||
switch (dev->regs[0x07]) {
|
||||
case 0x00:
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_KBD: case LD_MOUSE:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
kbc_handler(dev);
|
||||
break;
|
||||
case LD_FDC:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
fdc_handler(dev);
|
||||
break;
|
||||
case 0x01:
|
||||
case LD_LPT:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
lpt1_handler(dev);
|
||||
break;
|
||||
case 0x02:
|
||||
case LD_UART2:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
serial_handler(dev, 1);
|
||||
break;
|
||||
case 0x03:
|
||||
case LD_UART1:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
serial_handler(dev, 0);
|
||||
break;
|
||||
case 0x04:
|
||||
case LD_PM:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
pm_handler(dev);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* I/O Range Check. */
|
||||
case 0x31:
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_MIN ... LD_MAX:
|
||||
if (ld != LD_MOUSE)
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* Base Address 0 MSB. */
|
||||
case 0x60:
|
||||
case 0x62:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x07;
|
||||
if (dev->cur_reg == 0x62)
|
||||
break;
|
||||
switch (dev->regs[0x07]) {
|
||||
case 0x00:
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_KBD:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
kbc_handler(dev);
|
||||
break;
|
||||
case LD_FDC:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
fdc_handler(dev);
|
||||
break;
|
||||
case 0x01:
|
||||
case LD_LPT:
|
||||
dev->ld_regs[ld][reg] = (old & 0xfc) | (val & 0x03);
|
||||
lpt1_handler(dev);
|
||||
break;
|
||||
case 0x02:
|
||||
case LD_UART2:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
serial_handler(dev, 1);
|
||||
break;
|
||||
case 0x03:
|
||||
case LD_UART1:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
serial_handler(dev, 0);
|
||||
break;
|
||||
case 0x04:
|
||||
case LD_PM:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
pm_handler(dev);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x63:
|
||||
if (dev->regs[0x07] == 0x06)
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xf8) | 0x04;
|
||||
break;
|
||||
/* Base Address 0 LSB. */
|
||||
case 0x61:
|
||||
switch (dev->regs[0x07]) {
|
||||
case 0x00:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfa) | 0x02;
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_KBD:
|
||||
dev->ld_regs[ld][reg] = (old & 0x04) | (val & 0xfb);
|
||||
kbc_handler(dev);
|
||||
break;
|
||||
case LD_FDC:
|
||||
dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8);
|
||||
fdc_handler(dev);
|
||||
break;
|
||||
case 0x01:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfc;
|
||||
case LD_LPT:
|
||||
dev->ld_regs[ld][reg] = (old & 0x03) | (val & 0xfc);
|
||||
lpt1_handler(dev);
|
||||
break;
|
||||
case 0x02:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8;
|
||||
case LD_UART2:
|
||||
dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8);
|
||||
serial_handler(dev, 1);
|
||||
break;
|
||||
case 0x03:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8;
|
||||
case LD_UART1:
|
||||
dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8);
|
||||
serial_handler(dev, 0);
|
||||
break;
|
||||
case 0x04:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfe;
|
||||
case LD_PM:
|
||||
dev->ld_regs[ld][reg] = (old & 0x01) | (val & 0xfe);
|
||||
pm_handler(dev);
|
||||
break;
|
||||
case 0x06:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* Base Address 1 MSB (undocumented for Logical Device 7). */
|
||||
case 0x62:
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_KBD:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
kbc_handler(dev);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* Base Address 1 LSB (undocumented for Logical Device 7). */
|
||||
case 0x63:
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_KBD:
|
||||
dev->ld_regs[ld][reg] = (old & 0x04) | (val & 0xfb);
|
||||
kbc_handler(dev);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* Interrupt Select. */
|
||||
case 0x70:
|
||||
case 0x74:
|
||||
case 0x75:
|
||||
switch (dev->regs[0x07]) {
|
||||
case 0x00:
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_KBD: case LD_MOUSE:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
kbc_handler(dev);
|
||||
break;
|
||||
case LD_FDC:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
fdc_handler(dev);
|
||||
break;
|
||||
case 0x01:
|
||||
case LD_LPT:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
lpt1_handler(dev);
|
||||
break;
|
||||
case 0x02:
|
||||
case LD_UART2:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
serial_handler(dev, 1);
|
||||
break;
|
||||
case 0x03:
|
||||
case LD_UART1:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
serial_handler(dev, 0);
|
||||
break;
|
||||
case 0x04:
|
||||
pm_handler(dev);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* Interrupt Type. */
|
||||
case 0x71:
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_MIN ... LD_MAX:
|
||||
if ((ld == LD_KBD) || (ld == LD_MOUSE))
|
||||
dev->ld_regs[ld][reg] = (old & 0xfc) | (val & 0x03);
|
||||
else
|
||||
dev->ld_regs[ld][reg] = (old & 0xfd) | (val & 0x02);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* DMA Channel Select 0. */
|
||||
case 0x74:
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_FDC:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
fdc_handler(dev);
|
||||
break;
|
||||
case LD_LPT:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
lpt1_handler(dev);
|
||||
break;
|
||||
case LD_UART2:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* DMA Channel Select 1. */
|
||||
case 0x75:
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_UART2:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* Configuration Register 0. */
|
||||
case 0xf0:
|
||||
switch (dev->regs[0x07]) {
|
||||
case 0x00:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xe1;
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_KBD:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
break;
|
||||
case LD_FDC:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
fdc_update_densel_polarity(dev->fdc, (val & 0x20) ? 1 : 0);
|
||||
fdc_update_enh_mode(dev->fdc, (val & 0x40) ? 1 : 0);
|
||||
break;
|
||||
case 0x01:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf3;
|
||||
case LD_LPT:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
lpt1_handler(dev);
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x87;
|
||||
break;
|
||||
case 0x06:
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xc1;
|
||||
break;
|
||||
|
||||
default:
|
||||
case LD_UART2: case LD_UART1:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* Configuration Register 1. */
|
||||
case 0xf1:
|
||||
if (dev->regs[0x07] == 0x00)
|
||||
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x0f;
|
||||
switch (ld) {
|
||||
default:
|
||||
break;
|
||||
case LD_FDC:
|
||||
dev->ld_regs[ld][reg] = val;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -348,97 +547,102 @@ pc87309_write(uint16_t port, uint8_t val, void *priv)
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t
|
||||
static uint8_t
|
||||
pc87309_read(uint16_t port, void *priv)
|
||||
{
|
||||
const pc87309_t *dev = (pc87309_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t index;
|
||||
|
||||
index = (port & 1) ? 0 : 1;
|
||||
const pc87309_t *dev = (pc87309_t *) priv;
|
||||
uint8_t ld = dev->regs[0x07];
|
||||
uint8_t reg = dev->cur_reg - 0x30;
|
||||
uint8_t index = (port & 1) ? 0 : 1;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if (index)
|
||||
ret = dev->cur_reg & 0x1f;
|
||||
ret = dev->cur_reg;
|
||||
else {
|
||||
if (dev->cur_reg >= 0x30)
|
||||
ret = dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30];
|
||||
ret = dev->ld_regs[ld][reg];
|
||||
/* Write-only registers. */
|
||||
else if ((dev->cur_reg == 0x00) ||
|
||||
(dev->cur_reg == 0x02) || (dev->cur_reg == 0x03))
|
||||
ret = 0x00;
|
||||
else
|
||||
ret = dev->regs[dev->cur_reg];
|
||||
#ifdef ENABLE_PC87309_LOG
|
||||
if (dev->cur_reg >= 0x30)
|
||||
pc87309_log("[%04X:%08X] [R] (%04X) %02X:%02X = %02X\n",
|
||||
CS, cpu_state.pc, port, ld, dev->cur_reg, ret);
|
||||
else
|
||||
pc87309_log("[%04X:%08X] [R] (%04X) %02X = %02X\n",
|
||||
CS, cpu_state.pc, port, dev->cur_reg, ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
pc87309_reset(pc87309_t *dev)
|
||||
pc87309_reset(void *priv)
|
||||
{
|
||||
pc87309_t *dev = (pc87309_t *) priv;
|
||||
|
||||
memset(dev->regs, 0x00, 0x30);
|
||||
for (uint16_t i = 0; i < 256; i++)
|
||||
memset(dev->ld_regs[i], 0x00, 0xd0);
|
||||
memset(dev->pm, 0x00, 0x08);
|
||||
|
||||
dev->regs[0x20] = dev->id;
|
||||
dev->regs[0x21] = 0x04;
|
||||
dev->regs[0x21] = 0x04 | dev->baddr;
|
||||
|
||||
dev->ld_regs[0x00][0x01] = 0x01;
|
||||
dev->ld_regs[0x00][0x30] = 0x03;
|
||||
dev->ld_regs[0x00][0x31] = 0xf2;
|
||||
dev->ld_regs[0x00][0x40] = 0x06;
|
||||
dev->ld_regs[0x00][0x41] = 0x03;
|
||||
dev->ld_regs[0x00][0x44] = 0x02;
|
||||
dev->ld_regs[0x00][0x45] = 0x04;
|
||||
dev->ld_regs[0x00][0xc0] = 0x02;
|
||||
dev->ld_regs[LD_KBD ][0x00] = 0x01;
|
||||
dev->ld_regs[LD_KBD ][0x31] = 0x60;
|
||||
dev->ld_regs[LD_KBD ][0x33] = 0x64;
|
||||
dev->ld_regs[LD_KBD ][0x40] = 0x01;
|
||||
dev->ld_regs[LD_KBD ][0x41] = 0x02;
|
||||
dev->ld_regs[LD_KBD ][0x44] = 0x04;
|
||||
dev->ld_regs[LD_KBD ][0x45] = 0x04;
|
||||
dev->ld_regs[LD_KBD ][0xc0] = 0x40;
|
||||
|
||||
dev->ld_regs[0x01][0x30] = 0x02;
|
||||
dev->ld_regs[0x01][0x31] = 0x78;
|
||||
dev->ld_regs[0x01][0x40] = 0x07;
|
||||
dev->ld_regs[0x01][0x44] = 0x04;
|
||||
dev->ld_regs[0x01][0x45] = 0x04;
|
||||
dev->ld_regs[0x01][0xc0] = 0xf2;
|
||||
dev->ld_regs[LD_MOUSE][0x40] = 0x0c;
|
||||
dev->ld_regs[LD_MOUSE][0x41] = 0x02;
|
||||
dev->ld_regs[LD_MOUSE][0x44] = 0x04;
|
||||
dev->ld_regs[LD_MOUSE][0x45] = 0x04;
|
||||
|
||||
dev->ld_regs[0x02][0x30] = 0x02;
|
||||
dev->ld_regs[0x02][0x31] = 0xf8;
|
||||
dev->ld_regs[0x02][0x40] = 0x03;
|
||||
dev->ld_regs[0x02][0x41] = 0x03;
|
||||
dev->ld_regs[0x02][0x44] = 0x04;
|
||||
dev->ld_regs[0x02][0x45] = 0x04;
|
||||
dev->ld_regs[0x02][0xc0] = 0x02;
|
||||
dev->ld_regs[LD_FDC ][0x01] = 0x01;
|
||||
dev->ld_regs[LD_FDC ][0x30] = 0x03;
|
||||
dev->ld_regs[LD_FDC ][0x31] = 0xf0;
|
||||
dev->ld_regs[LD_FDC ][0x32] = 0x03;
|
||||
dev->ld_regs[LD_FDC ][0x33] = 0xf7;
|
||||
dev->ld_regs[LD_FDC ][0x40] = 0x06;
|
||||
dev->ld_regs[LD_FDC ][0x41] = 0x03;
|
||||
dev->ld_regs[LD_FDC ][0x44] = 0x02;
|
||||
dev->ld_regs[LD_FDC ][0x45] = 0x04;
|
||||
dev->ld_regs[LD_FDC ][0xc0] = 0x02;
|
||||
|
||||
dev->ld_regs[0x03][0x30] = 0x03;
|
||||
dev->ld_regs[0x03][0x31] = 0xf8;
|
||||
dev->ld_regs[0x03][0x40] = 0x04;
|
||||
dev->ld_regs[0x03][0x41] = 0x03;
|
||||
dev->ld_regs[0x03][0x44] = 0x04;
|
||||
dev->ld_regs[0x03][0x45] = 0x04;
|
||||
dev->ld_regs[0x03][0xc0] = 0x02;
|
||||
dev->ld_regs[LD_LPT ][0x30] = 0x02;
|
||||
dev->ld_regs[LD_LPT ][0x31] = 0x78;
|
||||
dev->ld_regs[LD_LPT ][0x40] = 0x07;
|
||||
dev->ld_regs[LD_LPT ][0x44] = 0x04;
|
||||
dev->ld_regs[LD_LPT ][0x45] = 0x04;
|
||||
dev->ld_regs[LD_LPT ][0xc0] = 0xf2;
|
||||
|
||||
dev->ld_regs[0x04][0x44] = 0x04;
|
||||
dev->ld_regs[0x04][0x45] = 0x04;
|
||||
dev->ld_regs[LD_UART2][0x30] = 0x02;
|
||||
dev->ld_regs[LD_UART2][0x31] = 0xf8;
|
||||
dev->ld_regs[LD_UART2][0x40] = 0x03;
|
||||
dev->ld_regs[LD_UART2][0x41] = 0x03;
|
||||
dev->ld_regs[LD_UART2][0x44] = 0x04;
|
||||
dev->ld_regs[LD_UART2][0x45] = 0x04;
|
||||
dev->ld_regs[LD_UART2][0xc0] = 0x02;
|
||||
|
||||
dev->ld_regs[0x05][0x40] = 0x0c;
|
||||
dev->ld_regs[0x05][0x41] = 0x02;
|
||||
dev->ld_regs[0x05][0x44] = 0x04;
|
||||
dev->ld_regs[0x05][0x45] = 0x04;
|
||||
dev->ld_regs[LD_UART1][0x30] = 0x03;
|
||||
dev->ld_regs[LD_UART1][0x31] = 0xf8;
|
||||
dev->ld_regs[LD_UART1][0x40] = 0x04;
|
||||
dev->ld_regs[LD_UART1][0x41] = 0x03;
|
||||
dev->ld_regs[LD_UART1][0x44] = 0x04;
|
||||
dev->ld_regs[LD_UART1][0x45] = 0x04;
|
||||
dev->ld_regs[LD_UART1][0xc0] = 0x02;
|
||||
|
||||
dev->ld_regs[0x06][0x01] = 0x01;
|
||||
dev->ld_regs[0x06][0x31] = 0x60;
|
||||
dev->ld_regs[0x06][0x33] = 0x64;
|
||||
dev->ld_regs[0x06][0x40] = 0x01;
|
||||
dev->ld_regs[0x06][0x41] = 0x02;
|
||||
dev->ld_regs[0x06][0x44] = 0x04;
|
||||
dev->ld_regs[0x06][0x45] = 0x04;
|
||||
dev->ld_regs[0x06][0xc0] = 0x40;
|
||||
|
||||
dev->regs[0x00] = 0x0B;
|
||||
dev->regs[0x01] = 0x01;
|
||||
dev->regs[0x03] = 0x01;
|
||||
dev->regs[0x05] = 0x0D;
|
||||
dev->regs[0x08] = 0x70;
|
||||
dev->regs[0x09] = 0xC0;
|
||||
dev->regs[0x0b] = 0x80;
|
||||
dev->regs[0x0f] = 0x1E;
|
||||
dev->regs[0x12] = 0x30;
|
||||
dev->regs[0x19] = 0xEF;
|
||||
dev->ld_regs[LD_PM ][0x44] = 0x04;
|
||||
dev->ld_regs[LD_PM ][0x45] = 0x04;
|
||||
|
||||
dev->pm[0] = 0x79;
|
||||
dev->pm[4] = 0x0e;
|
||||
@@ -449,10 +653,16 @@ pc87309_reset(pc87309_t *dev)
|
||||
0 = 360 rpm @ 500 kbps for 3.5"
|
||||
1 = Default, 300 rpm @ 500, 300, 250, 1000 kbps for 3.5"
|
||||
*/
|
||||
lpt1_remove();
|
||||
serial_remove(dev->uart[0]);
|
||||
serial_remove(dev->uart[1]);
|
||||
fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, 0);
|
||||
fdc_reset(dev->fdc);
|
||||
|
||||
kbc_handler(dev);
|
||||
fdc_handler(dev);
|
||||
lpt1_handler(dev);
|
||||
serial_handler(dev, 0);
|
||||
serial_handler(dev, 1);
|
||||
pm_handler(dev);
|
||||
superio_handler(dev);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -475,16 +685,27 @@ pc87309_init(const device_t *info)
|
||||
dev->uart[0] = device_add_inst(&ns16550_device, 1);
|
||||
dev->uart[1] = device_add_inst(&ns16550_device, 2);
|
||||
|
||||
pc87309_reset(dev);
|
||||
|
||||
if (info->local & 0x100) {
|
||||
io_sethandler(0x15c, 0x0002,
|
||||
pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev);
|
||||
} else {
|
||||
io_sethandler(0x02e, 0x0002,
|
||||
pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev);
|
||||
switch (info->local & PCX730X_KBC) {
|
||||
default:
|
||||
case PCX730X_AMI:
|
||||
dev->kbc = device_add(&keyboard_ps2_intel_ami_pci_device);
|
||||
break;
|
||||
/* Optiplex! */
|
||||
case PCX730X_PHOENIX_42:
|
||||
dev->kbc = device_add(&keyboard_ps2_phoenix_device);
|
||||
break;
|
||||
case PCX730X_PHOENIX_42I:
|
||||
dev->kbc = device_add(&keyboard_ps2_phoenix_pci_device);
|
||||
break;
|
||||
}
|
||||
|
||||
if (info->local & PCX730X_15C)
|
||||
dev->baddr = 0x0a;
|
||||
else
|
||||
dev->baddr = 0x0b;
|
||||
|
||||
pc87309_reset(dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
@@ -492,24 +713,10 @@ const device_t pc87309_device = {
|
||||
.name = "National Semiconductor PC87309 Super I/O",
|
||||
.internal_name = "pc87309",
|
||||
.flags = 0,
|
||||
.local = 0xe0,
|
||||
.local = 0,
|
||||
.init = pc87309_init,
|
||||
.close = pc87309_close,
|
||||
.reset = NULL,
|
||||
.available = NULL,
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t pc87309_15c_device = {
|
||||
.name = "National Semiconductor PC87309 Super I/O (Port 15Ch)",
|
||||
.internal_name = "pc87309_15c",
|
||||
.flags = 0,
|
||||
.local = 0x1e0,
|
||||
.init = pc87309_init,
|
||||
.close = pc87309_close,
|
||||
.reset = NULL,
|
||||
.reset = pc87309_reset,
|
||||
.available = NULL,
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
|
||||
@@ -180,9 +180,6 @@ endif()
|
||||
add_subdirectory(ymfm)
|
||||
target_link_libraries(86Box ymfm)
|
||||
|
||||
add_subdirectory(saasound)
|
||||
target_link_libraries(86Box saasound)
|
||||
|
||||
if(GUSMAX)
|
||||
target_compile_definitions(snd PRIVATE USE_GUSMAX)
|
||||
endif()
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
add_library(saasound OBJECT
|
||||
SAAAmp.cpp
|
||||
SAAAmp.h
|
||||
SAADevice.cpp
|
||||
SAADevice.h
|
||||
SAAEnv.cpp
|
||||
SAAEnv.h
|
||||
SAAFreq.cpp
|
||||
SAAFreq.h
|
||||
SAAImpl.cpp
|
||||
SAAImpl.h
|
||||
SAANoise.cpp
|
||||
SAANoise.h
|
||||
SAASndC.cpp
|
||||
SAASndC.h
|
||||
SAASound.cpp)
|
||||
@@ -1,203 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAAAmp.cpp: implementation of the CSAAAmp class.
|
||||
// This class handles Tone/Noise mixing, Envelope application and
|
||||
// amplification.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SAASound.h"
|
||||
#include "types.h"
|
||||
#include "SAANoise.h"
|
||||
#include "SAAEnv.h"
|
||||
#include "SAAFreq.h"
|
||||
#include "SAAAmp.h"
|
||||
#include "defns.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
CSAAAmp::CSAAAmp(CSAAFreq * const ToneGenerator, const CSAANoise * const NoiseGenerator, const CSAAEnv * const EnvGenerator)
|
||||
:
|
||||
m_pcConnectedToneGenerator(ToneGenerator),
|
||||
m_pcConnectedNoiseGenerator(NoiseGenerator),
|
||||
m_pcConnectedEnvGenerator(EnvGenerator),
|
||||
m_bUseEnvelope(EnvGenerator != NULL)
|
||||
{
|
||||
leftlevel = 0;
|
||||
leftlevela0x0e = 0;
|
||||
rightlevel = 0;
|
||||
rightlevela0x0e = 0;
|
||||
m_nMixMode = 0;
|
||||
m_bMute=true;
|
||||
m_bSync = false;
|
||||
m_nOutputIntermediate=0;
|
||||
last_level_byte=0;
|
||||
SetAmpLevel(0x00);
|
||||
|
||||
}
|
||||
|
||||
CSAAAmp::~CSAAAmp()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CSAAAmp::SetAmpLevel(BYTE level_byte)
|
||||
{
|
||||
// if level unchanged since last call then do nothing
|
||||
if (level_byte != last_level_byte)
|
||||
{
|
||||
last_level_byte = level_byte;
|
||||
leftlevel = level_byte & 0x0f;
|
||||
leftlevela0x0e = leftlevel & 0x0e;
|
||||
|
||||
rightlevel = (level_byte >> 4) & 0x0f;
|
||||
rightlevela0x0e = rightlevel & 0x0e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CSAAAmp::SetToneMixer(BYTE bEnabled)
|
||||
{
|
||||
if (bEnabled == 0)
|
||||
{
|
||||
// clear mixer bit
|
||||
m_nMixMode &= ~(0x01);
|
||||
}
|
||||
else
|
||||
{
|
||||
// set mixer bit
|
||||
m_nMixMode |= 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
void CSAAAmp::SetNoiseMixer(BYTE bEnabled)
|
||||
{
|
||||
if (bEnabled == 0)
|
||||
{
|
||||
m_nMixMode &= ~(0x02);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nMixMode |= 0x02;
|
||||
}
|
||||
}
|
||||
|
||||
void CSAAAmp::Mute(bool bMute)
|
||||
{
|
||||
// m_bMute refers to the GLOBAL mute setting (register 28 bit 0)
|
||||
// NOT the per-channel mixer settings !!
|
||||
m_bMute = bMute;
|
||||
}
|
||||
|
||||
void CSAAAmp::Sync(bool bSync)
|
||||
{
|
||||
// m_bSync refers to the GLOBAL sync setting (register 28 bit 1)
|
||||
m_bSync = bSync;
|
||||
}
|
||||
|
||||
void CSAAAmp::Tick(void)
|
||||
{
|
||||
// updates m_nOutputIntermediate to 0, 1 or 2
|
||||
//
|
||||
|
||||
// connected oscillator always ticks (this isn't really connected to the amp)
|
||||
int level = m_pcConnectedToneGenerator->Tick();
|
||||
|
||||
switch (m_nMixMode)
|
||||
{
|
||||
case 0:
|
||||
// no tone or noise for this channel
|
||||
m_nOutputIntermediate = 0;
|
||||
break;
|
||||
case 1:
|
||||
// tone only for this channel
|
||||
m_nOutputIntermediate = level * 2;
|
||||
// NOTE: ConnectedToneGenerator returns either 0 or 1
|
||||
break;
|
||||
case 2:
|
||||
// noise only for this channel
|
||||
m_nOutputIntermediate = m_pcConnectedNoiseGenerator->Level() * 2;
|
||||
// NOTE: ConnectedNoiseGenerator()->Level() returns either 0 or 1
|
||||
break;
|
||||
case 3:
|
||||
// tone+noise for this channel ... mixing algorithm :
|
||||
// tone noise output
|
||||
// 0 0 0
|
||||
// 1 0 2
|
||||
// 0 1 0
|
||||
// 1 1 1
|
||||
// = 2 * tone - 1 * (tone & noise)
|
||||
// = tone * (2 - noise)
|
||||
m_nOutputIntermediate = level * (2 - m_pcConnectedNoiseGenerator->Level());
|
||||
break;
|
||||
}
|
||||
// intermediate is between 0 and 2
|
||||
}
|
||||
|
||||
inline int CSAAAmp::EffectiveAmplitude(int amp, int env) const
|
||||
{
|
||||
// Return the effective amplitude of the low-pass-filtered result of the logical
|
||||
// AND of the amplitude PDM and envelope PDM patterns. This is a more accurate
|
||||
// evaluation of the SAA than simply returning amp * env , based on how the SAA
|
||||
// implements pulse-density modulation.
|
||||
static const int pdm[16][16] = {
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,2,2,2,2,2,2,2,2,4,4,4,4},
|
||||
{0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8},
|
||||
{0,1,1,2,4,5,5,6,6,7,7,8,10,11,11,12},
|
||||
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
|
||||
{0,1,2,3,6,7,8,9,10,11,12,13,16,17,18,19},
|
||||
{0,2,3,5,6,8,9,11,12,14,15,17,18,20,21,23},
|
||||
{0,2,3,5,8,10,11,13,14,16,17,19,22,24,25,27},
|
||||
{0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30},
|
||||
{0,2,4,6,10,12,14,16,18,20,22,24,28,30,32,34},
|
||||
{0,3,5,8,10,13,15,18,20,23,25,28,30,33,35,38},
|
||||
{0,3,5,8,12,15,17,20,22,25,27,30,34,37,39,42},
|
||||
{0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45},
|
||||
{0,3,6,9,14,17,20,23,26,29,32,35,40,43,46,49},
|
||||
{0,4,7,11,14,18,21,25,28,32,35,39,42,46,49,53},
|
||||
{0,4,7,11,16,20,23,27,30,34,37,41,46,50,53,57}
|
||||
};
|
||||
|
||||
return(pdm[amp][env] * 4);
|
||||
}
|
||||
|
||||
void CSAAAmp::TickAndOutputStereo(unsigned int & left, unsigned int & right)
|
||||
{
|
||||
// This returns a value between 0 and 480 inclusive.
|
||||
// This represents the full dynamic range of one output mixer (tone, or noise+tone, at full volume,
|
||||
// without envelopes enabled). Note that, with envelopes enabled, the actual dynamic range
|
||||
// is reduced on-chip to just over 88% of this (424), so the "loudest" output requires disabling envs.
|
||||
// NB for 6 channels at full volume, with simple additive mixing, you would see a combined
|
||||
// output of 2880, and a multiplier of 11 (=31680) fits comfortably within 16-bit signed output range.
|
||||
|
||||
if (m_bSync)
|
||||
{
|
||||
// TODO check this
|
||||
left = right = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// first, do the Tick:
|
||||
Tick();
|
||||
|
||||
// now calculate the returned amplitude for this sample:
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
if (m_bMute)
|
||||
{
|
||||
left = right = 0;
|
||||
}
|
||||
else if (m_bUseEnvelope && m_pcConnectedEnvGenerator->IsActive())
|
||||
{
|
||||
left = EffectiveAmplitude(m_pcConnectedEnvGenerator->LeftLevel(), leftlevela0x0e) * (2 - m_nOutputIntermediate);
|
||||
right = EffectiveAmplitude(m_pcConnectedEnvGenerator->RightLevel(), rightlevela0x0e) * (2 - m_nOutputIntermediate);
|
||||
}
|
||||
else
|
||||
{
|
||||
left = leftlevel * m_nOutputIntermediate * 16;
|
||||
right = rightlevel * m_nOutputIntermediate * 16;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAAAmp.h: interface for the CSAAAmp class.
|
||||
// This class handles Tone/Noise mixing, Envelope application and
|
||||
// amplification.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SAAAMP_H_INCLUDED
|
||||
#define SAAAMP_H_INCLUDED
|
||||
|
||||
class CSAAAmp
|
||||
{
|
||||
private:
|
||||
int leftlevel;
|
||||
int leftlevela0x0e;
|
||||
int rightlevel;
|
||||
int rightlevela0x0e;
|
||||
int m_nOutputIntermediate;
|
||||
unsigned int m_nMixMode;
|
||||
CSAAFreq * const m_pcConnectedToneGenerator; // not const because amp calls ->Tick()
|
||||
const CSAANoise * const m_pcConnectedNoiseGenerator;
|
||||
const CSAAEnv * const m_pcConnectedEnvGenerator;
|
||||
const bool m_bUseEnvelope;
|
||||
mutable bool m_bMute;
|
||||
mutable bool m_bSync;
|
||||
mutable BYTE last_level_byte;
|
||||
int EffectiveAmplitude(int amp, int env) const;
|
||||
|
||||
public:
|
||||
CSAAAmp(CSAAFreq * const ToneGenerator, const CSAANoise * const NoiseGenerator, const CSAAEnv * const EnvGenerator);
|
||||
~CSAAAmp();
|
||||
|
||||
void SetAmpLevel(BYTE level_byte); // really just a BYTE
|
||||
void SetToneMixer(BYTE bEnabled);
|
||||
void SetNoiseMixer(BYTE bEnabled);
|
||||
void Mute(bool bMute);
|
||||
void Sync(bool bSync);
|
||||
void Tick(void);
|
||||
void TickAndOutputStereo(unsigned int & left, unsigned int & right);
|
||||
|
||||
};
|
||||
|
||||
#endif // SAAAMP_H_INCLUDED
|
||||
@@ -1,41 +0,0 @@
|
||||
// Part of SAASound copyright 2020 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAAConfig.h: configuration file handler class
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "defns.h"
|
||||
#ifdef USE_CONFIG_FILE
|
||||
|
||||
#ifndef SAA_CONFIG_H_INCLUDED
|
||||
#define SAA_CONFIG_H_INCLUDED
|
||||
|
||||
#define INI_READONLY
|
||||
#define INI_ANSIONLY /*nb not really 'ANSI', this just forces all read/write to use 8-bit char*/
|
||||
#include "minIni/minIni.h"
|
||||
|
||||
class SAAConfig
|
||||
{
|
||||
private:
|
||||
minIni m_minIni;
|
||||
bool m_bHasReadConfig;
|
||||
|
||||
public:
|
||||
bool m_bGenerateRegisterLogs;
|
||||
bool m_bGeneratePcmLogs;
|
||||
bool m_bGeneratePcmSeparateChannels;
|
||||
t_string m_strRegisterLogPath;
|
||||
t_string m_strPcmOutputPath;
|
||||
unsigned int m_nOversample;
|
||||
bool m_bHighpass;
|
||||
double m_nBoost;
|
||||
|
||||
SAAConfig();
|
||||
void ReadConfig();
|
||||
|
||||
t_string getChannelPcmOutputPath(int);
|
||||
};
|
||||
|
||||
#endif // SAA_CONFIG_H_INCLUDED
|
||||
|
||||
#endif // USE_CONFIG_FILE
|
||||
@@ -1,392 +0,0 @@
|
||||
// Part of SAASound copyright 2020 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAADevice.cpp: connecting the subcomponents of the SAA1099 together.
|
||||
// This class handles device inputs and outputs (clocking, data and
|
||||
// address bus, and simulated output)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SAASound.h"
|
||||
#include "types.h"
|
||||
#include "SAAEnv.h"
|
||||
#include "SAANoise.h"
|
||||
#include "SAAFreq.h"
|
||||
#include "SAAAmp.h"
|
||||
#include "SAASound.h"
|
||||
#include "SAAImpl.h"
|
||||
#include "defns.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
CSAADevice::CSAADevice()
|
||||
:
|
||||
m_nCurrentSaaReg(0),
|
||||
m_bOutputEnabled(false),
|
||||
m_bSync(false),
|
||||
m_bHighpass(true),
|
||||
m_nOversample(0),
|
||||
m_Noise0(0xffffffff),
|
||||
m_Noise1(0xffffffff),
|
||||
m_Env0(),
|
||||
m_Env1(),
|
||||
m_Osc0(&m_Noise0, NULL),
|
||||
m_Osc1(NULL, &m_Env0),
|
||||
m_Osc2(NULL, NULL),
|
||||
m_Osc3(&m_Noise1, NULL),
|
||||
m_Osc4(NULL, &m_Env1),
|
||||
m_Osc5(NULL, NULL),
|
||||
m_Amp0(&m_Osc0, &m_Noise0, NULL),
|
||||
m_Amp1(&m_Osc1, &m_Noise0, NULL),
|
||||
m_Amp2(&m_Osc2, &m_Noise0, &m_Env0),
|
||||
m_Amp3(&m_Osc3, &m_Noise1, NULL),
|
||||
m_Amp4(&m_Osc4, &m_Noise1, NULL),
|
||||
m_Amp5(&m_Osc5, &m_Noise1, &m_Env1)
|
||||
{
|
||||
// Create and link up the objects that make up the emulator
|
||||
Noise[0] = &m_Noise0;
|
||||
Noise[1] = &m_Noise1;
|
||||
Env[0] = &m_Env0;
|
||||
Env[1] = &m_Env1;
|
||||
|
||||
// Create oscillators (tone generators) and link to noise generators and
|
||||
// envelope controllers
|
||||
Osc[0] = &m_Osc0;
|
||||
Osc[1] = &m_Osc1;
|
||||
Osc[2] = &m_Osc2;
|
||||
Osc[3] = &m_Osc3;
|
||||
Osc[4] = &m_Osc4;
|
||||
Osc[5] = &m_Osc5;
|
||||
|
||||
// Create amplification/mixing stages and link to appropriate oscillators,
|
||||
// noise generators and envelope controllers
|
||||
Amp[0] = &m_Amp0;
|
||||
Amp[1] = &m_Amp1;
|
||||
Amp[2] = &m_Amp2;
|
||||
Amp[3] = &m_Amp3;
|
||||
Amp[4] = &m_Amp4;
|
||||
Amp[5] = &m_Amp5;
|
||||
|
||||
_SetClockRate(EXTERNAL_CLK_HZ);
|
||||
_SetOversample(DEFAULT_OVERSAMPLE);
|
||||
}
|
||||
|
||||
CSAADevice::~CSAADevice()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// CSAASound members
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CSAADevice::_SetClockRate(unsigned int nClockRate)
|
||||
{
|
||||
m_Osc0._SetClockRate(nClockRate);
|
||||
m_Osc1._SetClockRate(nClockRate);
|
||||
m_Osc2._SetClockRate(nClockRate);
|
||||
m_Osc3._SetClockRate(nClockRate);
|
||||
m_Osc4._SetClockRate(nClockRate);
|
||||
m_Osc5._SetClockRate(nClockRate);
|
||||
m_Noise0._SetClockRate(nClockRate);
|
||||
m_Noise1._SetClockRate(nClockRate);
|
||||
}
|
||||
|
||||
void CSAADevice::_SetSampleRate(unsigned int nSampleRate)
|
||||
{
|
||||
m_Osc0._SetSampleRate(nSampleRate);
|
||||
m_Osc1._SetSampleRate(nSampleRate);
|
||||
m_Osc2._SetSampleRate(nSampleRate);
|
||||
m_Osc3._SetSampleRate(nSampleRate);
|
||||
m_Osc4._SetSampleRate(nSampleRate);
|
||||
m_Osc5._SetSampleRate(nSampleRate);
|
||||
m_Noise0._SetSampleRate(nSampleRate);
|
||||
m_Noise1._SetSampleRate(nSampleRate);
|
||||
}
|
||||
|
||||
void CSAADevice::_SetOversample(unsigned int nOversample)
|
||||
{
|
||||
if (((int) nOversample) != m_nOversample)
|
||||
{
|
||||
m_nOversample = nOversample;
|
||||
m_Osc0._SetOversample(nOversample);
|
||||
m_Osc1._SetOversample(nOversample);
|
||||
m_Osc2._SetOversample(nOversample);
|
||||
m_Osc3._SetOversample(nOversample);
|
||||
m_Osc4._SetOversample(nOversample);
|
||||
m_Osc5._SetOversample(nOversample);
|
||||
m_Noise0._SetOversample(nOversample);
|
||||
m_Noise1._SetOversample(nOversample);
|
||||
}
|
||||
}
|
||||
|
||||
void CSAADevice::_WriteData(BYTE nData)
|
||||
{
|
||||
#if defined(DEBUG) || defined(DEBUGSAA)
|
||||
m_Reg[m_nCurrentSaaReg] = nData;
|
||||
#endif
|
||||
|
||||
// route nData to the appropriate place
|
||||
switch (m_nCurrentSaaReg)
|
||||
{
|
||||
// Amplitude data (==> Amp)
|
||||
case 0:
|
||||
m_Amp0.SetAmpLevel(nData);
|
||||
break;
|
||||
case 1:
|
||||
m_Amp1.SetAmpLevel(nData);
|
||||
break;
|
||||
case 2:
|
||||
m_Amp2.SetAmpLevel(nData);
|
||||
break;
|
||||
case 3:
|
||||
m_Amp3.SetAmpLevel(nData);
|
||||
break;
|
||||
case 4:
|
||||
m_Amp4.SetAmpLevel(nData);
|
||||
break;
|
||||
case 5:
|
||||
m_Amp5.SetAmpLevel(nData);
|
||||
break;
|
||||
|
||||
// Freq data (==> Osc)
|
||||
case 8:
|
||||
m_Osc0.SetFreqOffset(nData);
|
||||
break;
|
||||
case 9:
|
||||
m_Osc1.SetFreqOffset(nData);
|
||||
break;
|
||||
case 10:
|
||||
m_Osc2.SetFreqOffset(nData);
|
||||
break;
|
||||
case 11:
|
||||
m_Osc3.SetFreqOffset(nData);
|
||||
break;
|
||||
case 12:
|
||||
m_Osc4.SetFreqOffset(nData);
|
||||
break;
|
||||
case 13:
|
||||
m_Osc5.SetFreqOffset(nData);
|
||||
break;
|
||||
|
||||
// Freq octave data (==> Osc) for channels 0,1
|
||||
case 16:
|
||||
m_Osc0.SetFreqOctave(nData & 0x07);
|
||||
m_Osc1.SetFreqOctave((nData >> 4) & 0x07);
|
||||
break;
|
||||
|
||||
// Freq octave data (==> Osc) for channels 2,3
|
||||
case 17:
|
||||
m_Osc2.SetFreqOctave(nData & 0x07);
|
||||
m_Osc3.SetFreqOctave((nData >> 4) & 0x07);
|
||||
break;
|
||||
|
||||
// Freq octave data (==> Osc) for channels 4,5
|
||||
case 18:
|
||||
m_Osc4.SetFreqOctave(nData & 0x07);
|
||||
m_Osc5.SetFreqOctave((nData >> 4) & 0x07);
|
||||
break;
|
||||
|
||||
// Tone mixer control (==> Amp)
|
||||
case 20:
|
||||
m_Amp0.SetToneMixer(nData & 0x01);
|
||||
m_Amp1.SetToneMixer(nData & 0x02);
|
||||
m_Amp2.SetToneMixer(nData & 0x04);
|
||||
m_Amp3.SetToneMixer(nData & 0x08);
|
||||
m_Amp4.SetToneMixer(nData & 0x10);
|
||||
m_Amp5.SetToneMixer(nData & 0x20);
|
||||
break;
|
||||
|
||||
// Noise mixer control (==> Amp)
|
||||
case 21:
|
||||
m_Amp0.SetNoiseMixer(nData & 0x01);
|
||||
m_Amp1.SetNoiseMixer(nData & 0x02);
|
||||
m_Amp2.SetNoiseMixer(nData & 0x04);
|
||||
m_Amp3.SetNoiseMixer(nData & 0x08);
|
||||
m_Amp4.SetNoiseMixer(nData & 0x10);
|
||||
m_Amp5.SetNoiseMixer(nData & 0x20);
|
||||
break;
|
||||
|
||||
// Noise frequency/source control (==> Noise)
|
||||
case 22:
|
||||
m_Noise0.SetSource(nData & 0x03);
|
||||
m_Noise1.SetSource((nData >> 4) & 0x03);
|
||||
break;
|
||||
|
||||
// Envelope control data (==> Env) for envelope controller #0
|
||||
case 24:
|
||||
m_Env0.SetEnvControl(nData);
|
||||
break;
|
||||
|
||||
// Envelope control data (==> Env) for envelope controller #1
|
||||
case 25:
|
||||
m_Env1.SetEnvControl(nData);
|
||||
break;
|
||||
|
||||
// Global enable and reset (sync) controls
|
||||
case 28:
|
||||
{
|
||||
// Reset (sync) bit
|
||||
bool bSync = bool(nData & 0x02);
|
||||
if (bSync != m_bSync)
|
||||
{
|
||||
// Sync all devices
|
||||
// This amounts to telling them all to reset to a
|
||||
// known state, which is also a state that doesn't change
|
||||
// (i.e. no audio output, although there are some exceptions)
|
||||
// bSync=true => all devices are sync (aka reset);
|
||||
// bSync=false => all devices are allowed to run and generate changing output
|
||||
m_Osc0.Sync(bSync);
|
||||
m_Osc1.Sync(bSync);
|
||||
m_Osc2.Sync(bSync);
|
||||
m_Osc3.Sync(bSync);
|
||||
m_Osc4.Sync(bSync);
|
||||
m_Osc5.Sync(bSync);
|
||||
m_Noise0.Sync(bSync);
|
||||
m_Noise1.Sync(bSync);
|
||||
m_Amp0.Sync(bSync);
|
||||
m_Amp1.Sync(bSync);
|
||||
m_Amp2.Sync(bSync);
|
||||
m_Amp3.Sync(bSync);
|
||||
m_Amp4.Sync(bSync);
|
||||
m_Amp5.Sync(bSync);
|
||||
m_bSync = bSync;
|
||||
}
|
||||
|
||||
// Global mute bit
|
||||
bool bOutputEnabled = bool(nData & 0x01);
|
||||
if (bOutputEnabled != m_bOutputEnabled)
|
||||
{
|
||||
// unmute all amps - sound 'enabled'
|
||||
m_Amp0.Mute(!bOutputEnabled);
|
||||
m_Amp1.Mute(!bOutputEnabled);
|
||||
m_Amp2.Mute(!bOutputEnabled);
|
||||
m_Amp3.Mute(!bOutputEnabled);
|
||||
m_Amp4.Mute(!bOutputEnabled);
|
||||
m_Amp5.Mute(!bOutputEnabled);
|
||||
m_bOutputEnabled = bOutputEnabled;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// anything else means data is being written to a register
|
||||
// that is not used within the SAA-1099 architecture
|
||||
// hence, we ignore it.
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
void CSAADevice::_WriteAddress(BYTE nReg)
|
||||
{
|
||||
m_nCurrentSaaReg = nReg & 31;
|
||||
if (m_nCurrentSaaReg == 24)
|
||||
{
|
||||
m_Env0.ExternalClock();
|
||||
}
|
||||
else if (m_nCurrentSaaReg == 25)
|
||||
{
|
||||
m_Env1.ExternalClock();
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
BYTE CSAADevice::_ReadAddress(void)
|
||||
{
|
||||
// Not a real hardware function of the SAA-1099, which is write-only
|
||||
// However, this is used by SAAImpl to generate debug logs (if enabled)
|
||||
return(m_nCurrentSaaReg);
|
||||
}
|
||||
#endif
|
||||
#if defined(DEBUG)
|
||||
BYTE CSAADevice::_ReadData(void)
|
||||
{
|
||||
// Not a real hardware function of the SAA-1099, which is write-only
|
||||
// This is only compiled for Debug builds
|
||||
return(m_Reg[m_nCurrentSaaReg]);
|
||||
}
|
||||
#endif
|
||||
|
||||
void CSAADevice::_TickAndOutputStereo(unsigned int& left_mixed, unsigned int& right_mixed)
|
||||
{
|
||||
unsigned int temp_left, temp_right;
|
||||
unsigned int accum_left = 0, accum_right = 0;
|
||||
for (int i = 1 << m_nOversample; i > 0; i--)
|
||||
{
|
||||
m_Noise0.Tick();
|
||||
m_Noise1.Tick();
|
||||
m_Amp0.TickAndOutputStereo(temp_left, temp_right);
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp1.TickAndOutputStereo(temp_left, temp_right);
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp2.TickAndOutputStereo(temp_left, temp_right);
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp3.TickAndOutputStereo(temp_left, temp_right);
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp4.TickAndOutputStereo(temp_left, temp_right);
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp5.TickAndOutputStereo(temp_left, temp_right);
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
}
|
||||
left_mixed = accum_left;
|
||||
right_mixed = accum_right;
|
||||
}
|
||||
|
||||
void CSAADevice::_TickAndOutputSeparate(unsigned int& left_mixed, unsigned int& right_mixed,
|
||||
unsigned int& left0, unsigned int& right0,
|
||||
unsigned int& left1, unsigned int& right1,
|
||||
unsigned int& left2, unsigned int& right2,
|
||||
unsigned int& left3, unsigned int& right3,
|
||||
unsigned int& left4, unsigned int& right4,
|
||||
unsigned int& left5, unsigned int& right5
|
||||
)
|
||||
{
|
||||
unsigned int temp_left, temp_right;
|
||||
unsigned int accum_left = 0, accum_right = 0;
|
||||
left0 = left1 = left2 = left3 = left4 = left5 = 0;
|
||||
right0 = right1 = right2 = right3 = right4 = right5 = 0;
|
||||
for (int i = 1 << m_nOversample; i > 0; i--)
|
||||
{
|
||||
m_Noise0.Tick();
|
||||
m_Noise1.Tick();
|
||||
m_Amp0.TickAndOutputStereo(temp_left, temp_right);
|
||||
left0 += temp_left;
|
||||
right0 += temp_right;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp1.TickAndOutputStereo(temp_left, temp_right);
|
||||
left1 += temp_left;
|
||||
right1 += temp_right;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp2.TickAndOutputStereo(temp_left, temp_right);
|
||||
left2 += temp_left;
|
||||
right2 += temp_right;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp3.TickAndOutputStereo(temp_left, temp_right);
|
||||
left3 += temp_left;
|
||||
right3 += temp_right;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp4.TickAndOutputStereo(temp_left, temp_right);
|
||||
left4 += temp_left;
|
||||
right4 += temp_right;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp5.TickAndOutputStereo(temp_left, temp_right);
|
||||
left5 += temp_left;
|
||||
right5 += temp_right;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
}
|
||||
left_mixed = accum_left;
|
||||
right_mixed = accum_right;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// Part of SAASound copyright 2020 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAADevice.h: connecting the subcomponents of the SAA1099 together.
|
||||
// This class handles device inputs and outputs (clocking, data and
|
||||
// address bus, and simulated output)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SAADEVICE_H_INCLUDED
|
||||
#define SAADEVICE_H_INCLUDED
|
||||
|
||||
#include "SAASound.h"
|
||||
#include "SAANoise.h"
|
||||
#include "SAAEnv.h"
|
||||
#include "SAAFreq.h"
|
||||
#include "SAAAmp.h"
|
||||
|
||||
class CSAADevice
|
||||
{
|
||||
private:
|
||||
int m_nCurrentSaaReg;
|
||||
bool m_bOutputEnabled;
|
||||
bool m_bSync;
|
||||
bool m_bHighpass;
|
||||
int m_nOversample;
|
||||
|
||||
CSAANoise m_Noise0, m_Noise1;
|
||||
CSAAEnv m_Env0, m_Env1;
|
||||
CSAAFreq m_Osc0, m_Osc1, m_Osc2, m_Osc3, m_Osc4, m_Osc5;
|
||||
CSAAAmp m_Amp0, m_Amp1, m_Amp2, m_Amp3, m_Amp4, m_Amp5;
|
||||
|
||||
CSAANoise* Noise[2];
|
||||
CSAAEnv* Env[2];
|
||||
CSAAFreq* Osc[6];
|
||||
CSAAAmp* Amp[6];
|
||||
|
||||
#if defined(DEBUG) || defined(DEBUGSAA)
|
||||
BYTE m_Reg[32];
|
||||
#endif
|
||||
|
||||
public:
|
||||
CSAADevice();
|
||||
~CSAADevice();
|
||||
|
||||
void _WriteAddress(BYTE nReg);
|
||||
void _WriteData(BYTE nData);
|
||||
#if 1
|
||||
BYTE _ReadAddress(void);
|
||||
#endif
|
||||
#if defined(DEBUG)
|
||||
BYTE _ReadData(void);
|
||||
#endif
|
||||
|
||||
void _SetClockRate(unsigned int nClockRate);
|
||||
void _SetSampleRate(unsigned int nSampleRate);
|
||||
void _SetOversample(unsigned int nOversample);
|
||||
void _TickAndOutputStereo(unsigned int& left_mixed, unsigned int& right_mixed);
|
||||
void _TickAndOutputSeparate(unsigned int& left_mixed, unsigned int& right_mixed,
|
||||
unsigned int& left0, unsigned int& right0,
|
||||
unsigned int& left1, unsigned int& right1,
|
||||
unsigned int& left2, unsigned int& right2,
|
||||
unsigned int& left3, unsigned int& right3,
|
||||
unsigned int& left4, unsigned int& right4,
|
||||
unsigned int& left5, unsigned int& right5
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
#endif // SAADEVICE_H_INCLUDED
|
||||
@@ -1,380 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAAEnv.cpp: implementation of the CSAAEnv class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SAASound.h"
|
||||
#include "types.h"
|
||||
#include "SAAEnv.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Static member initialisation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
const ENVDATA CSAAEnv::cs_EnvData[8] =
|
||||
{
|
||||
{1,false, { {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
|
||||
{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}},
|
||||
{1,true, { {{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15}},
|
||||
{{14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14},{14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14}}}},
|
||||
{1,false, { {{15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
|
||||
{{14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}},
|
||||
{1,true, { {{15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
|
||||
{{14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}},
|
||||
{2,false, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}},
|
||||
{{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}}}},
|
||||
{2,true, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}},
|
||||
{{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}}}},
|
||||
{1,false, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
|
||||
{{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}},
|
||||
{1,true, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
|
||||
{{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
CSAAEnv::CSAAEnv()
|
||||
:
|
||||
m_bEnabled(false),
|
||||
m_nPhase(0),
|
||||
m_nPhasePosition(0),
|
||||
m_bEnvelopeEnded(true),
|
||||
m_nResolution(1),
|
||||
m_bNewData(false),
|
||||
m_nNextData(0)
|
||||
{
|
||||
// initialise itself with the value 'zero'
|
||||
SetEnvControl(0);
|
||||
}
|
||||
|
||||
CSAAEnv::~CSAAEnv()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CSAAEnv::InternalClock(void)
|
||||
{
|
||||
// will only do something if envelope clock mode is set to internal
|
||||
// and the env control is enabled
|
||||
if (m_bEnabled && (!m_bClockExternally)) Tick();
|
||||
}
|
||||
|
||||
void CSAAEnv::ExternalClock(void)
|
||||
{
|
||||
// will only do something if envelope clock mode is set to external
|
||||
// and the env control is enabled
|
||||
if (m_bClockExternally && m_bEnabled) Tick();
|
||||
}
|
||||
|
||||
void CSAAEnv::SetEnvControl(int nData)
|
||||
{
|
||||
// process immediate stuff first:
|
||||
// start with the Enabled flag. if env is disabled,
|
||||
// there's not much to do
|
||||
bool bEnabled = ((nData & 0x80)==0x80);
|
||||
if (!bEnabled && !m_bEnabled)
|
||||
return;
|
||||
m_bEnabled = bEnabled;
|
||||
if (!m_bEnabled)
|
||||
{
|
||||
// env control was enabled, and now disabled
|
||||
// Any subsequent env control changes are immediate.
|
||||
m_bEnvelopeEnded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolution (3bit/4bit) is also immediately processed
|
||||
int new_resolution = ((nData & 0x10) == 0x10) ? 2 : 1;
|
||||
// NOTE: undocumented behaviour when changing resolution mid-waveform
|
||||
// Empirically, the following matches observations:
|
||||
// * When ticking the env generator with 4-bit resolution, the position += 1
|
||||
// * When ticking the env generator with 3-bit resolution, the position += 2
|
||||
// * When changing between 4-bit resolution and 3-bit resolution
|
||||
// without ticking the env generator, the position is unchanged
|
||||
// (although, effectively, the LSB is ignored. Purely as an implementation
|
||||
// detail, I'm implementing this as clearing the LSB ie LSB=0; see next point)
|
||||
// * When changing between 3-bit resolution and 4-bit resolution
|
||||
// without ticking the env generator, the position LSB is set to 1
|
||||
// See test case: envext_34b
|
||||
//
|
||||
if (m_nResolution == 1 && new_resolution == 2)
|
||||
{
|
||||
// change from 4-bit to 3-bit
|
||||
m_nPhasePosition &= 0xe;
|
||||
}
|
||||
else if (m_nResolution == 2 && new_resolution == 1)
|
||||
{
|
||||
// change from 3-bit to 4-bit
|
||||
m_nPhasePosition |= 0x1;
|
||||
}
|
||||
m_nResolution = new_resolution;
|
||||
|
||||
// now buffered stuff: but only if it's ok to, and only if the
|
||||
// envgenerator is not disabled. otherwise it just stays buffered until
|
||||
// the Tick() function sets m_bEnvelopeEnded to true and realises there is
|
||||
// already some new data waiting
|
||||
if (m_bEnvelopeEnded)
|
||||
{
|
||||
SetNewEnvData(nData); // also does the SetLevels() call for us.
|
||||
m_bNewData=false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// since the 'next resolution' changes arrive unbuffered, we
|
||||
// may need to change the current level because of this:
|
||||
SetLevels();
|
||||
|
||||
// store current new data, and set the newdata flag:
|
||||
m_bNewData = true;
|
||||
m_nNextData = nData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int CSAAEnv::LeftLevel(void) const
|
||||
{
|
||||
return m_nLeftLevel;
|
||||
}
|
||||
|
||||
int CSAAEnv::RightLevel(void) const
|
||||
{
|
||||
return m_nRightLevel;
|
||||
}
|
||||
|
||||
inline void CSAAEnv::Tick(void)
|
||||
{
|
||||
// if disabled, do nothing
|
||||
if (!m_bEnabled) // m_bEnabled is set directly, not buffered, so this is ok
|
||||
{
|
||||
// for sanity, reset stuff:
|
||||
m_bEnvelopeEnded = true;
|
||||
m_nPhase = 0;
|
||||
m_nPhasePosition = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// else : m_bEnabled
|
||||
|
||||
|
||||
if (m_bEnvelopeEnded)
|
||||
{
|
||||
// do nothing
|
||||
// (specifically, don't change the values of m_bEnvelopeEnded,
|
||||
// m_nPhase and m_nPhasePosition, as these will still be needed
|
||||
// by SetLevels() should it be called again)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// else : !m_bEnvelopeEnded
|
||||
// Continue playing the same envelope ...
|
||||
// increments the phaseposition within an envelope.
|
||||
// also handles looping and resolution appropriately.
|
||||
// Changes the level of the envelope accordingly
|
||||
// through calling SetLevels() . This must be called after making
|
||||
// any changes that will affect the output levels of the env controller!!
|
||||
// SetLevels also handles left-right channel inverting
|
||||
|
||||
// increment phase position
|
||||
m_nPhasePosition += m_nResolution;
|
||||
|
||||
// if this means we've gone past 16 (the end of a phase)
|
||||
// then change phase, and if necessary, loop
|
||||
// Refer to datasheet for meanings of (3) and (4) in following text
|
||||
// w.r.t SAA1099 envelopes
|
||||
|
||||
// Note that we will always reach position (3) or (4), even if we keep toggling
|
||||
// resolution from 4-bit to 3-bit and back, because the counter will always wrap to 0.
|
||||
// In fact it's quite elegant:
|
||||
// No matter how you increment and toggle and increment and toggle, the counter
|
||||
// will at some point be either 0xe (either 4-bit mode or 3-bit mode) or 0xf (4-bit mode only).
|
||||
// Depending on the mode, even if you change the mode, the next increment,
|
||||
// or the one after it, will then take it to 0.
|
||||
// 0xe + 2 (3bit mode) => 0x0
|
||||
// 0xe + 1 (4bit mode) => 0xf
|
||||
// 0xf + 1 (4bit mode) => 0x0
|
||||
// 0xe -> (toggle 3bit mode to 4bit mode) => 0xf
|
||||
// 0xe -> (toggle 4bit mode to 3bit mode) => 0xe
|
||||
// 0xf -> (toggle 4bit mode to 3bit mode) => 0xe
|
||||
//
|
||||
// but there is a subtlety (of course), which is that any changes at point (3)
|
||||
// can take place immediately you hit point (3), but changes at point (4) are actually
|
||||
// only acted upon when the counter transitions from 0xe (or 0xf) to 0x0 (which also
|
||||
// means that, for these looping envelopes, which are the ones that have a point(4),
|
||||
// immediately after the counter wrapping to 0x0, a write to the env data register will
|
||||
// NOT set the waveform and will NOT reset the phase/phaseposition (even though it
|
||||
// will still let you toggle the 4bit/3bit mode, which will change the phaseposition LSB!)
|
||||
// See test case: envext_34c
|
||||
|
||||
bool bProcessNewDataIfAvailable = false;
|
||||
if (m_nPhasePosition >= 16)
|
||||
{
|
||||
m_nPhase++;
|
||||
|
||||
// if we should loop, then do so - and we've reached position (4)
|
||||
// otherwise, if we shouldn't loop,
|
||||
// then we've reached position (3) and so we say that
|
||||
// we're ok for new data.
|
||||
if (m_nPhase == m_nNumberOfPhases)
|
||||
{
|
||||
// at position (3) or (4)
|
||||
if (!m_bLooping)
|
||||
{
|
||||
// position (3) only
|
||||
// note that it seems that the sustain level is ALWAYS zero
|
||||
// in the case of non-looping waveforms
|
||||
m_bEnvelopeEnded = true;
|
||||
bProcessNewDataIfAvailable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// position (4) only
|
||||
// note that any data already latched is ONLY acted upon
|
||||
// at THIS point. If (after this Tick has completed) any new
|
||||
// env data is written, it will NOT be acted upon, until
|
||||
// we get back to position (4) again.
|
||||
// this is why m_bEnvelopeEnded (which affects the behaviour
|
||||
// of the SetEnvControl method) is FALSE here.
|
||||
// See test case: envext_34c (as noted earlier)
|
||||
m_bEnvelopeEnded = false;
|
||||
// set phase pointer to start of envelope for loop
|
||||
// and reset m_nPhasePosition
|
||||
m_nPhase=0;
|
||||
m_nPhasePosition -= 16;
|
||||
bProcessNewDataIfAvailable = true;
|
||||
}
|
||||
}
|
||||
else // (m_nPhase < m_nNumberOfPhases)
|
||||
{
|
||||
// not at position (3) or (4) ...
|
||||
// (i.e., we're in the middle of an envelope with
|
||||
// more than one phase. Specifically, we're in
|
||||
// the middle of envelope 4 or 5 - the
|
||||
// triangle envelopes - but that's not important)
|
||||
|
||||
// any commands sent to this envelope controller
|
||||
// will be buffered. Set the flag to indicate this.
|
||||
m_bEnvelopeEnded = false;
|
||||
m_nPhasePosition -= 16;
|
||||
}
|
||||
}
|
||||
else // (m_nPhasePosition < 16)
|
||||
{
|
||||
// still within the same phase;
|
||||
// but, importantly, we are no longer at the start of the phase ...
|
||||
// so new data cannot be acted on immediately, and must
|
||||
// be buffered
|
||||
m_bEnvelopeEnded = false;
|
||||
// Phase and PhasePosition have already been updated.
|
||||
// SetLevels() will need to be called to actually calculate
|
||||
// the output 'level' of this envelope controller
|
||||
}
|
||||
|
||||
|
||||
// if we have new (buffered) data, now is the time to act on it
|
||||
if (m_bNewData && bProcessNewDataIfAvailable)
|
||||
{
|
||||
m_bNewData = false;
|
||||
SetNewEnvData(m_nNextData);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ok, we didn't have any new buffered date to act on,
|
||||
// so we just call SetLevels() to calculate the output level
|
||||
// for whatever the current envelope is
|
||||
SetLevels();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline void CSAAEnv::SetLevels(void)
|
||||
{
|
||||
// sets m_nLeftLevel
|
||||
// Also sets m_nRightLevel in terms of m_nLeftLevel
|
||||
// and m_bInvertRightChannel
|
||||
|
||||
// m_nResolution: 1 means 4-bit resolution; 2 means 3-bit resolution. Resolution of envelope waveform.
|
||||
|
||||
// Note that this is handled 'immediately', and doesn't wait for synchronisation of
|
||||
// the envelope waveform (this is important, see test case EnvExt_imm)
|
||||
// It is therefore possible to switch between 4-bit and 3-bit resolution in the middle of
|
||||
// an envelope waveform. if you are at an 'odd' phase position, you would be able to hear
|
||||
// the difference. if you are at an 'even' phase position, the volume level for 4-bit
|
||||
// and 3-bit would be the same.
|
||||
// NOTE: additional test cases are required.
|
||||
|
||||
switch (m_nResolution)
|
||||
{
|
||||
case 1: // 4 bit res waveforms
|
||||
default:
|
||||
{
|
||||
// special case: if envelope is not a looping one, and we're at the end
|
||||
// then our level should be zero (all of the non-looping waveforms have
|
||||
// a sustain level of zero):
|
||||
if (m_bEnvelopeEnded && !m_bLooping)
|
||||
m_nLeftLevel = 0;
|
||||
else
|
||||
m_nLeftLevel = m_pEnvData->nLevels[0][m_nPhase][m_nPhasePosition];
|
||||
|
||||
if (m_bInvertRightChannel)
|
||||
m_nRightLevel = 15-m_nLeftLevel;
|
||||
else
|
||||
m_nRightLevel = m_nLeftLevel;
|
||||
break;
|
||||
}
|
||||
case 2: // 3 bit res waveforms
|
||||
{
|
||||
// special case: if envelope is not a looping one, and we're at the end
|
||||
// then our level should be zero (all of the non-looping waveforms have
|
||||
// a sustain level of zero):
|
||||
if (m_bEnvelopeEnded && !m_bLooping)
|
||||
m_nLeftLevel = 0;
|
||||
else
|
||||
m_nLeftLevel = m_pEnvData->nLevels[1][m_nPhase][m_nPhasePosition];
|
||||
if (m_bInvertRightChannel)
|
||||
m_nRightLevel = 14-m_nLeftLevel;
|
||||
else
|
||||
m_nRightLevel = m_nLeftLevel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void CSAAEnv::SetNewEnvData(int nData)
|
||||
{
|
||||
// loads envgenerator's registers according to the bits set
|
||||
// in nData
|
||||
|
||||
m_nPhase = 0;
|
||||
m_nPhasePosition = 0;
|
||||
m_pEnvData = &(cs_EnvData[(nData >> 1) & 0x07]);
|
||||
m_bInvertRightChannel = ((nData & 0x01) == 0x01);
|
||||
m_bClockExternally = ((nData & 0x20) == 0x20);
|
||||
m_nNumberOfPhases = m_pEnvData->nNumberOfPhases;
|
||||
m_bLooping = m_pEnvData->bLooping;
|
||||
m_nResolution = (((nData & 0x10)==0x10) ? 2 : 1);
|
||||
m_bEnabled = ((nData & 0x80) == 0x80);
|
||||
if (m_bEnabled)
|
||||
{
|
||||
m_bEnvelopeEnded = false;
|
||||
// is this right?
|
||||
// YES. See test case EnvExt_34c (setting data multiple times
|
||||
// when at a point (3) resets the waveform so you're no longer
|
||||
// at a point (3).
|
||||
}
|
||||
else
|
||||
{
|
||||
// DISABLED - so set stuff accordingly
|
||||
m_bEnvelopeEnded = true;
|
||||
m_nPhase = 0;
|
||||
m_nPhasePosition = 0;
|
||||
}
|
||||
|
||||
SetLevels();
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAAEnv.h: interface for the CSAAEnv class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SAAENV_H_INCLUDED
|
||||
#define SAAENV_H_INCLUDED
|
||||
|
||||
class CSAAEnv
|
||||
{
|
||||
private:
|
||||
int m_nLeftLevel, m_nRightLevel;
|
||||
ENVDATA const * m_pEnvData;
|
||||
|
||||
bool m_bEnabled;
|
||||
bool m_bInvertRightChannel;
|
||||
BYTE m_nPhase;
|
||||
BYTE m_nPhasePosition;
|
||||
bool m_bEnvelopeEnded;
|
||||
char m_nPhaseAdd[2];
|
||||
char m_nCurrentPhaseAdd;
|
||||
bool m_bLooping;
|
||||
char m_nNumberOfPhases;
|
||||
char m_nResolution;
|
||||
char m_nInitialLevel;
|
||||
bool m_bNewData;
|
||||
BYTE m_nNextData;
|
||||
bool m_bClockExternally;
|
||||
static const ENVDATA cs_EnvData[8];
|
||||
|
||||
void Tick(void);
|
||||
void SetLevels(void);
|
||||
void SetNewEnvData(int nData);
|
||||
|
||||
public:
|
||||
CSAAEnv();
|
||||
~CSAAEnv();
|
||||
|
||||
void InternalClock(void);
|
||||
void ExternalClock(void);
|
||||
void SetEnvControl(int nData); // really just a BYTE
|
||||
int LeftLevel(void) const;
|
||||
int RightLevel(void) const;
|
||||
bool IsActive(void) const;
|
||||
|
||||
};
|
||||
|
||||
inline bool CSAAEnv::IsActive(void) const
|
||||
{
|
||||
return m_bEnabled;
|
||||
}
|
||||
|
||||
#endif // SAAENV_H_INCLUDED
|
||||
@@ -1,287 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAAFreq.cpp: implementation of the CSAAFreq class.
|
||||
// only 7-bit fractional accuracy on oscillator periods. I may consider fixing that.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SAASound.h"
|
||||
#include "types.h"
|
||||
#include "SAANoise.h"
|
||||
#include "SAAEnv.h"
|
||||
#include "SAAFreq.h"
|
||||
#include "defns.h"
|
||||
|
||||
#ifdef SAAFREQ_FIXED_CLOCKRATE
|
||||
// 'load in' the data for the static frequency lookup table
|
||||
// precomputed for a fixed clockrate
|
||||
// See: tools/freqdat.py
|
||||
const unsigned long CSAAFreq::m_FreqTable[2048] = {
|
||||
#include "SAAFreq.dat"
|
||||
};
|
||||
#else
|
||||
unsigned long CSAAFreq::m_FreqTable[2048];
|
||||
unsigned long CSAAFreq::m_nClockRate = 0;
|
||||
#endif // SAAFREQ_FIXED_CLOCKRATE
|
||||
|
||||
const int INITIAL_LEVEL = 1;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
CSAAFreq::CSAAFreq(CSAANoise * const NoiseGenerator, CSAAEnv * const EnvGenerator)
|
||||
:
|
||||
m_nCounter(0),
|
||||
m_nAdd(0),
|
||||
m_nCounter_low(0),
|
||||
m_nOversample(0),
|
||||
m_nCounterLimit_low(1),
|
||||
m_nLevel(INITIAL_LEVEL),
|
||||
m_nCurrentOffset(0),
|
||||
m_nCurrentOctave(0),
|
||||
m_nNextOffset(0),
|
||||
m_nNextOctave(0),
|
||||
m_bIgnoreOffsetData(false),
|
||||
m_bNewData(false),
|
||||
m_bSync(false),
|
||||
m_nSampleRate(SAMPLE_RATE_HZ),
|
||||
m_pcConnectedNoiseGenerator(NoiseGenerator),
|
||||
m_pcConnectedEnvGenerator(EnvGenerator),
|
||||
m_nConnectedMode((NoiseGenerator == NULL) ? ((EnvGenerator == NULL) ? 0 : 1) : 2)
|
||||
{
|
||||
_SetClockRate(EXTERNAL_CLK_HZ);
|
||||
SetAdd(); // current octave, current offset
|
||||
}
|
||||
|
||||
CSAAFreq::~CSAAFreq()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CSAAFreq::SetFreqOffset(BYTE nOffset)
|
||||
{
|
||||
// nOffset between 0 and 255
|
||||
|
||||
if (!m_bSync)
|
||||
{
|
||||
m_nNextOffset = nOffset;
|
||||
m_bNewData=true;
|
||||
if (m_nNextOctave==m_nCurrentOctave)
|
||||
{
|
||||
// According to Philips, if you send the SAA-1099
|
||||
// new Octave data and then new Offset data in that
|
||||
// order, on the next half-cycle of the current frequency
|
||||
// generator, ONLY the octave data is acted upon.
|
||||
// The offset data will be acted upon next time.
|
||||
|
||||
// ?? TEST CASE : if you set the octave and then the offset
|
||||
// but the octave you set it to is the same one it already was.
|
||||
// Will this ignore the offset data?
|
||||
// Do you get the same behaviour if you set offset THEN octave
|
||||
// even if you set octave to the same value it was before?
|
||||
|
||||
m_bIgnoreOffsetData=true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// updates straightaway if m_bSync
|
||||
m_bNewData=false;
|
||||
m_bIgnoreOffsetData = false;
|
||||
m_nCurrentOffset = nOffset;
|
||||
m_nNextOffset = nOffset;
|
||||
m_nCurrentOctave = m_nNextOctave;
|
||||
SetAdd();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CSAAFreq::SetFreqOctave(BYTE nOctave)
|
||||
{
|
||||
// nOctave between 0 and 7
|
||||
|
||||
if (!m_bSync)
|
||||
{
|
||||
m_nNextOctave = nOctave;
|
||||
m_bNewData=true;
|
||||
m_bIgnoreOffsetData = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// updates straightaway if m_bSync
|
||||
m_bNewData=false;
|
||||
m_bIgnoreOffsetData = false;
|
||||
m_nCurrentOctave = nOctave;
|
||||
m_nNextOctave = nOctave;
|
||||
m_nCurrentOffset = m_nNextOffset;
|
||||
SetAdd();
|
||||
}
|
||||
}
|
||||
|
||||
void CSAAFreq::UpdateOctaveOffsetData(void)
|
||||
{
|
||||
// loads the buffered new octave and new offset data into the current registers
|
||||
// and sets up the new frequency for this frequency generator (i.e. sets up m_nAdd)
|
||||
// - called during Sync, and called when waveform half-cycle completes
|
||||
|
||||
// How the SAA-1099 really treats new data:
|
||||
// if only new octave data is present,
|
||||
// then set new period based on just the octave data
|
||||
// Otherwise, if only new offset data is present,
|
||||
// then set new period based on just the offset data
|
||||
// Otherwise, if new octave data is present, and new offset data is present,
|
||||
// and the offset data was set BEFORE the octave data,
|
||||
// then set new period based on both the octave and offset data
|
||||
// Else, if the offset data came AFTER the new octave data
|
||||
// then set new period based on JUST THE OCTAVE DATA, and continue
|
||||
// signalling the offset data as 'new', so it will be acted upon
|
||||
// next half-cycle
|
||||
//
|
||||
// Weird, I know. But that's how it works. Philips even documented as much.
|
||||
|
||||
if (!m_bNewData)
|
||||
{
|
||||
// optimise for the most common case! No new data!
|
||||
return;
|
||||
}
|
||||
|
||||
m_nCurrentOctave=m_nNextOctave;
|
||||
if (!m_bIgnoreOffsetData)
|
||||
{
|
||||
m_nCurrentOffset=m_nNextOffset;
|
||||
m_bNewData=false;
|
||||
}
|
||||
m_bIgnoreOffsetData=false;
|
||||
|
||||
SetAdd();
|
||||
}
|
||||
|
||||
void CSAAFreq::_SetSampleRate(unsigned int nSampleRate)
|
||||
{
|
||||
m_nSampleRate = nSampleRate;
|
||||
}
|
||||
|
||||
void CSAAFreq::_SetOversample(unsigned int oversample)
|
||||
{
|
||||
// oversample is a power of 2 i.e.
|
||||
// if oversample == 2 then 4x oversample
|
||||
// if oversample == 6 then 64x oversample
|
||||
if (oversample < m_nOversample)
|
||||
{
|
||||
m_nCounter_low <<= (m_nOversample - oversample);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nCounter_low >>= (oversample - m_nOversample);
|
||||
}
|
||||
|
||||
m_nCounterLimit_low = 1<<oversample;
|
||||
m_nOversample = oversample;
|
||||
}
|
||||
|
||||
#ifdef SAAFREQ_FIXED_CLOCKRATE
|
||||
void CSAAFreq::_SetClockRate(int nClockRate)
|
||||
{
|
||||
// if SAAFREQ clock rate is hardcoded, then we don't support dynamically
|
||||
// adjusting the SAA clock rate, so this is a no-op
|
||||
}
|
||||
#else
|
||||
void CSAAFreq::_SetClockRate(int nClockRate)
|
||||
{
|
||||
// initialise the frequency table based on the SAA clockrate
|
||||
// Each item in m_FreqTable corresponds to the frequency calculated by
|
||||
// the standard formula (15625 << octave) / (511 - offset)
|
||||
// then multiplied by 8192 (and represented as a long integer value).
|
||||
// We are therefore using 12 bits (i.e. 2^12 = 4096) as fractional part.
|
||||
// The reason we multiply by 8192, not 4096, is that we use this as a counter
|
||||
// to toggle the oscillator state, so we need to count half-waves (i.e. twice
|
||||
// the frequency)
|
||||
//
|
||||
// Finally, note that the standard formula corresponds to a 8MHz base clock
|
||||
// so we rescale the final result by the ratio nClockRate/8000000
|
||||
|
||||
if (((unsigned long) nClockRate) != m_nClockRate)
|
||||
{
|
||||
m_nClockRate = nClockRate;
|
||||
int ix = 0;
|
||||
for (int nOctave = 0; nOctave < 8; nOctave++)
|
||||
for (int nOffset = 0; nOffset < 256; nOffset++)
|
||||
m_FreqTable[ix++] = (unsigned long)((8192.0 * 15625.0 * double(1 << nOctave) * (double(nClockRate) / 8000000.0)) / (511.0 - double(nOffset)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int CSAAFreq::Tick(void)
|
||||
{
|
||||
// set to the absolute level (0 or 1)
|
||||
if (m_bSync)
|
||||
return 1;
|
||||
|
||||
m_nCounter += m_nAdd;
|
||||
while (m_nCounter >= (m_nSampleRate<<12))
|
||||
{
|
||||
m_nCounter -= (m_nSampleRate<<12);
|
||||
m_nCounter_low++;
|
||||
if (m_nCounter_low >= m_nCounterLimit_low)
|
||||
{
|
||||
// period elapsed for (at least) one half-cycle of
|
||||
// current frequency
|
||||
m_nCounter_low = 0;
|
||||
// flip state - from 0 to 1 or vice versa
|
||||
m_nLevel = 1 - m_nLevel;
|
||||
|
||||
// trigger any connected devices
|
||||
switch (m_nConnectedMode)
|
||||
{
|
||||
case 1:
|
||||
// env trigger
|
||||
m_pcConnectedEnvGenerator->InternalClock();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// noise trigger
|
||||
m_pcConnectedNoiseGenerator->Trigger();
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
|
||||
// get new frequency (set period length m_nAdd) if new data is waiting:
|
||||
UpdateOctaveOffsetData();
|
||||
}
|
||||
}
|
||||
|
||||
return m_nLevel;
|
||||
}
|
||||
|
||||
void CSAAFreq::SetAdd(void)
|
||||
{
|
||||
// nOctave between 0 and 7; nOffset between 0 and 255
|
||||
|
||||
// Used to be:
|
||||
// m_nAdd = (15625 << nOctave) / (511 - nOffset);
|
||||
// Now just table lookup:
|
||||
m_nAdd = m_FreqTable[m_nCurrentOctave<<8 | m_nCurrentOffset];
|
||||
}
|
||||
|
||||
void CSAAFreq::Sync(bool bSync)
|
||||
{
|
||||
m_bSync = bSync;
|
||||
|
||||
// update straightaway if m_bSync
|
||||
if (m_bSync)
|
||||
{
|
||||
m_nCounter = 0;
|
||||
m_nCounter_low = 0;
|
||||
|
||||
// this seems to need to be required to make the Fred59 SPACE DEMO audio work correctly
|
||||
m_nLevel = INITIAL_LEVEL;
|
||||
|
||||
m_nCurrentOctave=m_nNextOctave;
|
||||
m_nCurrentOffset=m_nNextOffset;
|
||||
SetAdd();
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// Precalculated oscillator frequency period steps
|
||||
// Higher scaling for better accuracy.
|
||||
//
|
||||
// After construction, it's important to SetSampleRate before
|
||||
// trying to use the generator.
|
||||
// (Just because the CSAANoise object has a default samplerate
|
||||
// doesn't mean you should rely on it)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
250489 , 250980 , 251473 , 251969 , 252465 , 252964 , 253465 , 253968 , 254473 , 254980 , 255489 , 256000 , 256513 , 257028 , 257545 , 258065 ,
|
||||
258586 , 259109 , 259635 , 260163 , 260692 , 261224 , 261759 , 262295 , 262834 , 263374 , 263918 , 264463 , 265010 , 265560 , 266112 , 266667 ,
|
||||
267223 , 267782 , 268344 , 268908 , 269474 , 270042 , 270613 , 271186 , 271762 , 272340 , 272921 , 273504 , 274090 , 274678 , 275269 , 275862 ,
|
||||
276458 , 277056 , 277657 , 278261 , 278867 , 279476 , 280088 , 280702 , 281319 , 281938 , 282561 , 283186 , 283814 , 284444 , 285078 , 285714 ,
|
||||
286353 , 286996 , 287640 , 288288 , 288939 , 289593 , 290249 , 290909 , 291572 , 292237 , 292906 , 293578 , 294253 , 294931 , 295612 , 296296 ,
|
||||
296984 , 297674 , 298368 , 299065 , 299766 , 300469 , 301176 , 301887 , 302600 , 303318 , 304038 , 304762 , 305489 , 306220 , 306954 , 307692 ,
|
||||
308434 , 309179 , 309927 , 310680 , 311436 , 312195 , 312958 , 313725 , 314496 , 315271 , 316049 , 316832 , 317618 , 318408 , 319202 , 320000 ,
|
||||
320802 , 321608 , 322418 , 323232 , 324051 , 324873 , 325700 , 326531 , 327366 , 328205 , 329049 , 329897 , 330749 , 331606 , 332468 , 333333 ,
|
||||
334204 , 335079 , 335958 , 336842 , 337731 , 338624 , 339523 , 340426 , 341333 , 342246 , 343164 , 344086 , 345013 , 345946 , 346883 , 347826 ,
|
||||
348774 , 349727 , 350685 , 351648 , 352617 , 353591 , 354571 , 355556 , 356546 , 357542 , 358543 , 359551 , 360563 , 361582 , 362606 , 363636 ,
|
||||
364672 , 365714 , 366762 , 367816 , 368876 , 369942 , 371014 , 372093 , 373178 , 374269 , 375367 , 376471 , 377581 , 378698 , 379822 , 380952 ,
|
||||
382090 , 383234 , 384384 , 385542 , 386707 , 387879 , 389058 , 390244 , 391437 , 392638 , 393846 , 395062 , 396285 , 397516 , 398754 , 400000 ,
|
||||
401254 , 402516 , 403785 , 405063 , 406349 , 407643 , 408946 , 410256 , 411576 , 412903 , 414239 , 415584 , 416938 , 418301 , 419672 , 421053 ,
|
||||
422442 , 423841 , 425249 , 426667 , 428094 , 429530 , 430976 , 432432 , 433898 , 435374 , 436860 , 438356 , 439863 , 441379 , 442907 , 444444 ,
|
||||
445993 , 447552 , 449123 , 450704 , 452297 , 453901 , 455516 , 457143 , 458781 , 460432 , 462094 , 463768 , 465455 , 467153 , 468864 , 470588 ,
|
||||
472325 , 474074 , 475836 , 477612 , 479401 , 481203 , 483019 , 484848 , 486692 , 488550 , 490421 , 492308 , 494208 , 496124 , 498054 , 500000 ,
|
||||
500978 , 501961 , 502947 , 503937 , 504931 , 505929 , 506931 , 507937 , 508946 , 509960 , 510978 , 512000 , 513026 , 514056 , 515091 , 516129 ,
|
||||
517172 , 518219 , 519270 , 520325 , 521385 , 522449 , 523517 , 524590 , 525667 , 526749 , 527835 , 528926 , 530021 , 531120 , 532225 , 533333 ,
|
||||
534447 , 535565 , 536688 , 537815 , 538947 , 540084 , 541226 , 542373 , 543524 , 544681 , 545842 , 547009 , 548180 , 549356 , 550538 , 551724 ,
|
||||
552916 , 554113 , 555315 , 556522 , 557734 , 558952 , 560175 , 561404 , 562637 , 563877 , 565121 , 566372 , 567627 , 568889 , 570156 , 571429 ,
|
||||
572707 , 573991 , 575281 , 576577 , 577878 , 579186 , 580499 , 581818 , 583144 , 584475 , 585812 , 587156 , 588506 , 589862 , 591224 , 592593 ,
|
||||
593968 , 595349 , 596737 , 598131 , 599532 , 600939 , 602353 , 603774 , 605201 , 606635 , 608076 , 609524 , 610979 , 612440 , 613909 , 615385 ,
|
||||
616867 , 618357 , 619855 , 621359 , 622871 , 624390 , 625917 , 627451 , 628993 , 630542 , 632099 , 633663 , 635236 , 636816 , 638404 , 640000 ,
|
||||
641604 , 643216 , 644836 , 646465 , 648101 , 649746 , 651399 , 653061 , 654731 , 656410 , 658098 , 659794 , 661499 , 663212 , 664935 , 666667 ,
|
||||
668407 , 670157 , 671916 , 673684 , 675462 , 677249 , 679045 , 680851 , 682667 , 684492 , 686327 , 688172 , 690027 , 691892 , 693767 , 695652 ,
|
||||
697548 , 699454 , 701370 , 703297 , 705234 , 707182 , 709141 , 711111 , 713092 , 715084 , 717087 , 719101 , 721127 , 723164 , 725212 , 727273 ,
|
||||
729345 , 731429 , 733524 , 735632 , 737752 , 739884 , 742029 , 744186 , 746356 , 748538 , 750733 , 752941 , 755162 , 757396 , 759644 , 761905 ,
|
||||
764179 , 766467 , 768769 , 771084 , 773414 , 775758 , 778116 , 780488 , 782875 , 785276 , 787692 , 790123 , 792570 , 795031 , 797508 , 800000 ,
|
||||
802508 , 805031 , 807571 , 810127 , 812698 , 815287 , 817891 , 820513 , 823151 , 825806 , 828479 , 831169 , 833876 , 836601 , 839344 , 842105 ,
|
||||
844884 , 847682 , 850498 , 853333 , 856187 , 859060 , 861953 , 864865 , 867797 , 870748 , 873720 , 876712 , 879725 , 882759 , 885813 , 888889 ,
|
||||
891986 , 895105 , 898246 , 901408 , 904594 , 907801 , 911032 , 914286 , 917563 , 920863 , 924188 , 927536 , 930909 , 934307 , 937729 , 941176 ,
|
||||
944649 , 948148 , 951673 , 955224 , 958801 , 962406 , 966038 , 969697 , 973384 , 977099 , 980843 , 984615 , 988417 , 992248 , 996109 , 1000000 ,
|
||||
1001957 , 1003922 , 1005894 , 1007874 , 1009862 , 1011858 , 1013861 , 1015873 , 1017893 , 1019920 , 1021956 , 1024000 , 1026052 , 1028112 , 1030181 , 1032258 ,
|
||||
1034343 , 1036437 , 1038540 , 1040650 , 1042770 , 1044898 , 1047035 , 1049180 , 1051335 , 1053498 , 1055670 , 1057851 , 1060041 , 1062241 , 1064449 , 1066667 ,
|
||||
1068894 , 1071130 , 1073375 , 1075630 , 1077895 , 1080169 , 1082452 , 1084746 , 1087049 , 1089362 , 1091684 , 1094017 , 1096360 , 1098712 , 1101075 , 1103448 ,
|
||||
1105832 , 1108225 , 1110629 , 1113043 , 1115468 , 1117904 , 1120350 , 1122807 , 1125275 , 1127753 , 1130243 , 1132743 , 1135255 , 1137778 , 1140312 , 1142857 ,
|
||||
1145414 , 1147982 , 1150562 , 1153153 , 1155756 , 1158371 , 1160998 , 1163636 , 1166287 , 1168950 , 1171625 , 1174312 , 1177011 , 1179724 , 1182448 , 1185185 ,
|
||||
1187935 , 1190698 , 1193473 , 1196262 , 1199063 , 1201878 , 1204706 , 1207547 , 1210402 , 1213270 , 1216152 , 1219048 , 1221957 , 1224880 , 1227818 , 1230769 ,
|
||||
1233735 , 1236715 , 1239709 , 1242718 , 1245742 , 1248780 , 1251834 , 1254902 , 1257985 , 1261084 , 1264198 , 1267327 , 1270471 , 1273632 , 1276808 , 1280000 ,
|
||||
1283208 , 1286432 , 1289673 , 1292929 , 1296203 , 1299492 , 1302799 , 1306122 , 1309463 , 1312821 , 1316195 , 1319588 , 1322997 , 1326425 , 1329870 , 1333333 ,
|
||||
1336815 , 1340314 , 1343832 , 1347368 , 1350923 , 1354497 , 1358090 , 1361702 , 1365333 , 1368984 , 1372654 , 1376344 , 1380054 , 1383784 , 1387534 , 1391304 ,
|
||||
1395095 , 1398907 , 1402740 , 1406593 , 1410468 , 1414365 , 1418283 , 1422222 , 1426184 , 1430168 , 1434174 , 1438202 , 1442254 , 1446328 , 1450425 , 1454545 ,
|
||||
1458689 , 1462857 , 1467049 , 1471264 , 1475504 , 1479769 , 1484058 , 1488372 , 1492711 , 1497076 , 1501466 , 1505882 , 1510324 , 1514793 , 1519288 , 1523810 ,
|
||||
1528358 , 1532934 , 1537538 , 1542169 , 1546828 , 1551515 , 1556231 , 1560976 , 1565749 , 1570552 , 1575385 , 1580247 , 1585139 , 1590062 , 1595016 , 1600000 ,
|
||||
1605016 , 1610063 , 1615142 , 1620253 , 1625397 , 1630573 , 1635783 , 1641026 , 1646302 , 1651613 , 1656958 , 1662338 , 1667752 , 1673203 , 1678689 , 1684211 ,
|
||||
1689769 , 1695364 , 1700997 , 1706667 , 1712375 , 1718121 , 1723906 , 1729730 , 1735593 , 1741497 , 1747440 , 1753425 , 1759450 , 1765517 , 1771626 , 1777778 ,
|
||||
1783972 , 1790210 , 1796491 , 1802817 , 1809187 , 1815603 , 1822064 , 1828571 , 1835125 , 1841727 , 1848375 , 1855072 , 1861818 , 1868613 , 1875458 , 1882353 ,
|
||||
1889299 , 1896296 , 1903346 , 1910448 , 1917603 , 1924812 , 1932075 , 1939394 , 1946768 , 1954198 , 1961686 , 1969231 , 1976834 , 1984496 , 1992218 , 2000000 ,
|
||||
2003914 , 2007843 , 2011788 , 2015748 , 2019724 , 2023715 , 2027723 , 2031746 , 2035785 , 2039841 , 2043912 , 2048000 , 2052104 , 2056225 , 2060362 , 2064516 ,
|
||||
2068687 , 2072874 , 2077079 , 2081301 , 2085540 , 2089796 , 2094070 , 2098361 , 2102669 , 2106996 , 2111340 , 2115702 , 2120083 , 2124481 , 2128898 , 2133333 ,
|
||||
2137787 , 2142259 , 2146751 , 2151261 , 2155789 , 2160338 , 2164905 , 2169492 , 2174098 , 2178723 , 2183369 , 2188034 , 2192719 , 2197425 , 2202151 , 2206897 ,
|
||||
2211663 , 2216450 , 2221258 , 2226087 , 2230937 , 2235808 , 2240700 , 2245614 , 2250549 , 2255507 , 2260486 , 2265487 , 2270510 , 2275556 , 2280624 , 2285714 ,
|
||||
2290828 , 2295964 , 2301124 , 2306306 , 2311512 , 2316742 , 2321995 , 2327273 , 2332574 , 2337900 , 2343249 , 2348624 , 2354023 , 2359447 , 2364896 , 2370370 ,
|
||||
2375870 , 2381395 , 2386946 , 2392523 , 2398126 , 2403756 , 2409412 , 2415094 , 2420804 , 2426540 , 2432304 , 2438095 , 2443914 , 2449761 , 2455635 , 2461538 ,
|
||||
2467470 , 2473430 , 2479419 , 2485437 , 2491484 , 2497561 , 2503667 , 2509804 , 2515971 , 2522167 , 2528395 , 2534653 , 2540943 , 2547264 , 2553616 , 2560000 ,
|
||||
2566416 , 2572864 , 2579345 , 2585859 , 2592405 , 2598985 , 2605598 , 2612245 , 2618926 , 2625641 , 2632391 , 2639175 , 2645995 , 2652850 , 2659740 , 2666667 ,
|
||||
2673629 , 2680628 , 2687664 , 2694737 , 2701847 , 2708995 , 2716180 , 2723404 , 2730667 , 2737968 , 2745308 , 2752688 , 2760108 , 2767568 , 2775068 , 2782609 ,
|
||||
2790191 , 2797814 , 2805479 , 2813187 , 2820937 , 2828729 , 2836565 , 2844444 , 2852368 , 2860335 , 2868347 , 2876404 , 2884507 , 2892655 , 2900850 , 2909091 ,
|
||||
2917379 , 2925714 , 2934097 , 2942529 , 2951009 , 2959538 , 2968116 , 2976744 , 2985423 , 2994152 , 3002933 , 3011765 , 3020649 , 3029586 , 3038576 , 3047619 ,
|
||||
3056716 , 3065868 , 3075075 , 3084337 , 3093656 , 3103030 , 3112462 , 3121951 , 3131498 , 3141104 , 3150769 , 3160494 , 3170279 , 3180124 , 3190031 , 3200000 ,
|
||||
3210031 , 3220126 , 3230284 , 3240506 , 3250794 , 3261146 , 3271565 , 3282051 , 3292605 , 3303226 , 3313916 , 3324675 , 3335505 , 3346405 , 3357377 , 3368421 ,
|
||||
3379538 , 3390728 , 3401993 , 3413333 , 3424749 , 3436242 , 3447811 , 3459459 , 3471186 , 3482993 , 3494881 , 3506849 , 3518900 , 3531034 , 3543253 , 3555556 ,
|
||||
3567944 , 3580420 , 3592982 , 3605634 , 3618375 , 3631206 , 3644128 , 3657143 , 3670251 , 3683453 , 3696751 , 3710145 , 3723636 , 3737226 , 3750916 , 3764706 ,
|
||||
3778598 , 3792593 , 3806691 , 3820896 , 3835206 , 3849624 , 3864151 , 3878788 , 3893536 , 3908397 , 3923372 , 3938462 , 3953668 , 3968992 , 3984436 , 4000000 ,
|
||||
4007828 , 4015686 , 4023576 , 4031496 , 4039448 , 4047431 , 4055446 , 4063492 , 4071571 , 4079681 , 4087824 , 4096000 , 4104208 , 4112450 , 4120724 , 4129032 ,
|
||||
4137374 , 4145749 , 4154158 , 4162602 , 4171079 , 4179592 , 4188139 , 4196721 , 4205339 , 4213992 , 4222680 , 4231405 , 4240166 , 4248963 , 4257796 , 4266667 ,
|
||||
4275574 , 4284519 , 4293501 , 4302521 , 4311579 , 4320675 , 4329810 , 4338983 , 4348195 , 4357447 , 4366738 , 4376068 , 4385439 , 4394850 , 4404301 , 4413793 ,
|
||||
4423326 , 4432900 , 4442516 , 4452174 , 4461874 , 4471616 , 4481400 , 4491228 , 4501099 , 4511013 , 4520971 , 4530973 , 4541020 , 4551111 , 4561247 , 4571429 ,
|
||||
4581655 , 4591928 , 4602247 , 4612613 , 4623025 , 4633484 , 4643991 , 4654545 , 4665148 , 4675799 , 4686499 , 4697248 , 4708046 , 4718894 , 4729792 , 4740741 ,
|
||||
4751740 , 4762791 , 4773893 , 4785047 , 4796253 , 4807512 , 4818824 , 4830189 , 4841608 , 4853081 , 4864608 , 4876190 , 4887828 , 4899522 , 4911271 , 4923077 ,
|
||||
4934940 , 4946860 , 4958838 , 4970874 , 4982968 , 4995122 , 5007335 , 5019608 , 5031941 , 5044335 , 5056790 , 5069307 , 5081886 , 5094527 , 5107232 , 5120000 ,
|
||||
5132832 , 5145729 , 5158690 , 5171717 , 5184810 , 5197970 , 5211196 , 5224490 , 5237852 , 5251282 , 5264781 , 5278351 , 5291990 , 5305699 , 5319481 , 5333333 ,
|
||||
5347258 , 5361257 , 5375328 , 5389474 , 5403694 , 5417989 , 5432361 , 5446809 , 5461333 , 5475936 , 5490617 , 5505376 , 5520216 , 5535135 , 5550136 , 5565217 ,
|
||||
5580381 , 5595628 , 5610959 , 5626374 , 5641873 , 5657459 , 5673130 , 5688889 , 5704735 , 5720670 , 5736695 , 5752809 , 5769014 , 5785311 , 5801700 , 5818182 ,
|
||||
5834758 , 5851429 , 5868195 , 5885057 , 5902017 , 5919075 , 5936232 , 5953488 , 5970845 , 5988304 , 6005865 , 6023529 , 6041298 , 6059172 , 6077151 , 6095238 ,
|
||||
6113433 , 6131737 , 6150150 , 6168675 , 6187311 , 6206061 , 6224924 , 6243902 , 6262997 , 6282209 , 6301538 , 6320988 , 6340557 , 6360248 , 6380062 , 6400000 ,
|
||||
6420063 , 6440252 , 6460568 , 6481013 , 6501587 , 6522293 , 6543131 , 6564103 , 6585209 , 6606452 , 6627832 , 6649351 , 6671010 , 6692810 , 6714754 , 6736842 ,
|
||||
6759076 , 6781457 , 6803987 , 6826667 , 6849498 , 6872483 , 6895623 , 6918919 , 6942373 , 6965986 , 6989761 , 7013699 , 7037801 , 7062069 , 7086505 , 7111111 ,
|
||||
7135889 , 7160839 , 7185965 , 7211268 , 7236749 , 7262411 , 7288256 , 7314286 , 7340502 , 7366906 , 7393502 , 7420290 , 7447273 , 7474453 , 7501832 , 7529412 ,
|
||||
7557196 , 7585185 , 7613383 , 7641791 , 7670412 , 7699248 , 7728302 , 7757576 , 7787072 , 7816794 , 7846743 , 7876923 , 7907336 , 7937984 , 7968872 , 8000000 ,
|
||||
8015656 , 8031373 , 8047151 , 8062992 , 8078895 , 8094862 , 8110891 , 8126984 , 8143141 , 8159363 , 8175649 , 8192000 , 8208417 , 8224900 , 8241449 , 8258065 ,
|
||||
8274747 , 8291498 , 8308316 , 8325203 , 8342159 , 8359184 , 8376278 , 8393443 , 8410678 , 8427984 , 8445361 , 8462810 , 8480331 , 8497925 , 8515593 , 8533333 ,
|
||||
8551148 , 8569038 , 8587002 , 8605042 , 8623158 , 8641350 , 8659619 , 8677966 , 8696391 , 8714894 , 8733475 , 8752137 , 8770878 , 8789700 , 8808602 , 8827586 ,
|
||||
8846652 , 8865801 , 8885033 , 8904348 , 8923747 , 8943231 , 8962801 , 8982456 , 9002198 , 9022026 , 9041943 , 9061947 , 9082040 , 9102222 , 9122494 , 9142857 ,
|
||||
9163311 , 9183857 , 9204494 , 9225225 , 9246050 , 9266968 , 9287982 , 9309091 , 9330296 , 9351598 , 9372998 , 9394495 , 9416092 , 9437788 , 9459584 , 9481481 ,
|
||||
9503480 , 9525581 , 9547786 , 9570093 , 9592506 , 9615023 , 9637647 , 9660377 , 9683215 , 9706161 , 9729216 , 9752381 , 9775656 , 9799043 , 9822542 , 9846154 ,
|
||||
9869880 , 9893720 , 9917676 , 9941748 , 9965937 , 9990244 , 10014670 , 10039216 , 10063882 , 10088670 , 10113580 , 10138614 , 10163772 , 10189055 , 10214464 , 10240000 ,
|
||||
10265664 , 10291457 , 10317380 , 10343434 , 10369620 , 10395939 , 10422392 , 10448980 , 10475703 , 10502564 , 10529563 , 10556701 , 10583979 , 10611399 , 10638961 , 10666667 ,
|
||||
10694517 , 10722513 , 10750656 , 10778947 , 10807388 , 10835979 , 10864721 , 10893617 , 10922667 , 10951872 , 10981233 , 11010753 , 11040431 , 11070270 , 11100271 , 11130435 ,
|
||||
11160763 , 11191257 , 11221918 , 11252747 , 11283747 , 11314917 , 11346260 , 11377778 , 11409471 , 11441341 , 11473389 , 11505618 , 11538028 , 11570621 , 11603399 , 11636364 ,
|
||||
11669516 , 11702857 , 11736390 , 11770115 , 11804035 , 11838150 , 11872464 , 11906977 , 11941691 , 11976608 , 12011730 , 12047059 , 12082596 , 12118343 , 12154303 , 12190476 ,
|
||||
12226866 , 12263473 , 12300300 , 12337349 , 12374622 , 12412121 , 12449848 , 12487805 , 12525994 , 12564417 , 12603077 , 12641975 , 12681115 , 12720497 , 12760125 , 12800000 ,
|
||||
12840125 , 12880503 , 12921136 , 12962025 , 13003175 , 13044586 , 13086262 , 13128205 , 13170418 , 13212903 , 13255663 , 13298701 , 13342020 , 13385621 , 13429508 , 13473684 ,
|
||||
13518152 , 13562914 , 13607973 , 13653333 , 13698997 , 13744966 , 13791246 , 13837838 , 13884746 , 13931973 , 13979522 , 14027397 , 14075601 , 14124138 , 14173010 , 14222222 ,
|
||||
14271777 , 14321678 , 14371930 , 14422535 , 14473498 , 14524823 , 14576512 , 14628571 , 14681004 , 14733813 , 14787004 , 14840580 , 14894545 , 14948905 , 15003663 , 15058824 ,
|
||||
15114391 , 15170370 , 15226766 , 15283582 , 15340824 , 15398496 , 15456604 , 15515152 , 15574144 , 15633588 , 15693487 , 15753846 , 15814672 , 15875969 , 15937743 , 16000000 ,
|
||||
16031311 , 16062745 , 16094303 , 16125984 , 16157791 , 16189723 , 16221782 , 16253968 , 16286282 , 16318725 , 16351297 , 16384000 , 16416834 , 16449799 , 16482897 , 16516129 ,
|
||||
16549495 , 16582996 , 16616633 , 16650407 , 16684318 , 16718367 , 16752556 , 16786885 , 16821355 , 16855967 , 16890722 , 16925620 , 16960663 , 16995851 , 17031185 , 17066667 ,
|
||||
17102296 , 17138075 , 17174004 , 17210084 , 17246316 , 17282700 , 17319239 , 17355932 , 17392781 , 17429787 , 17466951 , 17504274 , 17541756 , 17579399 , 17617204 , 17655172 ,
|
||||
17693305 , 17731602 , 17770065 , 17808696 , 17847495 , 17886463 , 17925602 , 17964912 , 18004396 , 18044053 , 18083885 , 18123894 , 18164080 , 18204444 , 18244989 , 18285714 ,
|
||||
18326622 , 18367713 , 18408989 , 18450450 , 18492099 , 18533937 , 18575964 , 18618182 , 18660592 , 18703196 , 18745995 , 18788991 , 18832184 , 18875576 , 18919169 , 18962963 ,
|
||||
19006961 , 19051163 , 19095571 , 19140187 , 19185012 , 19230047 , 19275294 , 19320755 , 19366430 , 19412322 , 19458432 , 19504762 , 19551313 , 19598086 , 19645084 , 19692308 ,
|
||||
19739759 , 19787440 , 19835351 , 19883495 , 19931873 , 19980488 , 20029340 , 20078431 , 20127764 , 20177340 , 20227160 , 20277228 , 20327543 , 20378109 , 20428928 , 20480000 ,
|
||||
20531328 , 20582915 , 20634761 , 20686869 , 20739241 , 20791878 , 20844784 , 20897959 , 20951407 , 21005128 , 21059126 , 21113402 , 21167959 , 21222798 , 21277922 , 21333333 ,
|
||||
21389034 , 21445026 , 21501312 , 21557895 , 21614776 , 21671958 , 21729443 , 21787234 , 21845333 , 21903743 , 21962466 , 22021505 , 22080863 , 22140541 , 22200542 , 22260870 ,
|
||||
22321526 , 22382514 , 22443836 , 22505495 , 22567493 , 22629834 , 22692521 , 22755556 , 22818942 , 22882682 , 22946779 , 23011236 , 23076056 , 23141243 , 23206799 , 23272727 ,
|
||||
23339031 , 23405714 , 23472779 , 23540230 , 23608069 , 23676301 , 23744928 , 23813953 , 23883382 , 23953216 , 24023460 , 24094118 , 24165192 , 24236686 , 24308605 , 24380952 ,
|
||||
24453731 , 24526946 , 24600601 , 24674699 , 24749245 , 24824242 , 24899696 , 24975610 , 25051988 , 25128834 , 25206154 , 25283951 , 25362229 , 25440994 , 25520249 , 25600000 ,
|
||||
25680251 , 25761006 , 25842271 , 25924051 , 26006349 , 26089172 , 26172524 , 26256410 , 26340836 , 26425806 , 26511327 , 26597403 , 26684039 , 26771242 , 26859016 , 26947368 ,
|
||||
27036304 , 27125828 , 27215947 , 27306667 , 27397993 , 27489933 , 27582492 , 27675676 , 27769492 , 27863946 , 27959044 , 28054795 , 28151203 , 28248276 , 28346021 , 28444444 ,
|
||||
28543554 , 28643357 , 28743860 , 28845070 , 28946996 , 29049645 , 29153025 , 29257143 , 29362007 , 29467626 , 29574007 , 29681159 , 29789091 , 29897810 , 30007326 , 30117647 ,
|
||||
30228782 , 30340741 , 30453532 , 30567164 , 30681648 , 30796992 , 30913208 , 31030303 , 31148289 , 31267176 , 31386973 , 31507692 , 31629344 , 31751938 , 31875486 , 32000000 ,
|
||||
32062622 , 32125490 , 32188605 , 32251969 , 32315582 , 32379447 , 32443564 , 32507937 , 32572565 , 32637450 , 32702595 , 32768000 , 32833667 , 32899598 , 32965795 , 33032258 ,
|
||||
33098990 , 33165992 , 33233266 , 33300813 , 33368635 , 33436735 , 33505112 , 33573770 , 33642710 , 33711934 , 33781443 , 33851240 , 33921325 , 33991701 , 34062370 , 34133333 ,
|
||||
34204593 , 34276151 , 34348008 , 34420168 , 34492632 , 34565401 , 34638478 , 34711864 , 34785563 , 34859574 , 34933902 , 35008547 , 35083512 , 35158798 , 35234409 , 35310345 ,
|
||||
35386609 , 35463203 , 35540130 , 35617391 , 35694989 , 35772926 , 35851204 , 35929825 , 36008791 , 36088106 , 36167770 , 36247788 , 36328160 , 36408889 , 36489978 , 36571429 ,
|
||||
36653244 , 36735426 , 36817978 , 36900901 , 36984199 , 37067873 , 37151927 , 37236364 , 37321185 , 37406393 , 37491991 , 37577982 , 37664368 , 37751152 , 37838337 , 37925926 ,
|
||||
38013921 , 38102326 , 38191142 , 38280374 , 38370023 , 38460094 , 38550588 , 38641509 , 38732861 , 38824645 , 38916865 , 39009524 , 39102625 , 39196172 , 39290168 , 39384615 ,
|
||||
39479518 , 39574879 , 39670702 , 39766990 , 39863747 , 39960976 , 40058680 , 40156863 , 40255528 , 40354680 , 40454321 , 40554455 , 40655087 , 40756219 , 40857855 , 40960000 ,
|
||||
41062657 , 41165829 , 41269521 , 41373737 , 41478481 , 41583756 , 41689567 , 41795918 , 41902813 , 42010256 , 42118252 , 42226804 , 42335917 , 42445596 , 42555844 , 42666667 ,
|
||||
42778068 , 42890052 , 43002625 , 43115789 , 43229551 , 43343915 , 43458886 , 43574468 , 43690667 , 43807487 , 43924933 , 44043011 , 44161725 , 44281081 , 44401084 , 44521739 ,
|
||||
44643052 , 44765027 , 44887671 , 45010989 , 45134986 , 45259669 , 45385042 , 45511111 , 45637883 , 45765363 , 45893557 , 46022472 , 46152113 , 46282486 , 46413598 , 46545455 ,
|
||||
46678063 , 46811429 , 46945559 , 47080460 , 47216138 , 47352601 , 47489855 , 47627907 , 47766764 , 47906433 , 48046921 , 48188235 , 48330383 , 48473373 , 48617211 , 48761905 ,
|
||||
48907463 , 49053892 , 49201201 , 49349398 , 49498489 , 49648485 , 49799392 , 49951220 , 50103976 , 50257669 , 50412308 , 50567901 , 50724458 , 50881988 , 51040498 , 51200000 ,
|
||||
51360502 , 51522013 , 51684543 , 51848101 , 52012698 , 52178344 , 52345048 , 52512821 , 52681672 , 52851613 , 53022654 , 53194805 , 53368078 , 53542484 , 53718033 , 53894737 ,
|
||||
54072607 , 54251656 , 54431894 , 54613333 , 54795987 , 54979866 , 55164983 , 55351351 , 55538983 , 55727891 , 55918089 , 56109589 , 56302405 , 56496552 , 56692042 , 56888889 ,
|
||||
57087108 , 57286713 , 57487719 , 57690141 , 57893993 , 58099291 , 58306050 , 58514286 , 58724014 , 58935252 , 59148014 , 59362319 , 59578182 , 59795620 , 60014652 , 60235294 ,
|
||||
60457565 , 60681481 , 60907063 , 61134328 , 61363296 , 61593985 , 61826415 , 62060606 , 62296578 , 62534351 , 62773946 , 63015385 , 63258687 , 63503876 , 63750973 , 64000000
|
||||
@@ -1,72 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAAFreq.h: interface for the CSAAFreq class.
|
||||
// Note about Samplerates: 0=44100, 1=22050; 2=11025
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SAAFREQ_H_INCLUDE
|
||||
#define SAAFREQ_H_INCLUDE
|
||||
|
||||
#include "defns.h"
|
||||
|
||||
class CSAAFreq
|
||||
{
|
||||
private:
|
||||
#ifdef SAAFREQ_FIXED_CLOCKRATE
|
||||
// 'load in' the data for the static frequency lookup table
|
||||
// precomputed for a fixed clockrate
|
||||
// See: tools/freqdat.py
|
||||
const static unsigned long m_FreqTable[2048];
|
||||
#else
|
||||
// we'll calculate the frequency lookup table at runtime.
|
||||
static unsigned long m_FreqTable[2048];
|
||||
static unsigned long m_nClockRate;
|
||||
#endif
|
||||
|
||||
unsigned long m_nCounter;
|
||||
unsigned long m_nAdd;
|
||||
unsigned long m_nCounter_low;
|
||||
unsigned int m_nOversample;
|
||||
unsigned long m_nCounterLimit_low;
|
||||
int m_nLevel;
|
||||
|
||||
int m_nCurrentOffset;
|
||||
int m_nCurrentOctave;
|
||||
int m_nNextOffset;
|
||||
int m_nNextOctave;
|
||||
bool m_bIgnoreOffsetData;
|
||||
bool m_bNewData;
|
||||
bool m_bSync;
|
||||
|
||||
unsigned long m_nSampleRate;
|
||||
CSAANoise * const m_pcConnectedNoiseGenerator;
|
||||
CSAAEnv * const m_pcConnectedEnvGenerator;
|
||||
const int m_nConnectedMode; // 0 = nothing; 1 = envgenerator; 2 = noisegenerator
|
||||
|
||||
void UpdateOctaveOffsetData(void);
|
||||
void SetAdd(void);
|
||||
|
||||
public:
|
||||
CSAAFreq(CSAANoise * const pcNoiseGenerator, CSAAEnv * const pcEnvGenerator);
|
||||
~CSAAFreq();
|
||||
void SetFreqOffset(BYTE nOffset);
|
||||
void SetFreqOctave(BYTE nOctave);
|
||||
void _SetSampleRate(unsigned int nSampleRate);
|
||||
void _SetOversample(unsigned int oversample);
|
||||
void _SetClockRate(int nClockRate);
|
||||
void Sync(bool bSync);
|
||||
int Tick(void);
|
||||
int Level(void) const;
|
||||
|
||||
};
|
||||
|
||||
inline int CSAAFreq::Level(void) const
|
||||
{
|
||||
if (m_bSync)
|
||||
return 1;
|
||||
|
||||
return m_nLevel;
|
||||
}
|
||||
|
||||
#endif // SAAFREQ_H_INCLUDE
|
||||
@@ -1,488 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAAImpl.cpp: implementation of the CSAASound class.
|
||||
// the bones of the 'virtual SAA-1099' emulation
|
||||
//
|
||||
// the actual sound generation is carried out in the other classes;
|
||||
// this class provides the output stage and the external interface only
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SAASound.h"
|
||||
|
||||
#include "types.h"
|
||||
#include "SAAImpl.h"
|
||||
#include "defns.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
CSAASoundInternal::CSAASoundInternal()
|
||||
:
|
||||
m_chip(),
|
||||
m_uParam(0),
|
||||
m_uParamRate(0),
|
||||
m_nClockRate(EXTERNAL_CLK_HZ),
|
||||
m_nSampleRate(SAMPLE_RATE_HZ),
|
||||
m_nOversample(DEFAULT_OVERSAMPLE),
|
||||
#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE)
|
||||
m_bHighpass(false),
|
||||
m_nDebugSample(0)
|
||||
#else
|
||||
m_bHighpass(false)
|
||||
#endif
|
||||
{
|
||||
#ifdef USE_CONFIG_FILE
|
||||
m_Config.ReadConfig();
|
||||
#endif
|
||||
|
||||
#if defined(DEBUGSAA)
|
||||
m_dbgfile.open(_T(DEBUG_SAA_REGISTER_LOG), std::ios_base::out);
|
||||
m_pcmfile.open(_T(DEBUG_SAA_PCM_LOG), std::ios_base::out | std::ios_base::binary);
|
||||
#elif defined(USE_CONFIG_FILE)
|
||||
if (m_Config.m_bGenerateRegisterLogs)
|
||||
m_dbgfile.open(m_Config.m_strRegisterLogPath, std::ios_base::out);
|
||||
if (m_Config.m_bGeneratePcmLogs)
|
||||
m_pcmfile.open(m_Config.m_strPcmOutputPath, std::ios_base::out | std::ios_base::binary);
|
||||
|
||||
if (m_Config.m_bGeneratePcmLogs && m_Config.m_bGeneratePcmSeparateChannels)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_channel_pcmfile[i].open(m_Config.getChannelPcmOutputPath(i), std::ios_base::out | std::ios_base::binary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
// set parameters
|
||||
// TODO support defaults and overrides from config file
|
||||
// m_chip.SetSoundParameters(SAAP_FILTER | SAAP_11025 | SAAP_8BIT | SAAP_MONO);
|
||||
// reset the virtual SAA
|
||||
// m_chip.Clear();
|
||||
|
||||
m_chip._SetClockRate(m_nClockRate);
|
||||
m_chip._SetOversample(m_nOversample);
|
||||
}
|
||||
|
||||
CSAASoundInternal::~CSAASoundInternal()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// CSAASound members
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CSAASoundInternal::SetClockRate(unsigned int nClockRate)
|
||||
{
|
||||
m_nClockRate = nClockRate;
|
||||
m_chip._SetClockRate(m_nClockRate);
|
||||
}
|
||||
|
||||
void CSAASoundInternal::Clear(void)
|
||||
{
|
||||
// reinitialises virtual SAA:
|
||||
// sets reg 28 to 0x02; - sync and disabled
|
||||
// sets regs 00-31 (except 28) to 0x00;
|
||||
// sets reg 28 to 0x00;
|
||||
// sets current reg to 0
|
||||
WriteAddressData(28,2);
|
||||
for (int i=31; i>=0; i--)
|
||||
{
|
||||
if (i!=28) WriteAddressData(i,0);
|
||||
}
|
||||
WriteAddressData(28,0);
|
||||
WriteAddress(0);
|
||||
}
|
||||
|
||||
void CSAASoundInternal::WriteData(BYTE nData)
|
||||
{
|
||||
// originated from an OUT 255,d call
|
||||
m_chip._WriteData(nData);
|
||||
#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE)
|
||||
#ifdef USE_CONFIG_FILE
|
||||
if (m_Config.m_bGenerateRegisterLogs)
|
||||
{
|
||||
#endif
|
||||
m_dbgfile << m_nDebugSample << " " << (int)m_chip._ReadAddress() << ":" << (int)nData << std::endl;
|
||||
#ifdef USE_CONFIG_FILE
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void CSAASoundInternal::WriteAddress(BYTE nReg)
|
||||
{
|
||||
// originated from an OUT 511,r call
|
||||
m_chip._WriteAddress(nReg);
|
||||
#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE)
|
||||
#ifdef USE_CONFIG_FILE
|
||||
if (m_Config.m_bGenerateRegisterLogs)
|
||||
{
|
||||
#endif
|
||||
m_dbgfile << m_nDebugSample << " " << (int)nReg << ":";
|
||||
if (nReg==24)
|
||||
{
|
||||
m_dbgfile << "<!ENVO!>";
|
||||
}
|
||||
else if (nReg==25)
|
||||
{
|
||||
m_dbgfile << "<!ENV1!>";
|
||||
}
|
||||
m_dbgfile << std::endl;
|
||||
#ifdef USE_CONFIG_FILE
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void CSAASoundInternal::WriteAddressData(BYTE nReg, BYTE nData)
|
||||
{
|
||||
// performs WriteAddress(nReg) followed by WriteData(nData)
|
||||
m_chip._WriteAddress(nReg);
|
||||
m_chip._WriteData(nData);
|
||||
}
|
||||
|
||||
#if 1
|
||||
BYTE CSAASoundInternal::ReadAddress(void)
|
||||
{
|
||||
// Not a real hardware function of the SAA-1099, which is write-only
|
||||
return(m_chip._ReadAddress());
|
||||
}
|
||||
#else
|
||||
BYTE CSAASoundInternal::ReadAddress(void)
|
||||
{
|
||||
// Not a real hardware function of the SAA-1099, which is write-only
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void CSAASoundInternal::SetSoundParameters(SAAPARAM uParam)
|
||||
{
|
||||
// set samplerate properties from uParam (deprecated but still supported)
|
||||
unsigned int nSampleRate = m_nSampleRate;
|
||||
switch (uParam & SAAP_MASK_SAMPLERATE)
|
||||
{
|
||||
case SAAP_44100:
|
||||
nSampleRate = 44100;
|
||||
m_uParamRate = (m_uParamRate & ~SAAP_MASK_SAMPLERATE) | SAAP_44100;
|
||||
break;
|
||||
case SAAP_22050:
|
||||
nSampleRate = 22050;
|
||||
m_uParamRate = (m_uParamRate & ~SAAP_MASK_SAMPLERATE) | SAAP_22050;
|
||||
break;
|
||||
case SAAP_11025:
|
||||
nSampleRate = 11025;
|
||||
m_uParamRate = (m_uParamRate & ~SAAP_MASK_SAMPLERATE) | SAAP_11025;
|
||||
break;
|
||||
case 0:// change nothing!
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (nSampleRate != m_nSampleRate)
|
||||
{
|
||||
m_nSampleRate = nSampleRate;
|
||||
m_chip._SetSampleRate(m_nSampleRate);
|
||||
}
|
||||
|
||||
// set filter properties from uParam
|
||||
m_uParam = (m_uParam & ~SAAP_MASK_FILTER) | (uParam & SAAP_MASK_FILTER);
|
||||
|
||||
m_bHighpass=true;
|
||||
}
|
||||
|
||||
void CSAASoundInternal::SetSampleRate(unsigned int nSampleRate)
|
||||
{
|
||||
if (nSampleRate != m_nSampleRate)
|
||||
{
|
||||
m_nSampleRate = nSampleRate;
|
||||
m_chip._SetSampleRate(m_nSampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
void CSAASoundInternal::SetOversample(unsigned int nOversample)
|
||||
{
|
||||
if (nOversample != m_nOversample)
|
||||
{
|
||||
m_nOversample = nOversample;
|
||||
m_chip._SetOversample(m_nOversample);
|
||||
}
|
||||
}
|
||||
|
||||
SAAPARAM CSAASoundInternal::GetCurrentSoundParameters(void)
|
||||
{
|
||||
return m_uParam | m_uParamRate;
|
||||
}
|
||||
|
||||
unsigned short CSAASoundInternal::GetCurrentBytesPerSample(void)
|
||||
{
|
||||
// 16 bit stereo => 4 bytes per sample
|
||||
return 4;
|
||||
}
|
||||
|
||||
/*static*/ unsigned short CSAASound::GetBytesPerSample(SAAPARAM uParam)
|
||||
{
|
||||
// 16 bit stereo => 4 bytes per sample
|
||||
switch (uParam & (SAAP_MASK_CHANNELS | SAAP_MASK_BITDEPTH))
|
||||
{
|
||||
case SAAP_STEREO | SAAP_16BIT:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long CSAASoundInternal::GetCurrentSampleRate(void)
|
||||
{
|
||||
return CSAASound::GetSampleRate(m_uParamRate);
|
||||
}
|
||||
|
||||
/*static*/ unsigned long CSAASound::GetSampleRate(SAAPARAM uParam) // static member function
|
||||
{
|
||||
switch (uParam & SAAP_MASK_SAMPLERATE)
|
||||
{
|
||||
case SAAP_11025:
|
||||
return 11025;
|
||||
case SAAP_22050:
|
||||
return 22050;
|
||||
case SAAP_44100:
|
||||
return 44100;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(USE_CONFIG_FILE) || (defined(DEFAULT_BOOST) && DEFAULT_BOOST>1)
|
||||
#define DO_BOOST
|
||||
#endif
|
||||
|
||||
void scale_for_output(unsigned int left_input, unsigned int right_input,
|
||||
double oversample_scalar, bool highpass, double boost,
|
||||
double& filterout_z1_left, double& filterout_z1_right,
|
||||
BYTE* &pBuffer)
|
||||
{
|
||||
double float_left = (double)left_input;
|
||||
double float_right = (double)right_input;
|
||||
float_left /= oversample_scalar;
|
||||
float_right /= oversample_scalar;
|
||||
|
||||
// scale output into good range
|
||||
float_left *= DEFAULT_UNBOOSTED_MULTIPLIER;
|
||||
float_right *= DEFAULT_UNBOOSTED_MULTIPLIER;
|
||||
|
||||
if (highpass)
|
||||
{
|
||||
/* cutoff = 5 Hz (say)
|
||||
const double b1 = exp(-2.0 * M_PI * (Fc/Fs))
|
||||
const double a0 = 1.0 - b1;
|
||||
*/
|
||||
const double b1 = 0.99928787;
|
||||
const double a0 = 1.0 - b1;
|
||||
|
||||
filterout_z1_left = float_left * a0 + filterout_z1_left * b1;
|
||||
filterout_z1_right = float_right * a0 + filterout_z1_right * b1;
|
||||
float_left -= filterout_z1_left;
|
||||
float_right -= filterout_z1_right;
|
||||
}
|
||||
|
||||
// multiply by boost, if defined
|
||||
#if defined(DO_BOOST)
|
||||
float_left *= boost;
|
||||
float_right *= boost;
|
||||
#endif
|
||||
// convert to 16-bit signed range with hard clipping
|
||||
signed short left_output = (signed short)(float_left > 32767 ? 32767 : float_left < -32768 ? -32768 : float_left);
|
||||
signed short right_output = (signed short)(float_right > 32767 ? 32767 : float_right < -32768 ? -32768 : float_right);
|
||||
|
||||
*pBuffer++ = left_output & 0x00ff;
|
||||
*pBuffer++ = (left_output >> 8) & 0x00ff;
|
||||
*pBuffer++ = right_output & 0x00ff;
|
||||
*pBuffer++ = (right_output >> 8) & 0x00ff;
|
||||
}
|
||||
|
||||
void CSAASoundInternal::GenerateMany(BYTE* pBuffer, unsigned long nSamples)
|
||||
{
|
||||
unsigned int left_mixed, right_mixed;
|
||||
|
||||
#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE)
|
||||
BYTE* pBufferStart = pBuffer;
|
||||
unsigned long nTotalSamples = nSamples;
|
||||
#endif
|
||||
|
||||
#if defined(DO_BOOST)
|
||||
#if defined(USE_CONFIG_FILE)
|
||||
double nBoost = m_Config.m_nBoost;
|
||||
#else
|
||||
double nBoost = DEFAULT_BOOST;
|
||||
#endif
|
||||
#else
|
||||
double nBoost = 1.0;
|
||||
#endif
|
||||
|
||||
double oversample = double(1 << m_nOversample);
|
||||
|
||||
#if defined(USE_CONFIG_FILE)
|
||||
static double filterout_z1_left_0 = 0, filterout_z1_right_0 = 0;
|
||||
static double filterout_z1_left_1 = 0, filterout_z1_right_1 = 0;
|
||||
static double filterout_z1_left_2 = 0, filterout_z1_right_2 = 0;
|
||||
static double filterout_z1_left_3 = 0, filterout_z1_right_3 = 0;
|
||||
static double filterout_z1_left_4 = 0, filterout_z1_right_4 = 0;
|
||||
static double filterout_z1_left_5 = 0, filterout_z1_right_5 = 0;
|
||||
|
||||
if (m_Config.m_bGeneratePcmLogs && m_Config.m_bGeneratePcmSeparateChannels)
|
||||
{
|
||||
unsigned int left0, right0, left1, right1, left2, right2, left3, right3, left4, right4, left5, right5;
|
||||
BYTE* pChannelBufferPtr[6] = { m_pChannelBuffer[0], m_pChannelBuffer[1], m_pChannelBuffer[2], m_pChannelBuffer[3], m_pChannelBuffer[4], m_pChannelBuffer[5] };
|
||||
|
||||
while (nSamples--)
|
||||
{
|
||||
m_chip._TickAndOutputSeparate(left_mixed, right_mixed,
|
||||
left0, right0,
|
||||
left1, right1,
|
||||
left2, right2,
|
||||
left3, right3,
|
||||
left4, right4,
|
||||
left5, right5);
|
||||
scale_for_output(left_mixed, right_mixed, oversample, m_bHighpass, nBoost, filterout_z1_left_mixed, filterout_z1_right_mixed, pBuffer);
|
||||
|
||||
// and the separate channels
|
||||
scale_for_output(left0, right0, oversample, m_bHighpass, nBoost, filterout_z1_left_0, filterout_z1_right_0, pChannelBufferPtr[0]);
|
||||
scale_for_output(left1, right1, oversample, m_bHighpass, nBoost, filterout_z1_left_1, filterout_z1_right_1, pChannelBufferPtr[1]);
|
||||
scale_for_output(left2, right2, oversample, m_bHighpass, nBoost, filterout_z1_left_2, filterout_z1_right_2, pChannelBufferPtr[2]);
|
||||
scale_for_output(left3, right3, oversample, m_bHighpass, nBoost, filterout_z1_left_3, filterout_z1_right_3, pChannelBufferPtr[3]);
|
||||
scale_for_output(left4, right4, oversample, m_bHighpass, nBoost, filterout_z1_left_4, filterout_z1_right_4, pChannelBufferPtr[4]);
|
||||
scale_for_output(left5, right5, oversample, m_bHighpass, nBoost, filterout_z1_left_5, filterout_z1_right_5, pChannelBufferPtr[5]);
|
||||
|
||||
// flush channel output PCM buffers when full
|
||||
if (pChannelBufferPtr[0] >= m_pChannelBuffer[0] + CHANNEL_BUFFER_SIZE)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_channel_pcmfile[i].write((const char*)m_pChannelBuffer[i], CHANNEL_BUFFER_SIZE);
|
||||
pChannelBufferPtr[i] = m_pChannelBuffer[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
// flush remaining channel PCM output data
|
||||
if (pChannelBufferPtr[0] >= m_pChannelBuffer[0])
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_channel_pcmfile[i].write((const char*)m_pChannelBuffer[i], pChannelBufferPtr[i]-m_pChannelBuffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
while (nSamples--)
|
||||
{
|
||||
m_chip._TickAndOutputStereo(left_mixed, right_mixed);
|
||||
scale_for_output(left_mixed, right_mixed, oversample, m_bHighpass, nBoost, filterout_z1_left_mixed, filterout_z1_right_mixed, pBuffer);
|
||||
}
|
||||
|
||||
#if defined(USE_CONFIG_FILE)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE)
|
||||
#ifdef USE_CONFIG_FILE
|
||||
if (m_Config.m_bGeneratePcmLogs)
|
||||
{
|
||||
#endif
|
||||
m_pcmfile.write((const char *)pBufferStart, nTotalSamples * (unsigned long)GetCurrentBytesPerSample());
|
||||
m_nDebugSample += nTotalSamples;
|
||||
#ifdef USE_CONFIG_FILE
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
LPCSAASOUND SAAAPI CreateCSAASound(void)
|
||||
{
|
||||
return (new CSAASoundInternal);
|
||||
}
|
||||
|
||||
void SAAAPI DestroyCSAASound(LPCSAASOUND object)
|
||||
{
|
||||
delete (object);
|
||||
}
|
||||
|
||||
|
||||
/* thoughts on lowpass filtering as part of oversampling.
|
||||
I tried this and really it didn't seem to make a lot of (audible) difference.
|
||||
|
||||
// lowpass oversample filter adds complexity and not particularly audibly better than simple averaging.
|
||||
// use_lowpass_oversample_filter_average_output adds an additional averaging step to the output of the oversample
|
||||
// filter. this seems critical, because without this, the raw output of the lowpass filter is full of aliases
|
||||
// If use_lowpass_oversample_filter is False, then the _average_output flag is ignored.
|
||||
// Default, use_lowpass_oversample_filter is False, it sounds just fine really.
|
||||
|
||||
//#define USE_LOWPASS_OVERSAMPLE_FILTER
|
||||
#undef USE_LOWPASS_OVERSAMPLE_FILTER
|
||||
//#define USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT
|
||||
#undef USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT
|
||||
|
||||
#ifdef USE_LOWPASS_OVERSAMPLE_FILTER
|
||||
static double oversample_lp_filterout_z1_left_stages[10] = { 0,0,0,0,0,0,0,0,0,0 };
|
||||
static double oversample_lp_filterout_z1_right_stages[10] = { 0,0,0,0,0,0,0,0,0,0 };
|
||||
double averaged_filterout_left = 0.0, averaged_filterout_right = 0.0;
|
||||
const int nStages = 10;
|
||||
for (int i = 0; i < 1 << m_nOversample; i++)
|
||||
{
|
||||
Noise[0]->Tick();
|
||||
Noise[1]->Tick();
|
||||
f_left = f_right = 0;
|
||||
for (int c = 0; c < 6; c++)
|
||||
{
|
||||
Amp[c]->TickAndOutputStereo(temp_left, temp_right);
|
||||
f_left += (double)temp_left;
|
||||
f_right += (double)temp_right;
|
||||
}
|
||||
// apply lowpass here.
|
||||
// HACK: ASSUME m_nOversample is 64 (I was experimenting only using the 64x oversample anyway)
|
||||
// therefore Fs = 44100*64
|
||||
// let's set Fc = 10kHz
|
||||
// so Fc/Fs = 0.00354308390022675736961451247166
|
||||
// const double b1 = exp(-2.0 * M_PI * (Fc/Fs))
|
||||
// const double a0 = 1.0 - b1;
|
||||
// const double b1 = 0.9779841137335348363722276130195;
|
||||
const double b1 = 0.977;
|
||||
const double a0 = 1.0 - b1;
|
||||
|
||||
oversample_lp_filterout_z1_left_stages[0] = f_left * a0 + oversample_lp_filterout_z1_left_stages[0] * b1;
|
||||
for (int stage = 1; stage < nStages; stage++)
|
||||
oversample_lp_filterout_z1_left_stages[stage] = oversample_lp_filterout_z1_left_stages[stage - 1] * a0 + oversample_lp_filterout_z1_left_stages[stage] * b1;
|
||||
oversample_lp_filterout_z1_right_stages[0] = f_right * a0 + oversample_lp_filterout_z1_right_stages[0] * b1;
|
||||
for (int stage = 1; stage < nStages; stage++)
|
||||
oversample_lp_filterout_z1_right_stages[stage] = oversample_lp_filterout_z1_right_stages[stage - 1] * a0 + oversample_lp_filterout_z1_right_stages[stage] * b1;
|
||||
|
||||
#ifdef USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT
|
||||
averaged_filterout_left += oversample_lp_filterout_4z1_left;
|
||||
averaged_filterout_right += oversample_lp_filterout_4z1_right;
|
||||
#endif
|
||||
}
|
||||
|
||||
// by the end of this loop we will have computed the oversample lowpass filter m_nOversample times
|
||||
// and yielded exactly ONE sample output.
|
||||
#ifdef USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT
|
||||
f_left = averaged_filterout_left / (1 << m_nOversample);
|
||||
f_right = averaged_filterout_right / (1 << m_nOversample);
|
||||
#else
|
||||
f_left = oversample_lp_filterout_z1_left_stages[nStages - 1];
|
||||
f_right = oversample_lp_filterout_z1_right_stages[nStages - 1];
|
||||
#endif
|
||||
|
||||
#else
|
||||
// do the simple 1/N averaging which is easier and sounds good enough
|
||||
|
||||
#endif
|
||||
|
||||
*/
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// This is the internal implementation (header file) of the SAASound object.
|
||||
// This is done so that the external interface to the object always stays the same
|
||||
// (SAASound.h) even though the internal object can change
|
||||
// .. Meaning future releases don't require relinking everyone elses code against
|
||||
// the updated saasound stuff
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SAAIMPL_H_INCLUDED
|
||||
#define SAAIMPL_H_INCLUDED
|
||||
|
||||
#include "SAASound.h"
|
||||
#include "SAADevice.h"
|
||||
#ifdef USE_CONFIG_FILE
|
||||
#include "SAAConfig.h"
|
||||
#endif
|
||||
|
||||
#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE)
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#if defined(USE_CONFIG_FILE)
|
||||
const int CHANNEL_BUFFER_SIZE=1024;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class CSAASoundInternal : public CSAASound
|
||||
{
|
||||
private:
|
||||
CSAADevice m_chip;
|
||||
int m_uParam, m_uParamRate;
|
||||
unsigned int m_nClockRate;
|
||||
unsigned int m_nSampleRate;
|
||||
unsigned int m_nOversample;
|
||||
bool m_bHighpass;
|
||||
double filterout_z1_left_mixed = 0;
|
||||
double filterout_z1_right_mixed = 0;
|
||||
#ifdef USE_CONFIG_FILE
|
||||
SAAConfig m_Config;
|
||||
#endif
|
||||
#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE)
|
||||
unsigned long m_nDebugSample;
|
||||
std::ofstream m_dbgfile, m_pcmfile;
|
||||
#if defined(USE_CONFIG_FILE)
|
||||
std::ofstream m_channel_pcmfile[6];
|
||||
BYTE m_pChannelBuffer[6][CHANNEL_BUFFER_SIZE];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
public:
|
||||
CSAASoundInternal();
|
||||
~CSAASoundInternal();
|
||||
|
||||
void SetClockRate(unsigned int nClockRate);
|
||||
void SetSampleRate(unsigned int nClockRate);
|
||||
void SetOversample(unsigned int nOversample);
|
||||
void SetSoundParameters(SAAPARAM uParam);
|
||||
void WriteAddress(BYTE nReg);
|
||||
void WriteData(BYTE nData);
|
||||
void WriteAddressData(BYTE nReg, BYTE nData);
|
||||
BYTE ReadAddress(void);
|
||||
void Clear(void);
|
||||
|
||||
SAAPARAM GetCurrentSoundParameters(void);
|
||||
unsigned long GetCurrentSampleRate(void);
|
||||
static unsigned long GetSampleRate(SAAPARAM uParam);
|
||||
unsigned short GetCurrentBytesPerSample(void);
|
||||
static unsigned short GetBytesPerSample(SAAPARAM uParam);
|
||||
|
||||
void GenerateMany(BYTE * pBuffer, unsigned long nSamples);
|
||||
|
||||
};
|
||||
|
||||
#endif // SAAIMPL_H_INCLUDED
|
||||
@@ -1,180 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAANoise.cpp: implementation of the CSAANoise class.
|
||||
// One noise generator
|
||||
//
|
||||
// After construction, it's important to SetSampleRate before
|
||||
// trying to use the generator.
|
||||
// (Just because the CSAANoise object has a default samplerate
|
||||
// doesn't mean you should rely on it)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SAASound.h"
|
||||
|
||||
#include "types.h"
|
||||
#include "SAANoise.h"
|
||||
#include "defns.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
CSAANoise::CSAANoise()
|
||||
:
|
||||
m_nCounter(0),
|
||||
m_nCounter_low(0),
|
||||
m_nOversample(0),
|
||||
m_nCounterLimit_low(1),
|
||||
m_bSync(false),
|
||||
m_nSampleRate(SAMPLE_RATE_HZ),
|
||||
m_nSourceMode(0),
|
||||
m_nRand(1)
|
||||
{
|
||||
_SetClockRate(EXTERNAL_CLK_HZ);
|
||||
m_nAdd = m_nAddBase;
|
||||
}
|
||||
|
||||
CSAANoise::CSAANoise(unsigned long seed)
|
||||
:
|
||||
m_nCounter(0),
|
||||
m_nCounter_low(0),
|
||||
m_nOversample(0),
|
||||
m_nCounterLimit_low(1),
|
||||
m_bSync(false),
|
||||
m_nSampleRate(SAMPLE_RATE_HZ),
|
||||
m_nSourceMode(0),
|
||||
m_nRand(seed)
|
||||
{
|
||||
_SetClockRate(EXTERNAL_CLK_HZ);
|
||||
m_nAdd = m_nAddBase;
|
||||
}
|
||||
|
||||
CSAANoise::~CSAANoise()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CSAANoise::_SetClockRate(int nClockRate)
|
||||
{
|
||||
// at 8MHz the clock rate is 31.250kHZ
|
||||
// This is simply the clock rate divided by 256 i.e. 2^8
|
||||
// We then shift this by 2^12 (like the Freq) for better
|
||||
// period accuracy. So that's the same as shifting by (12-8)
|
||||
m_nAddBase = nClockRate << (12 - 8);
|
||||
}
|
||||
|
||||
void CSAANoise::Seed(unsigned long seed)
|
||||
{
|
||||
m_nRand = seed;
|
||||
}
|
||||
|
||||
void CSAANoise::SetSource(int nSource)
|
||||
{
|
||||
m_nSourceMode = nSource;
|
||||
m_nAdd = m_nAddBase >> m_nSourceMode;
|
||||
}
|
||||
|
||||
void CSAANoise::Trigger(void)
|
||||
{
|
||||
// Trigger only does anything useful when we're
|
||||
// clocking from the frequency generator - i.e
|
||||
// if bUseFreqGen = true (i.e. SourceMode = 3)
|
||||
|
||||
// So if we're clocking from the noise generator
|
||||
// clock (ie, SourceMode = 0, 1 or 2) then do nothing
|
||||
|
||||
// No point actually checking m_bSync here ... because if sync is true,
|
||||
// then frequency generators won't actually be generating Trigger pulses
|
||||
// so we wouldn't even get here!
|
||||
// EXCEPT - cool edge case: if sync is set, then actually the Noise Generator
|
||||
// is triggered on EVERY CLOCK PULSE (i.e. 8MHz noise). So indeed it is correct
|
||||
// to not check for sync here. NEEDS TEST CASE.
|
||||
|
||||
if (m_nSourceMode == 3)
|
||||
{
|
||||
ChangeLevel();
|
||||
}
|
||||
}
|
||||
|
||||
void CSAANoise::Tick(void)
|
||||
{
|
||||
// Tick only does anything useful when we're
|
||||
// clocking from the noise generator clock
|
||||
// (ie, SourceMode = 0, 1 or 2)
|
||||
|
||||
// So, if SourceMode = 3 (ie, we're clocking from a
|
||||
// frequency generator ==> bUseFreqGen = true)
|
||||
// then do nothing
|
||||
if ( (!m_bSync) && (m_nSourceMode!=3) )
|
||||
{
|
||||
m_nCounter += m_nAdd;
|
||||
while (m_nCounter >= (m_nSampleRate<<12))
|
||||
{
|
||||
m_nCounter -= (m_nSampleRate<<12);
|
||||
m_nCounter_low++;
|
||||
if (m_nCounter_low >= m_nCounterLimit_low)
|
||||
{
|
||||
m_nCounter_low = 0;
|
||||
ChangeLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSAANoise::Sync(bool bSync)
|
||||
{
|
||||
if (bSync)
|
||||
{
|
||||
m_nCounter = 0;
|
||||
m_nCounter_low = 0;
|
||||
}
|
||||
m_bSync = bSync;
|
||||
}
|
||||
|
||||
|
||||
void CSAANoise::_SetSampleRate(int nSampleRate)
|
||||
{
|
||||
m_nSampleRate = nSampleRate;
|
||||
}
|
||||
|
||||
|
||||
void CSAANoise::_SetOversample(unsigned int oversample)
|
||||
{
|
||||
// oversample is a power of 2 i.e.
|
||||
// if oversample == 2 then 4x oversample
|
||||
// if oversample == 6 then 64x oversample
|
||||
if (oversample < m_nOversample)
|
||||
{
|
||||
m_nCounter_low <<= (m_nOversample - oversample);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nCounter_low >>= (oversample - m_nOversample);
|
||||
}
|
||||
|
||||
m_nCounterLimit_low = 1<<oversample;
|
||||
m_nOversample = oversample;
|
||||
}
|
||||
|
||||
inline void CSAANoise::ChangeLevel(void)
|
||||
{
|
||||
/*
|
||||
https://www.vogons.org/viewtopic.php?f=9&t=51695
|
||||
SAA1099P noise generator as documented by Jepael
|
||||
18-bit Galois LFSR
|
||||
Feedback polynomial = x^18 + x^11 + x^1
|
||||
Period = 2^18-1 = 262143 bits
|
||||
Verified to match recorded noise from my SAA1099P
|
||||
*/
|
||||
|
||||
if (m_nRand & 1)
|
||||
{
|
||||
m_nRand = (m_nRand >> 1) ^ 0x20400;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nRand >>= 1;
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAANoise.h: interface for the CSAANoise class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SAANOISE_H_INCLUDED
|
||||
#define SAANOISE_H_INCLUDED
|
||||
|
||||
class CSAANoise
|
||||
{
|
||||
private:
|
||||
unsigned long m_nCounter;
|
||||
unsigned long m_nAdd;
|
||||
unsigned long m_nCounter_low;
|
||||
unsigned int m_nOversample;
|
||||
unsigned long m_nCounterLimit_low;
|
||||
bool m_bSync; // see description of "SYNC" bit of register 28
|
||||
unsigned long m_nSampleRate; // = 44100 when RateMode=0, for example
|
||||
int m_nSourceMode;
|
||||
unsigned long m_nAddBase; // nAdd for 31.25 kHz noise at 44.1 kHz samplerate
|
||||
|
||||
// pseudo-random number generator
|
||||
unsigned long m_nRand;
|
||||
|
||||
void ChangeLevel(void);
|
||||
|
||||
|
||||
public:
|
||||
CSAANoise();
|
||||
CSAANoise(unsigned long seed);
|
||||
~CSAANoise();
|
||||
|
||||
void SetSource(int nSource);
|
||||
void Trigger(void);
|
||||
void _SetSampleRate(int nSampleRate);
|
||||
void _SetOversample(unsigned int oversample);
|
||||
void _SetClockRate(int nClockRate);
|
||||
void Seed(unsigned long seed);
|
||||
|
||||
void Tick(void);
|
||||
int Level(void) const;
|
||||
void Sync(bool bSync);
|
||||
|
||||
};
|
||||
|
||||
inline int CSAANoise::Level(void) const
|
||||
{
|
||||
// returns 0 or 1
|
||||
return (m_nRand & 0x00000001);
|
||||
}
|
||||
|
||||
|
||||
#endif // SAANOISE_H_INCLUDED
|
||||
@@ -1,100 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// Thanks to this file (and associated header file) you can now
|
||||
// use CSAASound from within a standard 'C' program
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SAASound.h"
|
||||
#include "types.h"
|
||||
#include "SAAEnv.h"
|
||||
#include "SAANoise.h"
|
||||
#include "SAAFreq.h"
|
||||
#include "SAAAmp.h"
|
||||
#include "SAASound.h"
|
||||
#include "SAAImpl.h"
|
||||
|
||||
SAASND SAAAPI newSAASND(void)
|
||||
{
|
||||
return (SAASND)(new CSAASoundInternal());
|
||||
}
|
||||
|
||||
void SAAAPI deleteSAASND(SAASND object)
|
||||
{
|
||||
delete (LPCSAASOUND)(object);
|
||||
}
|
||||
|
||||
void SAAAPI SAASNDSetClockRate(SAASND object, unsigned int nClockRate)
|
||||
{
|
||||
((LPCSAASOUND)(object))->SetClockRate(nClockRate);
|
||||
}
|
||||
|
||||
void SAAAPI SAASNDSetSoundParameters(SAASND object, SAAPARAM uParam)
|
||||
{
|
||||
((LPCSAASOUND)(object))->SetSoundParameters(uParam);
|
||||
}
|
||||
|
||||
void SAAAPI SAASNDWriteAddress(SAASND object, BYTE nReg)
|
||||
{
|
||||
((LPCSAASOUND)(object))->WriteAddress(nReg);
|
||||
}
|
||||
|
||||
void SAAAPI SAASNDWriteData(SAASND object, BYTE nData)
|
||||
{
|
||||
((LPCSAASOUND)(object))->WriteData(nData);
|
||||
}
|
||||
|
||||
void SAAAPI SAASNDWriteAddressData(SAASND object, BYTE nReg, BYTE nData)
|
||||
{
|
||||
((LPCSAASOUND)(object))->WriteAddressData(nReg, nData);
|
||||
}
|
||||
|
||||
void SAAAPI SAASNDClear(SAASND object)
|
||||
{
|
||||
((LPCSAASOUND)(object))->Clear();
|
||||
}
|
||||
|
||||
SAAPARAM SAAAPI SAASNDGetCurrentSoundParameters(SAASND object)
|
||||
{
|
||||
return ((LPCSAASOUND)(object))->GetCurrentSoundParameters();
|
||||
}
|
||||
|
||||
unsigned short SAAAPI SAASNDGetCurrentBytesPerSample(SAASND object)
|
||||
{
|
||||
return ((LPCSAASOUND)(object))->GetCurrentBytesPerSample();
|
||||
}
|
||||
|
||||
unsigned short SAAAPI SAASNDGetBytesPerSample(SAAPARAM uParam)
|
||||
{
|
||||
return CSAASound::GetBytesPerSample(uParam);
|
||||
}
|
||||
|
||||
unsigned long SAAAPI SAASNDGetCurrentSampleRate(SAASND object)
|
||||
{
|
||||
return ((LPCSAASOUND)(object))->GetCurrentSampleRate();
|
||||
}
|
||||
|
||||
unsigned long SAAAPI SAASNDGetSampleRate(SAAPARAM uParam)
|
||||
{
|
||||
return CSAASound::GetSampleRate(uParam);
|
||||
}
|
||||
|
||||
void SAAAPI SAASNDGenerateMany(SAASND object, BYTE * pBuffer, unsigned long nSamples)
|
||||
{
|
||||
((LPCSAASOUND)(object))->GenerateMany(pBuffer, nSamples);
|
||||
}
|
||||
|
||||
void SAAAPI SAASNDSetSampleRate(SAASND object, unsigned int nSampleRate)
|
||||
{
|
||||
return ((LPCSAASOUND)(object))->SetSampleRate(nSampleRate);
|
||||
}
|
||||
|
||||
void SAAAPI SAASNDSetOversample(SAASND object, unsigned int nOversample)
|
||||
{
|
||||
return ((LPCSAASOUND)(object))->SetOversample(nOversample);
|
||||
}
|
||||
|
||||
BYTE SAAAPI SAASNDReadAddress(SAASND object)
|
||||
{
|
||||
return ((LPCSAASOUND)(object))->ReadAddress();
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// **********
|
||||
// * PUBLIC *
|
||||
// **********
|
||||
//
|
||||
// SAASndC.h: "C-style" interface for the CSAASound class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SAASNDC_H_INCLUDED
|
||||
#define SAASNDC_H_INCLUDED
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER >= 1000
|
||||
#endif
|
||||
|
||||
#ifndef SAASOUND_H_INCLUDED
|
||||
|
||||
// Parameters for use with SetSoundParameters, for example,
|
||||
// SetSoundParameters(SAAP_NOFILTER | SAAP_44100 | SAAP_16BIT | SAAP_STEREO);
|
||||
#define SAAP_FILTER_HIGHPASS_SIMPLE 0x00000400
|
||||
#define SAAP_FILTER_OVERSAMPLE64x 0x00000300
|
||||
#define SAAP_FILTER_OVERSAMPLE2x 0x00000200
|
||||
#define SAAP_FILTER SAAP_FILTER_OVERSAMPLE2x
|
||||
#define SAAP_NOFILTER 0x00000100
|
||||
#define SAAP_44100 0x00000030
|
||||
#define SAAP_22050 0x00000020
|
||||
#define SAAP_11025 0x00000010
|
||||
#define SAAP_16BIT 0x0000000c
|
||||
#define SAAP_8BIT 0x00000004
|
||||
#define SAAP_STEREO 0x00000003
|
||||
#define SAAP_MONO 0x00000001
|
||||
|
||||
// Bitmasks for use with GetCurrentSoundParameters, for example,
|
||||
// unsigned long CurrentSampleRateParameter = GetCurrentSoundParameters()
|
||||
#define SAAP_MASK_FILTER 0x00000f00
|
||||
#define SAAP_MASK_FILTER_HIGHPASS 0x00000c00
|
||||
#define SAAP_MASK_FILTER_OVERSAMPLE 0x00000300
|
||||
#define SAAP_MASK_SAMPLERATE 0x000000030
|
||||
#define SAAP_MASK_BITDEPTH 0x0000000c
|
||||
#define SAAP_MASK_CHANNELS 0x00000003
|
||||
|
||||
typedef unsigned long SAAPARAM;
|
||||
|
||||
|
||||
#ifndef BYTE
|
||||
#define BYTE unsigned char
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef WINAPI
|
||||
#define WINAPI __stdcall
|
||||
#endif
|
||||
#define EXTAPI __declspec(dllexport) WINAPI
|
||||
#else // Win32
|
||||
#ifndef WINAPI
|
||||
#define WINAPI /**/
|
||||
#endif
|
||||
#define EXTAPI /**/
|
||||
#endif // Win32
|
||||
|
||||
#endif // SAASOUND_H_INCLUDED
|
||||
|
||||
typedef void * SAASND;
|
||||
|
||||
// the following are implemented as calls, etc, to a class.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
SAASND EXTAPI newSAASND(void);
|
||||
void EXTAPI deleteSAASND(SAASND object);
|
||||
|
||||
void EXTAPI SAASNDSetSoundParameters(SAASND object, SAAPARAM uParam);
|
||||
void EXTAPI SAASNDWriteAddress(SAASND object, BYTE nReg);
|
||||
void EXTAPI SAASNDWriteData(SAASND object, BYTE nData);
|
||||
void EXTAPI SAASNDWriteAddressData(SAASND object, BYTE nReg, BYTE nData);
|
||||
void EXTAPI SAASNDClear(SAASND object);
|
||||
BYTE EXTAPI SAASNDReadAddress(SAASND object);
|
||||
|
||||
SAAPARAM EXTAPI SAASNDGetCurrentSoundParameters(SAASND object);
|
||||
unsigned short EXTAPI SAASNDGetCurrentBytesPerSample(SAASND object);
|
||||
unsigned short EXTAPI SAASNDGetBytesPerSample(SAAPARAM uParam);
|
||||
unsigned long EXTAPI SAASNDGetCurrentSampleRate(SAASND object);
|
||||
unsigned long EXTAPI SAASNDGetSampleRate(SAAPARAM uParam);
|
||||
|
||||
void EXTAPI SAASNDGenerateMany(SAASND object, BYTE * pBuffer, unsigned long nSamples);
|
||||
|
||||
void EXTAPI SAASNDSetClockRate(SAASND object, unsigned int nClockRate);
|
||||
void EXTAPI SAASNDSetSampleRate(SAASND object, unsigned int nSampleRate);
|
||||
void EXTAPI SAASNDSetOversample(SAASND object, unsigned int nOversample);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}; // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // SAASNDC_H_INCLUDED
|
||||
@@ -1,13 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAASound.cpp - dummy function
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// Provide something so the compiler doesn't optimise us out of existance
|
||||
int SomeFunction ()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// SAASound.h: interface for the CSAASound class.
|
||||
//
|
||||
// This corresponds to the public (exported) DLL interface, so all
|
||||
// APIs and client factory methods belong here.
|
||||
//
|
||||
// Compatibility notes : the intention is for this to be fully backwards
|
||||
// compatible across minor and patch versions. Any backwards breaking changes
|
||||
// should be reflected as a major version increment. New functionality can be added
|
||||
// in minor versions so long as backwards compatiblity is maintained
|
||||
//
|
||||
// Version 3.3.0 (4th Dec 2018)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SAASOUND_H_INCLUDED
|
||||
#define SAASOUND_H_INCLUDED
|
||||
|
||||
// define this if you want to output diagnostic text and PCM files
|
||||
//#define DEBUGSAA
|
||||
|
||||
// Parameters for use with SetSoundParameters, for example,
|
||||
// SetSoundParameters(SAAP_NOFILTER | SAAP_44100 | SAA_16BIT | SAA_STEREO);
|
||||
// SAAP_FILTER_HIGHPASS_SIMPLE can be ORd with SAAP_FILTER_OVERSAMPLE64x/2x
|
||||
#define SAAP_FILTER_HIGHPASS_SIMPLE 0x00000400
|
||||
#define SAAP_FILTER_OVERSAMPLE64x 0x00000300
|
||||
#define SAAP_FILTER_OVERSAMPLE2x 0x00000200
|
||||
#define SAAP_FILTER SAAP_FILTER_OVERSAMPLE2x
|
||||
#define SAAP_NOFILTER 0x00000100
|
||||
#define SAAP_44100 0x00000030
|
||||
#define SAAP_22050 0x00000020
|
||||
#define SAAP_11025 0x00000010
|
||||
#define SAAP_16BIT 0x0000000c
|
||||
#define SAAP_8BIT 0x00000004
|
||||
#define SAAP_STEREO 0x00000003
|
||||
#define SAAP_MONO 0x00000001
|
||||
|
||||
// Bitmasks for use with GetCurrentSoundParameters, for example,
|
||||
// unsigned long CurrentSampleRateParameter = GetCurrentSoundParameters()
|
||||
#define SAAP_MASK_FILTER 0x00000f00
|
||||
#define SAAP_MASK_FILTER_HIGHPASS 0x00000c00
|
||||
#define SAAP_MASK_FILTER_OVERSAMPLE 0x00000300
|
||||
#define SAAP_MASK_SAMPLERATE 0x000000030
|
||||
#define SAAP_MASK_BITDEPTH 0x0000000c
|
||||
#define SAAP_MASK_CHANNELS 0x00000003
|
||||
|
||||
typedef unsigned long SAAPARAM;
|
||||
|
||||
|
||||
#ifndef BYTE
|
||||
#define BYTE unsigned char
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SAAAPI _stdcall
|
||||
#else
|
||||
#define SAAAPI
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
class CSAASound
|
||||
{
|
||||
public:
|
||||
virtual ~CSAASound() { }
|
||||
|
||||
virtual void SetSoundParameters (SAAPARAM uParam) = 0;
|
||||
virtual void WriteAddress (BYTE nReg) = 0;
|
||||
virtual void WriteData (BYTE nData) = 0;
|
||||
virtual void WriteAddressData (BYTE nReg, BYTE nData) = 0;
|
||||
virtual void Clear () = 0;
|
||||
virtual BYTE ReadAddress () = 0;
|
||||
|
||||
virtual SAAPARAM GetCurrentSoundParameters () = 0;
|
||||
virtual unsigned long GetCurrentSampleRate () = 0;
|
||||
static unsigned long GetSampleRate (SAAPARAM uParam);
|
||||
virtual unsigned short GetCurrentBytesPerSample () = 0;
|
||||
static unsigned short GetBytesPerSample (SAAPARAM uParam);
|
||||
|
||||
virtual void GenerateMany (BYTE * pBuffer, unsigned long nSamples) = 0;
|
||||
|
||||
virtual void SetClockRate(unsigned int nClockRate) = 0;
|
||||
virtual void SetSampleRate(unsigned int nSampleRate) = 0;
|
||||
virtual void SetOversample(unsigned int nOversample) = 0;
|
||||
};
|
||||
|
||||
typedef class CSAASound * LPCSAASOUND;
|
||||
|
||||
LPCSAASOUND SAAAPI CreateCSAASound(void);
|
||||
void SAAAPI DestroyCSAASound(LPCSAASOUND object);
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void * SAASND;
|
||||
|
||||
// "C-style" interface for the CSAASound class
|
||||
SAASND SAAAPI newSAASND(void);
|
||||
void SAAAPI deleteSAASND(SAASND object);
|
||||
|
||||
void SAAAPI SAASNDSetSoundParameters(SAASND object, SAAPARAM uParam);
|
||||
void SAAAPI SAASNDWriteAddress(SAASND object, BYTE nReg);
|
||||
void SAAAPI SAASNDWriteData(SAASND object, BYTE nData);
|
||||
void SAAAPI SAASNDWriteAddressData(SAASND object, BYTE nReg, BYTE nData);
|
||||
void SAAAPI SAASNDClear(SAASND object);
|
||||
|
||||
SAAPARAM SAAAPI SAASNDGetCurrentSoundParameters(SAASND object);
|
||||
unsigned short SAAAPI SAASNDGetCurrentBytesPerSample(SAASND object);
|
||||
unsigned short SAAAPI SAASNDGetBytesPerSample(SAAPARAM uParam);
|
||||
unsigned long SAAAPI SAASNDGetCurrentSampleRate(SAASND object);
|
||||
unsigned long SAAAPI SAASNDGetSampleRate(SAAPARAM uParam);
|
||||
|
||||
void SAAAPI SAASNDGenerateMany(SAASND object, BYTE * pBuffer, unsigned long nSamples);
|
||||
void SAAAPI SAASNDSetClockRate(SAASND object, unsigned int nClockRate);
|
||||
void SAAAPI SAASNDSetSampleRate(SAASND object, unsigned int nSampleRate);
|
||||
void SAAAPI SAASNDSetOversample(SAASND object, unsigned int nOversample);
|
||||
|
||||
BYTE SAAAPI SAASNDReadAddress(SAASND object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}; // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // SAASOUND_H_INCLUDED
|
||||
@@ -1,59 +0,0 @@
|
||||
// Part of SAASound copyright 2020 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// defns.h: compile-time configuration parameters
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef DEFNS_H_INCLUDED
|
||||
#define DEFNS_H_INCLUDED
|
||||
|
||||
#define HAVE_CONFIG_H
|
||||
#ifdef HAVE_CONFIG_H
|
||||
// using CMAKE
|
||||
#include "saasound_cmake_config.h"
|
||||
#else
|
||||
|
||||
// initial default SAA1099 crystal clock rate in HZ (can be changed subsequently by calling SetClockRate)
|
||||
#define EXTERNAL_CLK_HZ 8000000
|
||||
|
||||
// define SAAFREQ_FIXED_CLOCKRATE if the above external clock rate is the only supported clock rate
|
||||
// i.e. only support a single compile-time clock rate (=> this also prevents using the SetClockRate method)
|
||||
#undef SAAFREQ_FIXED_CLOCKRATE
|
||||
// #define SAAFREQ_FIXED_CLOCKRATE
|
||||
|
||||
// initial default sample rate (audio samplerate)
|
||||
#define SAMPLE_RATE_HZ 44100
|
||||
|
||||
// initial default oversample (audio quality) recommend 0<=oversample<=6
|
||||
#define DEFAULT_OVERSAMPLE 6
|
||||
|
||||
// Whether to dump out a log of all register and value changes and raw output pcm
|
||||
//#define DEBUGSAA
|
||||
#undef DEBUGSAA
|
||||
|
||||
// the (default) names of the register output and pcm output log files.
|
||||
// If you're using a config file, you can change these (or, if you enable
|
||||
// debugging via the config file settings, but leave the filenames unspecified,
|
||||
// it will use these defaults)
|
||||
#define DEBUG_SAA_REGISTER_LOG "debugsaa.txt"
|
||||
#define DEBUG_SAA_PCM_LOG "debugsaa.pcm"
|
||||
// Whether to include support for these debug logs via config file (only making
|
||||
// sense if USE_CONFIG_FILE is also defined)
|
||||
|
||||
// Whether to support a startup configuration file that is parsed at load time
|
||||
// #undef USE_CONFIG_FILE
|
||||
#define USE_CONFIG_FILE
|
||||
|
||||
// and if so, what is its location
|
||||
#ifdef USE_CONFIG_FILE
|
||||
#define CONFIG_FILE_PATH "SAASound.cfg"
|
||||
#endif // USE_CONFIG_FILE
|
||||
|
||||
#define DEFAULT_UNBOOSTED_MULTIPLIER 11.35
|
||||
|
||||
#define DEFAULT_BOOST 1
|
||||
|
||||
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#endif // DEFNS_H_INCLUDED
|
||||
@@ -1,15 +0,0 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by SAASound.rc
|
||||
//
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define EXTERNAL_CLK_HZ 7159090
|
||||
/* #undef SAAFREQ_FIXED_CLOCKRATE */
|
||||
#define SAMPLE_RATE_HZ 44100
|
||||
#define DEFAULT_OVERSAMPLE 6
|
||||
#define DEFAULT_UNBOOSTED_MULTIPLIER 11.3
|
||||
#define DEFAULT_BOOST 1
|
||||
/* #undef DEBUGSAA */
|
||||
#define DEBUG_SAA_REGISTER_LOG "debugsaa.txt"
|
||||
#define DEBUG_SAA_PCM_LOG "debugsaa.pcm"
|
||||
|
||||
/* #undef USE_CONFIG_FILE */
|
||||
#define CONFIG_FILE_PATH "SAASound.cfg"
|
||||
@@ -1,34 +0,0 @@
|
||||
// Part of SAASound copyright 1998-2018 Dave Hooper <dave@beermex.com>
|
||||
//
|
||||
// handy typedefs
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TYPES_H_INCLUDED
|
||||
#define TYPES_H_INCLUDED
|
||||
|
||||
#if defined(__i386__) || defined(WIN32) || \
|
||||
(defined(__alpha__) || defined(__alpha)) || \
|
||||
defined(__arm__) || \
|
||||
(defined(__mips__) && defined(__MIPSEL__))
|
||||
#else
|
||||
#define __BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int nNumberOfPhases;
|
||||
bool bLooping;
|
||||
int nLevels[2][2][16]; // [Resolution][Phase][Withinphase]
|
||||
} ENVDATA;
|
||||
|
||||
#ifdef WIN32
|
||||
extern "C" void _stdcall OutputDebugStringA (char*);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/io.h>
|
||||
#include "saasound/SAASound.h"
|
||||
#include <86box/snd_cms.h>
|
||||
#include <86box/sound.h>
|
||||
#include <86box/plat_unused.h>
|
||||
@@ -16,13 +15,62 @@
|
||||
void
|
||||
cms_update(cms_t *cms)
|
||||
{
|
||||
if (cms->pos < wavetable_pos_global) {
|
||||
SAASNDGenerateMany(cms->saasound, (unsigned char*)&cms->buffer[cms->pos], wavetable_pos_global - cms->pos);
|
||||
cms->pos = wavetable_pos_global;
|
||||
}
|
||||
if (cms->pos2 < wavetable_pos_global) {
|
||||
SAASNDGenerateMany(cms->saasound2, (unsigned char*)&cms->buffer2[cms->pos2], wavetable_pos_global - cms->pos2);
|
||||
cms->pos2 = wavetable_pos_global;
|
||||
for (; cms->pos < sound_pos_global; cms->pos++) {
|
||||
int16_t out_l = 0;
|
||||
int16_t out_r = 0;
|
||||
|
||||
for (uint8_t c = 0; c < 4; c++) {
|
||||
switch (cms->noisetype[c >> 1][c & 1]) {
|
||||
case 0:
|
||||
cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 256;
|
||||
break;
|
||||
case 1:
|
||||
cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 512;
|
||||
break;
|
||||
case 2:
|
||||
cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 1024;
|
||||
break;
|
||||
case 3:
|
||||
cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (uint8_t c = 0; c < 2; c++) {
|
||||
if (cms->regs[c][0x1C] & 1) {
|
||||
for (uint8_t d = 0; d < 6; d++) {
|
||||
if (cms->regs[c][0x14] & (1 << d)) {
|
||||
if (cms->stat[c][d])
|
||||
out_l += (cms->vol[c][d][0] * 90);
|
||||
if (cms->stat[c][d])
|
||||
out_r += (cms->vol[c][d][1] * 90);
|
||||
cms->count[c][d] += cms->freq[c][d];
|
||||
if (cms->count[c][d] >= 24000) {
|
||||
cms->count[c][d] -= 24000;
|
||||
cms->stat[c][d] ^= 1;
|
||||
}
|
||||
} else if (cms->regs[c][0x15] & (1 << d)) {
|
||||
if (cms->noise[c][d / 3] & 1)
|
||||
out_l += (cms->vol[c][d][0] * 90);
|
||||
if (cms->noise[c][d / 3] & 1)
|
||||
out_r += (cms->vol[c][d][0] * 90);
|
||||
}
|
||||
}
|
||||
for (uint8_t d = 0; d < 2; d++) {
|
||||
cms->noisecount[c][d] += cms->noisefreq[c][d];
|
||||
while (cms->noisecount[c][d] >= 24000) {
|
||||
cms->noisecount[c][d] -= 24000;
|
||||
cms->noise[c][d] <<= 1;
|
||||
if (!(((cms->noise[c][d] & 0x4000) >> 8) ^ (cms->noise[c][d] & 0x40)))
|
||||
cms->noise[c][d] |= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cms->buffer[cms->pos << 1] = out_l;
|
||||
cms->buffer[(cms->pos << 1) + 1] = out_r;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,44 +82,68 @@ cms_get_buffer(int32_t *buffer, int len, void *priv)
|
||||
cms_update(cms);
|
||||
|
||||
for (int c = 0; c < len * 2; c++)
|
||||
buffer[c] += (cms->buffer[c] / 2);
|
||||
buffer[c] += cms->buffer[c];
|
||||
|
||||
cms->pos = 0;
|
||||
}
|
||||
|
||||
void
|
||||
cms_get_buffer_2(int32_t *buffer, int len, void *priv)
|
||||
{
|
||||
cms_t *cms = (cms_t *) priv;
|
||||
|
||||
cms_update(cms);
|
||||
|
||||
for (int c = 0; c < len * 2; c++)
|
||||
buffer[c] += (cms->buffer2[c] / 2);
|
||||
|
||||
cms->pos2 = 0;
|
||||
}
|
||||
|
||||
void
|
||||
cms_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
cms_t *cms = (cms_t *) priv;
|
||||
int voice;
|
||||
int chip = (addr & 2) >> 1;
|
||||
|
||||
switch (addr & 0xf) {
|
||||
case 0x1: /* SAA #1 Register Select Port */
|
||||
SAASNDWriteAddress(cms->saasound, val & 31);
|
||||
cms->addrs[0] = val & 31;
|
||||
break;
|
||||
case 0x3: /* SAA #2 Register Select Port */
|
||||
SAASNDWriteAddress(cms->saasound2, val & 31);
|
||||
cms->addrs[1] = val & 31;
|
||||
break;
|
||||
|
||||
case 0x0: /* SAA #1 Data Port */
|
||||
cms_update(cms);
|
||||
SAASNDWriteData(cms->saasound, val);
|
||||
break;
|
||||
case 0x2: /* SAA #2 Data Port */
|
||||
cms_update(cms);
|
||||
SAASNDWriteData(cms->saasound2, val);
|
||||
cms->regs[chip][cms->addrs[chip] & 31] = val;
|
||||
switch (cms->addrs[chip] & 31) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
case 0x02: /*Volume*/
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
voice = cms->addrs[chip] & 7;
|
||||
cms->vol[chip][voice][0] = val & 0xf;
|
||||
cms->vol[chip][voice][1] = val >> 4;
|
||||
break;
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0A: /*Frequency*/
|
||||
case 0x0B:
|
||||
case 0x0C:
|
||||
case 0x0D:
|
||||
voice = cms->addrs[chip] & 7;
|
||||
cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val;
|
||||
cms->freq[chip][voice] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255));
|
||||
break;
|
||||
case 0x10:
|
||||
case 0x11:
|
||||
case 0x12: /*Octave*/
|
||||
voice = (cms->addrs[chip] & 3) << 1;
|
||||
cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8);
|
||||
cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4);
|
||||
cms->freq[chip][voice] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255));
|
||||
cms->freq[chip][voice + 1] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255));
|
||||
break;
|
||||
case 0x16: /*Noise*/
|
||||
cms->noisetype[chip][0] = val & 3;
|
||||
cms->noisetype[chip][1] = (val >> 4) & 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6: /* GameBlaster Write Port */
|
||||
@@ -91,9 +163,9 @@ cms_read(uint16_t addr, void *priv)
|
||||
|
||||
switch (addr & 0xf) {
|
||||
case 0x1: /* SAA #1 Register Select Port */
|
||||
return SAASNDReadAddress(cms->saasound);
|
||||
return cms->addrs[0];
|
||||
case 0x3: /* SAA #2 Register Select Port */
|
||||
return SAASNDReadAddress(cms->saasound2);
|
||||
return cms->addrs[1];
|
||||
case 0x4: /* GameBlaster Read port (Always returns 0x7F) */
|
||||
return 0x7f;
|
||||
case 0xa: /* GameBlaster Read Port */
|
||||
@@ -113,12 +185,7 @@ cms_init(UNUSED(const device_t *info))
|
||||
|
||||
uint16_t addr = device_get_config_hex16("base");
|
||||
io_sethandler(addr, 0x0010, cms_read, NULL, NULL, cms_write, NULL, NULL, cms);
|
||||
cms->saasound = newSAASND();
|
||||
SAASNDSetSoundParameters(cms->saasound, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO);
|
||||
cms->saasound2 = newSAASND();
|
||||
SAASNDSetSoundParameters(cms->saasound2, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO);
|
||||
wavetable_add_handler(cms_get_buffer, cms);
|
||||
wavetable_add_handler(cms_get_buffer_2, cms);
|
||||
sound_add_handler(cms_get_buffer, cms);
|
||||
return cms;
|
||||
}
|
||||
|
||||
@@ -127,9 +194,6 @@ cms_close(void *priv)
|
||||
{
|
||||
cms_t *cms = (cms_t *) priv;
|
||||
|
||||
deleteSAASND(cms->saasound);
|
||||
deleteSAASND(cms->saasound2);
|
||||
|
||||
free(cms);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <86box/sound.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/timer.h>
|
||||
#include "saasound/SAASound.h"
|
||||
#include <86box/snd_sb.h>
|
||||
#include <86box/plat_unused.h>
|
||||
|
||||
@@ -146,42 +145,6 @@ sb_log(const char *fmt, ...)
|
||||
# define sb_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
void
|
||||
sb_cms_get_buffer(int32_t *buffer, int len, void *priv)
|
||||
{
|
||||
sb_t *sb = (sb_t *) priv;
|
||||
|
||||
cms_update(&sb->cms);
|
||||
|
||||
for (int c = 0; c < len * 2; c++) {
|
||||
if (sb->mixer_enabled) {
|
||||
buffer[c] += sb->cms.buffer[c] * sb->mixer_sb2.fm;
|
||||
}
|
||||
else
|
||||
buffer[c] += sb->cms.buffer[c];
|
||||
}
|
||||
|
||||
sb->cms.pos = 0;
|
||||
}
|
||||
|
||||
void
|
||||
sb_cms_get_buffer_2(int32_t *buffer, int len, void *priv)
|
||||
{
|
||||
sb_t *sb = (sb_t *) priv;
|
||||
|
||||
cms_update(&sb->cms);
|
||||
|
||||
for (int c = 0; c < len * 2; c++) {
|
||||
if (sb->mixer_enabled) {
|
||||
buffer[c] += sb->cms.buffer2[c] * sb->mixer_sb2.fm;
|
||||
}
|
||||
else
|
||||
buffer[c] += sb->cms.buffer2[c];
|
||||
}
|
||||
|
||||
sb->cms.pos2 = 0;
|
||||
}
|
||||
|
||||
/* SB 1, 1.5, MCV, and 2 do not have a mixer, so signal is hardwired. */
|
||||
static void
|
||||
sb_get_buffer_sb2(int32_t *buffer, int len, void *priv)
|
||||
@@ -192,10 +155,23 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *priv)
|
||||
|
||||
sb_dsp_update(&sb->dsp);
|
||||
|
||||
if (sb->cms_enabled)
|
||||
cms_update(&sb->cms);
|
||||
|
||||
for (int c = 0; c < len * 2; c += 2) {
|
||||
double out_l = 0.0;
|
||||
double out_r = 0.0;
|
||||
|
||||
if (sb->cms_enabled) {
|
||||
out_l += sb->cms.buffer[c];
|
||||
out_r += sb->cms.buffer[c + 1];
|
||||
}
|
||||
|
||||
if (sb->cms_enabled && sb->mixer_enabled) {
|
||||
out_l *= mixer->fm;
|
||||
out_r *= mixer->fm;
|
||||
}
|
||||
|
||||
/* TODO: Recording: I assume it has direct mic and line in like SB2.
|
||||
It is unclear from the docs if it has a filter, but it probably does. */
|
||||
/* TODO: Recording: Mic and line In with AGC. */
|
||||
@@ -216,6 +192,9 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *priv)
|
||||
}
|
||||
|
||||
sb->dsp.pos = 0;
|
||||
|
||||
if (sb->cms_enabled)
|
||||
sb->cms.pos = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2911,13 +2890,6 @@ sb_init(UNUSED(const device_t *info))
|
||||
cms_read, NULL, NULL,
|
||||
cms_write, NULL, NULL,
|
||||
&sb->cms);
|
||||
|
||||
sb->cms.saasound = newSAASND();
|
||||
SAASNDSetSoundParameters(sb->cms.saasound, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO);
|
||||
sb->cms.saasound2 = newSAASND();
|
||||
SAASNDSetSoundParameters(sb->cms.saasound2, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO);
|
||||
wavetable_add_handler(sb_cms_get_buffer, sb);
|
||||
wavetable_add_handler(sb_cms_get_buffer_2, sb);
|
||||
}
|
||||
|
||||
if (mixer_addr > 0x000) {
|
||||
@@ -4072,11 +4044,6 @@ sb_close(void *priv)
|
||||
sb_t *sb = (sb_t *) priv;
|
||||
sb_dsp_close(&sb->dsp);
|
||||
|
||||
if (sb->cms_enabled) {
|
||||
deleteSAASND(sb->cms.saasound);
|
||||
deleteSAASND(sb->cms.saasound2);
|
||||
}
|
||||
|
||||
free(sb);
|
||||
}
|
||||
|
||||
|
||||
@@ -2510,6 +2510,12 @@ mach_in(uint16_t addr, void *priv)
|
||||
case 0xa9:
|
||||
temp = svga->vc & 0xff;
|
||||
break;
|
||||
case 0xaa:
|
||||
if (ATI_GRAPHICS_ULTRA)
|
||||
temp = 0x06;
|
||||
else
|
||||
temp = 0x00;
|
||||
break;
|
||||
case 0xb0:
|
||||
temp = mach->regs[0xb0] | 0x80;
|
||||
temp &= ~0x18;
|
||||
@@ -2699,14 +2705,12 @@ mach_set_resolution(mach_t *mach, svga_t *svga)
|
||||
dev->vdisp += 2;
|
||||
|
||||
dev->v_total = dev->v_total_reg + 1;
|
||||
if (dev->interlace)
|
||||
dev->v_total >>= 1;
|
||||
|
||||
dev->v_syncstart = dev->v_sync_start + 1;
|
||||
if (dev->interlace)
|
||||
dev->v_syncstart >>= 1;
|
||||
|
||||
if (ATI_8514A_ULTRA) {
|
||||
mach_log("VSYNCSTART=%d, VTOTAL=%d, interlace=%02x, vdisp=%d.\n", dev->v_syncstart, dev->v_total, dev->interlace, dev->vdisp);
|
||||
|
||||
if (!ATI_MACH32) {
|
||||
if ((mach->accel.clock_sel & 0x01) &&
|
||||
!(dev->accel.advfunc_cntl & 0x01))
|
||||
ret = 2;
|
||||
@@ -3233,7 +3237,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u
|
||||
if (len == 1) {
|
||||
if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/
|
||||
if (!(mach->shadow_cntl & 0x20)) {
|
||||
WRITE8(port, dev->v_disp, val);
|
||||
WRITE8(port, dev->v_disp, val >> 8);
|
||||
dev->v_disp &= 0x1fff;
|
||||
}
|
||||
}
|
||||
@@ -3267,7 +3271,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u
|
||||
if (len == 1) {
|
||||
if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/
|
||||
if (!(mach->shadow_cntl & 0x10)) {
|
||||
WRITE8(port, dev->v_sync_start, val);
|
||||
WRITE8(port, dev->v_sync_start, val >> 8);
|
||||
dev->v_sync_start &= 0x1fff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4273,7 +4273,10 @@ gd54xx_init(const device_t *info)
|
||||
break;
|
||||
|
||||
case CIRRUS_ID_CLGD5428:
|
||||
if (info->local & 0x100)
|
||||
if (info->local & 0x200) {
|
||||
romfn = NULL;
|
||||
gd54xx->has_bios = 0;
|
||||
} else if (info->local & 0x100)
|
||||
if (gd54xx->vlb)
|
||||
romfn = BIOS_GD5428_DIAMOND_B1_VLB_PATH;
|
||||
else {
|
||||
@@ -4750,26 +4753,6 @@ static const device_config_t gd5426_config[] = {
|
||||
{ .name = "", .description = "", .type = CONFIG_END }
|
||||
};
|
||||
|
||||
static const device_config_t gd5428_onboard_config[] = {
|
||||
{
|
||||
.name = "memory",
|
||||
.description = "Memory size",
|
||||
.type = CONFIG_SELECTION,
|
||||
.default_string = NULL,
|
||||
.default_int = 2048,
|
||||
.file_filter = NULL,
|
||||
.spinner = { 0 },
|
||||
.selection = {
|
||||
{ .description = "512 KB", .value = 512 },
|
||||
{ .description = "1 MB", .value = 1024 },
|
||||
{ .description = "2 MB", .value = 2048 },
|
||||
{ .description = "" }
|
||||
},
|
||||
.bios = { { 0 } }
|
||||
},
|
||||
{ .name = "", .description = "", .type = CONFIG_END }
|
||||
};
|
||||
|
||||
static const device_config_t gd5429_config[] = {
|
||||
{
|
||||
.name = "memory",
|
||||
@@ -5176,7 +5159,7 @@ const device_t gd5428_onboard_device = {
|
||||
.available = gd5428_isa_available,
|
||||
.speed_changed = gd54xx_speed_changed,
|
||||
.force_redraw = gd54xx_force_redraw,
|
||||
.config = gd5428_onboard_config
|
||||
.config = gd5426_config
|
||||
};
|
||||
|
||||
const device_t gd5428_vlb_onboard_device = {
|
||||
@@ -5190,7 +5173,21 @@ const device_t gd5428_vlb_onboard_device = {
|
||||
.available = NULL,
|
||||
.speed_changed = gd54xx_speed_changed,
|
||||
.force_redraw = gd54xx_force_redraw,
|
||||
.config = gd5428_onboard_config
|
||||
.config = gd5426_config
|
||||
};
|
||||
|
||||
const device_t gd5428_onboard_vlb_device = {
|
||||
.name = "Cirrus Logic GD5428 (VLB) (On-Board) (Dell)",
|
||||
.internal_name = "cl_gd5428_onboard_vlb",
|
||||
.flags = DEVICE_VLB,
|
||||
.local = CIRRUS_ID_CLGD5428 | 0x200,
|
||||
.init = gd54xx_init,
|
||||
.close = gd54xx_close,
|
||||
.reset = gd54xx_reset,
|
||||
.available = NULL,
|
||||
.speed_changed = gd54xx_speed_changed,
|
||||
.force_redraw = gd54xx_force_redraw,
|
||||
.config = gd542x_config
|
||||
};
|
||||
|
||||
const device_t gd5429_isa_device = {
|
||||
|
||||
@@ -8042,7 +8042,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi
|
||||
|
||||
s3->accel.sy = s3->accel.maj_axis_pcnt;
|
||||
if ((s3->bpp == 0) && s3->color_16bit) {
|
||||
s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00);
|
||||
s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00) && rd_mask;
|
||||
if (s3->accel.rd_mask_16bit_check) {
|
||||
if ((s3->accel.cur_x_overflow & 0xc00) == 0xc00)
|
||||
s3->accel.start = 1;
|
||||
@@ -8353,7 +8353,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi
|
||||
s3->accel.dest = dstbase + s3->accel.cy * s3->width;
|
||||
|
||||
if ((s3->bpp == 0) && s3->color_16bit) {
|
||||
s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00);
|
||||
s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00) && rd_mask;
|
||||
if (s3->accel.rd_mask_16bit_check) {
|
||||
if (s3->accel.cmd == 0x41b3) {
|
||||
if (frgd_mix == 0) {
|
||||
@@ -8478,9 +8478,10 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi
|
||||
if ((s3_cpu_src(s3)) && !(s3->accel.cmd & 0x200)) {
|
||||
s3_log("FIXME: S3 911/924 15/16bpp documentation needed.\n");
|
||||
} else {
|
||||
if (!cpu_input && (s3->accel.cur_x & 0x400))
|
||||
if (!cpu_input && (s3->accel.cur_x & 0x400)) {
|
||||
s3_log("No Input.\n");
|
||||
break;
|
||||
else if (cpu_input && (s3->accel.cmd == 0x53b3) && (s3->accel.cur_x & 0x400))
|
||||
} else if (cpu_input && (s3->accel.cmd == 0x53b3) && (s3->accel.cur_x & 0x400))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -8756,7 +8757,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi
|
||||
s3->accel.cy = s3->accel.cur_y & 0xfff;
|
||||
|
||||
if ((s3->bpp == 0) && s3->color_16bit) {
|
||||
s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00);
|
||||
s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00) && rd_mask;
|
||||
if (s3->accel.rd_mask_16bit_check) {
|
||||
if (!(clip_r & 0x400))
|
||||
s3->accel.start = 1;
|
||||
@@ -8805,7 +8806,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi
|
||||
s3_log("CMDFULL=%04x, FRGDSEL=%x, BKGDSEL=%x, FRGDMIX=%02x, BKGDMIX=%02x, MASKCHECK=%x, RDMASK=%04x, MINUS=%d, WRTMASK=%04X, MIX=%04x, CX=%d, CY=%d, DX=%d, DY=%d, SX=%d, SY=%d, PIXCNTL=%02x, 16BITCOLOR=%x, RDCHECK=%x, CLIPL=%d, CLIPR=%d, OVERFLOW=%d, pitch=%d.\n", s3->accel.cmd, frgd_mix, bkgd_mix, s3->accel.frgd_mix & 0x0f, s3->accel.bkgd_mix & 0x0f, s3->accel.rd_mask_16bit_check, rd_mask, s3->accel.minus, wrt_mask, mix_dat & 0xffff, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy, s3->accel.sx, s3->accel.sy, s3->accel.multifunc[0x0a] & 0xc4, s3->accel.color_16bit_check, s3->accel.rd_mask_16bit_check, clip_l, clip_r, (s3->accel.destx_overflow & 0xc00) == 0xc00, s3->width);
|
||||
|
||||
if (!cpu_input && (frgd_mix == 3) && !vram_mask && !(s3->accel.multifunc[0xe] & 0x100) && ((s3->accel.cmd & 0xa0) == 0xa0) && ((s3->accel.frgd_mix & 0xf) == 7) && ((s3->accel.bkgd_mix & 0xf) == 7)) {
|
||||
pclog("Special BitBLT.\n");
|
||||
s3_log("Special BitBLT.\n");
|
||||
while (1) {
|
||||
if ((s3->accel.dx >= clip_l) && (s3->accel.dx <= clip_r) && (s3->accel.dy >= clip_t) && (s3->accel.dy <= clip_b)) {
|
||||
READ(s3->accel.src + s3->accel.cx - s3->accel.minus, src_dat);
|
||||
|
||||
@@ -125,6 +125,7 @@ typedef struct tgui_t {
|
||||
uint8_t rop;
|
||||
uint32_t flags;
|
||||
uint8_t pattern[0x80];
|
||||
uint8_t pattern_32bpp[0x100];
|
||||
int command;
|
||||
int offset;
|
||||
uint16_t ger22;
|
||||
@@ -142,6 +143,7 @@ typedef struct tgui_t {
|
||||
uint32_t pattern_8[8 * 8];
|
||||
uint32_t pattern_16[8 * 8];
|
||||
uint32_t pattern_32[8 * 8];
|
||||
int pattern_32_idx;
|
||||
} accel;
|
||||
|
||||
uint8_t copy_latch[16]; /*TGUI9400CXi only*/
|
||||
@@ -756,7 +758,7 @@ tgui_recalctimings(svga_t *svga)
|
||||
if (svga->vdisp == 1020)
|
||||
svga->vdisp += 2;
|
||||
|
||||
if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40))
|
||||
if (tgui->oldctrl2 & 0x10)
|
||||
svga->ma_latch <<= 1;
|
||||
|
||||
svga->lowres = !(svga->crtc[0x2a] & 0x40);
|
||||
@@ -2280,6 +2282,8 @@ tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui)
|
||||
if (count == -1)
|
||||
tgui->accel.x = tgui->accel.y = 0;
|
||||
|
||||
tgui->accel.pattern_32_idx = 0;
|
||||
|
||||
if (tgui->accel.flags & TGUI_SOLIDFILL) {
|
||||
for (y = 0; y < 8; y++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
@@ -2298,22 +2302,21 @@ tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui)
|
||||
if (tgui->accel.bpp == 0) {
|
||||
for (y = 0; y < 8; y++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
tgui->accel.pattern_8[(y * 8) + (7 - x)] = tgui->accel.pattern[x + y * 8];
|
||||
tgui->accel.pattern_8[(y * 8) + x] = tgui->accel.pattern[x + y * 8];
|
||||
}
|
||||
}
|
||||
pattern_data = tgui->accel.pattern_8;
|
||||
} else if (tgui->accel.bpp == 1) {
|
||||
for (y = 0; y < 8; y++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
tgui->accel.pattern_16[(y * 8) + (7 - x)] = tgui->accel.pattern[x * 2 + y * 16] | (tgui->accel.pattern[x * 2 + y * 16 + 1] << 8);
|
||||
tgui->accel.pattern_16[(y * 8) + x] = tgui->accel.pattern[x * 2 + y * 16] | (tgui->accel.pattern[x * 2 + y * 16 + 1] << 8);
|
||||
}
|
||||
}
|
||||
pattern_data = tgui->accel.pattern_16;
|
||||
} else {
|
||||
for (y = 0; y < 4; y++) {
|
||||
for (y = 0; y < 8; y++) {
|
||||
for (x = 0; x < 8; x++) {
|
||||
tgui->accel.pattern_32[(y * 8) + (7 - x)] = tgui->accel.pattern[x * 4 + y * 32] | (tgui->accel.pattern[x * 4 + y * 32 + 1] << 8) | (tgui->accel.pattern[x * 4 + y * 32 + 2] << 16) | (tgui->accel.pattern[x * 4 + y * 32 + 3] << 24);
|
||||
tgui->accel.pattern_32[((y + 4) * 8) + (7 - x)] = tgui->accel.pattern[x * 4 + y * 32] | (tgui->accel.pattern[x * 4 + y * 32 + 1] << 8) | (tgui->accel.pattern[x * 4 + y * 32 + 2] << 16) | (tgui->accel.pattern[x * 4 + y * 32 + 3] << 24);
|
||||
tgui->accel.pattern_32[(y * 8) + x] = tgui->accel.pattern_32bpp[x * 4 + y * 32] | (tgui->accel.pattern_32bpp[x * 4 + y * 32 + 1] << 8) | (tgui->accel.pattern_32bpp[x * 4 + y * 32 + 2] << 16) | (tgui->accel.pattern_32bpp[x * 4 + y * 32 + 3] << 24);
|
||||
}
|
||||
}
|
||||
pattern_data = tgui->accel.pattern_32;
|
||||
@@ -2396,6 +2399,7 @@ tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui)
|
||||
count -= 3;
|
||||
}
|
||||
|
||||
|
||||
READ(tgui->accel.dst, dst_dat);
|
||||
|
||||
pat_dat = pattern_data[((tgui->accel.pat_y & 7) * 8) + (tgui->accel.pat_x & 7)];
|
||||
@@ -3192,6 +3196,8 @@ tgui_accel_out(uint16_t addr, uint8_t val, void *priv)
|
||||
case 0x21fe:
|
||||
case 0x21ff:
|
||||
tgui->accel.pattern[addr & 0x7f] = val;
|
||||
tgui->accel.pattern_32bpp[tgui->accel.pattern_32_idx] = val;
|
||||
tgui->accel.pattern_32_idx = (tgui->accel.pattern_32_idx + 1) & 0xff;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user