From 30d7c8f51ca42b4a598b4b1b25a9712e9e531fef Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 17 May 2025 22:56:15 +0200 Subject: [PATCH 01/42] The recently introduced x86_64 variant of host_x86_MOV32_REG_ABS() was allocating the wrong number of bytes. --- src/codegen_new/codegen_backend_x86-64_ops.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/codegen_new/codegen_backend_x86-64_ops.c b/src/codegen_new/codegen_backend_x86-64_ops.c index ed218d7c4..1569e693c 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.c +++ b/src/codegen_new/codegen_backend_x86-64_ops.c @@ -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); From b3147ee4732112a62723d6b74a1d6bd44b50476f Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 02:20:18 +0200 Subject: [PATCH 02/42] LOCK instruction: ensure it is always illegal on opcodes 90h and ECh. --- src/codegen/codegen_x86-64.c | 13 ++++++++++++- src/codegen/codegen_x86.c | 13 ++++++++++++- src/codegen_new/codegen.c | 13 +++++++++++-- src/cpu/x86_ops_misc.h | 2 +- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/codegen/codegen_x86-64.c b/src/codegen/codegen_x86-64.c index c424cf8c5..fb775a2d0 100644 --- a/src/codegen/codegen_x86-64.c +++ b/src/codegen/codegen_x86-64.c @@ -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)*/ diff --git a/src/codegen/codegen_x86.c b/src/codegen/codegen_x86.c index bf34c2de8..e0b9b633a 100644 --- a/src/codegen/codegen_x86.c +++ b/src/codegen/codegen_x86.c @@ -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; diff --git a/src/codegen_new/codegen.c b/src/codegen_new/codegen.c index 44dd408ab..26a74016a 100644 --- a/src/codegen_new/codegen.c +++ b/src/codegen_new/codegen.c @@ -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; diff --git a/src/cpu/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index ffc79f0e8..5ae28abc4 100644 --- a/src/cpu/x86_ops_misc.h +++ b/src/cpu/x86_ops_misc.h @@ -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(); From 20b2b1c90177b5a60bcd7ad7f8b3e70342aa35d3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 02:40:49 +0200 Subject: [PATCH 03/42] RZ-1000: Do not initialize the second IDE channel if the controller is single-channel. --- src/disk/hdc_ide_rz1000.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/disk/hdc_ide_rz1000.c b/src/disk/hdc_ide_rz1000.c index 2c1a09e8e..e2c7179ad 100644 --- a/src/disk/hdc_ide_rz1000.c +++ b/src/disk/hdc_ide_rz1000.c @@ -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); From d6231de1bcff03db0cb808d06da6099927a9d4b9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 05:59:13 +0200 Subject: [PATCH 04/42] Added the Dell 466/NP, closes #3585. --- src/include/86box/machine.h | 2 ++ src/include/86box/video.h | 1 + src/machine/m_at_386dx_486.c | 37 ++++++++++++++++++++++++++++--- src/machine/machine_table.c | 40 +++++++++++++++++++++++++++++++++ src/video/vid_cl54xx.c | 43 +++++++++++++++++------------------- 5 files changed, 97 insertions(+), 26 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index febce3fa1..c76761b3c 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -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 *); diff --git a/src/include/86box/video.h b/src/include/86box/video.h index bbcc94fe7..085dd5f80 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -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; diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index c2cf82352..e03b6d65d 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -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) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 9b53257bf..ee3485373 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6934,6 +6934,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. */ { diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index dbb9d5993..13f96501c 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -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 = { From 8b4adebfd2bc22bc5f795c98ef288fd55b8ddae2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 06:17:24 +0200 Subject: [PATCH 05/42] AOpen AP5S: Add two more BIOS'es, including a 4.50PG, fulfills #643. --- src/machine/m_at_386dx_486.c | 3 -- src/machine/m_at_socket7_3v.c | 55 +++++++++++++++++++++++++++++++---- src/machine/machine_table.c | 3 +- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index e03b6d65d..46b93a37f 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -1727,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); diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 39dc2d735..b587a8551 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -706,17 +706,62 @@ 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); + if (!strcmp(fn, "roms/machines/sb486pv/amiboot.rom")) + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); + else + ret = bios_load_linear_inverted(fn, 0x000e0000, 131072, 0); + device_context_restore(); + machine_at_common_init_ex(model, 2); pci_init(PCI_CONFIG_TYPE_1 | FLAG_TRC_CONTROLS_CPURST); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index ee3485373..17fde9581 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -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 }, @@ -11820,7 +11821,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, From 8ff85bf36b638c6f804956bef0283cd5b5d1473f Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Sun, 18 May 2025 11:25:17 +0700 Subject: [PATCH 06/42] Moved "device" to .vid_device on SBC-490 --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 17fde9581..45986a50a 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -7857,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 }, From 3f93bde031d29fbb0e43990212d478f8776e7281 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 06:44:37 +0200 Subject: [PATCH 07/42] AOpen AP5S: Fix BIOS loading. --- src/machine/m_at_socket7_3v.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index b587a8551..5b5724e37 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -756,10 +756,7 @@ machine_at_ap5s_init(const machine_t *model) device_context(model->device); fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); - if (!strcmp(fn, "roms/machines/sb486pv/amiboot.rom")) - ret = bios_load_linear(fn, 0x000e0000, 131072, 0); - else - ret = bios_load_linear_inverted(fn, 0x000e0000, 131072, 0); + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); device_context_restore(); machine_at_common_init_ex(model, 2); From 7b9b2bc10df309d3b818e4e25e6b5022785dbc5c Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 08:14:46 +0200 Subject: [PATCH 08/42] Some FDC, SM(S)C FDC37C66x, and VLSI VL82C480 changes. --- src/chipset/vl82c480.c | 20 +++++++++++++++----- src/floppy/fdc.c | 35 +++++++++++++++++++++++++++++----- src/include/86box/fdc.h | 42 +++++++++++++++++++++-------------------- src/sio/sio_fdc37c6xx.c | 5 ++++- 4 files changed, 71 insertions(+), 31 deletions(-) diff --git a/src/chipset/vl82c480.c b/src/chipset/vl82c480.c index 6354ac15a..acb3568af 100644 --- a/src/chipset/vl82c480.c +++ b/src/chipset/vl82c480.c @@ -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 diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index e7166d1ba..b43daa32c 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -469,9 +469,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 +537,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 +772,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 +1398,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; @@ -2401,6 +2410,8 @@ fdc_init(const device_t *info) fdc_t *fdc = (fdc_t *) calloc(1, sizeof(fdc_t)); fdc->flags = info->local; + if (fdc->flags & FDC_FLAG_SMC661) + pclog("661!\n"); if (fdc->flags & FDC_FLAG_SEC) fdc->irq = FDC_SECONDARY_IRQ; @@ -2644,6 +2655,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", diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index ed62cb45f..53511daac 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -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; @@ -260,6 +261,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; diff --git a/src/sio/sio_fdc37c6xx.c b/src/sio/sio_fdc37c6xx.c index 3afd92e4c..aa66af883 100644 --- a/src/sio/sio_fdc37c6xx.c +++ b/src/sio/sio_fdc37c6xx.c @@ -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; From 196289d6e50c1f2f76fd220030117e61290775a3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 08:17:04 +0200 Subject: [PATCH 09/42] AT KBC fixes for the Dell. --- src/device/kbc_at.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index a8a8c51cc..58aab476c 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1088,12 +1088,24 @@ 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, 0x01); + } 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 From 76c3ad9868bf83c8f90a860e4a6ce15ca6053942 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 08:18:18 +0200 Subject: [PATCH 10/42] Removed an excess logging line. --- src/floppy/fdc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index b43daa32c..cf5ae41bf 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -2410,8 +2410,6 @@ fdc_init(const device_t *info) fdc_t *fdc = (fdc_t *) calloc(1, sizeof(fdc_t)); fdc->flags = info->local; - if (fdc->flags & FDC_FLAG_SMC661) - pclog("661!\n"); if (fdc->flags & FDC_FLAG_SEC) fdc->irq = FDC_SECONDARY_IRQ; From 5dc99cc137b1815b67069a29dc29d5453069ba2f Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 08:37:02 +0200 Subject: [PATCH 11/42] SiS 85c46x and 471 - implement AT bus speed configuration. --- src/chipset/sis_85c4xx.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index f715c5272..be5bd668e 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -15,6 +15,7 @@ * * Copyright 2019-2020 Miran Grca. */ +#include #include #include #include @@ -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 From 3b7515a4ff5b1b3ae611e19a50995f5e26b27ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Sun, 18 May 2025 09:11:13 +0200 Subject: [PATCH 12/42] Treat port 0x84, even if something is listening to it, as a delay port, fixes the Dell 466/NP on faster CPU's. --- src/io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/io.c b/src/io.c index 9554c971d..45dd4cb3d 100644 --- a/src/io.c +++ b/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 } From 643389e0fe0e1435d3581125a9c52adf9f9ffd3c Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 18 May 2025 13:44:04 +0600 Subject: [PATCH 13/42] Revert "SAASound filter fixes" This reverts commit 14ffb89f4d01fe01353e97edf7b874d9f6944477. --- src/sound/saasound/SAAImpl.cpp | 1 + src/sound/saasound/SAAImpl.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sound/saasound/SAAImpl.cpp b/src/sound/saasound/SAAImpl.cpp index cb5d8f739..f136eefc6 100644 --- a/src/sound/saasound/SAAImpl.cpp +++ b/src/sound/saasound/SAAImpl.cpp @@ -306,6 +306,7 @@ void scale_for_output(unsigned int left_input, unsigned int right_input, void CSAASoundInternal::GenerateMany(BYTE* pBuffer, unsigned long nSamples) { unsigned int left_mixed, right_mixed; + static double filterout_z1_left_mixed = 0, filterout_z1_right_mixed = 0; #if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) BYTE* pBufferStart = pBuffer; diff --git a/src/sound/saasound/SAAImpl.h b/src/sound/saasound/SAAImpl.h index 6cd3048fe..61fa79c58 100755 --- a/src/sound/saasound/SAAImpl.h +++ b/src/sound/saasound/SAAImpl.h @@ -36,8 +36,6 @@ private: 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 From 5fce54a7f0f36f886c836945c64e69a35d32c7a8 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 18 May 2025 13:44:22 +0600 Subject: [PATCH 14/42] Revert "CMS: Divide SAA samples by 2 so that the sum remains within the -32767 to 32768 range and avoids clipping." This reverts commit c63d900a9383b74fbd8a5fa7209a0b2a6364a913. --- src/sound/snd_cms.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/snd_cms.c b/src/sound/snd_cms.c index 9491e3076..c6591b1fc 100644 --- a/src/sound/snd_cms.c +++ b/src/sound/snd_cms.c @@ -34,7 +34,7 @@ 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; } @@ -47,7 +47,7 @@ cms_get_buffer_2(int32_t *buffer, int len, void *priv) cms_update(cms); for (int c = 0; c < len * 2; c++) - buffer[c] += (cms->buffer2[c] / 2); + buffer[c] += cms->buffer2[c]; cms->pos2 = 0; } From 9cfe5141d4595cf84b0afec21be56c592aba3ae7 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 18 May 2025 13:44:49 +0600 Subject: [PATCH 15/42] Revert "Port Sound Blaster 1.x/2.x SAA1099 emulation to SAASound" This reverts commit b644016d1e0a7a917637c2fadcf8d8056d09b4ab. --- src/sound/snd_sb.c | 65 ++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 49 deletions(-) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 4a17fe20b..e89946486 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -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); } From 5390f50e516aaa8ec4370db30cc528a1757bd4b3 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 18 May 2025 13:47:06 +0600 Subject: [PATCH 16/42] Revert "Switch to SAASound for CMS" This reverts commit fd618440618e3d6e426d60e59921fd8495531b09. --- src/include/86box/snd_cms.h | 23 +- src/sound/CMakeLists.txt | 3 - src/sound/saasound/CMakeLists.txt | 16 - src/sound/saasound/SAAAmp.cpp | 203 --------- src/sound/saasound/SAAAmp.h | 44 -- src/sound/saasound/SAAConfig.h | 41 -- src/sound/saasound/SAADevice.cpp | 392 ----------------- src/sound/saasound/SAADevice.h | 69 --- src/sound/saasound/SAAEnv.cpp | 380 ---------------- src/sound/saasound/SAAEnv.h | 54 --- src/sound/saasound/SAAFreq.cpp | 287 ------------ src/sound/saasound/SAAFreq.dat | 141 ------ src/sound/saasound/SAAFreq.h | 72 --- src/sound/saasound/SAAImpl.cpp | 489 --------------------- src/sound/saasound/SAAImpl.h | 75 ---- src/sound/saasound/SAANoise.cpp | 180 -------- src/sound/saasound/SAANoise.h | 54 --- src/sound/saasound/SAASndC.cpp | 100 ----- src/sound/saasound/SAASndC.h | 102 ----- src/sound/saasound/SAASound.cpp | 13 - src/sound/saasound/SAASound.h | 130 ------ src/sound/saasound/defns.h | 59 --- src/sound/saasound/resource.h | 15 - src/sound/saasound/saasound_cmake_config.h | 14 - src/sound/saasound/types.h | 34 -- src/sound/snd_cms.c | 140 ++++-- 26 files changed, 115 insertions(+), 3015 deletions(-) delete mode 100644 src/sound/saasound/CMakeLists.txt delete mode 100755 src/sound/saasound/SAAAmp.cpp delete mode 100755 src/sound/saasound/SAAAmp.h delete mode 100644 src/sound/saasound/SAAConfig.h delete mode 100644 src/sound/saasound/SAADevice.cpp delete mode 100644 src/sound/saasound/SAADevice.h delete mode 100755 src/sound/saasound/SAAEnv.cpp delete mode 100755 src/sound/saasound/SAAEnv.h delete mode 100755 src/sound/saasound/SAAFreq.cpp delete mode 100755 src/sound/saasound/SAAFreq.dat delete mode 100755 src/sound/saasound/SAAFreq.h delete mode 100644 src/sound/saasound/SAAImpl.cpp delete mode 100755 src/sound/saasound/SAAImpl.h delete mode 100755 src/sound/saasound/SAANoise.cpp delete mode 100755 src/sound/saasound/SAANoise.h delete mode 100755 src/sound/saasound/SAASndC.cpp delete mode 100644 src/sound/saasound/SAASndC.h delete mode 100755 src/sound/saasound/SAASound.cpp delete mode 100644 src/sound/saasound/SAASound.h delete mode 100644 src/sound/saasound/defns.h delete mode 100755 src/sound/saasound/resource.h delete mode 100644 src/sound/saasound/saasound_cmake_config.h delete mode 100755 src/sound/saasound/types.h diff --git a/src/include/86box/snd_cms.h b/src/include/86box/snd_cms.h index 8201fe32c..8eec22935 100644 --- a/src/include/86box/snd_cms.h +++ b/src/include/86box/snd_cms.h @@ -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); diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index d575717a0..0a04b0ff1 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -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() diff --git a/src/sound/saasound/CMakeLists.txt b/src/sound/saasound/CMakeLists.txt deleted file mode 100644 index 2db75493e..000000000 --- a/src/sound/saasound/CMakeLists.txt +++ /dev/null @@ -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) \ No newline at end of file diff --git a/src/sound/saasound/SAAAmp.cpp b/src/sound/saasound/SAAAmp.cpp deleted file mode 100755 index 8f2473fb1..000000000 --- a/src/sound/saasound/SAAAmp.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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; - } -} diff --git a/src/sound/saasound/SAAAmp.h b/src/sound/saasound/SAAAmp.h deleted file mode 100755 index 4a6761f21..000000000 --- a/src/sound/saasound/SAAAmp.h +++ /dev/null @@ -1,44 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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 diff --git a/src/sound/saasound/SAAConfig.h b/src/sound/saasound/SAAConfig.h deleted file mode 100644 index a655ec59f..000000000 --- a/src/sound/saasound/SAAConfig.h +++ /dev/null @@ -1,41 +0,0 @@ -// Part of SAASound copyright 2020 Dave Hooper -// -// 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 \ No newline at end of file diff --git a/src/sound/saasound/SAADevice.cpp b/src/sound/saasound/SAADevice.cpp deleted file mode 100644 index 718b05a95..000000000 --- a/src/sound/saasound/SAADevice.cpp +++ /dev/null @@ -1,392 +0,0 @@ -// Part of SAASound copyright 2020 Dave Hooper -// -// 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; -} \ No newline at end of file diff --git a/src/sound/saasound/SAADevice.h b/src/sound/saasound/SAADevice.h deleted file mode 100644 index 7b697821f..000000000 --- a/src/sound/saasound/SAADevice.h +++ /dev/null @@ -1,69 +0,0 @@ -// Part of SAASound copyright 2020 Dave Hooper -// -// 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 \ No newline at end of file diff --git a/src/sound/saasound/SAAEnv.cpp b/src/sound/saasound/SAAEnv.cpp deleted file mode 100755 index 049f51f96..000000000 --- a/src/sound/saasound/SAAEnv.cpp +++ /dev/null @@ -1,380 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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(); -} diff --git a/src/sound/saasound/SAAEnv.h b/src/sound/saasound/SAAEnv.h deleted file mode 100755 index 131659c06..000000000 --- a/src/sound/saasound/SAAEnv.h +++ /dev/null @@ -1,54 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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 diff --git a/src/sound/saasound/SAAFreq.cpp b/src/sound/saasound/SAAFreq.cpp deleted file mode 100755 index 61a04f6ad..000000000 --- a/src/sound/saasound/SAAFreq.cpp +++ /dev/null @@ -1,287 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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<= (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(); - } -} diff --git a/src/sound/saasound/SAAFreq.dat b/src/sound/saasound/SAAFreq.dat deleted file mode 100755 index 04fb9081a..000000000 --- a/src/sound/saasound/SAAFreq.dat +++ /dev/null @@ -1,141 +0,0 @@ -/* -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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 diff --git a/src/sound/saasound/SAAFreq.h b/src/sound/saasound/SAAFreq.h deleted file mode 100755 index 478754621..000000000 --- a/src/sound/saasound/SAAFreq.h +++ /dev/null @@ -1,72 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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 diff --git a/src/sound/saasound/SAAImpl.cpp b/src/sound/saasound/SAAImpl.cpp deleted file mode 100644 index f136eefc6..000000000 --- a/src/sound/saasound/SAAImpl.cpp +++ /dev/null @@ -1,489 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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 << ""; - } - else if (nReg==25) - { - m_dbgfile << ""; - } - 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; - static double filterout_z1_left_mixed = 0, filterout_z1_right_mixed = 0; - -#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 - -*/ - diff --git a/src/sound/saasound/SAAImpl.h b/src/sound/saasound/SAAImpl.h deleted file mode 100755 index 61fa79c58..000000000 --- a/src/sound/saasound/SAAImpl.h +++ /dev/null @@ -1,75 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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 -#include -#include - -#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; -#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 diff --git a/src/sound/saasound/SAANoise.cpp b/src/sound/saasound/SAANoise.cpp deleted file mode 100755 index 1cf3458dd..000000000 --- a/src/sound/saasound/SAANoise.cpp +++ /dev/null @@ -1,180 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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<> 1) ^ 0x20400; - } - else - { - m_nRand >>= 1; - } -} diff --git a/src/sound/saasound/SAANoise.h b/src/sound/saasound/SAANoise.h deleted file mode 100755 index 61a65dee8..000000000 --- a/src/sound/saasound/SAANoise.h +++ /dev/null @@ -1,54 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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 diff --git a/src/sound/saasound/SAASndC.cpp b/src/sound/saasound/SAASndC.cpp deleted file mode 100755 index 9af0d76e7..000000000 --- a/src/sound/saasound/SAASndC.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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(); -} diff --git a/src/sound/saasound/SAASndC.h b/src/sound/saasound/SAASndC.h deleted file mode 100644 index c6fd65765..000000000 --- a/src/sound/saasound/SAASndC.h +++ /dev/null @@ -1,102 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// ********** -// * 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 diff --git a/src/sound/saasound/SAASound.cpp b/src/sound/saasound/SAASound.cpp deleted file mode 100755 index c5e33d862..000000000 --- a/src/sound/saasound/SAASound.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAASound.cpp - dummy function -// -////////////////////////////////////////////////////////////////////// - -#include - -// Provide something so the compiler doesn't optimise us out of existance -int SomeFunction () -{ - return 42; -} diff --git a/src/sound/saasound/SAASound.h b/src/sound/saasound/SAASound.h deleted file mode 100644 index a5e9265ac..000000000 --- a/src/sound/saasound/SAASound.h +++ /dev/null @@ -1,130 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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 diff --git a/src/sound/saasound/defns.h b/src/sound/saasound/defns.h deleted file mode 100644 index e81d1c819..000000000 --- a/src/sound/saasound/defns.h +++ /dev/null @@ -1,59 +0,0 @@ -// Part of SAASound copyright 2020 Dave Hooper -// -// 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 diff --git a/src/sound/saasound/resource.h b/src/sound/saasound/resource.h deleted file mode 100755 index 0b893bf3a..000000000 --- a/src/sound/saasound/resource.h +++ /dev/null @@ -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 diff --git a/src/sound/saasound/saasound_cmake_config.h b/src/sound/saasound/saasound_cmake_config.h deleted file mode 100644 index da914a71b..000000000 --- a/src/sound/saasound/saasound_cmake_config.h +++ /dev/null @@ -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" diff --git a/src/sound/saasound/types.h b/src/sound/saasound/types.h deleted file mode 100755 index 4eb62f485..000000000 --- a/src/sound/saasound/types.h +++ /dev/null @@ -1,34 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// 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 diff --git a/src/sound/snd_cms.c b/src/sound/snd_cms.c index c6591b1fc..66dff80f3 100644 --- a/src/sound/snd_cms.c +++ b/src/sound/snd_cms.c @@ -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; } } @@ -39,39 +87,63 @@ cms_get_buffer(int32_t *buffer, int len, void *priv) 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]; - - 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); } From cdae57e7b4a28cd70f86a13be0d48724127e3193 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Sun, 18 May 2025 21:05:23 +0300 Subject: [PATCH 17/42] Preliminary attempt at implementing the Dell OptiPlex GN+ --- src/include/86box/machine.h | 1 + src/machine/m_at_socket7.c | 34 ++++++++++++++++++++++++++++ src/machine/machine_table.c | 44 +++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index c76761b3c..5153c4627 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -751,6 +751,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 */ diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 319856d41..17c89e39d 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -969,6 +969,40 @@ 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/Gn_a11.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(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Trio64V2/GX, temporarily Trio64V2/DX is given */ + 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); /* 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)); + + device_add(&i430tx_device); + device_add(&piix4_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87307_15c_device); + 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) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 45986a50a..f28079888 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -13103,6 +13103,50 @@ 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 likely an AMIKey-2 clone. */ + { + .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, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_VIDEO, /* Video: S3 86C785 (Trio64V2/GX), ethernet: 3C905 */ + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &s3_trio64v2_dx_onboard_pci_device, /* Stop-gap measure until the Trio64V2/GX is emulated, as both use the same VBIOS */ + .snd_device = NULL, + .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", From 9441b6f2cf04238f51c39d3e875ac76555ae0467 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 20:42:28 +0200 Subject: [PATCH 18/42] PC87309: Make the Super I/O chip relocatable. --- src/sio/sio_pc87309.c | 45 ++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index da53802c1..2219ede17 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -41,15 +41,19 @@ typedef struct pc87309_t { uint8_t regs[48]; uint8_t ld_regs[256][208]; uint8_t pm[8]; + uint8_t baddr; uint16_t pm_base; int cur_reg; 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); +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 pc87309_write(uint16_t port, uint8_t val, void *priv); +static uint8_t pc87309_read(uint16_t port, void *priv); static void pc87309_pm_write(uint16_t port, uint8_t val, void *priv) @@ -104,6 +108,26 @@ pc87309_pm_init(pc87309_t *dev, uint16_t addr) pc87309_pm_read, NULL, NULL, pc87309_pm_write, NULL, NULL, dev); } +static void +superio_handler(pc87309_t *dev) +{ + io_removehandler(0x15c, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + io_removehandler(0x02e, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + + switch (dev->baddr) { + case 2: + io_sethandler(0x15c, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + break; + case 3: + io_sethandler(0x02e, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + break; + } +} + static void fdc_handler(pc87309_t *dev) { @@ -197,6 +221,7 @@ pc87309_write(uint16_t port, uint8_t val, void *priv) break; case 0x22: dev->regs[dev->cur_reg] = val & 0x7f; + superio_handler(dev); break; default: if (dev->cur_reg >= 0x30) { @@ -379,6 +404,7 @@ pc87309_reset(pc87309_t *dev) dev->regs[0x20] = dev->id; dev->regs[0x21] = 0x04; + dev->regs[0x22] = dev->baddr; dev->ld_regs[0x00][0x01] = 0x01; dev->ld_regs[0x00][0x30] = 0x03; @@ -453,6 +479,8 @@ pc87309_reset(pc87309_t *dev) serial_remove(dev->uart[0]); serial_remove(dev->uart[1]); fdc_reset(dev->fdc); + + superio_handler(dev); } static void @@ -472,19 +500,10 @@ pc87309_init(const device_t *info) dev->fdc = device_add(&fdc_at_nsc_device); - dev->uart[0] = device_add_inst(&ns16550_device, 1); - dev->uart[1] = device_add_inst(&ns16550_device, 2); + dev->baddr = (info->local & 0x100) ? 2 : 3; 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); - } - return dev; } From a262a519cbba418fd918b5e1ef2828f34d5006eb Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 20:48:29 +0200 Subject: [PATCH 19/42] PC87309: Actually fix relocation so it's implemented according to the PC87309 datasheet, not the PC87306 one. --- src/sio/sio_pc87309.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index 2219ede17..5e417aefb 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -116,12 +116,16 @@ superio_handler(pc87309_t *dev) io_removehandler(0x02e, 0x0002, pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - switch (dev->baddr) { - case 2: + switch (dev->regs[0x21] & 0x0b) { + case 0x02: + case 0x08: + case 0x0a: io_sethandler(0x15c, 0x0002, pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); break; - case 3: + case 0x03: + case 0x09: + case 0x0b: io_sethandler(0x02e, 0x0002, pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); break; @@ -218,10 +222,10 @@ pc87309_write(uint16_t port, uint8_t val, void *priv) case 0x07: case 0x21: dev->regs[dev->cur_reg] = val; + superio_handler(dev); break; case 0x22: dev->regs[dev->cur_reg] = val & 0x7f; - superio_handler(dev); break; default: if (dev->cur_reg >= 0x30) { @@ -403,8 +407,7 @@ pc87309_reset(pc87309_t *dev) memset(dev->pm, 0x00, 0x08); dev->regs[0x20] = dev->id; - dev->regs[0x21] = 0x04; - dev->regs[0x22] = dev->baddr; + dev->regs[0x21] = 0x04 | dev->baddr; dev->ld_regs[0x00][0x01] = 0x01; dev->ld_regs[0x00][0x30] = 0x03; @@ -500,7 +503,7 @@ pc87309_init(const device_t *info) dev->fdc = device_add(&fdc_at_nsc_device); - dev->baddr = (info->local & 0x100) ? 2 : 3; + dev->baddr = (info->local & 0x100) ? 8 : 9; pc87309_reset(dev); From d5a63540067b599350e90669b871b7c75ecd4dea Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Mon, 19 May 2025 15:53:39 +0300 Subject: [PATCH 20/42] Add the Dell OptiPlex GXL/GXM --- src/include/86box/machine.h | 1 + src/machine/m_at_socket5.c | 32 +++++++++++++++++++++++++++++ src/machine/machine_table.c | 40 +++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index c76761b3c..e9dc5bda9 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -672,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 *); diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 4b3bbd49c..9981f8e85 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -236,6 +236,38 @@ 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(model); + + 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)); + + device_add(&keyboard_ps2_ami_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) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 45986a50a..d9e6f2940 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -10553,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_NONE, + .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_APM, /* Video: S3 Trio64V+ (86C765), 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 = NULL, + .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 . */ From ec613f16085fe70ce6fe02518f0e716cc2117a58 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Mon, 19 May 2025 16:18:32 +0300 Subject: [PATCH 21/42] Add the onboard sound for the OptiPlex GXL/GXM --- src/machine/m_at_socket5.c | 4 ++++ src/machine/machine_table.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 9981f8e85..7c5ab697a 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -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) @@ -259,6 +260,9 @@ machine_at_optiplex_gxl_init(const machine_t *model) 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_ami_pci_device); device_add(&i430fx_device); device_add(&piix_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d9e6f2940..3e50442c1 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -10575,7 +10575,7 @@ const machine_t machines[] = { .max_multi = 3.0 }, .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_APM, /* Video: S3 Trio64V+ (86C765), Network: 3Com ETHERLINK III (3C509B) */ + .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, @@ -10590,7 +10590,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = &s3_phoenix_trio64vplus_onboard_pci_device, - .snd_device = NULL, + .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 From d7282ddc46d2059cf1973d0b07d8dacfd5592850 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Mon, 19 May 2025 16:28:01 +0300 Subject: [PATCH 22/42] Block the Cyrix Cx6x86 from the Dell OptiPlex GXL/GXM as it cannot POST with it --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 3e50442c1..f4031c0b7 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -10566,7 +10566,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_Cx6x86), .min_bus = 60000000, .max_bus = 66666667, .min_voltage = 3380, From e04628cc7cf13131f872c8bc8304eb0c29fa8fbf Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 19 May 2025 19:25:21 +0200 Subject: [PATCH 23/42] Trident pattern and memory access changes (May 19th, 2025) 1. DirectDraw memory address fixes of the day (removing the bit 6 of crtc 2a side of the if in recalctimings). 2. In spite of no documentration or NDA manuals, get data from the pattern registers as best as possible in 32bpp mode, this fixes patterns in 32bpp mode using various stuff. --- src/video/vid_tgui9440.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index af203f327..6fbdb7c3f 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -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: From 9f46d0b9d8c700e5c04d89e4229958a75906e310 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Mon, 19 May 2025 20:59:08 +0300 Subject: [PATCH 24/42] Fix the initialization and general purpose I/O (GPIO) pins for the OptiPlex GXL/GXM --- src/device/kbc_at.c | 11 ++++++++++- src/machine/m_at_socket5.c | 5 +++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 58aab476c..7413b45cf 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1096,7 +1096,16 @@ write64_generic(void *priv, uint8_t val) - Bit 5: Manufacturing jumper (must be set); */ uint8_t p1 = 0x24; - kbc_delay_to_ob(dev, p1, 0, 0x01); + 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 { /* (B0 or F0) | (0x08 or 0x0c) */ uint8_t p1_out = ((dev->p1 | fixed_bits) & 0xf0) | diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 7c5ab697a..5572d0484 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -248,7 +248,8 @@ machine_at_optiplex_gxl_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); + 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); @@ -263,7 +264,7 @@ machine_at_optiplex_gxl_init(const machine_t *model) if (sound_card_current[0] == SOUND_INTERNAL) machine_snd = device_add(machine_get_snd_device(machine)); - device_add(&keyboard_ps2_ami_pci_device); + device_add(&keyboard_ps2_phoenix_pci_device); device_add(&i430fx_device); device_add(&piix_device); device_add(&pc87332_device); From dbc2baebe915f443e5ce0cb6c81739cdc0cd9d1e Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 19 May 2025 22:22:03 +0200 Subject: [PATCH 25/42] Small ATI Mach8 changes (May 19th, 2025) 1. Report the ATI 28800 of the Graphics Ultra as 28800-6. 2. Access the upper word properly on vdisp. 3. Make sure there's enough vsyncstart/vtotal space for a full vertical display. --- src/video/vid_ati_mach8.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 8423f096b..a9544e724 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -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,12 +2705,10 @@ 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; + + mach_log("VSYNCSTART=%d, VTOTAL=%d, interlace=%02x, vdisp=%d.\n", dev->v_syncstart, dev->v_total, dev->interlace, dev->vdisp); if (ATI_8514A_ULTRA) { if ((mach->accel.clock_sel & 0x01) && @@ -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; } } From 06f4491193967cec42871b0748bf73f3d68cc6f0 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 20 May 2025 20:33:22 +0200 Subject: [PATCH 26/42] Mach8 mode changes of the day (May 20th, 2025) Make the previously Mach8 add-on only mode changes also available to the Graphics Ultra, should fix incorrect resolutions after switching from fullscreen DOS prompt to windowed and viceversa under Win98 (and SE). --- src/video/vid_ati_mach8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index a9544e724..0b5673d69 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2710,7 +2710,7 @@ mach_set_resolution(mach_t *mach, svga_t *svga) mach_log("VSYNCSTART=%d, VTOTAL=%d, interlace=%02x, vdisp=%d.\n", dev->v_syncstart, dev->v_total, dev->interlace, dev->vdisp); - if (ATI_8514A_ULTRA) { + if (!ATI_MACH32) { if ((mach->accel.clock_sel & 0x01) && !(dev->accel.advfunc_cntl & 0x01)) ret = 2; From 39a3d1ded022201f2a48f0d63646ba2ece313682 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 21 May 2025 14:04:55 +0600 Subject: [PATCH 27/42] Backport RxConfig fixes from QEMU --- src/network/net_rtl8139.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/network/net_rtl8139.c b/src/network/net_rtl8139.c index 5138b5168..0d07a8f83 100644 --- a/src/network/net_rtl8139.c +++ b/src/network/net_rtl8139.c @@ -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; From accce358e8231aca604336df4925d2b643a7e6af Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Wed, 21 May 2025 12:04:55 +0300 Subject: [PATCH 28/42] Fix the Password "Disabled by Jumper" error on Dimension XPS Pxxx and Pxxxa/Mxxxa --- src/device/kbc_at.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 7413b45cf..60ca29fc1 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1106,6 +1106,14 @@ write64_generic(void *priv, uint8_t val) */ 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) | From b18f69c037060ae0ccc79457a138da0d52c061b0 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Wed, 21 May 2025 12:18:54 +0300 Subject: [PATCH 29/42] Fix a small typo that causes some checks to fail --- src/device/kbc_at.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 60ca29fc1..7b6bea0c4 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1106,7 +1106,7 @@ write64_generic(void *priv, uint8_t val) */ 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")) { + } 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); From e76a89bcc80cb693efaa9f6165df8868add35f11 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 21 May 2025 13:32:17 +0200 Subject: [PATCH 30/42] Windows: Change cursor clipping from cursor warping to ClipCursor(), fixes #5498. --- src/qt/qt_rendererstack.cpp | 16 +++++++++++++++- src/qt/qt_ui.cpp | 23 +++++++++++++++++++++++ src/qt/qt_winrawinputfilter.cpp | 4 ++-- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 79fa78097..c210f4dc2 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -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); diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index 5a6bda852..e54d64269 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -23,6 +23,7 @@ #include #include +#include #include "qt_mainwindow.hpp" #include "qt_machinestatus.hpp" @@ -122,6 +123,8 @@ plat_resize(int w, int h, int monitor_index) main_window->resizeContents(w, h); } +extern HWND rw_hwnd; + void plat_mouse_capture(int on) { @@ -129,6 +132,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 diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index e94101a77..a62d71920 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -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); */ } From 75e76899da86b832e9d6631bf1a5c9a4d4cc1e5b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 21 May 2025 13:43:23 +0200 Subject: [PATCH 31/42] S3 911/924 high color: check if rd_mask is not 0 (May 21st, 2025) This fixes wrong colors in certain instances of Windows 95 builds' 911/924 drivers. --- src/video/vid_s3.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 683d2be34..99521f061 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -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); From 05ac5b62b0364019a7e229f81d05685c0dd9e719 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 21 May 2025 13:45:12 +0200 Subject: [PATCH 32/42] Add some forgotten #ifdef. --- src/qt/qt_ui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index e54d64269..6e0b3cfbb 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -123,7 +123,9 @@ 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) From 07c1bb5534d92694e4441d0e835722711c6c986b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 22 May 2025 00:19:57 +0600 Subject: [PATCH 33/42] Fix cursor clipping on Windows --- src/qt/qt_rendererstack.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index c210f4dc2..31cc495b0 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -663,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); From 455622492bbd1d129938638071f92e8300e4a18e Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 21 May 2025 20:49:54 +0200 Subject: [PATCH 34/42] All the required fixes - the Dell OptiPlex Gn+ now works correctly. --- src/acpi.c | 8 +- src/chipset/intel_piix.c | 39 +- src/device/kbc_at.c | 381 +++++++++++------- src/device/postcard.c | 54 +++ src/dma.c | 2 +- src/floppy/fdc.c | 25 +- src/include/86box/fdc.h | 1 + src/include/86box/keyboard.h | 4 +- src/include/86box/sio.h | 18 +- src/lpt.c | 4 +- src/machine/m_at_slot1.c | 2 +- src/machine/m_at_slot2.c | 2 +- src/machine/m_at_socket7.c | 13 +- src/machine/m_at_socket8.c | 9 +- src/machine/machine_table.c | 20 +- src/nvr_at.c | 5 +- src/sio/sio_fdc37c93x.c | 2 +- src/sio/sio_pc87307.c | 750 +++++++++++++++++++++++------------ src/sio/sio_pc87309.c | 643 +++++++++++++++++++----------- 19 files changed, 1310 insertions(+), 672 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index e9549adb0..e7a0de53d 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -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; diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index ed9fd9460..b73285f70 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -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, diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 58aab476c..78fc32ffd 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -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; @@ -1161,7 +1180,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; @@ -1231,7 +1250,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; @@ -1436,11 +1455,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; @@ -1513,7 +1532,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; @@ -1659,11 +1678,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; @@ -1692,11 +1711,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; @@ -1713,7 +1732,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; @@ -1734,11 +1753,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; @@ -1757,11 +1776,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; @@ -1779,7 +1798,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; @@ -1868,7 +1887,7 @@ write64_toshiba(void *priv, uint8_t val) break; } - return write64_generic(dev, val); + return write_cmd_generic(dev, val); } static void @@ -1912,8 +1931,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; @@ -1932,7 +1953,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; } @@ -2047,8 +2069,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); } @@ -2134,8 +2156,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); @@ -2145,7 +2167,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; @@ -2153,83 +2175,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; @@ -2237,7 +2265,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; @@ -2245,26 +2273,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); @@ -2303,11 +2337,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; } @@ -2350,21 +2387,52 @@ 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)) { + pclog("Disabling keyboard controller port %i at %04X...\n", num, dev->base_addr[num]); + + io_removehandler(dev->base_addr[num], 1, + dev->handlers[num].read, NULL, NULL, + dev->handlers[num].write, NULL, NULL, priv); } - kbc_handler_set = set; + dev->handler_enable[num] = set; + dev->base_addr[num] = port; - 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); + if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000)) { + pclog("Enabling keyboard controller port %i at %04X...\n", num, dev->base_addr[num]); + + 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]); + } + + dev->irq[num] = irq; +} + static void * kbc_at_init(const device_t *info) { @@ -2383,16 +2451,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; @@ -2401,8 +2474,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: @@ -2411,24 +2484,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: @@ -2451,23 +2524,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: @@ -2493,6 +2566,8 @@ kbc_at_init(const device_t *info) fast_reset = 0x00; + kbc_at_handler(1, 0x0060, dev); + return dev; } diff --git a/src/device/postcard.c b/src/device/postcard.c index 95a4df646..058684c0b 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -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; } diff --git a/src/dma.c b/src/dma.c index 4edeb39f8..2265947b9 100644 --- a/src/dma.c +++ b/src/dma.c @@ -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; } diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index cf5ae41bf..ebc16cbfd 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -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) { @@ -1484,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; @@ -2235,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)) { @@ -2266,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)) { diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index 53511daac..c98a03f67 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -183,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); diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 9dfb1c8e4..b9bac0821 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -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); diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index 06bf57f8f..358cd8c9a 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -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; diff --git a/src/lpt.c b/src/lpt.c index 26174d96b..072f4a34c 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -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 diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index b2f05d33e..773826316 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -584,7 +584,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_params(&pc87309_device, (void *) (PCX730X_AMI | PC87309_PC87309)); device_add(&keyboard_ps2_ami_pci_device); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x7, 256); diff --git a/src/machine/m_at_slot2.c b/src/machine/m_at_slot2.c index da160c138..37c0acdfd 100644 --- a/src/machine/m_at_slot2.c +++ b/src/machine/m_at_slot2.c @@ -141,7 +141,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); diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 17c89e39d..9ceebe2e0 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -984,19 +984,21 @@ machine_at_optiplex_gn_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Trio64V2/GX, temporarily Trio64V2/DX is given */ - 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(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(&keyboard_ps2_ami_pci_device); - device_add(&pc87307_15c_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); @@ -1040,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); diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index 006e0f419..aabfb9b4f 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -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) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f28079888..f16f4e5ae 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -13103,11 +13103,15 @@ 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. + /* + 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 likely an AMIKey-2 clone. */ + 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", @@ -13129,7 +13133,8 @@ const machine_t machines[] = { .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_VIDEO, /* Video: S3 86C785 (Trio64V2/GX), ethernet: 3C905 */ + /* Video: S3 86C785 (Trio64V2/GX), ethernet: 3C905. */ + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_VIDEO | MACHINE_SOUND, .ram = { .min = 8192, .max = 262144, @@ -13143,8 +13148,9 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = &s3_trio64v2_dx_onboard_pci_device, /* Stop-gap measure until the Trio64V2/GX is emulated, as both use the same VBIOS */ - .snd_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. */ diff --git a/src/nvr_at.c b/src/nvr_at.c index 2acfa47a4..4deda98be 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -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; diff --git a/src/sio/sio_fdc37c93x.c b/src/sio/sio_fdc37c93x.c index ebc500c96..dce5b11dc 100644 --- a/src/sio/sio_fdc37c93x.c +++ b/src/sio/sio_fdc37c93x.c @@ -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 diff --git a/src/sio/sio_pc87307.c b/src/sio/sio_pc87307.c index ae21d34af..7bc9bb441 100644 --- a/src/sio/sio_pc87307.c +++ b/src/sio/sio_pc87307.c @@ -8,11 +8,9 @@ * * Emulation of the NatSemi PC87307 Super I/O chip. * - * - * * Authors: Miran Grca, * - * Copyright 2020 Miran Grca. + * Copyright 2020-2025 Miran Grca. */ #include #include @@ -24,45 +22,89 @@ #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 pc87307_t { uint8_t id; + uint8_t baddr; uint8_t pm_idx; uint8_t regs[48]; uint8_t ld_regs[256][208]; uint8_t pcregs[16]; - uint8_t gpio[2][4]; + uint8_t gpio[2][8]; uint8_t pm[8]; + uint16_t superio_base; uint16_t gpio_base; uint16_t gpio_base2; uint16_t pm_base; int cur_reg; + void *kbc; fdc_t *fdc; serial_t *uart[2]; } pc87307_t; -static void fdc_handler(pc87307_t *dev); -static void lpt1_handler(pc87307_t *dev); -static void serial_handler(pc87307_t *dev, int uart); +enum { + LD_KBD = 0, + LD_MOUSE, + LD_RTC, + LD_FDC, + LD_LPT, + LD_UART2, + LD_UART1, + LD_GPIO, + LD_PM +} pc87307_ld_t; + +#define LD_MIN LD_KBD +#define LD_MAX LD_PM + +static void fdc_handler(pc87307_t *dev); +static void lpt1_handler(pc87307_t *dev); +static void serial_handler(pc87307_t *dev, int uart); +static void kbc_handler(pc87307_t *dev); +static void pc87307_write(uint16_t port, uint8_t val, void *priv); +static uint8_t pc87307_read(uint16_t port, void *priv); + +#ifdef ENABLE_PC87307_LOG +int pc87307_do_log = ENABLE_PC87307_LOG; + +static void +pc87307_log(const char *fmt, ...) +{ + va_list ap; + + if (pc87307_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define pc87307_log(fmt, ...) +#endif static void pc87307_gpio_write(uint16_t port, uint8_t val, void *priv) { pc87307_t *dev = (pc87307_t *) priv; - uint8_t bank = ((port & 0xfffc) == dev->gpio_base2); + uint8_t bank = !!(dev->regs[0x22] & 0x80); - dev->gpio[bank][port & 3] = val; + /* Bit 7 of SCNF2 = bank. */ + pc87307_log("[%04X:%08X] [W] (%04X) Bank %i = %02X\n", + CS, cpu_state.pc, port, bank, val); + + dev->gpio[bank][port & 0x0007] = val; } uint8_t @@ -70,20 +112,36 @@ pc87307_gpio_read(uint16_t port, void *priv) { const pc87307_t *dev = (pc87307_t *) priv; uint8_t pins = 0xff; - uint8_t bank = ((port & 0xfffc) == dev->gpio_base2); - uint8_t mask; - uint8_t ret = dev->gpio[bank][port & 0x0003]; + uint8_t bank = !!(dev->regs[0x22] & 0x80); + uint8_t ret = dev->gpio[bank][port & 0x0007]; switch (port & 0x0003) { case 0x0000: - mask = dev->gpio[bank][0x0001]; - ret = (ret & mask) | (pins & ~mask); + if (bank == 0) { + uint8_t mask = dev->gpio[0][1]; + pins = 0x7f; + ret = (ret & mask) | (pins & ~mask); + } + break; + case 0x0004: + if (bank == 0) { + uint8_t mask = dev->gpio[0][5]; + pins = 0xfb; + ret = (ret & mask) | (pins & ~mask); + } else + ret = 0xff; break; default: + if (bank == 1) + ret = 0xff; break; } + /* Bit 7 of SCNF2 = bank. */ + pc87307_log("[%04X:%08X] [R] (%04X) Bank %i = %02X\n", + CS, cpu_state.pc, port, bank, ret); + return ret; } @@ -123,6 +181,7 @@ pc87307_pm_write(uint16_t port, uint8_t val, void *priv) dev->pm[dev->pm_idx] = val; else { dev->pm_idx = val & 0x07; + switch (dev->pm_idx) { case 0x00: fdc_handler(dev); @@ -167,20 +226,49 @@ pc87307_pm_init(pc87307_t *dev, uint16_t addr) pc87307_pm_read, NULL, NULL, pc87307_pm_write, NULL, NULL, dev); } +static void +kbc_handler(pc87307_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]; + + pc87307_log("%02X, %02X, %02X, %02X, %04X, %04X\n", + active, active_2, irq, irq_2, addr, addr_2); + + if (addr <= 0xfff8) { + pc87307_log("Enabling KBC #1 on %04X...\n", addr); + kbc_at_port_handler(0, active, addr, dev->kbc); + } + + if (addr_2 <= 0xfff8) { + pc87307_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(pc87307_t *dev) { - uint8_t irq; - uint8_t active; - uint16_t addr; - fdc_remove(dev->fdc); - active = (dev->ld_regs[0x03][0x00] & 0x01) && (dev->pm[0x00] & 0x08); - addr = ((dev->ld_regs[0x03][0x30] << 8) | dev->ld_regs[0x03][0x31]) - 0x0002; - irq = (dev->ld_regs[0x03][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 && (addr <= 0xfff8)) { + pc87307_log("Enabling FDC on %04X, IRQ %i...\n", addr, irq); fdc_set_base(dev->fdc, addr); fdc_set_irq(dev->fdc, irq); } @@ -189,268 +277,405 @@ fdc_handler(pc87307_t *dev) static void lpt1_handler(pc87307_t *dev) { - uint8_t irq; - uint8_t active; - uint16_t addr; - - lpt1_remove(); - - active = (dev->ld_regs[0x04][0x00] & 0x01) && (dev->pm[0x00] & 0x10); - addr = (dev->ld_regs[0x04][0x30] << 8) | dev->ld_regs[0x04][0x31]; - irq = (dev->ld_regs[0x04][0x40] & 0x0f); + 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]; if (active && (addr <= 0xfffc)) { + pc87307_log("Enabling LPT1 on %04X...\n", addr); lpt1_setup(addr); - lpt1_irq(irq); - } + } else + lpt1_setup(0xffff); + + lpt1_irq(irq); } static void serial_handler(pc87307_t *dev, int uart) { - uint8_t irq; - uint8_t active; - uint16_t addr; - serial_remove(dev->uart[uart]); - active = (dev->ld_regs[0x06 - uart][0x00] & 0x01) && (dev->pm[0x00] & (1 << (6 - uart))); - addr = (dev->ld_regs[0x06 - uart][0x30] << 8) | dev->ld_regs[0x06 - uart][0x31]; - irq = (dev->ld_regs[0x06 - 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 && (addr <= 0xfff8)) + if (active && (addr <= 0xfff8)) { + pc87307_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 gpio_handler(pc87307_t *dev) { - uint8_t active; - uint16_t addr; - pc87307_gpio_remove(dev); - active = (dev->ld_regs[0x07][0x00] & 0x01); - addr = (dev->ld_regs[0x07][0x30] << 8) | dev->ld_regs[0x07][0x31]; + uint8_t active = (dev->ld_regs[LD_GPIO][0x00] & 0x01); + uint16_t addr = (dev->ld_regs[LD_GPIO][0x30] << 8) | + dev->ld_regs[LD_GPIO][0x31]; + uint16_t addr_2 = (dev->ld_regs[LD_GPIO][0x32] << 8) | + dev->ld_regs[LD_GPIO][0x33]; - if (active) + if (active) { + pc87307_log("Enabling GPIO #1 on %04X...\n", addr); pc87307_gpio_init(dev, 0, addr); - - addr = (dev->ld_regs[0x07][0x32] << 8) | dev->ld_regs[0x07][0x33]; - - if (active) - pc87307_gpio_init(dev, 1, addr); + pc87307_log("Enabling GPIO #2 on %04X...\n", addr_2); + pc87307_gpio_init(dev, 1, addr_2); + } } static void pm_handler(pc87307_t *dev) { - uint8_t active; - uint16_t addr; - pc87307_pm_remove(dev); - active = (dev->ld_regs[0x08][0x00] & 0x01); - addr = (dev->ld_regs[0x08][0x30] << 8) | dev->ld_regs[0x08][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) { + pc87307_log("Enabling power management on %04X...\n", addr); pc87307_pm_init(dev, addr); + } +} + +static void +superio_handler(pc87307_t *dev) +{ + if (dev->superio_base != 0x0000) + io_removehandler(dev->superio_base, 0x0002, + pc87307_read, NULL, NULL, + pc87307_write, NULL, NULL, dev); + + switch (dev->regs[0x22] & 0x03) { + default: + dev->superio_base = 0x0000; + break; case 0x02: + dev->superio_base = 0x015c; + break; + case 0x03: + dev->superio_base = 0x002e; + break; + } + + if (dev->superio_base != 0x0000) { + pc87307_log("Enabling Super I/O on %04X...\n", dev->superio_base); + io_sethandler(dev->superio_base, 0x0002, + pc87307_read, NULL, NULL, + pc87307_write, NULL, NULL, dev); + } } static void pc87307_write(uint16_t port, uint8_t val, void *priv) { - pc87307_t *dev = (pc87307_t *) priv; - uint8_t index; - - index = (port & 1) ? 0 : 1; + pc87307_t *dev = (pc87307_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_PC87307_LOG + if (dev->cur_reg >= 0x30) + pc87307_log("[%04X:%08X] [W] (%04X) %02X:%02X = %02X\n", + CS, cpu_state.pc, port, ld, dev->cur_reg, val); + else + pc87307_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)); + break; case 0x22: - dev->regs[dev->cur_reg] = val & 0x7f; + dev->regs[dev->cur_reg] = val; + superio_handler(dev); break; case 0x23: - dev->regs[dev->cur_reg] = val & 0x0f; + dev->regs[dev->cur_reg] = (old & 0xf0) | (val & 0x0f); break; case 0x24: dev->pcregs[dev->regs[0x23]] = 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 0x03: + switch (ld) { + default: + break; + case LD_KBD: case LD_MOUSE: + dev->ld_regs[ld][reg] = val; + kbc_handler(dev); + break; + case LD_RTC: + dev->ld_regs[ld][reg] = val; + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; fdc_handler(dev); break; - case 0x04: + case LD_LPT: + dev->ld_regs[ld][reg] = val; lpt1_handler(dev); break; - case 0x05: + case LD_UART2: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 1); break; - case 0x06: + case LD_UART1: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 0); break; - case 0x07: + case LD_GPIO: + dev->ld_regs[ld][reg] = val; gpio_handler(dev); break; - case 0x08: + 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: - if (dev->regs[0x07] == 0x04) { - val &= 0x03; - } - fallthrough; - case 0x62: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val; - if ((dev->cur_reg == 0x62) && (dev->regs[0x07] != 0x07)) - break; - switch (dev->regs[0x07]) { - case 0x03: + switch (ld) { + default: + break; + case LD_KBD: + dev->ld_regs[ld][reg] = val; + kbc_handler(dev); + break; + case LD_RTC: + dev->ld_regs[ld][reg] = val; + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; fdc_handler(dev); break; - case 0x04: + case LD_LPT: + dev->ld_regs[ld][reg] = (old & 0xfc) | (val & 0x03); lpt1_handler(dev); break; - case 0x05: + case LD_UART2: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 1); break; - case 0x06: + case LD_UART1: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 0); break; - case 0x07: + case LD_GPIO: + dev->ld_regs[ld][reg] = val; gpio_handler(dev); break; - case 0x08: + case LD_PM: + dev->ld_regs[ld][reg] = val; pm_handler(dev); break; - - default: - break; } break; + /* Base Address 0 LSB. */ case 0x61: - switch (dev->regs[0x07]) { - case 0x00: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfb; + switch (ld) { + default: break; - case 0x03: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfa) | 0x02; + case LD_KBD: + dev->ld_regs[ld][reg] = (old & 0x04) | (val & 0xfb); + kbc_handler(dev); + break; + case LD_RTC: + dev->ld_regs[ld][reg] = (old & 0x01) | (val & 0xfe); + break; + case LD_FDC: + dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8); fdc_handler(dev); break; - case 0x04: - 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 0x05: - 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 0x06: - 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 0x07: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + case LD_GPIO: + dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8); gpio_handler(dev); break; - case 0x08: - 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; - - 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; + case LD_GPIO: + dev->ld_regs[ld][reg] = val; + gpio_handler(dev); + break; + } + break; + /* Base Address 1 LSB (undocumented for Logical Device 7). */ case 0x63: - if (dev->regs[0x07] == 0x00) - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfb) | 0x04; - else if (dev->regs[0x07] == 0x07) { - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfe; - gpio_handler(dev); - } - break; - case 0x70: - case 0x74: - case 0x75: - switch (dev->regs[0x07]) { - case 0x03: - fdc_handler(dev); - break; - case 0x04: - lpt1_handler(dev); - break; - case 0x05: - serial_handler(dev, 1); - break; - case 0x06: - serial_handler(dev, 0); - break; - case 0x07: - gpio_handler(dev); - break; - case 0x08: - pm_handler(dev); - break; - + switch (ld) { default: break; + case LD_KBD: + dev->ld_regs[ld][reg] = (old & 0x04) | (val & 0xfb); + kbc_handler(dev); + break; + case LD_GPIO: + dev->ld_regs[ld][reg] = (old & 0x01) | (val & 0xfe); + gpio_handler(dev); + break; } break; - case 0xf0: - switch (dev->regs[0x07]) { - case 0x00: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xc1; + /* Interrupt Select. */ + case 0x70: + switch (ld) { + default: break; - case 0x03: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xe1; + case LD_KBD: case LD_MOUSE: + dev->ld_regs[ld][reg] = val; + kbc_handler(dev); + break; + case LD_RTC: + dev->ld_regs[ld][reg] = val; + 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; + serial_handler(dev, 1); + break; + case LD_UART1: + dev->ld_regs[ld][reg] = val; + serial_handler(dev, 0); + 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 (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 0x04: - 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 0x05: - case 0x06: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x87; - 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] == 0x03) - 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: @@ -458,32 +683,46 @@ pc87307_write(uint16_t port, uint8_t val, void *priv) } } -uint8_t +static uint8_t pc87307_read(uint16_t port, void *priv) { - const pc87307_t *dev = (pc87307_t *) priv; - uint8_t ret = 0xff; - uint8_t index; - - index = (port & 1) ? 0 : 1; + const pc87307_t *dev = (pc87307_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; else { if (dev->cur_reg >= 0x30) - ret = dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30]; + ret = dev->ld_regs[ld][reg]; else if (dev->cur_reg == 0x24) ret = dev->pcregs[dev->regs[0x23]]; + /* 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 EANBLE_PC87307_LOG + if (dev->cur_reg >= 0x30) + pc87307_log("[%04X:%08X] [R] (%04X) %02X:%02X = %02X\n", + CS, cpu_state.pc, port, ld, dev->cur_reg, ret); + else + pc87307_log("[%04X:%08X] [R] (%04X) %02X = %02X\n", + CS, cpu_state.pc, port, dev->cur_reg, ret); +#endif } return ret; } void -pc87307_reset(pc87307_t *dev) +pc87307_reset(void *priv) { + pc87307_t *dev = (pc87307_t *) priv; + memset(dev->regs, 0x00, 0x30); for (uint16_t i = 0; i < 256; i++) memset(dev->ld_regs[i], 0x00, 0xd0); @@ -493,77 +732,77 @@ pc87307_reset(pc87307_t *dev) dev->regs[0x20] = dev->id; dev->regs[0x21] = 0x04; + dev->regs[0x22] = dev->baddr; - dev->ld_regs[0x00][0x01] = 0x01; - dev->ld_regs[0x00][0x31] = 0x60; - dev->ld_regs[0x00][0x33] = 0x64; - dev->ld_regs[0x00][0x40] = 0x01; - dev->ld_regs[0x00][0x41] = 0x02; - dev->ld_regs[0x00][0x44] = 0x04; - dev->ld_regs[0x00][0x45] = 0x04; - dev->ld_regs[0x00][0xc0] = 0x40; + 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][0x40] = 0x0c; - dev->ld_regs[0x01][0x41] = 0x02; - dev->ld_regs[0x01][0x44] = 0x04; - dev->ld_regs[0x01][0x45] = 0x04; + 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][0x00] = 0x01; - dev->ld_regs[0x02][0x31] = 0x70; - dev->ld_regs[0x02][0x40] = 0x08; - dev->ld_regs[0x02][0x44] = 0x04; - dev->ld_regs[0x02][0x45] = 0x04; + dev->ld_regs[LD_RTC ][0x00] = 0x01; + dev->ld_regs[LD_RTC ][0x31] = 0x70; + dev->ld_regs[LD_RTC ][0x40] = 0x08; + dev->ld_regs[LD_RTC ][0x44] = 0x04; + dev->ld_regs[LD_RTC ][0x45] = 0x04; - dev->ld_regs[0x03][0x01] = 0x01; - dev->ld_regs[0x03][0x30] = 0x03; - dev->ld_regs[0x03][0x31] = 0xf2; - dev->ld_regs[0x03][0x40] = 0x06; - dev->ld_regs[0x03][0x41] = 0x03; - dev->ld_regs[0x03][0x44] = 0x02; - dev->ld_regs[0x03][0x45] = 0x04; - dev->ld_regs[0x03][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[0x04][0x30] = 0x02; - dev->ld_regs[0x04][0x31] = 0x78; - dev->ld_regs[0x04][0x40] = 0x07; - dev->ld_regs[0x04][0x44] = 0x04; - dev->ld_regs[0x04][0x45] = 0x04; - dev->ld_regs[0x04][0xc0] = 0xf2; + 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[0x05][0x30] = 0x02; - dev->ld_regs[0x05][0x31] = 0xf8; - dev->ld_regs[0x05][0x40] = 0x03; - dev->ld_regs[0x05][0x41] = 0x03; - dev->ld_regs[0x05][0x44] = 0x04; - dev->ld_regs[0x05][0x45] = 0x04; - dev->ld_regs[0x05][0xc0] = 0x02; + 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[0x06][0x30] = 0x03; - dev->ld_regs[0x06][0x31] = 0xf8; - dev->ld_regs[0x06][0x40] = 0x04; - dev->ld_regs[0x06][0x41] = 0x03; - dev->ld_regs[0x06][0x44] = 0x04; - dev->ld_regs[0x06][0x45] = 0x04; - dev->ld_regs[0x06][0xc0] = 0x02; + 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[0x07][0x44] = 0x04; - dev->ld_regs[0x07][0x45] = 0x04; + dev->ld_regs[LD_GPIO ][0x44] = 0x04; + dev->ld_regs[LD_GPIO ][0x45] = 0x04; - dev->ld_regs[0x08][0x44] = 0x04; - dev->ld_regs[0x08][0x45] = 0x04; + dev->ld_regs[LD_PM ][0x44] = 0x04; + dev->ld_regs[LD_PM ][0x45] = 0x04; -#if 0 - dev->gpio[0] = 0xff; - dev->gpio[1] = 0xfb; -#endif dev->gpio[0][0] = 0xff; dev->gpio[0][1] = 0x00; dev->gpio[0][2] = 0x00; dev->gpio[0][3] = 0xff; - dev->gpio[1][0] = 0xff; + dev->gpio[0][4] = 0xff; + dev->gpio[0][5] = 0x00; + dev->gpio[0][6] = 0x00; + dev->gpio[0][7] = 0xff; dev->gpio[1][1] = 0x00; - dev->gpio[1][2] = 0x00; - dev->gpio[1][3] = 0xff; dev->pm[0] = 0xff; dev->pm[1] = 0xff; @@ -576,10 +815,17 @@ pc87307_reset(pc87307_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); + gpio_handler(dev); + pm_handler(dev); + superio_handler(dev); } static void @@ -602,16 +848,26 @@ pc87307_init(const device_t *info) dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); - pc87307_reset(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 & 0x100) { - io_sethandler(0x02e, 0x0002, - pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, dev); - } - if (info->local & 0x200) { - io_sethandler(0x15c, 0x0002, - pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, dev); - } + if (info->local & PCX730X_15C) + dev->baddr = 0x02; + else + dev->baddr = 0x03; + + pc87307_reset(dev); return dev; } @@ -623,7 +879,7 @@ const device_t pc87307_device = { .local = 0x1c0, .init = pc87307_init, .close = pc87307_close, - .reset = NULL, + .reset = pc87307_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -637,7 +893,7 @@ const device_t pc87307_15c_device = { .local = 0x2c0, .init = pc87307_init, .close = pc87307_close, - .reset = NULL, + .reset = pc87307_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -651,7 +907,7 @@ const device_t pc87307_both_device = { .local = 0x3c0, .init = pc87307_init, .close = pc87307_close, - .reset = NULL, + .reset = pc87307_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -665,7 +921,7 @@ const device_t pc97307_device = { .local = 0x1cf, .init = pc87307_init, .close = pc87307_close, - .reset = NULL, + .reset = pc87307_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index 5e417aefb..d2d3f4ac0 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -8,11 +8,9 @@ * * Emulation of the NatSemi PC87309 Super I/O chip. * - * - * * Authors: Miran Grca, * - * Copyright 2020 Miran Grca. + * Copyright 2020-2025 Miran Grca. */ #include #include @@ -24,44 +22,81 @@ #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]; - uint8_t baddr; + uint16_t superio_base; uint16_t pm_base; int cur_reg; + void *kbc; fdc_t *fdc; serial_t *uart[2]; } pc87309_t; +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: @@ -74,8 +109,7 @@ pc87309_pm_write(uint16_t port, uint8_t val, void *priv) default: break; } - } else - dev->pm_idx = val & 0x07; + } } uint8_t @@ -109,43 +143,48 @@ pc87309_pm_init(pc87309_t *dev, uint16_t addr) } static void -superio_handler(pc87309_t *dev) +kbc_handler(pc87309_t *dev) { - io_removehandler(0x15c, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - io_removehandler(0x02e, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, 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]; - switch (dev->regs[0x21] & 0x0b) { - case 0x02: - case 0x08: - case 0x0a: - io_sethandler(0x15c, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - break; - case 0x03: - case 0x09: - case 0x0b: - io_sethandler(0x02e, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - break; + 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); } @@ -154,222 +193,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[0x22] & 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 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: @@ -377,30 +545,44 @@ 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); @@ -409,65 +591,56 @@ pc87309_reset(pc87309_t *dev) dev->regs[0x20] = dev->id; 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; @@ -478,11 +651,15 @@ 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); } @@ -503,7 +680,27 @@ pc87309_init(const device_t *info) dev->fdc = device_add(&fdc_at_nsc_device); - dev->baddr = (info->local & 0x100) ? 8 : 9; + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + 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); @@ -514,24 +711,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, From d8a53f6fdb09ed94c965282db9872139b2fbdcf7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 21 May 2025 20:55:00 +0200 Subject: [PATCH 35/42] Make it use the A12 BIOS. --- src/machine/m_at_socket7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 9ceebe2e0..3d51e1a06 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -974,7 +974,7 @@ machine_at_optiplex_gn_init(const machine_t *model) { int ret; - ret = bios_load_linear("roms/machines/optiplex_gn/Gn_a11.rom", + ret = bios_load_linear("roms/machines/optiplex_gn/DELL.ROM", 0x000c0000, 262144, 0); if (bios_only || !ret) From e9a1768da935313187c2312f357966a1324bdae4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 22 May 2025 00:35:07 +0200 Subject: [PATCH 36/42] KBC AT: Remove some excess logging. --- src/device/kbc_at.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 78fc32ffd..f068b8699 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -2391,24 +2391,18 @@ kbc_at_port_handler(int num, int set, uint16_t port, void *priv) { atkbc_t *dev = (atkbc_t *) priv; - if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000)) { - pclog("Disabling keyboard controller port %i at %04X...\n", num, dev->base_addr[num]); - + 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)) { - pclog("Enabling keyboard controller port %i at %04X...\n", num, dev->base_addr[num]); - + 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 From f6dd42ca87010f7dcc1fb08979322aee61448198 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 22 May 2025 00:54:57 +0200 Subject: [PATCH 37/42] Packard Bell PB410: Fix on-board video. --- src/machine/m_at_386dx_486.c | 2 +- src/machine/machine_table.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 46b93a37f..c1f471ff3 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -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; } diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f16f4e5ae..e864f580b 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6647,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 }, From c8fbee1b62845e9894a849509527573cc96d48d1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 22 May 2025 06:20:04 +0200 Subject: [PATCH 38/42] Fixes to the two recently NSC Super I/O chips and the two boards that use the PC87309 (Tyan Tsunami ATX and the Freeway). --- src/machine/m_at_slot1.c | 1 - src/machine/m_at_slot2.c | 1 - src/sio/sio_pc87307.c | 4 +++- src/sio/sio_pc87309.c | 6 ++++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 773826316..c764b4229 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -585,7 +585,6 @@ machine_at_s1846_init(const machine_t *model) device_add(&i440bx_device); device_add(&piix4e_device); device_add_params(&pc87309_device, (void *) (PCX730X_AMI | PC87309_PC87309)); - device_add(&keyboard_ps2_ami_pci_device); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x7, 256); diff --git a/src/machine/m_at_slot2.c b/src/machine/m_at_slot2.c index 37c0acdfd..7bf412823 100644 --- a/src/machine/m_at_slot2.c +++ b/src/machine/m_at_slot2.c @@ -140,7 +140,6 @@ 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_params(&pc87309_device, (void *) (PCX730X_15C | PCX730X_AMI | PC87309_PC87309)); device_add(ics9xxx_get(ICS9250_08)); device_add(&sst_flash_29ee020_device); diff --git a/src/sio/sio_pc87307.c b/src/sio/sio_pc87307.c index 7bc9bb441..7e51c5975 100644 --- a/src/sio/sio_pc87307.c +++ b/src/sio/sio_pc87307.c @@ -12,11 +12,13 @@ * * Copyright 2020-2025 Miran Grca. */ +#include #include #include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/io.h> #include <86box/timer.h> @@ -400,7 +402,7 @@ pc87307_write(uint16_t port, uint8_t val, void *priv) break; case 0x21: dev->regs[dev->cur_reg] = val; - fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !!(val & 0x04)); + fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !(val & 0x04)); break; case 0x22: dev->regs[dev->cur_reg] = val; diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index d2d3f4ac0..8bbbb7036 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -12,11 +12,13 @@ * * Copyright 2020-2025 Miran Grca. */ +#include #include #include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/io.h> #include <86box/timer.h> @@ -249,7 +251,7 @@ superio_handler(pc87309_t *dev) pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - switch (dev->regs[0x22] & 0x0b) { + switch (dev->regs[0x21] & 0x0b) { default: dev->superio_base = 0x0000; break; @@ -300,7 +302,7 @@ pc87309_write(uint16_t port, uint8_t val, void *priv) break; case 0x21: dev->regs[dev->cur_reg] = val; - fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !!(val & 0x04)); + fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !(val & 0x04)); superio_handler(dev); break; case 0x22: From 2139e3dd511cd0d9a099c4a558499a3ed50efd6b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 23 May 2025 00:34:12 +0600 Subject: [PATCH 39/42] Attempt to make OpenGL 3.0 filter settings consistent --- src/qt/qt_openglrenderer.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 45bae6ea7..9ca2d887e 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -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); From 0278077a4ba75ed62ced41aa0a8b32cdc742ab8c Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Thu, 22 May 2025 22:48:52 +0300 Subject: [PATCH 40/42] Add the Dell OptiPlex GXa --- src/include/86box/machine.h | 2 +- src/machine/m_at_slot1.c | 33 +++++++++++++++++++++++++++++ src/machine/machine_table.c | 41 +++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index cbf2fda15..be9f17505 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -822,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 *); diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index c764b4229..d7a47c901 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -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_NORMAL, 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) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 10ce1694b..d2bd76ca6 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -15170,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_onboard_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. */ { From 734885b930c90e7b94a10dad668ff83adea9df3f Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Fri, 23 May 2025 00:01:42 +0300 Subject: [PATCH 41/42] Fix the onboard audio on the OptiPlex GXa --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d2bd76ca6..de830cb89 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -15208,7 +15208,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, /* not yet emulated */ - .snd_device = &cs4236b_onboard_device, + .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 From 8c2ee25b39e9fcc4f50ee1e4c32f401ac2f31e9c Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Fri, 23 May 2025 00:13:55 +0300 Subject: [PATCH 42/42] Fix a small mistake with the IRQ table of the OptiPlex GXA --- src/machine/m_at_slot1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index d7a47c901..54cf1a03a 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -167,7 +167,7 @@ machine_at_optiplex_gxa_init(const machine_t *model) 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_NORMAL, 4, 0, 0, 0); + 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);