From 3d7b7b4ae6b19ae92d3e780ac8dda2b4fd7d30ea Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sun, 30 May 2021 23:57:03 +0500 Subject: [PATCH 01/59] Add config migrations for merged multi-socket machines --- src/config.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/config.c b/src/config.c index f1fc95293..d412e1553 100644 --- a/src/config.c +++ b/src/config.c @@ -589,6 +589,14 @@ load_machine(void) machine = machine_get_machine_from_internal_name("m30015"); else if (! strcmp(p, "cbm_sl386sx25")) machine = machine_get_machine_from_internal_name("cmdsl386sx25"); + else if (! strcmp(p, "award386dx")) /* ...merged machines... */ + machine = machine_get_machine_from_internal_name("award486"); + else if (! strcmp(p, "ami386dx")) + machine = machine_get_machine_from_internal_name("ami486"); + else if (! strcmp(p, "mr386dx")) + machine = machine_get_machine_from_internal_name("mr486"); + else if (! strcmp(p, "fw6400gx_s1")) + machine = machine_get_machine_from_internal_name("fw6400gx"); else if (! strcmp(p, "president")) { /* ...and removed machines */ machine = machine_get_machine_from_internal_name("mb500n"); migrate_from = NULL; From fee0ea1d245903fd16ba0d5c0b0ab295cfe660a3 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 30 May 2021 22:07:22 +0200 Subject: [PATCH 02/59] Ported the x87 fix from the other emulator as well as the GUS one. Fixed 15bpp mode in all cards. --- src/cpu/x87_ops_misc.h | 2 + src/sound/snd_gus.c | 84 ++++++++++++++++++++++++------------- src/video/vid_svga_render.c | 4 +- 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index bd8b1a851..c902d12c8 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -787,6 +787,8 @@ static int opFLDCW_a32(uint32_t fetchdat) static int FSTENV() { FP_ENTER(); + cpu_state.npxs = (cpu_state.npxs & ~(7 << 11)) | ((cpu_state.TOP & 7) << 11); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) { case 0x000: /*16-bit real mode*/ diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 40a0a405b..fe94ebf2f 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -130,33 +130,66 @@ int gusfreqs[]= double vol16bit[4096]; -void pollgusirqs(gus_t *gus) +void gus_update_int_status(gus_t *gus) { int c; + int irq_pending = 0; + int midi_irq_pending = 0; gus->irqstatus&=~0x60; + gus->irqstatus2=0xE0; for (c=0;c<32;c++) { if (gus->waveirqs[c]) { gus->irqstatus2=0x60|c; - if (gus->rampirqs[c]) gus->irqstatus2 |= 0x80; + if (gus->rampirqs[c]) + gus->irqstatus2 |= 0x80; gus->irqstatus|=0x20; - if (gus->irq != -1) - picint(1 << gus->irq); - return; + irq_pending = 1; + break; } if (gus->rampirqs[c]) { gus->irqstatus2=0xA0|c; gus->irqstatus|=0x40; - if (gus->irq != -1) - picint(1 << gus->irq); - return; + irq_pending = 1; + break; + } + } + if ((gus->tctrl & 4) && (gus->irqstatus & 0x04)) + irq_pending = 1; /*Timer 1 interrupt pending*/ + if ((gus->tctrl & 8) && (gus->irqstatus & 0x08)) + irq_pending = 1; /*Timer 2 interrupt pending*/ + if ((gus->irqstatus & 0x80) && (gus->dmactrl & 0x20)) + irq_pending = 1; /*DMA TC interrupt pending*/ + + midi_irq_pending = gus->midi_status & MIDI_INT_MASTER; + + if (gus->irq == gus->irq_midi && gus->irq != -1) + { + if (irq_pending || midi_irq_pending) + picintlevel(1 << gus->irq); + else + picintc(1 << gus->irq); + } + else + { + if (gus->irq != -1) + { + if (irq_pending) + picintlevel(1 << gus->irq); + else + picintc(1 << gus->irq); + } + if (gus->irq_midi != -1) + { + if (midi_irq_pending) + picintlevel(1 << gus->irq_midi); + else + picintc(1 << gus->irq_midi); } } - gus->irqstatus2=0xE0; - if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq); } void gus_midi_update_int_status(gus_t *gus) @@ -178,10 +211,7 @@ void gus_midi_update_int_status(gus_t *gus) else gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE; - if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1)) - { - picint(1 << gus->irq_midi); - } + gus_update_int_status(gus); } void writegus(uint16_t addr, uint8_t val, void *p) @@ -283,6 +313,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); break; case 0x45: /*Timer control*/ gus->tctrl=val; + gus_update_int_status(gus); break; } break; @@ -295,7 +326,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); old = gus->waveirqs[gus->voice]; gus->waveirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; if (gus->waveirqs[gus->voice] != old) - pollgusirqs(gus); + gus_update_int_status(gus); break; case 1: /*Frequency control*/ gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF)|(val<<8); @@ -347,7 +378,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); gus->rctrl[gus->voice] = val & 0x7F; gus->rampirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; if (gus->rampirqs[gus->voice] != old) - pollgusirqs(gus); + gus_update_int_status(gus); break; case 0xE: @@ -396,7 +427,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); break; } gus->dmactrl=val&~0x40; - if (val&0x20) gus->irqnext=1; + gus->irqnext=1; } else { @@ -427,7 +458,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); break; } gus->dmactrl=val&~0x40; - if (val&0x20) gus->irqnext=1; + gus->irqnext=1; } } break; @@ -457,6 +488,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); } gus->tctrl=val; gus->sb_ctrl = val; + gus_update_int_status(gus); break; case 0x46: /*Timer 1*/ gus->t1 = gus->t1l = val; @@ -699,7 +731,7 @@ uint8_t readgus(uint16_t addr, void *p) val=gus->irqstatus2; gus->rampirqs[gus->irqstatus2&0x1F]=0; gus->waveirqs[gus->irqstatus2&0x1F]=0; - pollgusirqs(gus); + gus_update_int_status(gus); return val; case 0x00: case 0x01: case 0x02: case 0x03: @@ -739,7 +771,7 @@ uint8_t readgus(uint16_t addr, void *p) val=gus->irqstatus2; gus->rampirqs[gus->irqstatus2&0x1F]=0; gus->waveirqs[gus->irqstatus2&0x1F]=0; - pollgusirqs(gus); + gus_update_int_status(gus); return val; case 0x41: /*DMA control*/ @@ -844,8 +876,6 @@ void gus_poll_timer_1(void *p) gus->ad_status |= 0x40; if (gus->tctrl&4) { - if (gus->irq != -1) - picint(1 << gus->irq); gus->ad_status |= 0x04; gus->irqstatus |= 0x04; } @@ -855,11 +885,10 @@ void gus_poll_timer_1(void *p) { gus->irqnext=0; gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); } gus_midi_update_int_status(gus); + gus_update_int_status(gus); } void gus_poll_timer_2(void *p) @@ -876,8 +905,6 @@ void gus_poll_timer_2(void *p) gus->ad_status |= 0x20; if (gus->tctrl&8) { - if (gus->irq != -1) - picint(1 << gus->irq); gus->ad_status |= 0x02; gus->irqstatus |= 0x08; } @@ -887,9 +914,8 @@ void gus_poll_timer_2(void *p) { gus->irqnext=0; gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); } + gus_update_int_status(gus); } static void gus_update(gus_t *gus) @@ -1069,7 +1095,7 @@ void gus_poll_wave(void *p) } if (update_irqs) - pollgusirqs(gus); + gus_update_int_status(gus); } static void gus_get_buffer(int32_t *buffer, int len, void *p) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 530b4e2c3..7cd9fa8b1 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -906,8 +906,8 @@ svga_render_15bpp_lowres(svga_t *svga) *p++ = video_15to32[dat >> 16]; } else memset(&(p[x]), 0x00, 2 * sizeof(uint32_t)); + svga->ma += 4; } - svga->ma += 4; } svga->ma &= svga->vram_display_mask; } @@ -966,8 +966,8 @@ svga_render_15bpp_highres(svga_t *svga) *p++ = video_15to32[dat >> 16]; } else memset(&(p[x]), 0x00, 2 * sizeof(uint32_t)); + svga->ma += 4; } - svga->ma += 4; } svga->ma &= svga->vram_display_mask; } From 963b530d10af9b6d2bda1e4d9e3a45812732bd91 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 30 May 2021 23:40:56 +0200 Subject: [PATCH 03/59] Ported the Cirrus by16 fix. --- src/include/86box/vid_svga.h | 1 + src/video/vid_cl54xx.c | 6 ++++-- src/video/vid_svga.c | 10 +++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index e843bbb95..73c176742 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -23,6 +23,7 @@ #define FLAG_EXT_WRITE 4 #define FLAG_LATCH8 8 #define FLAG_NOSKEW 16 +#define FLAG_ADDR_BY16 32 typedef struct { diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 5725d8914..777fdb348 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -901,6 +901,8 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga->adv_flags |= FLAG_EXT_WRITE; if (svga->gdcreg[0xb] & 0x08) svga->adv_flags |= FLAG_LATCH8; + if (svga->gdcreg[0xb] & 0x10) + svga->adv_flags |= FLAG_ADDR_BY16; gd54xx_recalc_banking(gd54xx); break; @@ -1994,7 +1996,7 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) switch (svga->writemode) { case 4: - if (svga->gdcreg[0xb] & 0x10) { + if (svga->adv_flags & FLAG_ADDR_BY16) { addr <<= 2; addr &= svga->decode_mask; @@ -2016,7 +2018,7 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) break; case 5: - if (svga->gdcreg[0xb] & 0x10) { + if (svga->adv_flags & FLAG_ADDR_BY16) { addr <<= 2; addr &= svga->decode_mask; diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 2dbd1566f..07f6f3823 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1056,9 +1056,11 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) } if (!(svga->gdcreg[6] & 1)) - svga->fullchange = 2; + svga->fullchange = 2; - if ((svga->adv_flags & FLAG_ADDR_BY8) && (svga->writemode < 4)) + if ((svga->adv_flags & FLAG_ADDR_BY16) && (svga->writemode == 4 || svga->writemode == 5)) + addr <<= 4; + else if ((svga->adv_flags & FLAG_ADDR_BY8) && (svga->writemode < 4)) addr <<= 3; else if (((svga->chain4 && svga->packed_chain4) || svga->fb_only) && (svga->writemode < 4)) { writemask2 = 1 << (addr & 3); @@ -1244,7 +1246,9 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p) latch_addr = (addr << count) & svga->decode_mask; count = (1 << count); - if (svga->adv_flags & FLAG_ADDR_BY8) + if (svga->adv_flags & FLAG_ADDR_BY16) + addr <<= 4; + else if (svga->adv_flags & FLAG_ADDR_BY8) addr <<= 3; else if ((svga->chain4 && svga->packed_chain4) || svga->fb_only) { addr &= svga->decode_mask; From a8f86df2a5a0b87e2ae19ee271245d3c26ed05df Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 31 May 2021 13:53:44 +0200 Subject: [PATCH 04/59] Properly fix the by16 addressing of the Cirrus 542x. --- src/video/vid_cl54xx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 777fdb348..ddd424232 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -1997,7 +1997,6 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) switch (svga->writemode) { case 4: if (svga->adv_flags & FLAG_ADDR_BY16) { - addr <<= 2; addr &= svga->decode_mask; for (i = 0; i < 8; i++) { @@ -2019,7 +2018,6 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) case 5: if (svga->adv_flags & FLAG_ADDR_BY16) { - addr <<= 2; addr &= svga->decode_mask; for (i = 0; i < 8; i++) { From 5cd17bb293711be65936832eefd5fa575f423bef Mon Sep 17 00:00:00 2001 From: qeeg Date: Wed, 2 Jun 2021 15:25:21 -0500 Subject: [PATCH 05/59] Port over MDK2 fade-in fix from PCem --- src/cpu/x87_ops_misc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index c902d12c8..ba5e37f7a 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -679,7 +679,8 @@ static int opFSCALE(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; temp64 = (int64_t)ST(1); - ST(0) = ST(0) * pow(2.0, (double)temp64); + if(ST(0) != 0.0) + ST(0) = ST(0) * pow(2.0, (double)temp64); FP_TAG_VALID; CLOCK_CYCLES((fpu_type >= FPU_487SX) ? (x87_timings.fscale) : (x87_timings.fscale * cpu_multi)); return 0; From 736eb46847b01284ed8adc44adf553ae7bef40fe Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 3 Jun 2021 05:02:22 +0200 Subject: [PATCH 06/59] Reverted the ROM read cycles back to the old (and evidently, more correct) ones. --- src/cpu/cpu.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 379606c25..34d3db534 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -142,8 +142,7 @@ void (*cpu_exec)(int cycs); static uint8_t ccr0, ccr1, ccr2, ccr3, ccr4, ccr5, ccr6; -static int cyrix_addr, cpu_rom_read_cycles = 4; -static uint64_t rom_read_timing_ns = 150; +static int cyrix_addr; static void cpu_write(uint16_t addr, uint8_t val, void *priv); @@ -407,7 +406,10 @@ cpu_set(void) isa_cycles = cpu_s->atclk_div; - cpu_rom_prefetch_cycles = (cpu_rom_read_cycles * cpu_s->rspeed * rom_read_timing_ns + 999999999ULL) / 1000000000ULL; + if (cpu_s->rspeed <= 8000000) + cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; + else + cpu_rom_prefetch_cycles = cpu_s->rspeed / 1000000; cpu_set_isa_pci_div(0); cpu_set_pci_speed(0); @@ -1377,8 +1379,10 @@ cpu_set_isa_speed(int speed) if (speed) { cpu_isa_speed = speed; pc_speed_changed(); - } else + } else if (cpu_busspeed >= 8000000) cpu_isa_speed = 8000000; + else + cpu_isa_speed = cpu_busspeed; cpu_log("cpu_set_isa_speed(%d) = %d\n", speed, cpu_isa_speed); } @@ -3069,5 +3073,6 @@ cpu_update_waitstates(void) cpu_mem_prefetch_cycles = cpu_prefetch_cycles; - cpu_rom_prefetch_cycles = (cpu_rom_read_cycles * cpu_s->rspeed * rom_read_timing_ns + 999999999ULL) / 1000000000ULL; + if (cpu_s->rspeed <= 8000000) + cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; } From 756e1dfc83ddaeba3118a628485d3f87f7c15c96 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 May 2021 00:30:56 -0300 Subject: [PATCH 07/59] Fix quaternary IDE PnP ROM --- src/disk/hdc_ide.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index d8bbb9762..6953bda83 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -168,8 +168,8 @@ static uint8_t ide_qua_pnp_rom[] = { 0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x01, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */ 0x30, /* start dependent functions, acceptable */ 0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */ - 0x47, 0x01, 0x68, 0x01, 0x68, 0x01, 0x01, 0x08, /* I/O 0x168, decodes 16-bit, 1-byte alignment, 8 addresses */ - 0x47, 0x01, 0x6e, 0x03, 0x6e, 0x03, 0x01, 0x01, /* I/O 0x36E, decodes 16-bit, 1-byte alignment, 1 address */ + 0x47, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x01, 0x08, /* I/O 0x1E8, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x01, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */ 0x30, /* start dependent functions, acceptable */ 0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */ 0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ From 1ba56e268198aa3ffda190c3aefb19adc1528c4c Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 19 May 2021 00:46:15 -0300 Subject: [PATCH 08/59] Crystal CS4237, part 1 --- src/include/86box/snd_ad1848.h | 1 + src/include/86box/snd_sb.h | 3 + src/include/86box/sound.h | 6 +- src/sound/snd_ad1848.c | 20 +- src/sound/snd_cs423x.c | 467 +++++++++++++++++++++++++++++++++ src/sound/snd_sb.c | 36 +++ src/sound/sound.c | 1 + src/win/Makefile.mingw | 2 +- 8 files changed, 529 insertions(+), 7 deletions(-) create mode 100644 src/sound/snd_cs423x.c diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index b6782c139..a25e46951 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -1,6 +1,7 @@ #define AD1848_TYPE_DEFAULT 0 #define AD1848_TYPE_CS4248 1 #define AD1848_TYPE_CS4231 2 +#define AD1848_TYPE_CS4236 3 typedef struct ad1848_t { diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index 3bb2a6496..8195345df 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -134,6 +134,9 @@ extern void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p); extern uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p); extern void sb_ct1345_mixer_reset(sb_t* sb); +extern uint8_t sb_pro_v1_opl_read(uint16_t port, void *priv); +extern void sb_pro_v1_opl_write(uint16_t port, uint8_t val, void *priv); + extern void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p); extern void sbpro_filter_cd_audio(int channel, double *buffer, void *p); extern void sb_close(void *p); diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index 00ce1fb95..af10917e0 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -99,7 +99,7 @@ extern const device_t gus_device; extern const device_t pas16_device; #endif -/* PSSJ - What is this device? */ +/* Tandy PSSJ */ extern const device_t pssj_device; /* Creative Labs Sound Blaster */ @@ -110,6 +110,7 @@ extern const device_t sb_2_device; extern const device_t sb_pro_v1_device; extern const device_t sb_pro_v2_device; extern const device_t sb_pro_mcv_device; +extern const device_t sb_pro_cs423x_device; extern const device_t sb_16_device; extern const device_t sb_16_pnp_device; extern const device_t sb_32_pnp_device; @@ -122,6 +123,9 @@ extern const device_t ssi2001_device; /* Windows Sound System */ extern const device_t wss_device; extern const device_t ncr_business_audio_device; + +/* Crystal CS423x */ +extern const device_t cs4237b_device; #endif #endif /*EMU_SOUND_H*/ diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index fc859f8cc..c45d69063 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -14,6 +14,7 @@ #include <86box/snd_ad1848.h> #define CS4231 0x80 +#define CS4236 0x03 static int ad1848_vols_6bits[64]; static double ad1848_vols_5bits_aux_gain[32]; @@ -59,7 +60,7 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) switch (addr & 3) { case 0: /*Index*/ - if ((ad1848->regs[12] & 0x40) && (ad1848->type == AD1848_TYPE_CS4231)) + if ((ad1848->regs[12] & 0x40) && (ad1848->type >= AD1848_TYPE_CS4231)) ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ else ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ @@ -247,15 +248,14 @@ void ad1848_init(ad1848_t *ad1848, int type) ad1848->regs[8] = 0; ad1848->regs[9] = 0x08; ad1848->regs[10] = ad1848->regs[11] = 0; - if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231)) + if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231) || (type == AD1848_TYPE_CS4236)) ad1848->regs[12] = 0x8a; else ad1848->regs[12] = 0xa; ad1848->regs[13] = 0; ad1848->regs[14] = ad1848->regs[15] = 0; - if (type == AD1848_TYPE_CS4231) - { + if (type == AD1848_TYPE_CS4231) { ad1848->regs[16] = ad1848->regs[17] = 0; ad1848->regs[18] = ad1848->regs[19] = 0x88; ad1848->regs[22] = 0x80; @@ -263,7 +263,17 @@ void ad1848_init(ad1848_t *ad1848, int type) ad1848->regs[25] = CS4231; ad1848->regs[26] = 0x80; ad1848->regs[29] = 0x80; - } + } else if (type == AD1848_TYPE_CS4236) { + ad1848->regs[16] = ad1848->regs[17] = 0; + ad1848->regs[18] = ad1848->regs[19] = 0; + ad1848->regs[20] = ad1848->regs[21] = 0; + ad1848->regs[22] = ad1848->regs[23] = 0; + ad1848->regs[24] = 0; + ad1848->regs[25] = CS4236; + ad1848->regs[26] = 0xa0; + ad1848->regs[27] = ad1848->regs[29] = 0; + ad1848->regs[30] = ad1848->regs[31] = 0; + } ad1848->out_l = 0; ad1848->out_r = 0; diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c new file mode 100644 index 000000000..6456d5a8d --- /dev/null +++ b/src/sound/snd_cs423x.c @@ -0,0 +1,467 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Crystal CS423x (SBPro/WSS compatible sound chips) emulation. + * + * + * + * Authors: RichardG, + * + * Copyright 2021 RichardG. + */ +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/pic.h> +#include <86box/dma.h> +#include <86box/device.h> +#include <86box/i2c.h> +#include <86box/isapnp.h> +#include <86box/sound.h> +#include <86box/midi.h> +#include <86box/snd_ad1848.h> +#include <86box/snd_opl.h> +#include <86box/snd_sb.h> + + +enum { + CRYSTAL_CS4237B = 37 +}; + + +static const uint8_t cs4237b_eeprom[384] = { + 0x55, 0xbb, 0x00, 0x00, 0x00, 0x03, 0x80, 0x80, 0x0b, 0x20, 0x04, 0x08, 0x10, 0x80, 0x00, 0x00, 0x00, 0x48, 0x75, 0xb9, 0xfc, 0x10, 0x03, /* CS4237B stuff */ + + 0x0e, 0x63, 0x42, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, /* CSC4237, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x01, /* PnP version 1.0, vendor version 0.1 */ + 0x82, 0x0e, 0x00, 'C', 'r', 'y', 's', 't', 'a', 'l', ' ', 'C', 'o', 'd', 'e' ,'c', 0x00, /* ANSI identifier */ + + 0x15, 0x0e, 0x63, 0x00, 0x00, 0x00, /* logical device CSC0000 */ + 0x82, 0x07, 0x00, 'W', 'S', 'S', '/', 'S', 'B', 0x00, /* ANSI identifier */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x2a, 0x02, 0x28, /* DMA 1, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x2a, 0x09, 0x28, /* DMA 0/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x22, 0x20, 0x00, /* IRQ 5 */ + 0x47, 0x01, 0x34, 0x05, 0x34, 0x05, 0x04, 0x04, /* I/O 0x534, decodes 16-bit, 4-byte alignment, 4 addresses */ + 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x08, 0x04, /* I/O 0x388, decodes 16-bit, 8-byte alignment, 4 addresses */ + 0x47, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x10, /* I/O 0x220, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x2a, 0x0a, 0x28, /* DMA 1/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x2a, 0x0b, 0x28, /* DMA 0/1/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x22, 0xa0, 0x9a, /* IRQ 5/7/9/11/12/15 */ + 0x47, 0x01, 0x34, 0x05, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x534-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */ + 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x08, 0x04, /* I/O 0x388, decodes 16-bit, 8-byte alignment, 4 addresses */ + 0x47, 0x01, 0x20, 0x02, 0x60, 0x02, 0x20, 0x10, /* I/O 0x220-0x260, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x31, 0x02, /* start dependent functions, sub-optimal */ + 0x2a, 0x0b, 0x28, /* DMA 0/1/3, type A, no count by word, count by byte, not bus master, 8-bit only */ + 0x22, 0xa0, 0x9a, /* IRQ 5/7/9/11/12/15 */ + 0x47, 0x01, 0x34, 0x05, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x534-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */ + 0x47, 0x01, 0x88, 0x03, 0xf8, 0x03, 0x08, 0x04, /* I/O 0x388-0x3F8, decodes 16-bit, 8-byte alignment, 4 addresses */ + 0x47, 0x01, 0x20, 0x02, 0x00, 0x03, 0x20, 0x10, /* I/O 0x220-0x300, decodes 16-bit, 32-byte alignment, 16 addresses */ + 0x38, /* end dependent functions */ +#if 0 + 0x15, 0x0e, 0x63, 0x00, 0x01, 0x00, /* logical device CSC0001 */ + 0x82, 0x05, 0x00, 'G', 'A', 'M', 'E', 0x00, /* ANSI identifier */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x200, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x38, /* end dependent functions */ +#endif + 0x15, 0x0e, 0x63, 0x00, 0x10, 0x00, /* logical device CSC0010 */ + 0x82, 0x05, 0x00, 'C', 'T', 'R', 'L', 0x00, /* ANSI identifier */ + 0x47, 0x01, 0x20, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x120-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x0e, 0x63, 0x00, 0x03, 0x00, /* logical device CSC0003 */ + 0x82, 0x04, 0x00, 'M', 'P', 'U', 0x00, /* ANSI identifier */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x22, 0x00, 0x02, /* IRQ 9 */ + 0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x08, 0x02, /* I/O 0x330, decodes 16-bit, 8-byte alignment, 2 addresses */ + 0x31, 0x01, /* start dependent functions, acceptable */ + 0x22, 0x00, 0x9a, /* IRQ 9/11/12/15 */ + 0x47, 0x01, 0x30, 0x03, 0x60, 0x03, 0x08, 0x02, /* I/O 0x330-0x360, decodes 16-bit, 8-byte alignment, 2 addresses */ + 0x31, 0x02, /* start dependent functions, sub-optimal */ + 0x47, 0x01, 0x30, 0x03, 0xe0, 0x03, 0x08, 0x02, /* I/O 0x330-0x3E0, decodes 16-bit, 8-byte alignment, 2 addresses */ + 0x38, /* end dependent functions */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; + + +typedef struct cs423x_t +{ + void *pnp_card; + ad1848_t ad1848; + sb_t *sb; + void *i2c, *eeprom; + + uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size; + uint8_t regs[8], indirect_regs[16], eeprom_data[2048], ram_dl; +} cs423x_t; + + +static uint8_t +cs423x_read(uint16_t port, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t reg = port & 7; + uint8_t ret = dev->regs[reg]; + + switch (reg) { + case 1: /* EEPROM Interface */ + ret &= ~0x04; + if ((dev->regs[1] & 0x04) && i2c_gpio_get_sda(dev->i2c)) + ret |= 0x04; + break; + + case 4: /* Control Indirect Data Register */ + ret = dev->indirect_regs[dev->regs[3]]; + break; + + case 7: /* Global Status */ + ret = 0x00; + if (dev->sb->mpu->state.irq_pending) + ret |= 0x08; + if (dev->ad1848.regs[10] & 2) + ret |= 0x10; + if (dev->sb->dsp.sb_irq8 || dev->sb->dsp.sb_irq16 || dev->sb->dsp.sb_irq401) + ret |= 0x20; + } + + return ret; +} + + +static void +cs423x_write(uint16_t port, uint8_t val, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t reg = port & 7; + + switch (reg) { + case 1: /* EEPROM Interface */ + if (val & 0x04) + i2c_gpio_set(dev->i2c, val & 0x01, val & 0x02); + break; + + case 3: /* Control Indirect Access Register */ + val &= 0x0f; + break; + + case 4: /* Control Indirect Data Register */ + switch (dev->regs[3] & 15) { + case 0: /* WSS Master Control */ + if (val & 0x80) + ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); + val = 0x00; + break; + + case 1: /* Version / Chip ID */ + case 7: /* Reserved */ + case 9 ... 15: /* unspecified */ + return; + + case 3: /* 3D Enable */ + val &= 0xe0; + break; + + case 4: /* Consumer Serial Port Enable */ + val &= 0xf0; + break; + + case 5: /* Lower Channel Status */ + val &= 0xfe; + break; + + case 8: /* CS9236 Wavetable Control */ + val &= 0xf0; + break; + } + dev->indirect_regs[dev->regs[3]] = val; + break; + + case 5: /* Control/RAM Access */ + switch (dev->ram_dl) { + case 0: /* commands */ + switch (val) { + case 0x55: /* Disable PnP Key */ + isapnp_enable_card(dev->pnp_card, 0); + break; + + /* TODO: Crystal's PnP bypass method? */ + + case 0xaa: /* Download RAM */ + dev->ram_dl = 1; + break; + } + break; + + case 1: /* low address byte */ + dev->ram_addr = val; + dev->ram_dl++; + break; + + case 2: /* high address byte */ + dev->ram_addr |= (val << 8); + dev->ram_dl++; + break; + + case 3: /* data */ + /* The only documented RAM region is 0x4000 (384 bytes in size), for + loading the chip's configuration and PnP ROM without an EEPROM. */ + if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) + dev->eeprom_data[dev->ram_addr - 0x3ffc] = val; /* skip first 4 bytes (EEPROM header) */ + dev->ram_addr++; + break; + } + break; + + case 6: /* RAM Access End */ + if (!val) + dev->ram_dl = 0; + break; + + case 7: /* Global Status */ + return; + } + + dev->regs[reg] = val; +} + + +static uint8_t +cs423x_ctxswitch_read(uint16_t addr, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t prev_context = dev->regs[7] & 0x80, switched = 0; + + /* Determine the active context (WSS or SBPro) through the address being read/written. */ + if ((prev_context == 0x80) && ((addr & 0xfff0) == dev->sb_base)) { + dev->regs[7] &= ~0x80; + switched = 1; + } else if ((prev_context == 0x00) && ((addr & 0xfffc) == dev->wss_base)) { + dev->regs[7] |= 0x80; + switched = 1; + } + + /* Fire the context switch interrupt if enabled. */ + if (switched && (dev->regs[0] & 0x20) && dev->ad1848.irq) + picint(1 << dev->ad1848.irq); + + return 0xff; /* don't interfere with the actual handlers */ +} + + +static void +cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) +{ + cs423x_ctxswitch_read(addr, priv); +} + + +static void +cs423x_get_buffer(int32_t *buffer, int len, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + int c; + + /* Output audio from the WSS codec. SBPro and OPL3 are + already handled by the Sound Blaster emulation. */ + ad1848_update(&dev->ad1848); + + for (c = 0; c < len * 2; c++) { + buffer[c] += (dev->ad1848.buffer[c] / 2); + } + + dev->ad1848.pos = 0; +} + + +static void +cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + switch (ld) { + case 0: /* WSS, OPL3 and SBPro */ + if (dev->wss_base) { + io_removehandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848); + io_removehandler(dev->wss_base, 4, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + dev->wss_base = 0; + } + + if (dev->opl_base) { + io_removehandler(dev->opl_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + dev->opl_base = 0; + } + + if (dev->sb_base) { + sb_dsp_setaddr(&dev->sb->dsp, 0); + io_removehandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_removehandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_removehandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); + io_removehandler(dev->sb_base, 16, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + dev->sb_base = 0; + } + + ad1848_setirq(&dev->ad1848, 0); + sb_dsp_setirq(&dev->sb->dsp, 0); + + ad1848_setdma(&dev->ad1848, 0); + sb_dsp_setdma8(&dev->sb->dsp, 0); + + if (config->activate) { + if (config->io[0].base != ISAPNP_IO_DISABLED) { + dev->wss_base = config->io[0].base; + io_sethandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848); + io_sethandler(dev->wss_base, 4, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + } + + if (config->io[1].base != ISAPNP_IO_DISABLED) { + dev->opl_base = config->io[1].base; + io_sethandler(dev->opl_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + } + + if (config->io[2].base != ISAPNP_IO_DISABLED) { + dev->sb_base = config->io[2].base; + sb_dsp_setaddr(&dev->sb->dsp, dev->sb_base); + io_sethandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_sethandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); + io_sethandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); + io_sethandler(dev->sb_base, 16, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + } + + if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) { + ad1848_setirq(&dev->ad1848, config->irq[0].irq); + sb_dsp_setirq(&dev->sb->dsp, config->irq[0].irq); + } + + if (config->dma[0].dma != ISAPNP_DMA_DISABLED) { + ad1848_setdma(&dev->ad1848, config->dma[0].dma); + sb_dsp_setdma8(&dev->sb->dsp, config->dma[0].dma); + } + } + + break; + +#if 0 + case 1: /* Game Port */ + gameport_remap(0); + + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) + gameport_remap(config->io[0].base); + + break; +#endif + + case 1: /* Control Registers */ + if (dev->ctrl_base) { + io_removehandler(dev->ctrl_base, 8, cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, dev); + dev->ctrl_base = 0; + } + + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { + dev->ctrl_base = config->io[0].base; + io_sethandler(dev->ctrl_base, 8, cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, dev); + } + + break; + + case 2: /* MPU-401 */ + mpu401_change_addr(dev->sb->mpu, 0); + mpu401_setirq(dev->sb->mpu, 0); + + if (config->activate) { + if (config->io[0].base != ISAPNP_IO_DISABLED) + mpu401_change_addr(dev->sb->mpu, config->io[0].base); + + if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) + mpu401_setirq(dev->sb->mpu, config->irq[0].irq); + } + + break; + } +} + + +static void * +cs423x_init(const device_t *info) +{ + cs423x_t *dev = malloc(sizeof(cs423x_t)); + memset(dev, 0, sizeof(cs423x_t)); + + dev->indirect_regs[1] = 0x88; + + switch (info->local) { + case CRYSTAL_CS4237B: + dev->eeprom_size = sizeof(cs4237b_eeprom); + memcpy(dev->eeprom_data, cs4237b_eeprom, dev->eeprom_size); + break; + } + + dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); + + ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); + + sound_add_handler(cs423x_get_buffer, dev); + + dev->i2c = i2c_gpio_init("nvr_cs423x"); + + if (dev->eeprom_size) { + dev->eeprom_data[2] = dev->eeprom_size >> 8; + dev->eeprom_data[3] = dev->eeprom_size & 0xff; + + dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->eeprom_data, sizeof(dev->eeprom_data), 1); + } + + dev->pnp_card = isapnp_add_card(&dev->eeprom_data[23], dev->eeprom_size - 23, cs423x_pnp_config_changed, NULL, NULL, NULL, dev); + + return dev; +} + + +static void +cs423x_close(void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + if (dev->eeprom) + i2c_eeprom_close(dev->eeprom); + + i2c_gpio_close(dev->i2c); + + free(dev); +} + + +static void +cs423x_speed_changed(void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + ad1848_speed_changed(&dev->ad1848); +} + + +const device_t cs4237b_device = +{ + "Crystal CS4237B", + DEVICE_ISA | DEVICE_AT, + CRYSTAL_CS4237B, + cs423x_init, cs423x_close, NULL, + { NULL }, + cs423x_speed_changed, + NULL, + NULL +}; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 2dc147285..bc08c2956 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1602,6 +1602,31 @@ sb_pro_mcv_init(const device_t *info) } +static void * +sb_pro_cs423x_init(const device_t *info) +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = 1; + opl3_init(&sb->opl); + + sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); + sb_ct1345_mixer_reset(sb); + + sb->mixer_enabled = 1; + sound_add_handler(sb_get_buffer_sbpro, sb); + sound_set_cd_audio_filter(sbpro_filter_cd_audio, sb); + + sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); + memset(sb->mpu, 0, sizeof(mpu_t)); + mpu401_init(sb->mpu, 0, 0, M_UART, 1); + sb_dsp_set_mpu(&sb->dsp, sb->mpu); + + return sb; +} + + static void * sb_16_init(const device_t *info) { @@ -2483,6 +2508,17 @@ const device_t sb_pro_mcv_device = NULL }; +const device_t sb_pro_cs423x_device = +{ + "Crystal CS423x Sound Blaster Pro compatibility", + DEVICE_ISA | DEVICE_AT, + 0, + sb_pro_cs423x_init, sb_close, NULL, { NULL }, + sb_speed_changed, + NULL, + NULL +}; + const device_t sb_16_device = { "Sound Blaster 16", diff --git a/src/sound/sound.c b/src/sound/sound.c index 16e092c01..39a3a44b6 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -88,6 +88,7 @@ static const SOUND_CARD sound_cards[] = { "adlibgold", &adgold_device }, { "azt2316a", &azt2316a_device }, { "azt1605", &azt1605_device }, + { "cs4237b", &cs4237b_device }, { "sb", &sb_1_device }, { "sb1.5", &sb_15_device }, { "sb2.0", &sb_2_device }, diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index fb1a320d4..79ee75f06 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -724,7 +724,7 @@ SNDOBJ := sound.o \ snd_pssj.o \ snd_lpt_dac.o snd_lpt_dss.o \ snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ - snd_azt2316a.o \ + snd_azt2316a.o snd_cs423x.o \ snd_cms.o \ snd_gus.o \ snd_sb.o snd_sb_dsp.o \ From 1de2e3dd2fb95c7084071bb8bb1080e209685583 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 20 May 2021 00:30:12 -0300 Subject: [PATCH 09/59] Crystal CS4237, part 2 --- src/device/isapnp.c | 40 ++++-- src/include/86box/isapnp.h | 8 ++ src/include/86box/snd_sb.h | 3 - src/sio/sio_um8669f.c | 4 +- src/sound/snd_cs423x.c | 284 ++++++++++++++++++++++++++++++++----- 5 files changed, 283 insertions(+), 56 deletions(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index f611a18ae..e08e2d300 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -478,9 +478,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) isapnp_log("ISAPnP: Reset CSN\n"); card = dev->first_card; while (card) { - card->csn = 0; - if (card->csn_changed) - card->csn_changed(card->csn, card->priv); + isapnp_set_csn(card, 0); card = card->next; } } @@ -506,9 +504,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) case 0x06: /* Card Select Number */ if (dev->isolated_card) { isapnp_log("ISAPnP: Set CSN %02X\n", val); - dev->isolated_card->csn = val; - if (dev->isolated_card->csn_changed) - dev->isolated_card->csn_changed(dev->isolated_card->csn, dev->isolated_card->priv); + isapnp_set_csn(dev->isolated_card, val); dev->isolated_card->state = PNP_STATE_CONFIG; dev->isolated_card = NULL; } else { @@ -685,8 +681,6 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, memset(card, 0, sizeof(isapnp_card_t)); card->enable = 1; - card->rom = rom; - card->rom_size = rom_size; card->priv = priv; card->config_changed = config_changed; card->csn_changed = csn_changed; @@ -702,6 +696,18 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, prev_card->next = card; } + isapnp_update_card_rom(card, rom, rom_size); + return card; +} + + +void +isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) +{ + isapnp_card_t *card = (isapnp_card_t *) priv; + card->rom = rom; + card->rom_size = rom_size; + /* Parse resources in ROM to allocate logical devices, and determine the state of read-only register bits. */ #ifdef ENABLE_ISAPNP_LOG @@ -712,8 +718,16 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, uint8_t ldn = 0, res, in_df = 0; uint8_t irq = 0, io = 0, mem_range = 0, mem_range_32 = 0, irq_df = 0, io_df = 0, mem_range_df = 0, mem_range_32_df = 0; uint32_t len; - isapnp_device_t *ld = NULL, *prev_ld = NULL; + isapnp_device_t *ld = card->first_ld, *prev_ld = NULL; + /* Clear any existing logical devices. */ + while (ld) { + prev_ld = ld->next; + free(ld); + ld = prev_ld; + } + + /* Iterate through ROM resources. */ while (i < card->rom_size) { if (card->rom[i] & 0x80) { /* large resource */ res = card->rom[i] & 0x7f; @@ -890,8 +904,6 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, /* We're done with the last logical device. */ if (ld) isapnp_reset_ld_regs(ld); - - return card; } @@ -907,10 +919,8 @@ isapnp_enable_card(void *priv, uint8_t enable) while (card) { if (card == priv) { /* Enable or disable the card. */ - card->enable = !!enable; - - /* enable=2 is a cheat code to jump straight into CONFIG state. */ - card->state = (enable == 2) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY; + card->enable = (enable >= ISAPNP_CARD_ENABLE); + card->state = (enable == ISAPNP_CARD_FORCE_CONFIG) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY; /* Invalidate other references if we're disabling this card. */ if (!card->enable) { diff --git a/src/include/86box/isapnp.h b/src/include/86box/isapnp.h index d241d74f3..38fc59d07 100644 --- a/src/include/86box/isapnp.h +++ b/src/include/86box/isapnp.h @@ -25,6 +25,13 @@ #define ISAPNP_DMA_DISABLED 4 +enum { + ISAPNP_CARD_DISABLE = 0, + ISAPNP_CARD_ENABLE = 1, + ISAPNP_CARD_FORCE_CONFIG /* cheat code for UMC UM8669F */ +}; + + typedef struct { uint8_t activate; struct { @@ -51,6 +58,7 @@ void *isapnp_add_card(uint8_t *rom, uint16_t rom_size, uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv), void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv), void *priv); +void isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size); void isapnp_enable_card(void *priv, uint8_t enable); void isapnp_set_csn(void *priv, uint8_t csn); void isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config); diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index 8195345df..3bb2a6496 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -134,9 +134,6 @@ extern void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p); extern uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p); extern void sb_ct1345_mixer_reset(sb_t* sb); -extern uint8_t sb_pro_v1_opl_read(uint16_t port, void *priv); -extern void sb_pro_v1_opl_write(uint16_t port, uint8_t val, void *priv); - extern void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p); extern void sbpro_filter_cd_audio(int channel, double *buffer, void *p); extern void sb_close(void *p); diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index 2cfff686c..4a6869a02 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -39,7 +39,7 @@ #include <86box/isapnp.h> -/* This ROM is reconstructed out of the several assumptions, some of which are based on the IT8671F. */ +/* This ROM is reconstructed out of several assumptions, some of which are based on the IT8671F. */ static uint8_t um8669f_pnp_rom[] = { 0x55, 0xa3, 0x86, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, /* UMC8669, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ @@ -211,7 +211,7 @@ um8669f_write(uint16_t port, uint8_t val, void *priv) if (dev->cur_reg_108 == 0xc1) { um8669f_log("UM8669F: ISAPnP %sabled\n", (val & 0x80) ? "en" : "dis"); - isapnp_enable_card(dev->pnp_card, (val & 0x80) ? 2 : 0); + isapnp_enable_card(dev->pnp_card, (val & 0x80) ? ISAPNP_CARD_FORCE_CONFIG : ISAPNP_CARD_DISABLE); } } } diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 6456d5a8d..88f15c49c 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -36,13 +36,35 @@ enum { - CRYSTAL_CS4237B = 37 + CRYSTAL_CS4237B = 0xc8 +}; +enum { + CRYSTAL_SLAM_NONE = 0, + CRYSTAL_SLAM_INDEX, + CRYSTAL_SLAM_BYTE1, + CRYSTAL_SLAM_BYTE2 }; -static const uint8_t cs4237b_eeprom[384] = { - 0x55, 0xbb, 0x00, 0x00, 0x00, 0x03, 0x80, 0x80, 0x0b, 0x20, 0x04, 0x08, 0x10, 0x80, 0x00, 0x00, 0x00, 0x48, 0x75, 0xb9, 0xfc, 0x10, 0x03, /* CS4237B stuff */ +static const uint8_t slam_init_key[32] = { 0x96, 0x35, 0x9A, 0xCD, 0xE6, 0xF3, 0x79, 0xBC, + 0x5E, 0xAF, 0x57, 0x2B, 0x15, 0x8A, 0xC5, 0xE2, + 0xF1, 0xF8, 0x7C, 0x3E, 0x9F, 0x4F, 0x27, 0x13, + 0x09, 0x84, 0x42, 0xA1, 0xD0, 0x68, 0x34, 0x1A }; +static const uint8_t cs4237b_eeprom[] = { + /* CS4237B configuration */ + 0x55, 0xbb, /* magic */ + 0x00, 0x00, /* length */ + 0x00, 0x03, /* CD-ROM and modem decode */ + 0x80, /* misc. config */ + 0x80, /* global config */ + 0x0b, /* chip ID */ + 0x20, 0x04, 0x08, 0x10, 0x80, 0x00, 0x00, /* reserved */ + 0x00, /* external decode length */ + 0x48, /* reserved */ + 0x75, 0xb9, 0xfc, /* IRQ routing */ + 0x10, 0x03, /* DMA routing */ + /* PnP resources */ 0x0e, 0x63, 0x42, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, /* CSC4237, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x01, /* PnP version 1.0, vendor version 0.1 */ 0x82, 0x0e, 0x00, 'C', 'r', 'y', 's', 't', 'a', 'l', ' ', 'C', 'o', 'd', 'e' ,'c', 0x00, /* ANSI identifier */ @@ -106,11 +128,19 @@ typedef struct cs423x_t sb_t *sb; void *i2c, *eeprom; - uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size; - uint8_t regs[8], indirect_regs[16], eeprom_data[2048], ram_dl; + uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11; + uint8_t type, regs[8], indirect_regs[16], eeprom_data[2048], ram_dl; + + uint8_t key_pos: 5, enable_slam: 1, slam_state: 2, slam_ld, slam_reg; + isapnp_device_config_t *slam_config; } cs423x_t; +static void cs423x_slam_remap(cs423x_t *dev, uint8_t enable); +static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv); +static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); + + static uint8_t cs423x_read(uint16_t port, void *priv) { @@ -130,12 +160,15 @@ cs423x_read(uint16_t port, void *priv) break; case 7: /* Global Status */ - ret = 0x00; - if (dev->sb->mpu->state.irq_pending) + /* Context switching: take active context and interrupt flag, then clear interrupt flag. */ + ret &= 0xc0; + dev->regs[7] &= 0x80; + + if (dev->sb->mpu->state.irq_pending) /* MPU interrupt */ ret |= 0x08; - if (dev->ad1848.regs[10] & 2) + if (dev->ad1848.regs[10] & 2) /* WSS interrupt */ ret |= 0x10; - if (dev->sb->dsp.sb_irq8 || dev->sb->dsp.sb_irq16 || dev->sb->dsp.sb_irq401) + if (dev->sb->dsp.sb_irq8 || dev->sb->dsp.sb_irq16 || dev->sb->dsp.sb_irq401) /* SBPro interrupt */ ret |= 0x20; } @@ -148,6 +181,7 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) { cs423x_t *dev = (cs423x_t *) priv; uint8_t reg = port & 7; + uint16_t eeprom_addr; switch (reg) { case 1: /* EEPROM Interface */ @@ -199,7 +233,16 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) isapnp_enable_card(dev->pnp_card, 0); break; - /* TODO: Crystal's PnP bypass method? */ + case 0x56: /* Disable Crystal Key */ + cs423x_slam_remap(dev, 0); + break; + + case 0x57: /* Jump to ROM */ + break; + + case 0x5a: /* Update Hardware Configuration Data */ + isapnp_update_card_rom(dev->pnp_card, dev->eeprom_data + 23, dev->eeprom_size - 23); + break; case 0xaa: /* Download RAM */ dev->ram_dl = 1; @@ -220,8 +263,12 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) case 3: /* data */ /* The only documented RAM region is 0x4000 (384 bytes in size), for loading the chip's configuration and PnP ROM without an EEPROM. */ - if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) - dev->eeprom_data[dev->ram_addr - 0x3ffc] = val; /* skip first 4 bytes (EEPROM header) */ + if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) { + eeprom_addr = dev->ram_addr - 0x3ffc; /* skip first 4 bytes (header on real EEPROM) */ + dev->eeprom_data[eeprom_addr] = val; + if (dev->eeprom_size < ++eeprom_addr) /* update EEPROM size if required */ + dev->eeprom_size = eeprom_addr; + } dev->ram_addr++; break; } @@ -240,25 +287,149 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) } +static void +cs423x_slam_write(uint16_t addr, uint8_t val, void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + uint8_t idx; + + switch (dev->slam_state) { + case CRYSTAL_SLAM_NONE: + /* Not in SLAM: read and compare Crystal key. */ + if (val == slam_init_key[dev->key_pos]) { + dev->key_pos++; + /* Was the key successfully written? */ + if (!dev->key_pos) { + /* Discard any pending logical device configuration, just to be safe. */ + if (dev->slam_config) { + free(dev->slam_config); + dev->slam_config = NULL; + } + + /* Enter SLAM. */ + dev->slam_state = CRYSTAL_SLAM_INDEX; + } + } else { + dev->key_pos = 0; + } + break; + + case CRYSTAL_SLAM_INDEX: + /* Write register index. */ + dev->slam_reg = val; + dev->slam_state = CRYSTAL_SLAM_BYTE1; + break; + + case CRYSTAL_SLAM_BYTE1: + case CRYSTAL_SLAM_BYTE2: + /* Write register value: two bytes for I/O ports, single byte otherwise. */ + switch (dev->slam_reg) { + case 0x06: /* Card Select Number */ + isapnp_set_csn(dev->pnp_card, val); + break; + + case 0x15: /* Logical Device ID */ + /* Apply the previous logical device's configuration, and reuse its config structure. */ + if (dev->slam_config) + cs423x_pnp_config_changed(dev->slam_ld, dev->slam_config, dev); + else + dev->slam_config = (isapnp_device_config_t *) malloc(sizeof(isapnp_device_config_t)); + + /* Start new logical device. */ + memset(dev->slam_config, 0, sizeof(isapnp_device_config_t)); + dev->slam_ld = val; + break; + + case 0x47: /* I/O Port Base Address 0 */ + case 0x48: /* I/O Port Base Address 1 */ + case 0x42: /* I/O Port Base Address 2 */ + idx = (dev->slam_reg == 0x42) ? 2 : (dev->slam_reg - 0x47); + if (dev->slam_state == CRYSTAL_SLAM_BYTE1) { + /* Set high byte, or ignore it if no logical device is selected. */ + if (dev->slam_config) + dev->slam_config->io[idx].base = val << 8; + + /* Prepare for the second (low byte) write. */ + dev->slam_state = CRYSTAL_SLAM_BYTE2; + return; + } else if (dev->slam_config) { + /* Set low byte, or ignore it if no logical device is selected. */ + dev->slam_config->io[idx].base |= val; + } + break; + + case 0x22: /* Interrupt Select 0 */ + case 0x27: /* Interrupt Select 1 */ + /* Stop if no logical device is selected. */ + if (!dev->slam_config) + break; + + /* Set IRQ value. */ + idx = (dev->slam_reg == 0x22) ? 0 : 1; + dev->slam_config->irq[idx].irq = val & 15; + break; + + case 0x2a: /* DMA Select 0 */ + case 0x25: /* DMA Select 1 */ + /* Stop if no logical device is selected. */ + if (!dev->slam_config) + break; + + /* Set DMA value. */ + idx = (dev->slam_reg == 0x2a) ? 0 : 1; + dev->slam_config->dma[idx].dma = val & 7; + break; + + case 0x33: /* Activate Device */ + /* Stop if no logical device is selected. */ + if (!dev->slam_config) + break; + + /* Activate or deactivate the device. */ + dev->slam_config->activate = val & 0x01; + break; + + case 0x79: /* activate chip */ + /* Apply the last logical device's configuration. */ + if (dev->slam_config) { + cs423x_pnp_config_changed(dev->slam_ld, dev->slam_config, dev); + free(dev->slam_config); + dev->slam_config = NULL; + } + + /* Exit out of SLAM. */ + dev->slam_state = CRYSTAL_SLAM_NONE; + break; + } + + /* Prepare for the next register, unless a two-byte read returns above. */ + dev->slam_state = CRYSTAL_SLAM_INDEX; + break; + } +} + + +static void +cs423x_slam_remap(cs423x_t *dev, uint8_t enable) +{ + /* Disable SLAM. */ + if (dev->enable_slam) { + dev->enable_slam = 0; + io_removehandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); + } + + /* Enable SLAM if not blocked by EEPROM configuration. */ + if (enable && !(dev->eeprom_data[7] & 0x10)) { + dev->enable_slam = 1; + io_sethandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); + } +} + + static uint8_t cs423x_ctxswitch_read(uint16_t addr, void *priv) { - cs423x_t *dev = (cs423x_t *) priv; - uint8_t prev_context = dev->regs[7] & 0x80, switched = 0; - - /* Determine the active context (WSS or SBPro) through the address being read/written. */ - if ((prev_context == 0x80) && ((addr & 0xfff0) == dev->sb_base)) { - dev->regs[7] &= ~0x80; - switched = 1; - } else if ((prev_context == 0x00) && ((addr & 0xfffc) == dev->wss_base)) { - dev->regs[7] |= 0x80; - switched = 1; - } - - /* Fire the context switch interrupt if enabled. */ - if (switched && (dev->regs[0] & 0x20) && dev->ad1848.irq) - picint(1 << dev->ad1848.irq); - + cs423x_ctxswitch_write(addr, 0, priv); return 0xff; /* don't interfere with the actual handlers */ } @@ -266,7 +437,23 @@ cs423x_ctxswitch_read(uint16_t addr, void *priv) static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) { - cs423x_ctxswitch_read(addr, priv); + cs423x_t *dev = (cs423x_t *) priv; + uint8_t prev_context = dev->regs[7] & 0x80, switched = 0; + + /* Determine the active context (WSS or SBPro) through the address being read/written. */ + if ((prev_context == 0x80) && ((addr & 0xfff0) == dev->sb_base)) { + dev->regs[7] &= ~0x80; + switched = 1; + } else if ((prev_context == 0x00) && ((addr & 0xfffc) == dev->wss_base)) { + dev->regs[7] |= 0x80; + switched = 1; + } + + /* Fire the context switch interrupt if enabled. */ + if (switched && (dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) { + dev->regs[7] |= 0x40; /* set interrupt flag */ + picint(1 << dev->ad1848.irq); /* control device shares its IRQ with WSS and SBPro */ + } } @@ -395,37 +582,62 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv } +static void +cs423x_reset(void *priv) +{ + cs423x_t *dev = (cs423x_t *) priv; + + /* Reset registers. */ + memset(dev->indirect_regs, 0, sizeof(dev->indirect_regs)); + dev->indirect_regs[1] = dev->type; + + /* Reset logical devices. */ + for (uint8_t i = 0; i < 6; i++) + isapnp_reset_device(dev->pnp_card, i); + + /* Enable SLAM. */ + cs423x_slam_remap(dev, 1); +} + + static void * cs423x_init(const device_t *info) { cs423x_t *dev = malloc(sizeof(cs423x_t)); memset(dev, 0, sizeof(cs423x_t)); - dev->indirect_regs[1] = 0x88; - - switch (info->local) { + dev->type = info->local; + switch (dev->type) { case CRYSTAL_CS4237B: dev->eeprom_size = sizeof(cs4237b_eeprom); memcpy(dev->eeprom_data, cs4237b_eeprom, dev->eeprom_size); break; } + /* Initialize codecs. */ dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); - - ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); - + ad1848_init(&dev->ad1848, AD1848_TYPE_CS4236); sound_add_handler(cs423x_get_buffer, dev); + /* Initialize I2C bus for the EEPROM. */ dev->i2c = i2c_gpio_init("nvr_cs423x"); if (dev->eeprom_size) { + /* Set EEPROM length. */ dev->eeprom_data[2] = dev->eeprom_size >> 8; dev->eeprom_data[3] = dev->eeprom_size & 0xff; + /* Initialize I2C EEPROM. */ dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->eeprom_data, sizeof(dev->eeprom_data), 1); } + /* Initialize ISAPnP. */ dev->pnp_card = isapnp_add_card(&dev->eeprom_data[23], dev->eeprom_size - 23, cs423x_pnp_config_changed, NULL, NULL, NULL, dev); + if (dev->eeprom_data[7] & 0x20) /* hide PnP card if PKD is set */ + isapnp_enable_card(dev->pnp_card, 0); + + /* Initialize registers. */ + cs423x_reset(dev); return dev; } @@ -459,7 +671,7 @@ const device_t cs4237b_device = "Crystal CS4237B", DEVICE_ISA | DEVICE_AT, CRYSTAL_CS4237B, - cs423x_init, cs423x_close, NULL, + cs423x_init, cs423x_close, cs423x_reset, { NULL }, cs423x_speed_changed, NULL, From 77f311b179fe3d1646a8efc3c708b17eda29f5ba Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 20 May 2021 22:51:55 -0300 Subject: [PATCH 10/59] Game port overhaul --- src/game/gameport.c | 335 +++++++++++++++++++++++------------ src/include/86box/gameport.h | 41 ++--- src/include/86box/snd_sb.h | 1 + src/machine/m_amstrad.c | 3 +- src/machine/m_at.c | 3 +- src/machine/m_ps1.c | 3 +- src/machine/m_tandy.c | 3 +- src/machine/m_xt.c | 3 +- src/machine/m_xt_compaq.c | 3 +- src/machine/m_xt_laserxt.c | 3 +- src/machine/m_xt_olivetti.c | 3 +- src/machine/m_xt_philips.c | 3 +- src/machine/m_xt_xi8088.c | 3 +- src/machine/machine.c | 2 + src/sio/sio_um8669f.c | 21 ++- src/sound/snd_audiopci.c | 6 +- src/sound/snd_sb.c | 150 +++++++++------- 17 files changed, 352 insertions(+), 234 deletions(-) diff --git a/src/game/gameport.c b/src/game/gameport.c index 7df2e7eda..d7f399ab3 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Implementation of a generic Game Port. * @@ -12,27 +12,11 @@ * * Authors: Miran Grca, * Sarah Walker, + * RichardG, * * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. + * Copyright 2021 RichardG. */ #include #include @@ -45,6 +29,7 @@ #include <86box/device.h> #include <86box/io.h> #include <86box/timer.h> +#include <86box/isapnp.h> #include <86box/gameport.h> #include <86box/joystick_ch_flightstick_pro.h> #include <86box/joystick_standard.h> @@ -55,21 +40,25 @@ typedef struct { pc_timer_t timer; int axis_nr; - struct _gameport_ *gameport; + struct _joystick_instance_ *joystick; } g_axis_t; typedef struct _gameport_ { - uint8_t state; uint16_t addr; - - g_axis_t axis[4]; - - const joystick_if_t *joystick; - void *joystick_dat; + struct _joystick_instance_ *joystick; + struct _gameport_ *next; } gameport_t; +typedef struct _joystick_instance_ { + uint8_t state; + g_axis_t axis[4]; -int joystick_type = 0; + const joystick_if_t *intf; + void *dat; +} joystick_instance_t; + + +int joystick_type = 1; static const joystick_if_t joystick_none = { @@ -101,22 +90,54 @@ static const struct { { "thrustmaster_fcs", &joystick_tm_fcs }, { "", NULL } }; -static gameport_t *gameport_global = NULL; +static joystick_instance_t *joystick_instance = NULL; + + +static uint8_t gameport_pnp_rom[] = { + 0x09, 0xf8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, /* BOX0002, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ + 0x82, 0x09, 0x00, 'G', 'a', 'm', 'e', ' ', 'P', 'o', 'r', 't', /* ANSI identifier */ + + 0x15, 0x09, 0xf8, 0x00, 0x02, 0x01, /* logical device BOX0002, can participate in boot */ + 0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */ + 0x31, 0x00, /* start dependent functions, preferred */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x200, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x30, /* start dependent functions, acceptable */ + 0x47, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x31, 0x02, /* start dependent functions, sub-optimal */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x38, /* end dependent functions */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ +}; +static const isapnp_device_config_t gameport_pnp_defaults[] = { + { + .activate = 1, + .io = { { .base = 0x200 }, } + } +}; + + +const device_t *standalone_gameport_type; +static int gameport_instance_id = 0; +/* Linked list of active game ports. Only the top port responds to reads + or writes, and ports at the standard 200h location are prioritized. */ +static gameport_t *active_gameports = NULL; char * joystick_get_name(int js) { - if (! joysticks[js].joystick) - return(NULL); - return((char *)joysticks[js].joystick->name); + if (!joysticks[js].joystick) + return NULL; + return (char *) joysticks[js].joystick->name; } char * joystick_get_internal_name(int js) { - return((char *) joysticks[js].internal_name); + return (char *) joysticks[js].internal_name; } @@ -125,8 +146,7 @@ joystick_get_from_internal_name(char *s) { int c = 0; - while (strlen((char *) joysticks[c].internal_name)) - { + while (strlen((char *) joysticks[c].internal_name)) { if (!strcmp((char *) joysticks[c].internal_name, s)) return c; c++; @@ -139,62 +159,63 @@ joystick_get_from_internal_name(char *s) int joystick_get_max_joysticks(int js) { - return(joysticks[js].joystick->max_joysticks); + return joysticks[js].joystick->max_joysticks; } int joystick_get_axis_count(int js) { - return(joysticks[js].joystick->axis_count); + return joysticks[js].joystick->axis_count; } int joystick_get_button_count(int js) { - return(joysticks[js].joystick->button_count); + return joysticks[js].joystick->button_count; } int joystick_get_pov_count(int js) { - return(joysticks[js].joystick->pov_count); + return joysticks[js].joystick->pov_count; } char * joystick_get_axis_name(int js, int id) { - return((char *)joysticks[js].joystick->axis_names[id]); + return (char *) joysticks[js].joystick->axis_names[id]; } char * joystick_get_button_name(int js, int id) { - return((char *)joysticks[js].joystick->button_names[id]); + return (char *) joysticks[js].joystick->button_names[id]; } char * joystick_get_pov_name(int js, int id) { - return (char *)joysticks[js].joystick->pov_names[id]; + return (char *) joysticks[js].joystick->pov_names[id]; } static void -gameport_time(gameport_t *gameport, int nr, int axis) +gameport_time(joystick_instance_t *joystick, int nr, int axis) { if (axis == AXIS_NOT_PRESENT) - timer_disable(&gameport->axis[nr].timer); + timer_disable(&joystick->axis[nr].timer); else { + /* Convert axis value to 555 timing. */ axis += 32768; - axis = (axis * 100) / 65; /*Axis now in ohms*/ + axis = (axis * 100) / 65; /* axis now in ohms */ axis = (axis * 11) / 1000; - timer_set_delay_u64(&gameport->axis[nr].timer, TIMER_USEC * (axis + 24)); /*max = 11.115 ms*/ + timer_set_delay_u64(&joystick->axis[nr].timer, TIMER_USEC * (axis + 24)); /* max = 11.115 ms */ } } @@ -202,16 +223,23 @@ gameport_time(gameport_t *gameport, int nr, int axis) static void gameport_write(uint16_t addr, uint8_t val, void *priv) { - gameport_t *p = (gameport_t *)priv; + gameport_t *dev = (gameport_t *) priv; + joystick_instance_t *joystick = dev->joystick; - p->state |= 0x0f; + /* Respond only if a joystick is present and this port is at the top of the active ports list. */ + if (!joystick || (active_gameports != dev)) + return; - gameport_time(p, 0, p->joystick->read_axis(p->joystick_dat, 0)); - gameport_time(p, 1, p->joystick->read_axis(p->joystick_dat, 1)); - gameport_time(p, 2, p->joystick->read_axis(p->joystick_dat, 2)); - gameport_time(p, 3, p->joystick->read_axis(p->joystick_dat, 3)); - - p->joystick->write(p->joystick_dat); + /* Read all axes. */ + joystick->state |= 0x0f; + + gameport_time(joystick, 0, joystick->intf->read_axis(joystick->dat, 0)); + gameport_time(joystick, 1, joystick->intf->read_axis(joystick->dat, 1)); + gameport_time(joystick, 2, joystick->intf->read_axis(joystick->dat, 2)); + gameport_time(joystick, 3, joystick->intf->read_axis(joystick->dat, 3)); + + /* Notify the interface. */ + joystick->intf->write(joystick->dat); cycles -= ISA_CYCLES(8); } @@ -220,114 +248,184 @@ gameport_write(uint16_t addr, uint8_t val, void *priv) static uint8_t gameport_read(uint16_t addr, void *priv) { - gameport_t *p = (gameport_t *)priv; - uint8_t ret; + gameport_t *dev = (gameport_t *) priv; + joystick_instance_t *joystick = dev->joystick; - ret = p->state | p->joystick->read(p->joystick_dat); + /* Respond only if a joystick is present and this port is at the top of the active ports list. */ + if (!joystick || (active_gameports != dev)) + return 0xff; + + /* Merge axis state with button state. */ + uint8_t ret = joystick->state | joystick->intf->read(joystick->dat); cycles -= ISA_CYCLES(8); - return(ret); + return ret; } static void timer_over(void *priv) { - g_axis_t *axis = (g_axis_t *)priv; - gameport_t *p = axis->gameport; + g_axis_t *axis = (g_axis_t *) priv; - p->state &= ~(1 << axis->axis_nr); + axis->joystick->state &= ~(1 << axis->axis_nr); - if (axis == &p->axis[0]) - p->joystick->a0_over(p->joystick_dat); + if (axis == &axis->joystick->axis[0]) + axis->joystick->intf->a0_over(axis->joystick->dat); } void gameport_update_joystick_type(void) { - gameport_t *p = gameport_global; + /* Add a standalone game port if a joystick is enabled but no other game ports exist. */ + if (standalone_gameport_type) + gameport_add(standalone_gameport_type); - if (p != NULL) { - p->joystick->close(p->joystick_dat); - p->joystick = joysticks[joystick_type].joystick; - p->joystick_dat = p->joystick->init(); + /* Reset the joystick interface. */ + if (joystick_instance) { + joystick_instance->intf->close(joystick_instance->dat); + joystick_instance->intf = joysticks[joystick_type].joystick; + joystick_instance->dat = joystick_instance->intf->init(); } } void -gameport_remap(uint16_t address) +gameport_remap(void *priv, uint16_t address) { - gameport_t *p = gameport_global; - if (!p) + gameport_t *dev = (gameport_t *) priv, *other_dev; + + if (dev->addr) { + /* Remove this port from the active ports list. */ + if (active_gameports == dev) { + active_gameports = dev->next; + dev->next = NULL; + } else { + other_dev = active_gameports; + while (other_dev) { + if (other_dev->next == dev) { + other_dev->next = dev->next; + dev->next = NULL; + break; + } + other_dev = other_dev->next; + } + } + + io_removehandler(dev->addr, (dev->addr & 1) ? 1 : 8, + gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev); + } + + dev->addr = address; + + if (dev->addr) { + /* Add this port to the active ports list. */ + if ((dev->addr & 0xfff8) == 0x200) { + /* Port within 200-207h: add to top. */ + dev->next = active_gameports; + active_gameports = dev; + } else { + /* Port at other addresses: add to bottom. */ + other_dev = active_gameports; + while (other_dev->next) + other_dev = other_dev->next; + other_dev->next = dev; + } + + io_sethandler(dev->addr, (dev->addr & 1) ? 1 : 8, + gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev); + } +} + + +static void +gameport_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + if (ld > 0) return; - if (p->addr) - io_removehandler(p->addr, (p->addr & 1) ? 1 : 8, - gameport_read, NULL, NULL, gameport_write, NULL, NULL, p); + gameport_t *dev = (gameport_t *) priv; - p->addr = address; + /* Remap the game port to the specified address, or disable it. */ + gameport_remap(dev, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); +} - if (p->addr) - io_sethandler(p->addr, (p->addr & 1) ? 1 : 8, - gameport_read, NULL, NULL, gameport_write, NULL, NULL, p); + +void * +gameport_add(const device_t *gameport_type) +{ + /* Prevent a standalone game port from being added later on. */ + standalone_gameport_type = NULL; + + /* Add game port device. */ + return device_add_inst(gameport_type, gameport_instance_id++); } static void * gameport_init(const device_t *info) { - gameport_t *p = NULL; + gameport_t *dev = NULL; - if (!joystick_type) { - gameport_global = p = NULL; - return(p); + dev = malloc(sizeof(gameport_t)); + memset(dev, 0x00, sizeof(gameport_t)); + + /* Allocate global instance. */ + if (!joystick_instance && joystick_type) { + joystick_instance = malloc(sizeof(joystick_instance_t)); + memset(joystick_instance, 0x00, sizeof(joystick_instance_t)); + + joystick_instance->axis[0].joystick = joystick_instance; + joystick_instance->axis[1].joystick = joystick_instance; + joystick_instance->axis[2].joystick = joystick_instance; + joystick_instance->axis[3].joystick = joystick_instance; + + joystick_instance->axis[0].axis_nr = 0; + joystick_instance->axis[1].axis_nr = 1; + joystick_instance->axis[2].axis_nr = 2; + joystick_instance->axis[3].axis_nr = 3; + + timer_add(&joystick_instance->axis[0].timer, timer_over, &joystick_instance->axis[0], 0); + timer_add(&joystick_instance->axis[1].timer, timer_over, &joystick_instance->axis[1], 0); + timer_add(&joystick_instance->axis[2].timer, timer_over, &joystick_instance->axis[2], 0); + timer_add(&joystick_instance->axis[3].timer, timer_over, &joystick_instance->axis[3], 0); + + joystick_instance->intf = joysticks[joystick_type].joystick; + joystick_instance->dat = joystick_instance->intf->init(); } - p = malloc(sizeof(gameport_t)); + dev->joystick = joystick_instance; - memset(p, 0x00, sizeof(gameport_t)); + /* Map game port to the default address. Not applicable on PnP-only ports. */ + gameport_remap(dev, info->local); - p->axis[0].gameport = p; - p->axis[1].gameport = p; - p->axis[2].gameport = p; - p->axis[3].gameport = p; + /* Register ISAPnP if this is a standard game port card. */ + if (info->local == 0x200) + isapnp_set_device_defaults(isapnp_add_card(gameport_pnp_rom, sizeof(gameport_pnp_rom), gameport_pnp_config_changed, NULL, NULL, NULL, dev), 0, gameport_pnp_defaults); - p->axis[0].axis_nr = 0; - p->axis[1].axis_nr = 1; - p->axis[2].axis_nr = 2; - p->axis[3].axis_nr = 3; - - timer_add(&p->axis[0].timer, timer_over, &p->axis[0], 0); - timer_add(&p->axis[1].timer, timer_over, &p->axis[1], 0); - timer_add(&p->axis[2].timer, timer_over, &p->axis[2], 0); - timer_add(&p->axis[3].timer, timer_over, &p->axis[3], 0); - - p->joystick = joysticks[joystick_type].joystick; - p->joystick_dat = p->joystick->init(); - - gameport_global = p; - - gameport_remap(info->local); - - return(p); + return dev; } static void gameport_close(void *priv) { - gameport_t *p = (gameport_t *)priv; + gameport_t *dev = (gameport_t *) priv; - if (p == NULL) return; + /* If this port was active, remove it from the active ports list. */ + gameport_remap(dev, 0); - p->joystick->close(p->joystick_dat); + /* Free the global instance here, if it wasn't already freed. */ + if (joystick_instance) { + joystick_instance->intf->close(joystick_instance->dat); - gameport_global = NULL; + free(joystick_instance); + joystick_instance = NULL; + } - free(p); + free(dev); } @@ -348,3 +446,12 @@ const device_t gameport_201_device = { NULL, { NULL }, NULL, NULL }; + +const device_t gameport_pnp_device = { + "Game port (Plug and Play only)", + 0, 0, + gameport_init, + gameport_close, + NULL, { NULL }, NULL, + NULL +}; diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index 4ceac12e9..406234f45 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -1,40 +1,22 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Definitions for the generic game port handlers. * - * NOTE: This module needs a good cleanup someday. - * * * * Authors: Miran Grca, * Sarah Walker, + * RichardG, * * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2017 Sarah Walker. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2021 RichardG. */ #ifndef EMU_GAMEPORT_H # define EMU_GAMEPORT_H @@ -125,8 +107,10 @@ extern "C" { #ifdef EMU_DEVICE_H extern const device_t gameport_device; extern const device_t gameport_201_device; -#endif +extern const device_t gameport_pnp_device; +extern const device_t *standalone_gameport_type; +#endif extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; extern joystick_t joystick_state[MAX_JOYSTICKS]; extern int joysticks_present; @@ -150,7 +134,8 @@ extern char *joystick_get_button_name(int js, int id); extern char *joystick_get_pov_name(int js, int id); extern void gameport_update_joystick_type(void); -extern void gameport_remap(uint16_t address); +extern void gameport_remap(void *priv, uint16_t address); +extern void *gameport_add(const device_t *gameport_type); #ifdef __cplusplus } diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index 3bb2a6496..7889380f5 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -122,6 +122,7 @@ typedef struct sb_t }; mpu_t *mpu; emu8k_t emu8k; + void *gameport; int pos; diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 6996ab1da..ddddc6705 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -2516,8 +2516,7 @@ machine_amstrad_init(const machine_t *model, int type) mouse_set_poll(ms_poll, ams); } - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; } diff --git a/src/machine/m_at.c b/src/machine/m_at.c index e10e1f549..0e5589927 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -74,8 +74,7 @@ machine_at_common_init_ex(const machine_t *model, int type) else if (type == 0) device_add(&at_nvr_device); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; } diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 7edc81883..33b67aabe 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -516,8 +516,7 @@ ps1_common_init(const machine_t *model) device_add(&keyboard_ps2_ps1_device); /* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */ - if (joystick_type) - device_add(&gameport_201_device); + standalone_gameport_type = &gameport_201_device; } diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index 0ec09c21f..c09ca21c8 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -1541,8 +1541,7 @@ machine_tandy1k_init(const machine_t *model, int type) break; } - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; eep_data_out = 0x0000; } diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 581a5d7c9..127495259 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -30,8 +30,7 @@ machine_xt_common_init(const machine_t *model) device_add(&fdc_xt_device); nmi_init(); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; } diff --git a/src/machine/m_xt_compaq.c b/src/machine/m_xt_compaq.c index 4874106f6..5950ec3f9 100644 --- a/src/machine/m_xt_compaq.c +++ b/src/machine/m_xt_compaq.c @@ -56,8 +56,7 @@ machine_xt_compaq_deskpro_init(const machine_t *model) if (fdc_type == FDC_INTERNAL) device_add(&fdc_xt_device); nmi_init(); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; lpt1_remove(); lpt1_init(0x03bc); diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index cc9d32dd7..58b7d3774 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -174,8 +174,7 @@ machine_xt_lxt3_init(const machine_t *model) if (fdc_type == FDC_INTERNAL) device_add(&fdc_xt_device); nmi_init(); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; laserxt_init(1); diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index 331ebdcac..bc9edb672 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -738,8 +738,7 @@ machine_xt_m24_init(const machine_t *model) /* FIXME: make sure this is correct?? */ device_add(&at_nvr_device); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; nmi_init(); diff --git a/src/machine/m_xt_philips.c b/src/machine/m_xt_philips.c index f9b205d4c..164e8b093 100644 --- a/src/machine/m_xt_philips.c +++ b/src/machine/m_xt_philips.c @@ -155,8 +155,7 @@ machine_xt_philips_common_init(const machine_t *model) nmi_init(); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; device_add(&keyboard_pc_device); diff --git a/src/machine/m_xt_xi8088.c b/src/machine/m_xt_xi8088.c index e5cd0e87a..d7a127119 100644 --- a/src/machine/m_xt_xi8088.c +++ b/src/machine/m_xt_xi8088.c @@ -181,8 +181,7 @@ machine_xt_xi8088_init(const machine_t *model) nmi_init(); device_add(&ibmat_nvr_device); pic2_init(); - if (joystick_type) - device_add(&gameport_device); + standalone_gameport_type = &gameport_device; return ret; } diff --git a/src/machine/machine.c b/src/machine/machine.c index 685165f89..e3f2ef600 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -34,6 +34,7 @@ #include <86box/rom.h> #include <86box/lpt.h> #include <86box/serial.h> +#include <86box/gameport.h> #include "cpu.h" #include <86box/video.h> #include <86box/machine.h> @@ -74,6 +75,7 @@ machine_init_ex(int m) machine_log("Initializing as \"%s\"\n", machine_getname()); is_vpc = 0; + standalone_gameport_type = NULL; /* Set up the architecture flags. */ AT = IS_AT(machine); diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index 4a6869a02..e7131bb45 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -117,14 +117,15 @@ um8669f_log(const char *fmt, ...) typedef struct um8669f_t { - int locked, cur_reg_108; - void *pnp_card; + int locked, cur_reg_108; + void *pnp_card; isapnp_device_config_t *pnp_config[5]; - uint8_t regs_108[256]; + uint8_t regs_108[256]; - fdc_t *fdc; - serial_t *uart[2]; + fdc_t *fdc; + serial_t *uart[2]; + void *gameport; } um8669f_t; @@ -179,13 +180,13 @@ um8669f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pri break; case 5: - gameport_remap(0); - if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { um8669f_log("UM8669F: Game port enabled at port %04X\n", config->io[0].base); - gameport_remap(config->io[0].base); - } else + gameport_remap(dev->gameport, config->io[0].base); + } else { um8669f_log("UM8669F: Game port disabled\n"); + gameport_remap(dev->gameport, 0); + } } } @@ -286,6 +287,8 @@ um8669f_init(const device_t *info) dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); + dev->gameport = gameport_add(&gameport_pnp_device); + io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, dev); diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index bfa4d7eb0..1c697a3a8 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -8,6 +8,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> +#include <86box/gameport.h> #include <86box/io.h> #include <86box/nmi.h> #include <86box/mem.h> @@ -1352,13 +1353,16 @@ static void *es1371_init(const device_t *info) sound_add_handler(es1371_get_buffer, es1371); sound_set_cd_audio_filter(es1371_filter_cd_audio, es1371); + /* Add our own always-present game port to override the standalone ISAPnP one. */ + gameport_remap(gameport_add(&gameport_pnp_device), 0x200); + es1371->card = pci_add_card(info->local ? PCI_ADD_SOUND : PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, es1371); timer_add(&es1371->dac[1].timer, es1371_poll, es1371, 1); generate_es1371_filter(); - /* Return a CS4297A like VMWare does. */ + /* Return a CS4297A like VMware does. */ es1371->codec_regs[0x7c] = 0x4352; es1371->codec_regs[0x7e] = 0x5910; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index bc08c2956..9712f9cc6 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -31,6 +31,7 @@ #include <86box/mem.h> #include <86box/rom.h> #include <86box/device.h> +#include <86box/gameport.h> #include <86box/pic.h> #include <86box/sound.h> #include <86box/midi.h> @@ -71,6 +72,9 @@ static const uint16_t sb_mcv_addr[8] = {0x200, 0x210, 0x220, 0x230, 0x240, 0x250 static const int sb_pro_mcv_irqs[4] = {7, 5, 3, 3}; +/* Each card in the SB16 family has a million variants, and it shows in the large variety of device IDs for the PnP models. + These ROMs were reconstructed in a best-effort basis, around what Linux pnpdump configs and kernel logs could be found + in mailing lists, forums and other places, as well as Linux's own SB PnP card tables for ALSA and OSS. */ static uint8_t sb_16_pnp_rom[] = { 0x0e, 0x8c, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0028, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ @@ -87,14 +91,19 @@ static uint8_t sb_16_pnp_rom[] = { 0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */ 0x38, /* end dependent functions */ + 0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */ + 0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */ + 0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ }; static uint8_t sb_32_pnp_rom[] = { - 0x0e, 0x8c, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL009C, dummy checksum (filled in by isapnp_add_card) */ + 0x0e, 0x8c, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0048, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ 0x82, 0x11, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', '3', '2', ' ', 'P', 'n', 'P', /* ANSI identifier */ - 0x16, 0x0e, 0x8c, 0x00, 0x41, 0x00, 0xa9, /* logical device CTL0041, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */ + 0x16, 0x0e, 0x8c, 0x00, 0x31, 0x00, 0xa9, /* logical device CTL0031, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */ 0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */ 0x31, 0x00, /* start dependent functions, preferred */ 0x22, 0x20, 0x00, /* IRQ 5 */ @@ -153,14 +162,19 @@ static uint8_t sb_32_pnp_rom[] = { 0x47, 0x01, 0x20, 0x06, 0x80, 0x06, 0x20, 0x04, /* I/O 0x620-0x680, decodes 16-bit, 32-byte alignment, 4 addresses */ 0x38, /* end dependent functions */ + 0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */ + 0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */ + 0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ }; static uint8_t sb_awe32_pnp_rom[] = { - 0x0e, 0x8c, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL009A, dummy checksum (filled in by isapnp_add_card) */ + 0x0e, 0x8c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0043, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ 0x82, 0x15, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', ' ', 'A', 'W', 'E', '3', '2', ' ', 'P', 'n', 'P', /* ANSI identifier */ - 0x16, 0x0e, 0x8c, 0x00, 0x41, 0x00, 0xa9, /* logical device CTL0041, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */ + 0x16, 0x0e, 0x8c, 0x00, 0x31, 0x00, 0xa9, /* logical device CTL0031, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */ 0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */ 0x31, 0x00, /* start dependent functions, preferred */ 0x22, 0x20, 0x00, /* IRQ 5 */ @@ -223,6 +237,11 @@ static uint8_t sb_awe32_pnp_rom[] = { 0x47, 0x01, 0x20, 0x0e, 0x80, 0x0e, 0x20, 0x04, /* I/O 0xE20-0xE80, decodes 16-bit, 32-byte alignment, 4 addresses */ 0x38, /* end dependent functions */ + 0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */ + 0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */ + 0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */ + 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */ + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ }; @@ -1188,69 +1207,75 @@ sb_pro_mcv_write(int port, uint8_t val, void *p) static void sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) { - if (ld != 0) - return; - sb_t *sb = (sb_t *) priv; uint16_t addr = sb->dsp.sb_addr; uint8_t val; - io_removehandler(addr, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - io_removehandler(addr + 8, 0x0002, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - io_removehandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, - sb_ct1745_mixer_write, NULL, NULL, sb); + switch (ld) { + case 0: /* Audio */ + io_removehandler(addr, 0x0004, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + io_removehandler(addr + 8, 0x0002, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + io_removehandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, sb); - addr = sb->opl_pnp_addr; - if (addr) { - sb->opl_pnp_addr = 0; - io_removehandler(addr, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - } + addr = sb->opl_pnp_addr; + if (addr) { + sb->opl_pnp_addr = 0; + io_removehandler(addr, 0x0004, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + } - sb_dsp_setaddr(&sb->dsp, 0); - sb_dsp_setirq(&sb->dsp, 0); - sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED); - sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED); + sb_dsp_setaddr(&sb->dsp, 0); + sb_dsp_setirq(&sb->dsp, 0); + sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED); + sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED); - mpu401_change_addr(sb->mpu, 0); + mpu401_change_addr(sb->mpu, 0); - if (config->activate) { - addr = config->io[0].base; - if (addr != ISAPNP_IO_DISABLED) { - io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, - sb_ct1745_mixer_write, NULL, NULL, sb); + if (config->activate) { + addr = config->io[0].base; + if (addr != ISAPNP_IO_DISABLED) { + io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, sb); - sb_dsp_setaddr(&sb->dsp, addr); - } + sb_dsp_setaddr(&sb->dsp, addr); + } - addr = config->io[1].base; - if (addr != ISAPNP_IO_DISABLED) - mpu401_change_addr(sb->mpu, addr); + addr = config->io[1].base; + if (addr != ISAPNP_IO_DISABLED) + mpu401_change_addr(sb->mpu, addr); - addr = config->io[2].base; - if (addr != ISAPNP_IO_DISABLED) { - sb->opl_pnp_addr = addr; - io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, - opl3_write, NULL, NULL, &sb->opl); - } + addr = config->io[2].base; + if (addr != ISAPNP_IO_DISABLED) { + sb->opl_pnp_addr = addr; + io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, + opl3_write, NULL, NULL, &sb->opl); + } - val = config->irq[0].irq; - if (val != ISAPNP_IRQ_DISABLED) - sb_dsp_setirq(&sb->dsp, val); + val = config->irq[0].irq; + if (val != ISAPNP_IRQ_DISABLED) + sb_dsp_setirq(&sb->dsp, val); - val = config->dma[0].dma; - if (val != ISAPNP_DMA_DISABLED) - sb_dsp_setdma8(&sb->dsp, val); + val = config->dma[0].dma; + if (val != ISAPNP_DMA_DISABLED) + sb_dsp_setdma8(&sb->dsp, val); - val = config->dma[1].dma; - if (val != ISAPNP_DMA_DISABLED) - sb_dsp_setdma16(&sb->dsp, val); + val = config->dma[1].dma; + if (val != ISAPNP_DMA_DISABLED) + sb_dsp_setdma16(&sb->dsp, val); + } + + break; + + case 1: /* Game */ + gameport_remap(sb->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); + break; } } @@ -1259,21 +1284,18 @@ static void sb_awe32_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) { sb_t *sb = (sb_t *) priv; - uint16_t addr; switch (ld) { - case 0: + case 0: /* Audio */ sb_16_pnp_config_changed(0, config, sb); break; - case 1: - emu8k_change_addr(&sb->emu8k, 0); + case 1: /* WaveTable */ + emu8k_change_addr(&sb->emu8k, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); + break; - if (config->activate) { - addr = config->io[0].base; - if (addr != ISAPNP_IO_DISABLED) - emu8k_change_addr(&sb->emu8k, addr); - } + case 2: /* Game */ + sb_16_pnp_config_changed(1, config, sb); break; } } @@ -1701,6 +1723,8 @@ sb_16_pnp_init(const device_t *info) if (device_get_config_int("receive_input")) midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + sb->gameport = gameport_add(&gameport_pnp_device); + isapnp_add_card(sb_16_pnp_rom, sizeof(sb_16_pnp_rom), sb_16_pnp_config_changed, NULL, NULL, NULL, sb); return sb; @@ -1796,6 +1820,8 @@ sb_awe32_pnp_init(const device_t *info) if (device_get_config_int("receive_input")) midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); + sb->gameport = gameport_add(&gameport_pnp_device); + if (info->local == 1) isapnp_add_card(sb_32_pnp_rom, sizeof(sb_32_pnp_rom), sb_awe32_pnp_config_changed, NULL, NULL, NULL, sb); else From 7461108f38142c2210202941fde8b2b8ed04ff29 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 20 May 2021 23:06:29 -0300 Subject: [PATCH 11/59] Crystal CS4237, part 3: just the game port --- src/sound/snd_cs423x.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 88f15c49c..d7a332b7b 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -26,6 +26,7 @@ #include <86box/pic.h> #include <86box/dma.h> #include <86box/device.h> +#include <86box/gameport.h> #include <86box/i2c.h> #include <86box/isapnp.h> #include <86box/sound.h> @@ -92,15 +93,15 @@ static const uint8_t cs4237b_eeprom[] = { 0x47, 0x01, 0x88, 0x03, 0xf8, 0x03, 0x08, 0x04, /* I/O 0x388-0x3F8, decodes 16-bit, 8-byte alignment, 4 addresses */ 0x47, 0x01, 0x20, 0x02, 0x00, 0x03, 0x20, 0x10, /* I/O 0x220-0x300, decodes 16-bit, 32-byte alignment, 16 addresses */ 0x38, /* end dependent functions */ -#if 0 + 0x15, 0x0e, 0x63, 0x00, 0x01, 0x00, /* logical device CSC0001 */ 0x82, 0x05, 0x00, 'G', 'A', 'M', 'E', 0x00, /* ANSI identifier */ 0x31, 0x00, /* start dependent functions, preferred */ 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x200, decodes 16-bit, 8-byte alignment, 8 addresses */ 0x31, 0x01, /* start dependent functions, acceptable */ - 0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x47, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */ 0x38, /* end dependent functions */ -#endif + 0x15, 0x0e, 0x63, 0x00, 0x10, 0x00, /* logical device CSC0010 */ 0x82, 0x05, 0x00, 'C', 'T', 'R', 'L', 0x00, /* ANSI identifier */ 0x47, 0x01, 0x20, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x120-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ @@ -126,6 +127,7 @@ typedef struct cs423x_t void *pnp_card; ad1848_t ad1848; sb_t *sb; + void *gameport; void *i2c, *eeprom; uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11; @@ -452,7 +454,7 @@ cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) /* Fire the context switch interrupt if enabled. */ if (switched && (dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) { dev->regs[7] |= 0x40; /* set interrupt flag */ - picint(1 << dev->ad1848.irq); /* control device shares its IRQ with WSS and SBPro */ + picint(1 << dev->ad1848.irq); /* control device shares IRQ with WSS and SBPro */ } } @@ -542,17 +544,11 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv break; -#if 0 case 1: /* Game Port */ - gameport_remap(0); - - if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) - gameport_remap(config->io[0].base); - + gameport_remap(dev->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); break; -#endif - case 1: /* Control Registers */ + case 2: /* Control Registers */ if (dev->ctrl_base) { io_removehandler(dev->ctrl_base, 8, cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, dev); dev->ctrl_base = 0; @@ -565,7 +561,7 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv break; - case 2: /* MPU-401 */ + case 3: /* MPU-401 */ mpu401_change_addr(dev->sb->mpu, 0); mpu401_setirq(dev->sb->mpu, 0); @@ -616,9 +612,12 @@ cs423x_init(const device_t *info) /* Initialize codecs. */ dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); - ad1848_init(&dev->ad1848, AD1848_TYPE_CS4236); + ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); sound_add_handler(cs423x_get_buffer, dev); + /* Initialize game port. */ + dev->gameport = gameport_add(&gameport_pnp_device); + /* Initialize I2C bus for the EEPROM. */ dev->i2c = i2c_gpio_init("nvr_cs423x"); From ef4c900b8fd13d17045b67d43596616b1c4b2508 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 20 May 2021 23:17:07 -0300 Subject: [PATCH 12/59] Clean up formatting on the AD1848 and WSS code --- src/include/86box/snd_ad1848.h | 82 +++-- src/sound/snd_ad1848.c | 562 +++++++++++++++++---------------- src/sound/snd_wss.c | 332 +++++++++---------- 3 files changed, 520 insertions(+), 456 deletions(-) diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index a25e46951..d1f4a4499 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -1,45 +1,65 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation. + * + * + * + * Authors: Sarah Walker, + * TheCollector1995, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2018-2020 TheCollector1995. + */ + #define AD1848_TYPE_DEFAULT 0 #define AD1848_TYPE_CS4248 1 #define AD1848_TYPE_CS4231 2 #define AD1848_TYPE_CS4236 3 -typedef struct ad1848_t -{ - int index; - uint8_t regs[32]; /* 16 original + 16 CS4231A extensions */ - uint8_t status; - - int trd; - int mce; - - int count; - - int16_t out_l, out_r; - double cd_vol_l, cd_vol_r; +typedef struct { + int index; + uint8_t regs[32]; /* 16 original + 16 CS4231A extensions */ + uint8_t status; + + int trd; + int mce; + + int count; + + int16_t out_l, out_r; - int enable; + double cd_vol_l, cd_vol_r; - int irq, dma; - - int freq; - - pc_timer_t timer_count; - uint64_t timer_latch; + int enable; - int16_t buffer[SOUNDBUFLEN * 2]; - int pos; - - int type; + int irq, dma; + + int freq; + + pc_timer_t timer_count; + uint64_t timer_latch; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; + + int type; } ad1848_t; -void ad1848_setirq(ad1848_t *ad1848, int irq); -void ad1848_setdma(ad1848_t *ad1848, int dma); -uint8_t ad1848_read(uint16_t addr, void *p); -void ad1848_write(uint16_t addr, uint8_t val, void *p); +extern void ad1848_setirq(ad1848_t *ad1848, int irq); +extern void ad1848_setdma(ad1848_t *ad1848, int dma); -void ad1848_update(ad1848_t *ad1848); -void ad1848_speed_changed(ad1848_t *ad1848); +extern uint8_t ad1848_read(uint16_t addr, void *p); +extern void ad1848_write(uint16_t addr, uint8_t val, void *p); -void ad1848_init(ad1848_t *ad1848, int type); +extern void ad1848_update(ad1848_t *ad1848); +extern void ad1848_speed_changed(ad1848_t *ad1848); + +extern void ad1848_init(ad1848_t *ad1848, int type); diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index c45d69063..51c0423bd 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -1,6 +1,21 @@ /* - AD1848 / CS4248 / CS4231 CODEC emulation (Windows Sound System compatible)*/ - + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation. + * + * + * + * Authors: Sarah Walker, + * TheCollector1995, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2018-2020 TheCollector1995. + */ #include #include #include @@ -13,302 +28,317 @@ #include <86box/sound.h> #include <86box/snd_ad1848.h> + #define CS4231 0x80 #define CS4236 0x03 -static int ad1848_vols_6bits[64]; -static double ad1848_vols_5bits_aux_gain[32]; + +static int ad1848_vols_6bits[64]; +static double ad1848_vols_5bits_aux_gain[32]; -void ad1848_setirq(ad1848_t *ad1848, int irq) +void +ad1848_setirq(ad1848_t *ad1848, int irq) { - ad1848->irq = irq; + ad1848->irq = irq; } -void ad1848_setdma(ad1848_t *ad1848, int dma) + +void +ad1848_setdma(ad1848_t *ad1848, int dma) { - ad1848->dma = dma; + ad1848->dma = dma; } -uint8_t ad1848_read(uint16_t addr, void *p) + +uint8_t +ad1848_read(uint16_t addr, void *priv) { - ad1848_t *ad1848 = (ad1848_t *)p; - uint8_t temp = 0xff; - switch (addr & 3) - { - case 0: /*Index*/ - temp = ad1848->index | ad1848->trd | ad1848->mce; - break; - case 1: - temp = ad1848->regs[ad1848->index]; - if (ad1848->index == 0x0b) { - temp ^= 0x20; - ad1848->regs[ad1848->index] = temp; + ad1848_t *ad1848 = (ad1848_t *) priv; + uint8_t ret = 0xff; + + switch (addr & 3) { + case 0: /*Index*/ + ret = ad1848->index | ad1848->trd | ad1848->mce; + break; + + case 1: + ret = ad1848->regs[ad1848->index]; + if (ad1848->index == 0x0b) { + ret ^= 0x20; + ad1848->regs[ad1848->index] = ret; } - break; - case 2: - temp = ad1848->status; - break; - } - return temp; + break; + + case 2: + ret = ad1848->status; + break; + } + + return ret; } -void ad1848_write(uint16_t addr, uint8_t val, void *p) + +void +ad1848_write(uint16_t addr, uint8_t val, void *priv) { - ad1848_t *ad1848 = (ad1848_t *)p; - double freq; - switch (addr & 3) - { - case 0: /*Index*/ - if ((ad1848->regs[12] & 0x40) && (ad1848->type >= AD1848_TYPE_CS4231)) - ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ - else - ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ - ad1848->trd = val & 0x20; - ad1848->mce = val & 0x40; - break; - case 1: - switch (ad1848->index) - { - case 8: - freq = (val & 1) ? 16934400LL : 24576000LL; - switch ((val >> 1) & 7) - { - case 0: freq /= 3072; break; - case 1: freq /= 1536; break; - case 2: freq /= 896; break; - case 3: freq /= 768; break; - case 4: freq /= 448; break; - case 5: freq /= 384; break; - case 6: freq /= 512; break; - case 7: freq /= 2560; break; - } - ad1848->freq = freq; - ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); - break; - - case 9: - if (!ad1848->enable && (val & 0x41) == 0x01) { - if (ad1848->timer_latch) - timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch); - else - timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC); - } - ad1848->enable = ((val & 0x41) == 0x01); - if (!ad1848->enable) { - timer_disable(&ad1848->timer_count); - ad1848->out_l = ad1848->out_r = 0; - } - break; - - - case 11: - break; - - case 12: - if (ad1848->type != AD1848_TYPE_DEFAULT) - ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; - return; - - case 14: - ad1848->count = ad1848->regs[15] | (val << 8); - break; + ad1848_t *ad1848 = (ad1848_t *) priv; + double freq; + switch (addr & 3) { + case 0: /* Index */ + if ((ad1848->regs[12] & 0x40) && (ad1848->type >= AD1848_TYPE_CS4231)) + ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ + else + ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ + ad1848->trd = val & 0x20; + ad1848->mce = val & 0x40; + break; - case 24: - if (! (val & 0x70)) - ad1848->status &= 0xfe; - break; - - case 25: + case 1: + switch (ad1848->index) { + case 8: + freq = (val & 1) ? 16934400LL : 24576000LL; + switch ((val >> 1) & 7) { + case 0: freq /= 3072; break; + case 1: freq /= 1536; break; + case 2: freq /= 896; break; + case 3: freq /= 768; break; + case 4: freq /= 448; break; + case 5: freq /= 384; break; + case 6: freq /= 512; break; + case 7: freq /= 2560; break; + } + ad1848->freq = freq; + ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + break; + + case 9: + if (!ad1848->enable && (val & 0x41) == 0x01) { + if (ad1848->timer_latch) + timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch); + else + timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC); + } + ad1848->enable = ((val & 0x41) == 0x01); + if (!ad1848->enable) { + timer_disable(&ad1848->timer_count); + ad1848->out_l = ad1848->out_r = 0; + } break; - } - ad1848->regs[ad1848->index] = val; - if (ad1848->type == AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */ - if (ad1848->regs[0x12] & 0x80) - ad1848->cd_vol_l = 0; - else - ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; - if (ad1848->regs[0x13] & 0x80) - ad1848->cd_vol_r = 0; - else - ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; - } - break; - case 2: - ad1848->status &= 0xfe; - break; - } + case 11: + break; + + case 12: + if (ad1848->type != AD1848_TYPE_DEFAULT) + ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; + return; + + case 14: + ad1848->count = ad1848->regs[15] | (val << 8); + break; + + case 24: + if (!(val & 0x70)) + ad1848->status &= 0xfe; + break; + + case 25: + break; + } + ad1848->regs[ad1848->index] = val; + + if (ad1848->type == AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */ + if (ad1848->regs[0x12] & 0x80) + ad1848->cd_vol_l = 0; + else + ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; + if (ad1848->regs[0x13] & 0x80) + ad1848->cd_vol_r = 0; + else + ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; + } + break; + + case 2: + ad1848->status &= 0xfe; + break; + } } -void ad1848_speed_changed(ad1848_t *ad1848) + +void +ad1848_speed_changed(ad1848_t *ad1848) { - ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq)); } -void ad1848_update(ad1848_t *ad1848) + +void +ad1848_update(ad1848_t *ad1848) { - for (; ad1848->pos < sound_pos_global; ad1848->pos++) - { - ad1848->buffer[ad1848->pos*2] = ad1848->out_l; - ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r; - } + for (; ad1848->pos < sound_pos_global; ad1848->pos++) { + ad1848->buffer[ad1848->pos*2] = ad1848->out_l; + ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r; + } } -static void ad1848_poll(void *p) + +static void +ad1848_poll(void *priv) { - ad1848_t *ad1848 = (ad1848_t *)p; - - if (ad1848->timer_latch) - timer_advance_u64(&ad1848->timer_count, ad1848->timer_latch); - else - timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000); + ad1848_t *ad1848 = (ad1848_t *) priv; - ad1848_update(ad1848); - - if (ad1848->enable) - { - int32_t temp; - - switch (ad1848->regs[8] & 0x70) - { - case 0x00: /*Mono, 8-bit PCM*/ - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - case 0x10: /*Stereo, 8-bit PCM*/ - ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - - case 0x40: /*Mono, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; - case 0x50: /*Stereo, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; - temp = dma_channel_read(ad1848->dma); - ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; - } + if (ad1848->timer_latch) + timer_advance_u64(&ad1848->timer_count, ad1848->timer_latch); + else + timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000); - if (ad1848->regs[6] & 0x80) - ad1848->out_l = 0; - else - ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[ad1848->regs[6] & 0x3f]) >> 16; + ad1848_update(ad1848); - if (ad1848->regs[7] & 0x80) - ad1848->out_r = 0; - else - ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16; - - if (ad1848->count < 0) - { - ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); - if (!(ad1848->status & 0x01)) - { - ad1848->status |= 0x01; - if (ad1848->regs[10] & 2) - picint(1 << ad1848->irq); - } - } - - ad1848->count--; - } - else - { - ad1848->out_l = ad1848->out_r = 0; - ad1848->cd_vol_l = ad1848->cd_vol_r = 0; - } -} - -static void ad1848_filter_cd_audio(int channel, double *buffer, void *p) -{ - ad1848_t *ad1848 = (ad1848_t *)p; - double c; - double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l; - - c = ((*buffer) * volume) / 65536.0; - *buffer = c; -} - -void ad1848_init(ad1848_t *ad1848, int type) -{ - int c; - double attenuation; - - ad1848->status = 0xcc; - ad1848->index = ad1848->trd = 0; - ad1848->mce = 0x40; - - ad1848->regs[0] = ad1848->regs[1] = 0; - ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */ - ad1848->regs[4] = ad1848->regs[5] = 0x80; - ad1848->regs[6] = ad1848->regs[7] = 0x80; /* Left/right Output */ - ad1848->regs[8] = 0; - ad1848->regs[9] = 0x08; - ad1848->regs[10] = ad1848->regs[11] = 0; - if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231) || (type == AD1848_TYPE_CS4236)) - ad1848->regs[12] = 0x8a; - else - ad1848->regs[12] = 0xa; - ad1848->regs[13] = 0; - ad1848->regs[14] = ad1848->regs[15] = 0; - - if (type == AD1848_TYPE_CS4231) { - ad1848->regs[16] = ad1848->regs[17] = 0; - ad1848->regs[18] = ad1848->regs[19] = 0x88; - ad1848->regs[22] = 0x80; - ad1848->regs[24] = 0; - ad1848->regs[25] = CS4231; - ad1848->regs[26] = 0x80; - ad1848->regs[29] = 0x80; - } else if (type == AD1848_TYPE_CS4236) { - ad1848->regs[16] = ad1848->regs[17] = 0; - ad1848->regs[18] = ad1848->regs[19] = 0; - ad1848->regs[20] = ad1848->regs[21] = 0; - ad1848->regs[22] = ad1848->regs[23] = 0; - ad1848->regs[24] = 0; - ad1848->regs[25] = CS4236; - ad1848->regs[26] = 0xa0; - ad1848->regs[27] = ad1848->regs[29] = 0; - ad1848->regs[30] = ad1848->regs[31] = 0; - } + if (ad1848->enable) { + int32_t temp; - ad1848->out_l = 0; - ad1848->out_r = 0; - - for (c = 0; c < 64; c++) { - attenuation = 0.0; - if (c & 0x01) attenuation -= 1.5; - if (c & 0x02) attenuation -= 3.0; - if (c & 0x04) attenuation -= 6.0; - if (c & 0x08) attenuation -= 12.0; - if (c & 0x10) attenuation -= 24.0; - if (c & 0x20) attenuation -= 48.0; - - attenuation = pow(10, attenuation / 10); - - ad1848_vols_6bits[c] = (int)(attenuation * 65536); - } - - for (c = 0; c < 32; c++) { - attenuation = 12.0; - if (c & 0x01) attenuation -= 1.5; - if (c & 0x02) attenuation -= 3.0; - if (c & 0x04) attenuation -= 6.0; - if (c & 0x08) attenuation -= 12.0; - if (c & 0x10) attenuation -= 24.0; - - attenuation = pow(10, attenuation / 10); - - ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536); - } + switch (ad1848->regs[8] & 0x70) { + case 0x00: /*Mono, 8-bit PCM*/ + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + case 0x10: /*Stereo, 8-bit PCM*/ + ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; - ad1848->type = type; - - timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); + case 0x40: /*Mono, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + case 0x50: /*Stereo, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + } - if (ad1848->type != AD1848_TYPE_DEFAULT && ad1848->type != AD1848_TYPE_CS4248) - sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848); + if (ad1848->regs[6] & 0x80) + ad1848->out_l = 0; + else + ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[ad1848->regs[6] & 0x3f]) >> 16; + + if (ad1848->regs[7] & 0x80) + ad1848->out_r = 0; + else + ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16; + + if (ad1848->count < 0) + { + ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); + if (!(ad1848->status & 0x01)) + { + ad1848->status |= 0x01; + if (ad1848->regs[10] & 2) + picint(1 << ad1848->irq); + } + } + + ad1848->count--; + } else { + ad1848->out_l = ad1848->out_r = 0; + ad1848->cd_vol_l = ad1848->cd_vol_r = 0; + } +} + + +static void +ad1848_filter_cd_audio(int channel, double *buffer, void *priv) +{ + ad1848_t *ad1848 = (ad1848_t *) priv; + double c; + double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l; + + c = ((*buffer) * volume) / 65536.0; + *buffer = c; +} + + +void +ad1848_init(ad1848_t *ad1848, int type) +{ + int c; + double attenuation; + + ad1848->status = 0xcc; + ad1848->index = ad1848->trd = 0; + ad1848->mce = 0x40; + + ad1848->regs[0] = ad1848->regs[1] = 0; + ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */ + ad1848->regs[4] = ad1848->regs[5] = 0x80; + ad1848->regs[6] = ad1848->regs[7] = 0x80; /* Left/right Output */ + ad1848->regs[8] = 0; + ad1848->regs[9] = 0x08; + ad1848->regs[10] = ad1848->regs[11] = 0; + if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231) || (type == AD1848_TYPE_CS4236)) + ad1848->regs[12] = 0x8a; + else + ad1848->regs[12] = 0xa; + ad1848->regs[13] = 0; + ad1848->regs[14] = ad1848->regs[15] = 0; + + if (type == AD1848_TYPE_CS4231) { + ad1848->regs[16] = ad1848->regs[17] = 0; + ad1848->regs[18] = ad1848->regs[19] = 0x88; + ad1848->regs[22] = 0x80; + ad1848->regs[24] = 0; + ad1848->regs[25] = CS4231; + ad1848->regs[26] = 0x80; + ad1848->regs[29] = 0x80; + } else if (type == AD1848_TYPE_CS4236) { + ad1848->regs[16] = ad1848->regs[17] = 0; + ad1848->regs[18] = ad1848->regs[19] = 0; + ad1848->regs[20] = ad1848->regs[21] = 0; + ad1848->regs[22] = ad1848->regs[23] = 0; + ad1848->regs[24] = 0; + ad1848->regs[25] = CS4236; + ad1848->regs[26] = 0xa0; + ad1848->regs[27] = ad1848->regs[29] = 0; + ad1848->regs[30] = ad1848->regs[31] = 0; + } + + ad1848->out_l = 0; + ad1848->out_r = 0; + + for (c = 0; c < 64; c++) { + attenuation = 0.0; + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + if (c & 0x20) attenuation -= 48.0; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols_6bits[c] = (int)(attenuation * 65536); + } + + for (c = 0; c < 32; c++) { + attenuation = 12.0; + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536); + } + + ad1848->type = type; + + timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); + + if (ad1848->type != AD1848_TYPE_DEFAULT && ad1848->type != AD1848_TYPE_CS4248) + sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848); } diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index f7f813098..d77b781ea 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -34,217 +34,231 @@ #include <86box/snd_opl.h> -/*530, 11, 3 - 530=23*/ -/*530, 11, 1 - 530=22*/ -/*530, 11, 0 - 530=21*/ -/*530, 10, 1 - 530=1a*/ -/*530, 9, 1 - 530=12*/ -/*530, 7, 1 - 530=0a*/ -/*604, 11, 1 - 530=22*/ -/*e80, 11, 1 - 530=22*/ -/*f40, 11, 1 - 530=22*/ +/* 530, 11, 3 - 530=23 + * 530, 11, 1 - 530=22 + * 530, 11, 0 - 530=21 + * 530, 10, 1 - 530=1a + * 530, 9, 1 - 530=12 + * 530, 7, 1 - 530=0a + * 604, 11, 1 - 530=22 + * e80, 11, 1 - 530=22 + * f40, 11, 1 - 530=22 + */ -static int wss_dma[4] = {0, 0, 1, 3}; -static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/ +static const int wss_dma[4] = {0, 0, 1, 3}; +static const int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /* W95 only uses 7-9, others may be wrong */ -typedef struct wss_t -{ - uint8_t config; - ad1848_t ad1848; - opl_t opl; +typedef struct wss_t { + uint8_t config; - int opl_enabled; - uint8_t pos_regs[8]; + ad1848_t ad1848; + opl_t opl; + + int opl_enabled; + uint8_t pos_regs[8]; } wss_t; -uint8_t wss_read(uint16_t addr, void *p) -{ - wss_t *wss = (wss_t *)p; - uint8_t temp; - temp = 4 | (wss->config & 0x40); - return temp; + +uint8_t +wss_read(uint16_t addr, void *priv) { + wss_t *wss = (wss_t *) priv; + return 4 | (wss->config & 0x40); } -void wss_write(uint16_t addr, uint8_t val, void *p) -{ - wss_t *wss = (wss_t *)p; - wss->config = val; - ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); - ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); +void +wss_write(uint16_t addr, uint8_t val, void *priv) +{ + wss_t *wss = (wss_t *) priv; + + wss->config = val; + ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); + ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); } -static void wss_get_buffer(int32_t *buffer, int len, void *p) + +static void +wss_get_buffer(int32_t *buffer, int len, void *priv) { - wss_t *wss = (wss_t *)p; - int c; + wss_t *wss = (wss_t *) priv; + int c; - opl3_update(&wss->opl); - ad1848_update(&wss->ad1848); - for (c = 0; c < len * 2; c++) { - buffer[c] += wss->opl.buffer[c]; - buffer[c] += (wss->ad1848.buffer[c] / 2); - } + opl3_update(&wss->opl); + ad1848_update(&wss->ad1848); + for (c = 0; c < len * 2; c++) { + buffer[c] += wss->opl.buffer[c]; + buffer[c] += (wss->ad1848.buffer[c] / 2); + } - wss->opl.pos = 0; - wss->ad1848.pos = 0; + wss->opl.pos = 0; + wss->ad1848.pos = 0; } -void *wss_init(const device_t *info) + +void * +wss_init(const device_t *info) { - wss_t *wss = malloc(sizeof(wss_t)); - memset(wss, 0, sizeof(wss_t)); + wss_t *wss = malloc(sizeof(wss_t)); + memset(wss, 0, sizeof(wss_t)); - uint16_t addr = device_get_config_hex16("base"); - wss->opl_enabled = device_get_config_int("opl"); + uint16_t addr = device_get_config_hex16("base"); + wss->opl_enabled = device_get_config_int("opl"); - if (wss->opl_enabled) - opl3_init(&wss->opl); - - ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); + if (wss->opl_enabled) + opl3_init(&wss->opl); - ad1848_setirq(&wss->ad1848, 7); - ad1848_setdma(&wss->ad1848, 3); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); - if (wss->opl_enabled) + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); + + if (wss->opl_enabled) + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + + io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + + sound_add_handler(wss_get_buffer, wss); + + return wss; +} + + +static uint8_t +ncr_audio_mca_read(int port, void *priv) +{ + wss_t *wss = (wss_t *) priv; + return wss->pos_regs[port & 7]; +} + + +static void +ncr_audio_mca_write(int port, uint8_t val, void *priv) +{ + wss_t *wss = (wss_t *) priv; + uint16_t ports[4] = {0x530, 0xE80, 0xF40, 0x604}; + uint16_t addr; + + if (port < 0x102) + return; + + wss->opl_enabled = (wss->pos_regs[2] & 0x20) ? 1 : 0; + addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + + io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_removehandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + + wss->pos_regs[port & 7] = val; + + if (wss->pos_regs[2] & 1) { + addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + + if (wss->opl_enabled) io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - + io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); - - sound_add_handler(wss_get_buffer, wss); - - return wss; + } } -static uint8_t ncr_audio_mca_read(int port, void *p) + +static uint8_t +ncr_audio_mca_feedb(void *priv) { - wss_t *wss = (wss_t *)p; - - return wss->pos_regs[port & 7]; + wss_t *wss = (wss_t *) priv; + return (wss->pos_regs[2] & 1); } -static void ncr_audio_mca_write(int port, uint8_t val, void *p) + +void * +ncr_audio_init(const device_t *info) { - wss_t *wss = (wss_t *)p; - uint16_t ports[4] = {0x530, 0xE80, 0xF40, 0x604}; - uint16_t addr; + wss_t *wss = malloc(sizeof(wss_t)); + memset(wss, 0, sizeof(wss_t)); - if (port < 0x102) - return; + opl3_init(&wss->opl); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); - wss->opl_enabled = (wss->pos_regs[2] & 0x20) ? 1 : 0; - addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; - - io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - io_removehandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); - wss->pos_regs[port & 7] = val; + mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, NULL, wss); + wss->pos_regs[0] = 0x16; + wss->pos_regs[1] = 0x51; - if (wss->pos_regs[2] & 1) { - addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + sound_add_handler(wss_get_buffer, wss); - if (wss->opl_enabled) - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - - io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); - } + return wss; } -static uint8_t ncr_audio_mca_feedb(void *p) -{ - wss_t *wss = (wss_t *)p; - return (wss->pos_regs[2] & 1); +void +wss_close(void *priv) +{ + wss_t *wss = (wss_t *) priv; + free(wss); } -void *ncr_audio_init(const device_t *info) + +void +wss_speed_changed(void *priv) { - wss_t *wss = malloc(sizeof(wss_t)); - - memset(wss, 0, sizeof(wss_t)); - - opl3_init(&wss->opl); - ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); - - ad1848_setirq(&wss->ad1848, 7); - ad1848_setdma(&wss->ad1848, 3); - - mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, NULL, wss); - wss->pos_regs[0] = 0x16; - wss->pos_regs[1] = 0x51; - - sound_add_handler(wss_get_buffer, wss); - - return wss; + wss_t *wss = (wss_t *) priv; + ad1848_speed_changed(&wss->ad1848); } -void wss_close(void *p) -{ - wss_t *wss = (wss_t *)p; - free(wss); -} - -void wss_speed_changed(void *p) -{ - wss_t *wss = (wss_t *)p; - - ad1848_speed_changed(&wss->ad1848); -} - -static const device_config_t wss_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x530, "", { 0 }, - { - { - "0x530", 0x530 - }, - { - "0x604", 0x604 - }, - { - "0xe80", 0xe80 - }, - { - "0xf40", 0xf40 - }, - { - "" - } - } - }, +static const device_config_t wss_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x530, "", { 0 }, { - "opl", "Enable OPL", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 - } + { + "0x530", 0x530 + }, + { + "0x604", 0x604 + }, + { + "0xe80", 0xe80 + }, + { + "0xf40", 0xf40 + }, + { + "" + } + } + }, + { + "opl", "Enable OPL", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } }; + const device_t wss_device = { - "Windows Sound System", - DEVICE_ISA | DEVICE_AT, 0, - wss_init, wss_close, NULL, - { NULL }, - wss_speed_changed, - NULL, - wss_config + "Windows Sound System", + DEVICE_ISA | DEVICE_AT, 0, + wss_init, wss_close, NULL, + { NULL }, + wss_speed_changed, + NULL, + wss_config }; const device_t ncr_business_audio_device = { - "NCR Business Audio", - DEVICE_MCA, 0, - ncr_audio_init, wss_close, NULL, - { NULL }, - wss_speed_changed, - NULL, - NULL + "NCR Business Audio", + DEVICE_MCA, 0, + ncr_audio_init, wss_close, NULL, + { NULL }, + wss_speed_changed, + NULL, + NULL }; From f2f8d4a02e4bca5c7681c6a93ea283995b8e52a6 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 21 May 2021 12:52:14 -0300 Subject: [PATCH 13/59] Some AD1848 cleanups I forgot --- src/include/86box/snd_ad1848.h | 30 ++++++++++-------------------- src/sound/snd_ad1848.c | 10 +++++----- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index d1f4a4499..51579cd09 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -24,32 +24,22 @@ typedef struct { - int index; - uint8_t regs[32]; /* 16 original + 16 CS4231A extensions */ - uint8_t status; + int index; + uint8_t regs[32], status; /* 16 original registers + 16 CS4231A extensions */ - int trd; - int mce; + int trd, mce, count; - int count; - - int16_t out_l, out_r; + int16_t out_l, out_r; - double cd_vol_l, cd_vol_r; + double cd_vol_l, cd_vol_r; - int enable; + int enable, irq, dma, freq; - int irq, dma; - - int freq; - - pc_timer_t timer_count; - uint64_t timer_latch; + pc_timer_t timer_count; + uint64_t timer_latch; - int16_t buffer[SOUNDBUFLEN * 2]; - int pos; - - int type; + int16_t buffer[SOUNDBUFLEN * 2]; + int pos, type; } ad1848_t; diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 51c0423bd..c991ff381 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -40,14 +40,14 @@ static double ad1848_vols_5bits_aux_gain[32]; void ad1848_setirq(ad1848_t *ad1848, int irq) { - ad1848->irq = irq; + ad1848->irq = irq; } void ad1848_setdma(ad1848_t *ad1848, int dma) { - ad1848->dma = dma; + ad1848->dma = dma; } @@ -90,8 +90,8 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ else ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ - ad1848->trd = val & 0x20; - ad1848->mce = val & 0x40; + ad1848->trd = val & 0x20; + ad1848->mce = val & 0x40; break; case 1: @@ -109,7 +109,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 7: freq /= 2560; break; } ad1848->freq = freq; - ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq)); break; case 9: From c8c4aac16788ebfecee1b873308ba22661bea4ff Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 22 May 2021 22:27:21 -0300 Subject: [PATCH 14/59] ISAPnP tweaks: allow initialization with a null ROM; disable fatals for bad resource data; only change state on enable/disable if a change occurred. --- src/device/isapnp.c | 70 +++++++++++++++++++++++++++++++++++-------- src/sio/sio_um8669f.c | 2 +- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index e08e2d300..44885f837 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -527,7 +527,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv) } if (!ld) - fatal("ISAPnP: CSN %02X has no device %02X\n", card->csn, val); + isapnp_log("ISAPnP: CSN %02X has no device %02X\n", card->csn, val); break; @@ -696,7 +696,9 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, prev_card->next = card; } - isapnp_update_card_rom(card, rom, rom_size); + if (rom && rom_size) + isapnp_update_card_rom(card, rom, rom_size); + return card; } @@ -737,15 +739,29 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) case 0x01: /* memory range */ case 0x05: /* 32-bit memory range */ if (res == 0x01) { - if (mem_range > 3) - fatal("ISAPnP: Memory descriptor overflow (%d)\n", mem_range); + if (!ld) { + isapnp_log("ISAPnP: >>%s Memory descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (mem_range > 3) { + isapnp_log("ISAPnP: >>%s Memory descriptor overflow (%d)\n", in_df ? ">" : "", mem_range++); + break; + } isapnp_log("ISAPnP: >>%s Memory range %d uses upper limit = ", in_df ? ">" : "", mem_range); res = 1 << mem_range; mem_range++; } else { - if (mem_range_32 > 3) - fatal("ISAPnP: 32-bit memory descriptor overflow (%d)\n", mem_range_32); + if (!ld) { + isapnp_log("ISAPnP: >>%s 32-bit memory descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (mem_range_32 > 3) { + isapnp_log("ISAPnP: >>%s 32-bit memory descriptor overflow (%d)\n", in_df ? ">" : "", mem_range_32++); + break; + } isapnp_log("ISAPnP: >>%s 32-bit memory range %d uses upper limit = ", in_df ? ">" : "", mem_range_32); res = 1 << (4 + mem_range_32); @@ -812,14 +828,26 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) #ifdef ENABLE_ISAPNP_LOG case 0x03: /* compatible device ID */ + if (!ld) { + isapnp_log("ISAPnP: >> Compatible device ID with no logical device\n"); + break; + } + vendor = (card->rom[i + 1] << 8) | card->rom[i + 2]; isapnp_log("ISAPnP: >> Compatible device ID: %c%c%c%02X%02X\n", '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[i + 3], card->rom[i + 4]); break; #endif case 0x04: /* IRQ */ - if (irq > 1) - fatal("ISAPnP: IRQ descriptor overflow (%d)\n", irq); + if (!ld) { + isapnp_log("ISAPnP: >>%s IRQ descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (irq > 1) { + isapnp_log("ISAPnP: >>%s IRQ descriptor overflow (%d)\n", in_df ? ">" : "", irq++); + break; + } if (len == 2) /* default */ res = 0x01; /* high true edge sensitive */ @@ -836,6 +864,11 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) break; case 0x06: /* start dependent function */ + if (!ld) { + isapnp_log("ISAPnP: >> Start dependent function with no logical device\n"); + break; + } + isapnp_log("ISAPnP: >> Start dependent function: %s\n", (((len == 0) || (card->rom[i + 1] == 1)) ? "acceptable" : ((card->rom[i + 1] == 0) ? "good" : ((card->rom[i + 1] == 2) ? "sub-optimal" : "unknown priority")))); if (in_df) { @@ -862,8 +895,15 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) break; case 0x08: /* I/O port */ - if (io > 7) - fatal("ISAPnP: I/O descriptor overflow (%d)\n", io); + if (!ld) { + isapnp_log("ISAPnP: >>%s I/O descriptor with no logical device\n", in_df ? ">" : ""); + break; + } + + if (io > 7) { + isapnp_log("ISAPnP: >>%s I/O descriptor overflow (%d)\n", in_df ? ">" : "", io++); + break; + } isapnp_log("ISAPnP: >>%s I/O range %d %d-bit decode, %d ports\n", in_df ? ">" : "", io, (card->rom[i + 1] & 0x01) ? 16 : 10, card->rom[i + 7]); @@ -887,6 +927,9 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) card->rom[i + 1] = -res; isapnp_log("ISAPnP: End card resources (checksum %02X)\n", card->rom[i + 1]); + + /* Stop parsing here. */ + card->rom_size = i + 2; break; #ifdef ENABLE_ISAPNP_LOG @@ -916,11 +959,14 @@ isapnp_enable_card(void *priv, uint8_t enable) /* Look for a matching card. */ isapnp_card_t *card = dev->first_card; + uint8_t will_enable; while (card) { if (card == priv) { /* Enable or disable the card. */ - card->enable = (enable >= ISAPNP_CARD_ENABLE); - card->state = (enable == ISAPNP_CARD_FORCE_CONFIG) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY; + will_enable = (enable >= ISAPNP_CARD_ENABLE); + if (will_enable ^ card->enable) + card->state = (enable == ISAPNP_CARD_FORCE_CONFIG) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY; + card->enable = will_enable; /* Invalidate other references if we're disabling this card. */ if (!card->enable) { diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index e7131bb45..5087c7439 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -251,7 +251,7 @@ um8669f_reset(um8669f_t *dev) lpt1_remove(); - isapnp_enable_card(dev->pnp_card, 0); + isapnp_enable_card(dev->pnp_card, ISAPNP_CARD_DISABLE); dev->locked = 1; From 8b9b6c885d3c796033f04959be3e2f556ebd6aff Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 22 May 2021 22:28:42 -0300 Subject: [PATCH 15/59] Minor formatting cleanups --- src/sound/snd_sb.c | 2 +- src/sound/snd_wss.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 9712f9cc6..aa00b33a4 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1630,7 +1630,7 @@ sb_pro_cs423x_init(const device_t *info) sb_t *sb = malloc(sizeof(sb_t)); memset(sb, 0, sizeof(sb_t)); - sb->opl_enabled = 1; + sb->opl_enabled = 1; /* WSS can disable this to take ownership of the OPL */ opl3_init(&sb->opl); sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index d77b781ea..80b27cf9d 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -89,7 +89,7 @@ wss_get_buffer(int32_t *buffer, int len, void *priv) ad1848_update(&wss->ad1848); for (c = 0; c < len * 2; c++) { buffer[c] += wss->opl.buffer[c]; - buffer[c] += (wss->ad1848.buffer[c] / 2); + buffer[c] += wss->ad1848.buffer[c] / 2; } wss->opl.pos = 0; From 18289a9a647c6140145e7eeda10956643ee5d573 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 22 May 2021 22:29:25 -0300 Subject: [PATCH 16/59] Crystal CS4236, part 4: the one that took two days --- src/include/86box/snd_ad1848.h | 15 +- src/include/86box/sound.h | 2 +- src/sound/snd_ad1848.c | 334 +++++++++++++++++++++++++-------- src/sound/snd_cs423x.c | 220 ++++++++++++++-------- src/sound/sound.c | 2 +- 5 files changed, 413 insertions(+), 160 deletions(-) diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index 51579cd09..ac1b1a85f 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -24,14 +24,15 @@ typedef struct { - int index; - uint8_t regs[32], status; /* 16 original registers + 16 CS4231A extensions */ + int index, xindex; + uint8_t regs[32], xregs[32], status; /* 16 original registers + 16 CS4231A extensions + 32 CS4236 extensions */ - int trd, mce, count; + int trd, mce, count, wten; int16_t out_l, out_r; - double cd_vol_l, cd_vol_r; + int fm_vol_l, fm_vol_r; + uint8_t fmt_mask, wave_vol_mask; int enable, irq, dma, freq; @@ -45,11 +46,13 @@ typedef struct { extern void ad1848_setirq(ad1848_t *ad1848, int irq); extern void ad1848_setdma(ad1848_t *ad1848, int dma); +extern void ad1848_updatevolmask(ad1848_t *ad1848); -extern uint8_t ad1848_read(uint16_t addr, void *p); -extern void ad1848_write(uint16_t addr, uint8_t val, void *p); +extern uint8_t ad1848_read(uint16_t addr, void *priv); +extern void ad1848_write(uint16_t addr, uint8_t val, void *priv); extern void ad1848_update(ad1848_t *ad1848); extern void ad1848_speed_changed(ad1848_t *ad1848); +extern void ad1848_filter_cd_audio(int channel, double *buffer, void *priv); extern void ad1848_init(ad1848_t *ad1848, int type); diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index af10917e0..d280460e5 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -125,7 +125,7 @@ extern const device_t wss_device; extern const device_t ncr_business_audio_device; /* Crystal CS423x */ -extern const device_t cs4237b_device; +extern const device_t cs4236b_device; #endif #endif /*EMU_SOUND_H*/ diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index c991ff381..3b452a607 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -29,12 +29,14 @@ #include <86box/snd_ad1848.h> -#define CS4231 0x80 -#define CS4236 0x03 +#define CS4231 0x80 +#define CS4236 0x03 -static int ad1848_vols_6bits[64]; +static int ad1848_vols_7bits[128]; static double ad1848_vols_5bits_aux_gain[32]; +static double ad1848_vols_7bits_debug[128]; +static double ad1848_vols_5bits_debug[32]; void @@ -51,6 +53,67 @@ ad1848_setdma(ad1848_t *ad1848, int dma) } +void +ad1848_updatevolmask(ad1848_t *ad1848) +{ + if ((ad1848->type == AD1848_TYPE_CS4236) && ((ad1848->xregs[4] & 0x10) || ad1848->wten)) + ad1848->wave_vol_mask = 0x3f; + else + ad1848->wave_vol_mask = 0x7f; +} + + +static void +ad1848_updatefreq(ad1848_t *ad1848) +{ + double freq; + uint8_t set = 0; + + if (ad1848->type == AD1848_TYPE_CS4236) { + if (ad1848->xregs[11] & 0x20) { + freq = 16934400LL; + switch (ad1848->xregs[13]) { + case 1: freq /= 353; break; + case 2: freq /= 529; break; + case 3: freq /= 617; break; + case 4: freq /= 1058; break; + case 5: freq /= 1764; break; + case 6: freq /= 2117; break; + case 7: freq /= 2558; break; + default: freq /= 16 * MAX(ad1848->xregs[13], 21); break; + } + set = 1; + } else if (ad1848->regs[22] & 0x80) { + freq = (ad1848->regs[22] & 1) ? 33868800LL : 49152000LL; + set = (ad1848->regs[22] >> 1) & 0x3f; + switch (ad1848->regs[10] & 0x30) { + case 0x00: freq /= 128 * set; break; + case 0x10: freq /= 64 * set; break; + case 0x20: freq /= 256 * set; break; + } + set = 1; + } + } + + if (!set) { + freq = (ad1848->regs[8] & 1) ? 16934400LL : 24576000LL; + switch ((ad1848->regs[8] >> 1) & 7) { + case 0: freq /= 3072; break; + case 1: freq /= 1536; break; + case 2: freq /= 896; break; + case 3: freq /= 768; break; + case 4: freq /= 448; break; + case 5: freq /= 384; break; + case 6: freq /= 512; break; + case 7: freq /= 2560; break; + } + } + + ad1848->freq = freq; + ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq)); +} + + uint8_t ad1848_read(uint16_t addr, void *priv) { @@ -58,15 +121,35 @@ ad1848_read(uint16_t addr, void *priv) uint8_t ret = 0xff; switch (addr & 3) { - case 0: /*Index*/ + case 0: /* Index */ ret = ad1848->index | ad1848->trd | ad1848->mce; break; case 1: ret = ad1848->regs[ad1848->index]; - if (ad1848->index == 0x0b) { - ret ^= 0x20; - ad1848->regs[ad1848->index] = ret; + switch (ad1848->index) { + case 11: + ret ^= 0x20; + ad1848->regs[ad1848->index] = ret; + break; + + case 18: case 19: + if (ad1848->type == AD1848_TYPE_CS4236) { + if (ad1848->xregs[4] & 0x04) /* FM remapping */ + return ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */ + else if (ad1848->xregs[4] & 0x08) /* wavetable remapping */ + return ad1848->xregs[ad1848->index - 2]; /* real wavetable volume on registers 16 and 17 */ + } + break; + + case 23: + if ((ad1848->type == AD1848_TYPE_CS4236) && (ad1848->regs[23] & 0x08)) { + if ((ad1848->xindex & 0xfe) == 0x00) /* remapped line volume */ + ret = ad1848->regs[18 + ad1848->xindex]; + else + ret = ad1848->xregs[ad1848->xindex]; + } + break; } break; @@ -83,33 +166,29 @@ void ad1848_write(uint16_t addr, uint8_t val, void *priv) { ad1848_t *ad1848 = (ad1848_t *) priv; - double freq; + uint8_t temp, updatefreq = 0; + switch (addr & 3) { case 0: /* Index */ if ((ad1848->regs[12] & 0x40) && (ad1848->type >= AD1848_TYPE_CS4231)) ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ else ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ + if (ad1848->type == AD1848_TYPE_CS4236) + ad1848->regs[23] &= ~0x08; /* clear XRAE */ ad1848->trd = val & 0x20; ad1848->mce = val & 0x40; break; case 1: switch (ad1848->index) { + case 10: + if (ad1848->type != AD1848_TYPE_CS4236) + break; + /* fall-through */ + case 8: - freq = (val & 1) ? 16934400LL : 24576000LL; - switch ((val >> 1) & 7) { - case 0: freq /= 3072; break; - case 1: freq /= 1536; break; - case 2: freq /= 896; break; - case 3: freq /= 768; break; - case 4: freq /= 448; break; - case 5: freq /= 384; break; - case 6: freq /= 512; break; - case 7: freq /= 2560; break; - } - ad1848->freq = freq; - ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq)); + updatefreq = 1; break; case 9: @@ -127,7 +206,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) break; case 11: - break; + return; case 12: if (ad1848->type != AD1848_TYPE_DEFAULT) @@ -138,25 +217,94 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) ad1848->count = ad1848->regs[15] | (val << 8); break; + case 17: + if (ad1848->type >= AD1848_TYPE_CS4231) /* enable additional data formats on modes 2 and 3 */ + ad1848->fmt_mask = (val & 0x40) ? 0xf0 : 0x70; + break; + + case 18: case 19: + if (ad1848->type == AD1848_TYPE_CS4236) { + if (ad1848->xregs[4] & 0x04) { /* FM remapping */ + temp = val; + val = ad1848->xregs[ad1848->index - 18]; /* real line volume on registers 0 and 1 */ + ad1848->xregs[ad1848->index - 12] = temp; /* real FM volume on registers 6 and 7 */ + } else if (ad1848->xregs[4] & 0x08) { /* wavetable remapping */ + temp = val; + val = ad1848->xregs[ad1848->index - 18]; /* real line volume on registers 0 and 1 */ + ad1848->xregs[ad1848->index - 2] = temp; /* real wavetable volume on registers 16 and 17 */ + } + } + break; + + case 22: + updatefreq = 1; + break; + + case 23: + if ((ad1848->type == AD1848_TYPE_CS4236) && ((ad1848->regs[12] & 0x60) == 0x60)) { + if (!(ad1848->regs[23] & 0x08)) { /* existing (not new) XRAE is clear */ + ad1848->xindex = (((val & 0x04) << 2) | (val >> 4)) & 0x1f; + break; + } + switch (ad1848->xindex) { + case 0: case 1: /* remapped line volume */ + ad1848->regs[18 + ad1848->xindex] = val; + return; + + case 6: + if (val & 0x80) + ad1848->fm_vol_l = 0; + else + ad1848->fm_vol_l = ad1848_vols_7bits[val & 0x3f]; + break; + + case 7: + if (val & 0x80) + ad1848->fm_vol_r = 0; + else + ad1848->fm_vol_r = ad1848_vols_7bits[val & 0x3f]; + break; + + case 11: case 13: + updatefreq = 1; + break; + + case 25: + return; + } + ad1848->xregs[ad1848->xindex] = val; + + if (updatefreq) + ad1848_updatefreq(ad1848); + + return; + } + break; + case 24: if (!(val & 0x70)) ad1848->status &= 0xfe; break; case 25: - break; + return; } ad1848->regs[ad1848->index] = val; - if (ad1848->type == AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */ - if (ad1848->regs[0x12] & 0x80) + if (updatefreq) + ad1848_updatefreq(ad1848); + + if ((ad1848->type == AD1848_TYPE_CS4231) || (ad1848->type == AD1848_TYPE_CS4236)) { /* TODO: configure CD volume for CS4248/AD1848 too */ + temp = (ad1848->type == AD1848_TYPE_CS4231) ? 18 : 4; + if (ad1848->regs[temp] & 0x80) ad1848->cd_vol_l = 0; else - ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; - if (ad1848->regs[0x13] & 0x80) + ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f]; + temp++; + if (ad1848->regs[temp] & 0x80) ad1848->cd_vol_r = 0; else - ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; + ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f]; } break; @@ -198,43 +346,55 @@ ad1848_poll(void *priv) if (ad1848->enable) { int32_t temp; + + switch (ad1848->regs[8] & ad1848->fmt_mask) { + case 0x00: /* Mono, 8-bit PCM */ + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + + case 0x10: /* Stereo, 8-bit PCM */ + ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; - switch (ad1848->regs[8] & 0x70) { - case 0x00: /*Mono, 8-bit PCM*/ - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - case 0x10: /*Stereo, 8-bit PCM*/ - ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - - case 0x40: /*Mono, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; - case 0x50: /*Stereo, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; - temp = dma_channel_read(ad1848->dma); - ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; + case 0x40: /* Mono, 16-bit PCM little endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + + case 0x50: /* Stereo, 16-bit PCM little endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + + case 0xc0: /* Mono, 16-bit PCM big endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = dma_channel_read(ad1848->dma) | (temp << 8); + break; + + case 0xd0: /* Stereo, 16-bit PCM big endian */ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = dma_channel_read(ad1848->dma) | (temp << 8); + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = dma_channel_read(ad1848->dma) | (temp << 8); + break; } if (ad1848->regs[6] & 0x80) ad1848->out_l = 0; else - ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[ad1848->regs[6] & 0x3f]) >> 16; + ad1848->out_l = (ad1848->out_l * ad1848_vols_7bits[ad1848->regs[6] & ad1848->wave_vol_mask]) >> 16; if (ad1848->regs[7] & 0x80) ad1848->out_r = 0; else - ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16; + ad1848->out_r = (ad1848->out_r * ad1848_vols_7bits[ad1848->regs[7] & ad1848->wave_vol_mask]) >> 16; - if (ad1848->count < 0) - { + if (ad1848->count < 0) { ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); - if (!(ad1848->status & 0x01)) - { + if (!(ad1848->status & 0x01)) { ad1848->status |= 0x01; if (ad1848->regs[10] & 2) picint(1 << ad1848->irq); @@ -249,7 +409,7 @@ ad1848_poll(void *priv) } -static void +void ad1848_filter_cd_audio(int channel, double *buffer, void *priv) { ad1848_t *ad1848 = (ad1848_t *) priv; @@ -270,7 +430,8 @@ ad1848_init(ad1848_t *ad1848, int type) ad1848->status = 0xcc; ad1848->index = ad1848->trd = 0; ad1848->mce = 0x40; - + ad1848->wten = 0; + ad1848->regs[0] = ad1848->regs[1] = 0; ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */ ad1848->regs[4] = ad1848->regs[5] = 0x80; @@ -284,7 +445,7 @@ ad1848_init(ad1848_t *ad1848, int type) ad1848->regs[12] = 0xa; ad1848->regs[13] = 0; ad1848->regs[14] = ad1848->regs[15] = 0; - + if (type == AD1848_TYPE_CS4231) { ad1848->regs[16] = ad1848->regs[17] = 0; ad1848->regs[18] = ad1848->regs[19] = 0x88; @@ -303,25 +464,42 @@ ad1848_init(ad1848_t *ad1848, int type) ad1848->regs[26] = 0xa0; ad1848->regs[27] = ad1848->regs[29] = 0; ad1848->regs[30] = ad1848->regs[31] = 0; - } - - ad1848->out_l = 0; - ad1848->out_r = 0; - for (c = 0; c < 64; c++) { - attenuation = 0.0; - if (c & 0x01) attenuation -= 1.5; - if (c & 0x02) attenuation -= 3.0; - if (c & 0x04) attenuation -= 6.0; - if (c & 0x08) attenuation -= 12.0; - if (c & 0x10) attenuation -= 24.0; - if (c & 0x20) attenuation -= 48.0; - - attenuation = pow(10, attenuation / 10); - - ad1848_vols_6bits[c] = (int)(attenuation * 65536); + ad1848->xregs[0] = ad1848->xregs[1] = 0xe8; + ad1848->xregs[2] = ad1848->xregs[3] = 0xcf; + ad1848->xregs[4] = 0x84; + ad1848->xregs[5] = 0; + ad1848->xregs[6] = ad1848->xregs[7] = 0x80; + ad1848->xregs[8] = ad1848->xregs[9] = 0; + ad1848->xregs[10] = 0x3f; + ad1848->xregs[11] = 0xc0; + ad1848->xregs[14] = ad1848->xregs[15] = 0; + ad1848->xregs[16] = ad1848->xregs[17] = 0; } - + + ad1848->out_l = ad1848->out_r = 0; + ad1848->fm_vol_l = ad1848->fm_vol_r = 1; + ad1848_updatevolmask(ad1848); + ad1848->fmt_mask = 0x70; + + for (c = 0; c < 128; c++) { + attenuation = 0.0; + if (c & 0x40) { + if (c < 72) attenuation = (c - 72) * -1.5; + } else { + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + if (c & 0x20) attenuation -= 48.0; + } +ad1848_vols_7bits_debug[c] = attenuation; + attenuation = pow(10, attenuation / 10); + + ad1848_vols_7bits[c] = (int) (attenuation * 65536); + } + for (c = 0; c < 32; c++) { attenuation = 12.0; if (c & 0x01) attenuation -= 1.5; @@ -329,16 +507,16 @@ ad1848_init(ad1848_t *ad1848, int type) if (c & 0x04) attenuation -= 6.0; if (c & 0x08) attenuation -= 12.0; if (c & 0x10) attenuation -= 24.0; - +ad1848_vols_5bits_debug[c] = attenuation; attenuation = pow(10, attenuation / 10); ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536); - } - + } + ad1848->type = type; - + timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); - if (ad1848->type != AD1848_TYPE_DEFAULT && ad1848->type != AD1848_TYPE_CS4248) + if ((ad1848->type != AD1848_TYPE_DEFAULT) && (ad1848->type != AD1848_TYPE_CS4248)) sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848); } diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index d7a332b7b..b95d0618d 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -37,7 +37,9 @@ enum { - CRYSTAL_CS4237B = 0xc8 + CRYSTAL_CS4236B = 0xcb, + CRYSTAL_CS4237B = 0xc8, + CRYSTAL_CS4238B = 0xc9 }; enum { CRYSTAL_SLAM_NONE = 0, @@ -51,8 +53,8 @@ static const uint8_t slam_init_key[32] = { 0x96, 0x35, 0x9A, 0xCD, 0xE6, 0xF3, 0 0x5E, 0xAF, 0x57, 0x2B, 0x15, 0x8A, 0xC5, 0xE2, 0xF1, 0xF8, 0x7C, 0x3E, 0x9F, 0x4F, 0x27, 0x13, 0x09, 0x84, 0x42, 0xA1, 0xD0, 0x68, 0x34, 0x1A }; -static const uint8_t cs4237b_eeprom[] = { - /* CS4237B configuration */ +static const uint8_t cs4236b_eeprom[] = { + /* Chip configuration */ 0x55, 0xbb, /* magic */ 0x00, 0x00, /* length */ 0x00, 0x03, /* CD-ROM and modem decode */ @@ -66,7 +68,7 @@ static const uint8_t cs4237b_eeprom[] = { 0x10, 0x03, /* DMA routing */ /* PnP resources */ - 0x0e, 0x63, 0x42, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, /* CSC4237, dummy checksum (filled in by isapnp_add_card) */ + 0x0e, 0x63, 0x42, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, /* CSC4236, dummy checksum (filled in by isapnp_add_card) */ 0x0a, 0x10, 0x01, /* PnP version 1.0, vendor version 0.1 */ 0x82, 0x0e, 0x00, 'C', 'r', 'y', 's', 't', 'a', 'l', ' ', 'C', 'o', 'd', 'e' ,'c', 0x00, /* ANSI identifier */ @@ -131,14 +133,16 @@ typedef struct cs423x_t void *i2c, *eeprom; uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11; - uint8_t type, regs[8], indirect_regs[16], eeprom_data[2048], ram_dl; + uint8_t type, pnp_offset, regs[8], indirect_regs[16], eeprom_data[2048], ram_data[384], ram_dl; + int ad1848_type; - uint8_t key_pos: 5, enable_slam: 1, slam_state: 2, slam_ld, slam_reg; + uint8_t pnp_enable: 1, key_pos: 5, slam_enable: 1, slam_state: 2, slam_ld, slam_reg; isapnp_device_config_t *slam_config; } cs423x_t; -static void cs423x_slam_remap(cs423x_t *dev, uint8_t enable); +static void cs423x_slam_enable(cs423x_t *dev, uint8_t enable); +static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom); static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv); static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); @@ -183,7 +187,6 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) { cs423x_t *dev = (cs423x_t *) priv; uint8_t reg = port & 7; - uint16_t eeprom_addr; switch (reg) { case 1: /* EEPROM Interface */ @@ -199,7 +202,7 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) switch (dev->regs[3] & 15) { case 0: /* WSS Master Control */ if (val & 0x80) - ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); + ad1848_init(&dev->ad1848, dev->ad1848_type); val = 0x00; break; @@ -221,10 +224,15 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) break; case 8: /* CS9236 Wavetable Control */ - val &= 0xf0; + val &= 0x0f; break; } dev->indirect_regs[dev->regs[3]] = val; + + if (dev->ad1848.wten ^ !!(dev->indirect_regs[8] & 0x08)) { + dev->ad1848.wten ^= 1; + ad1848_updatevolmask(&dev->ad1848); + } break; case 5: /* Control/RAM Access */ @@ -232,20 +240,20 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) case 0: /* commands */ switch (val) { case 0x55: /* Disable PnP Key */ - isapnp_enable_card(dev->pnp_card, 0); + dev->pnp_enable = 0; + /* fall-through */ + + case 0x5a: /* Update Hardware Configuration Data */ + cs423x_pnp_enable(dev, 0); break; case 0x56: /* Disable Crystal Key */ - cs423x_slam_remap(dev, 0); + cs423x_slam_enable(dev, 0); break; case 0x57: /* Jump to ROM */ break; - case 0x5a: /* Update Hardware Configuration Data */ - isapnp_update_card_rom(dev->pnp_card, dev->eeprom_data + 23, dev->eeprom_size - 23); - break; - case 0xaa: /* Download RAM */ dev->ram_dl = 1; break; @@ -264,21 +272,21 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) case 3: /* data */ /* The only documented RAM region is 0x4000 (384 bytes in size), for - loading the chip's configuration and PnP ROM without an EEPROM. */ - if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) { - eeprom_addr = dev->ram_addr - 0x3ffc; /* skip first 4 bytes (header on real EEPROM) */ - dev->eeprom_data[eeprom_addr] = val; - if (dev->eeprom_size < ++eeprom_addr) /* update EEPROM size if required */ - dev->eeprom_size = eeprom_addr; - } + loading chip configuration and PnP resources without an EEPROM. */ + if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) + dev->ram_data[dev->ram_addr & 0x01ff] = val; dev->ram_addr++; break; } break; case 6: /* RAM Access End */ - if (!val) + if (!val) { dev->ram_dl = 0; + + /* Update PnP resource data and state. */ + cs423x_pnp_enable(dev, 1); + } break; case 7: /* Global Status */ @@ -412,17 +420,18 @@ cs423x_slam_write(uint16_t addr, uint8_t val, void *priv) static void -cs423x_slam_remap(cs423x_t *dev, uint8_t enable) +cs423x_slam_enable(cs423x_t *dev, uint8_t enable) { /* Disable SLAM. */ - if (dev->enable_slam) { - dev->enable_slam = 0; + if (dev->slam_enable) { + dev->slam_state = CRYSTAL_SLAM_NONE; + dev->slam_enable = 0; io_removehandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); } - /* Enable SLAM if not blocked by EEPROM configuration. */ - if (enable && !(dev->eeprom_data[7] & 0x10)) { - dev->enable_slam = 1; + /* Enable SLAM if the CKD bit is not set. */ + if (enable && !(dev->ram_data[2] & 0x10)) { + dev->slam_enable = 1; io_sethandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); } } @@ -440,21 +449,26 @@ static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) { cs423x_t *dev = (cs423x_t *) priv; - uint8_t prev_context = dev->regs[7] & 0x80, switched = 0; - /* Determine the active context (WSS or SBPro) through the address being read/written. */ - if ((prev_context == 0x80) && ((addr & 0xfff0) == dev->sb_base)) { - dev->regs[7] &= ~0x80; - switched = 1; - } else if ((prev_context == 0x00) && ((addr & 0xfffc) == dev->wss_base)) { - dev->regs[7] |= 0x80; - switched = 1; - } + /* Check if a context switch (WSS=1 <-> SBPro=0) occurred through the address being read/written. */ + if ((dev->regs[7] & 0x80) ? ((addr & 0xfff0) == dev->sb_base) : ((addr & 0xfffc) == dev->wss_base)) { + /* Flip context bit. */ + dev->regs[7] ^= 0x80; - /* Fire the context switch interrupt if enabled. */ - if (switched && (dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) { - dev->regs[7] |= 0x40; /* set interrupt flag */ - picint(1 << dev->ad1848.irq); /* control device shares IRQ with WSS and SBPro */ + /* Switch the CD audio filter and OPL ownership. + FIXME: not thread-safe: filter function TOCTTOU in sound_cd_thread! */ + sound_set_cd_audio_filter(NULL, NULL); + dev->sb->opl_enabled = !(dev->regs[7] & 0x80); + if (dev->sb->opl_enabled) /* SBPro */ + sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb); + else /* WSS */ + sound_set_cd_audio_filter(ad1848_filter_cd_audio, &dev->ad1848); + + /* Fire a context switch interrupt if enabled. */ + if ((dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) { + dev->regs[7] |= 0x40; /* set interrupt flag */ + picint(1 << dev->ad1848.irq); /* control device shares IRQ with WSS and SBPro */ + } } } @@ -463,17 +477,44 @@ static void cs423x_get_buffer(int32_t *buffer, int len, void *priv) { cs423x_t *dev = (cs423x_t *) priv; - int c; + int c, opl_wss = !dev->sb->opl_enabled; - /* Output audio from the WSS codec. SBPro and OPL3 are - already handled by the Sound Blaster emulation. */ + /* Output audio from the WSS codec, and also the OPL if we're in WSS mode. */ ad1848_update(&dev->ad1848); + if (opl_wss) + opl3_update(&dev->sb->opl); - for (c = 0; c < len * 2; c++) { - buffer[c] += (dev->ad1848.buffer[c] / 2); + for (c = 0; c < len * 2; c += 2) { + if (opl_wss) { + buffer[c] += (dev->sb->opl.buffer[c] * dev->ad1848.fm_vol_l) >> 16; + buffer[c + 1] += (dev->sb->opl.buffer[c + 1] * dev->ad1848.fm_vol_r) >> 16; + } + + buffer[c] += dev->ad1848.buffer[c] / 2; + buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2; } dev->ad1848.pos = 0; + if (opl_wss) + dev->sb->opl.pos = 0; +} + + +static void +cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom) +{ + uint8_t enable = ISAPNP_CARD_ENABLE; + + /* Hide PnP card if the PKD bit is set, or if PnP was disabled by command 0x55. */ + if ((dev->ram_data[2] & 0x20) || !dev->pnp_enable) + enable = ISAPNP_CARD_DISABLE; + + /* Update PnP resource data if requested. */ + if (update_rom) + isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], sizeof(dev->ram_data) - dev->pnp_offset); + + /* Update PnP state. */ + isapnp_enable_card(dev->pnp_card, enable); } @@ -541,7 +582,6 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv sb_dsp_setdma8(&dev->sb->dsp, config->dma[0].dma); } } - break; case 1: /* Game Port */ @@ -583,16 +623,28 @@ cs423x_reset(void *priv) { cs423x_t *dev = (cs423x_t *) priv; + /* Load EEPROM data to RAM, or just clear RAM if there's no EEPROM. */ + if (dev->eeprom) + memcpy(dev->ram_data, &dev->eeprom_data[4], MIN(sizeof(dev->ram_data), sizeof(dev->eeprom_data) - 4)); + else + memset(dev->ram_data, 0, sizeof(dev->ram_data)); + /* Reset registers. */ memset(dev->indirect_regs, 0, sizeof(dev->indirect_regs)); dev->indirect_regs[1] = dev->type; - /* Reset logical devices. */ - for (uint8_t i = 0; i < 6; i++) - isapnp_reset_device(dev->pnp_card, i); + /* Reset WSS codec. */ + ad1848_init(&dev->ad1848, dev->ad1848_type); - /* Enable SLAM. */ - cs423x_slam_remap(dev, 1); + /* Reset PnP resource data, state and logical devices. */ + dev->pnp_enable = 1; + if (dev->pnp_card) { + cs423x_pnp_enable(dev, 1); + isapnp_reset_card(dev->pnp_card); + } + + /* Reset SLAM. */ + cs423x_slam_enable(dev, 1); } @@ -602,17 +654,46 @@ cs423x_init(const device_t *info) cs423x_t *dev = malloc(sizeof(cs423x_t)); memset(dev, 0, sizeof(cs423x_t)); + /* Initialize model-specific data. */ dev->type = info->local; switch (dev->type) { + case CRYSTAL_CS4236B: case CRYSTAL_CS4237B: - dev->eeprom_size = sizeof(cs4237b_eeprom); - memcpy(dev->eeprom_data, cs4237b_eeprom, dev->eeprom_size); + case CRYSTAL_CS4238B: + /* Same WSS codec and EEPROM structure. */ + dev->ad1848_type = AD1848_TYPE_CS4236; + dev->pnp_offset = 19; + + /* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init */ + dev->ad1848.xregs[25] = dev->type; + + /* Load EEPROM contents from template. */ + memcpy(dev->eeprom_data, cs4236b_eeprom, sizeof(cs4236b_eeprom)); + + /* Set content size. */ + dev->eeprom_data[2] = sizeof(cs4236b_eeprom) >> 8; + dev->eeprom_data[3] = sizeof(cs4236b_eeprom) & 0xff; + + /* Set PnP card ID. */ + switch (dev->type) { + case CRYSTAL_CS4237B: + dev->eeprom_data[26] = 0x37; + break; + + case CRYSTAL_CS4238B: + dev->eeprom_data[26] = 0x38; + break; + } + break; } - /* Initialize codecs. */ + /* Initialize SBPro codec first to get the correct CD audio filter for the default + context, which is SBPro. The WSS codec is initialized later by cs423x_reset */ dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); - ad1848_init(&dev->ad1848, AD1848_TYPE_DEFAULT); + + /* Initialize RAM, registers and WSS codec. */ + cs423x_reset(dev); sound_add_handler(cs423x_get_buffer, dev); /* Initialize game port. */ @@ -621,22 +702,13 @@ cs423x_init(const device_t *info) /* Initialize I2C bus for the EEPROM. */ dev->i2c = i2c_gpio_init("nvr_cs423x"); - if (dev->eeprom_size) { - /* Set EEPROM length. */ - dev->eeprom_data[2] = dev->eeprom_size >> 8; - dev->eeprom_data[3] = dev->eeprom_size & 0xff; - - /* Initialize I2C EEPROM. */ + /* Initialize I2C EEPROM if the contents are valid. */ + if ((dev->eeprom_data[0] == 0x55) && (dev->eeprom_data[1] == 0xbb)) dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->eeprom_data, sizeof(dev->eeprom_data), 1); - } /* Initialize ISAPnP. */ - dev->pnp_card = isapnp_add_card(&dev->eeprom_data[23], dev->eeprom_size - 23, cs423x_pnp_config_changed, NULL, NULL, NULL, dev); - if (dev->eeprom_data[7] & 0x20) /* hide PnP card if PKD is set */ - isapnp_enable_card(dev->pnp_card, 0); - - /* Initialize registers. */ - cs423x_reset(dev); + dev->pnp_card = isapnp_add_card(NULL, 0, cs423x_pnp_config_changed, NULL, NULL, NULL, dev); + cs423x_pnp_enable(dev, 1); return dev; } @@ -665,11 +737,11 @@ cs423x_speed_changed(void *priv) } -const device_t cs4237b_device = +const device_t cs4236b_device = { - "Crystal CS4237B", + "Crystal CS4236B", DEVICE_ISA | DEVICE_AT, - CRYSTAL_CS4237B, + CRYSTAL_CS4236B, cs423x_init, cs423x_close, cs423x_reset, { NULL }, cs423x_speed_changed, diff --git a/src/sound/sound.c b/src/sound/sound.c index 39a3a44b6..851ccc92a 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -88,7 +88,7 @@ static const SOUND_CARD sound_cards[] = { "adlibgold", &adgold_device }, { "azt2316a", &azt2316a_device }, { "azt1605", &azt1605_device }, - { "cs4237b", &cs4237b_device }, + { "cs4236b", &cs4236b_device }, { "sb", &sb_1_device }, { "sb1.5", &sb_15_device }, { "sb2.0", &sb_2_device }, From 19d2bda4cee3f6f03ff1ec3f112c92b303ce54ad Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 23 May 2021 12:57:41 -0300 Subject: [PATCH 17/59] Confirm P2B-LS onboard SCSI and LAN slot numbers (props to computerguy08 on Discord) --- src/machine/m_at_slot1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 2f3edfd82..1ab48f7b4 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -204,8 +204,8 @@ machine_at_p2bls_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x04, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* SCSI */ + pci_register_slot(0x07, PCI_CARD_NORMAL, 3, 4, 1, 2); /* LAN */ pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); From ff4f0ee59e713697631fe1c226262342e3c800d7 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 23 May 2021 23:00:42 -0300 Subject: [PATCH 18/59] Crystal CS4236, part 5: Windows 9x now works --- src/include/86box/snd_ad1848.h | 27 ++++++----- src/sound/snd_ad1848.c | 83 ++++++++++++++++++++++++---------- src/sound/snd_cs423x.c | 83 ++++++++++++++++++++++++---------- src/sound/snd_wss.c | 2 +- 4 files changed, 136 insertions(+), 59 deletions(-) diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index ac1b1a85f..3e61deea7 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -12,35 +12,40 @@ * * Authors: Sarah Walker, * TheCollector1995, + * RichardG, * * Copyright 2008-2020 Sarah Walker. * Copyright 2018-2020 TheCollector1995. + * Copyright 2021 RichardG. */ -#define AD1848_TYPE_DEFAULT 0 -#define AD1848_TYPE_CS4248 1 -#define AD1848_TYPE_CS4231 2 -#define AD1848_TYPE_CS4236 3 +enum { + AD1848_TYPE_DEFAULT = 0, + AD1848_TYPE_CS4248, + AD1848_TYPE_CS4231, + AD1848_TYPE_CS4236 +}; typedef struct { - int index, xindex; - uint8_t regs[32], xregs[32], status; /* 16 original registers + 16 CS4231A extensions + 32 CS4236 extensions */ - - int trd, mce, count, wten; + uint8_t type, index, xindex, regs[32], xregs[32], status; /* 16 original registers + 16 CS4231A extensions + 32 CS4236 extensions */ + + int count; + uint8_t trd, mce, wten: 1; int16_t out_l, out_r; double cd_vol_l, cd_vol_r; int fm_vol_l, fm_vol_r; uint8_t fmt_mask, wave_vol_mask; - int enable, irq, dma, freq; + uint8_t enable: 1, irq: 4, dma: 3; + int freq; pc_timer_t timer_count; uint64_t timer_latch; int16_t buffer[SOUNDBUFLEN * 2]; - int pos, type; + int pos; } ad1848_t; @@ -55,4 +60,4 @@ extern void ad1848_update(ad1848_t *ad1848); extern void ad1848_speed_changed(ad1848_t *ad1848); extern void ad1848_filter_cd_audio(int channel, double *buffer, void *priv); -extern void ad1848_init(ad1848_t *ad1848, int type); +extern void ad1848_init(ad1848_t *ad1848, uint8_t type); diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 3b452a607..176da40da 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -12,9 +12,11 @@ * * Authors: Sarah Walker, * TheCollector1995, + * RichardG, * * Copyright 2008-2020 Sarah Walker. * Copyright 2018-2020 TheCollector1995. + * Copyright 2021 RichardG. */ #include #include @@ -35,8 +37,6 @@ static int ad1848_vols_7bits[128]; static double ad1848_vols_5bits_aux_gain[32]; -static double ad1848_vols_7bits_debug[128]; -static double ad1848_vols_5bits_debug[32]; void @@ -136,9 +136,9 @@ ad1848_read(uint16_t addr, void *priv) case 18: case 19: if (ad1848->type == AD1848_TYPE_CS4236) { if (ad1848->xregs[4] & 0x04) /* FM remapping */ - return ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */ + ret = ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */ else if (ad1848->xregs[4] & 0x08) /* wavetable remapping */ - return ad1848->xregs[ad1848->index - 2]; /* real wavetable volume on registers 16 and 17 */ + ret = ad1848->xregs[ad1848->index - 2]; /* real wavetable volume on registers 16 and 17 */ } break; @@ -166,7 +166,7 @@ void ad1848_write(uint16_t addr, uint8_t val, void *priv) { ad1848_t *ad1848 = (ad1848_t *) priv; - uint8_t temp, updatefreq = 0; + uint8_t temp = 0, updatefreq = 0; switch (addr & 3) { case 0: /* Index */ @@ -224,14 +224,43 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 18: case 19: if (ad1848->type == AD1848_TYPE_CS4236) { - if (ad1848->xregs[4] & 0x04) { /* FM remapping */ - temp = val; - val = ad1848->xregs[ad1848->index - 18]; /* real line volume on registers 0 and 1 */ - ad1848->xregs[ad1848->index - 12] = temp; /* real FM volume on registers 6 and 7 */ - } else if (ad1848->xregs[4] & 0x08) { /* wavetable remapping */ - temp = val; - val = ad1848->xregs[ad1848->index - 18]; /* real line volume on registers 0 and 1 */ - ad1848->xregs[ad1848->index - 2] = temp; /* real wavetable volume on registers 16 and 17 */ + if ((ad1848->xregs[4] & 0x14) == 0x14) { /* FM remapping */ + ad1848->xregs[ad1848->index - 12] = val; /* real FM volume on extended registers 6 and 7 */ + temp = 1; + + if (ad1848->index == 18) { + if (val & 0x80) + ad1848->fm_vol_l = 0; + else + ad1848->fm_vol_l = ad1848_vols_7bits[val & 0x3f]; + } else { + if (val & 0x80) + ad1848->fm_vol_r = 0; + else + ad1848->fm_vol_r = ad1848_vols_7bits[val & 0x3f]; + } + } + if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) { /* wavetable remapping */ + ad1848->xregs[ad1848->index - 2] = val; /* real wavetable volume on extended registers 16 and 17 */ + temp = 1; + } + + /* Stop here if any remapping is enabled. */ + if (temp) + return; + + /* HACK: the Windows 9x driver's "Synth" control writes to this + register with no remapping, even if internal FM is enabled. */ + if (ad1848->index == 18) { + if (val & 0x80) + ad1848->fm_vol_l = 0; + else + ad1848->fm_vol_l = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; + } else { + if (val & 0x80) + ad1848->fm_vol_r = 0; + else + ad1848->fm_vol_r = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; } } break; @@ -243,9 +272,10 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 23: if ((ad1848->type == AD1848_TYPE_CS4236) && ((ad1848->regs[12] & 0x60) == 0x60)) { if (!(ad1848->regs[23] & 0x08)) { /* existing (not new) XRAE is clear */ - ad1848->xindex = (((val & 0x04) << 2) | (val >> 4)) & 0x1f; + ad1848->xindex = ((val & 0x04) << 2) | (val >> 4); break; } + switch (ad1848->xindex) { case 0: case 1: /* remapped line volume */ ad1848->regs[18 + ad1848->xindex] = val; @@ -282,8 +312,11 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) break; case 24: - if (!(val & 0x70)) + val = ad1848->regs[24] & ((val & 0x70) | 0x0f); + if (!(val & 0x70)) { ad1848->status &= 0xfe; + picintc(1 << ad1848->irq); + } break; case 25: @@ -310,6 +343,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 2: ad1848->status &= 0xfe; + ad1848->regs[24] &= 0x0f; break; } } @@ -391,14 +425,15 @@ ad1848_poll(void *priv) ad1848->out_r = 0; else ad1848->out_r = (ad1848->out_r * ad1848_vols_7bits[ad1848->regs[7] & ad1848->wave_vol_mask]) >> 16; - + if (ad1848->count < 0) { ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); if (!(ad1848->status & 0x01)) { ad1848->status |= 0x01; + ad1848->regs[24] |= 0x10; if (ad1848->regs[10] & 2) picint(1 << ad1848->irq); - } + } } ad1848->count--; @@ -422,11 +457,11 @@ ad1848_filter_cd_audio(int channel, double *buffer, void *priv) void -ad1848_init(ad1848_t *ad1848, int type) +ad1848_init(ad1848_t *ad1848, uint8_t type) { - int c; + uint8_t c; double attenuation; - + ad1848->status = 0xcc; ad1848->index = ad1848->trd = 0; ad1848->mce = 0x40; @@ -477,8 +512,10 @@ ad1848_init(ad1848_t *ad1848, int type) ad1848->xregs[16] = ad1848->xregs[17] = 0; } + ad1848_updatefreq(ad1848); + ad1848->out_l = ad1848->out_r = 0; - ad1848->fm_vol_l = ad1848->fm_vol_r = 1; + ad1848->fm_vol_l = ad1848->fm_vol_r = 65536; ad1848_updatevolmask(ad1848); ad1848->fmt_mask = 0x70; @@ -494,7 +531,7 @@ ad1848_init(ad1848_t *ad1848, int type) if (c & 0x10) attenuation -= 24.0; if (c & 0x20) attenuation -= 48.0; } -ad1848_vols_7bits_debug[c] = attenuation; + attenuation = pow(10, attenuation / 10); ad1848_vols_7bits[c] = (int) (attenuation * 65536); @@ -507,7 +544,7 @@ ad1848_vols_7bits_debug[c] = attenuation; if (c & 0x04) attenuation -= 6.0; if (c & 0x08) attenuation -= 12.0; if (c & 0x10) attenuation -= 24.0; -ad1848_vols_5bits_debug[c] = attenuation; + attenuation = pow(10, attenuation / 10); ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536); diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index b95d0618d..57bf083ca 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -42,10 +42,10 @@ enum { CRYSTAL_CS4238B = 0xc9 }; enum { - CRYSTAL_SLAM_NONE = 0, - CRYSTAL_SLAM_INDEX, - CRYSTAL_SLAM_BYTE1, - CRYSTAL_SLAM_BYTE2 + CRYSTAL_SLAM_NONE = 0, + CRYSTAL_SLAM_INDEX = 1, + CRYSTAL_SLAM_BYTE1 = 2, + CRYSTAL_SLAM_BYTE2 = 3 }; @@ -133,8 +133,7 @@ typedef struct cs423x_t void *i2c, *eeprom; uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11; - uint8_t type, pnp_offset, regs[8], indirect_regs[16], eeprom_data[2048], ram_data[384], ram_dl; - int ad1848_type; + uint8_t type, ad1848_type, pnp_offset, regs[8], indirect_regs[16], eeprom_data[2048], ram_data[384], ram_dl; uint8_t pnp_enable: 1, key_pos: 5, slam_enable: 1, slam_state: 2, slam_ld, slam_reg; isapnp_device_config_t *slam_config; @@ -148,10 +147,10 @@ static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config static uint8_t -cs423x_read(uint16_t port, void *priv) +cs423x_read(uint16_t addr, void *priv) { cs423x_t *dev = (cs423x_t *) priv; - uint8_t reg = port & 7; + uint8_t reg = addr & 7; uint8_t ret = dev->regs[reg]; switch (reg) { @@ -165,6 +164,17 @@ cs423x_read(uint16_t port, void *priv) ret = dev->indirect_regs[dev->regs[3]]; break; + case 5: /* Control/RAM Access */ + /* Reading RAM is undocumented; the WDM driver does so. */ + if (dev->ram_dl) { + if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) /* chip configuration and PnP resources */ + ret = dev->ram_data[dev->ram_addr & 0x01ff]; + else + ret = 0xff; + dev->ram_addr++; + } + break; + case 7: /* Global Status */ /* Context switching: take active context and interrupt flag, then clear interrupt flag. */ ret &= 0xc0; @@ -172,10 +182,12 @@ cs423x_read(uint16_t port, void *priv) if (dev->sb->mpu->state.irq_pending) /* MPU interrupt */ ret |= 0x08; - if (dev->ad1848.regs[10] & 2) /* WSS interrupt */ + if (dev->ad1848.status & 0x01) /* WSS interrupt */ ret |= 0x10; if (dev->sb->dsp.sb_irq8 || dev->sb->dsp.sb_irq16 || dev->sb->dsp.sb_irq401) /* SBPro interrupt */ ret |= 0x20; + + break; } return ret; @@ -183,10 +195,10 @@ cs423x_read(uint16_t port, void *priv) static void -cs423x_write(uint16_t port, uint8_t val, void *priv) +cs423x_write(uint16_t addr, uint8_t val, void *priv) { cs423x_t *dev = (cs423x_t *) priv; - uint8_t reg = port & 7; + uint8_t reg = addr & 0x07; switch (reg) { case 1: /* EEPROM Interface */ @@ -199,7 +211,7 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) break; case 4: /* Control Indirect Data Register */ - switch (dev->regs[3] & 15) { + switch (dev->regs[3] & 0x0f) { case 0: /* WSS Master Control */ if (val & 0x80) ad1848_init(&dev->ad1848, dev->ad1848_type); @@ -211,28 +223,36 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) case 9 ... 15: /* unspecified */ return; + case 2: /* 3D Space and {Center|Volume} */ + case 6: /* Upper Channel Status */ + if (dev->type < CRYSTAL_CS4237B) + return; + break; + case 3: /* 3D Enable */ + if (dev->type < CRYSTAL_CS4237B) + return; val &= 0xe0; break; case 4: /* Consumer Serial Port Enable */ + if (dev->type < CRYSTAL_CS4237B) + return; val &= 0xf0; break; case 5: /* Lower Channel Status */ + if (dev->type < CRYSTAL_CS4237B) + return; val &= 0xfe; break; case 8: /* CS9236 Wavetable Control */ val &= 0x0f; + cs423x_pnp_enable(dev, 0); /* update WTEN bit */ break; } dev->indirect_regs[dev->regs[3]] = val; - - if (dev->ad1848.wten ^ !!(dev->indirect_regs[8] & 0x08)) { - dev->ad1848.wten ^= 1; - ad1848_updatevolmask(&dev->ad1848); - } break; case 5: /* Control/RAM Access */ @@ -271,9 +291,7 @@ cs423x_write(uint16_t port, uint8_t val, void *priv) break; case 3: /* data */ - /* The only documented RAM region is 0x4000 (384 bytes in size), for - loading chip configuration and PnP resources without an EEPROM. */ - if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) + if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) /* chip configuration and PnP resources */ dev->ram_data[dev->ram_addr & 0x01ff] = val; dev->ram_addr++; break; @@ -424,7 +442,7 @@ cs423x_slam_enable(cs423x_t *dev, uint8_t enable) { /* Disable SLAM. */ if (dev->slam_enable) { - dev->slam_state = CRYSTAL_SLAM_NONE; + dev->slam_state = CRYSTAL_SLAM_NONE; dev->slam_enable = 0; io_removehandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); } @@ -455,10 +473,10 @@ cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) /* Flip context bit. */ dev->regs[7] ^= 0x80; - /* Switch the CD audio filter and OPL ownership. + /* Switch OPL ownership and CD audio filter. FIXME: not thread-safe: filter function TOCTTOU in sound_cd_thread! */ - sound_set_cd_audio_filter(NULL, NULL); dev->sb->opl_enabled = !(dev->regs[7] & 0x80); + sound_set_cd_audio_filter(NULL, NULL); if (dev->sb->opl_enabled) /* SBPro */ sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb); else /* WSS */ @@ -496,7 +514,7 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv) dev->ad1848.pos = 0; if (opl_wss) - dev->sb->opl.pos = 0; + dev->sb->opl.pos = 0; } @@ -515,6 +533,21 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom) /* Update PnP state. */ isapnp_enable_card(dev->pnp_card, enable); + + /* While we're here, update FM and wavetable enable bits based on the config data in RAM. */ + if (dev->ram_data[3] & 0x08) { + dev->indirect_regs[8] |= 0x08; + dev->ad1848.wten = 1; + } else { + dev->indirect_regs[8] &= ~0x08; + dev->ad1848.wten = 0; + } + if (dev->ram_data[3] & 0x80) + dev->ad1848.xregs[4] |= 0x10; + else + dev->ad1848.xregs[4] &= ~0x10; + + ad1848_updatevolmask(&dev->ad1848); } @@ -632,6 +665,8 @@ cs423x_reset(void *priv) /* Reset registers. */ memset(dev->indirect_regs, 0, sizeof(dev->indirect_regs)); dev->indirect_regs[1] = dev->type; + if (dev->type == CRYSTAL_CS4238B) + dev->indirect_regs[2] = 0x20; /* Reset WSS codec. */ ad1848_init(&dev->ad1848, dev->ad1848_type); diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index 80b27cf9d..9017fe2c1 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -53,7 +53,7 @@ static const int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /* W95 only uses 7- typedef struct wss_t { uint8_t config; - ad1848_t ad1848; + ad1848_t ad1848; opl_t opl; int opl_enabled; From 82a38618050df5909f7cf505191a7c28b9c4d7aa Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 00:28:05 -0300 Subject: [PATCH 19/59] Make PCI TRC reset all devices --- src/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pci.c b/src/pci.c index 2283ca60d..a8c76b003 100644 --- a/src/pci.c +++ b/src/pci.c @@ -709,7 +709,7 @@ trc_reset(uint8_t val) { if (val & 2) { dma_reset(); - device_reset_all_pci(); + device_reset_all(); cpu_alt_reset = 0; From b5a295e91dad42b934ded20527fe21c9b4fecb26 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 00:53:52 -0300 Subject: [PATCH 20/59] Continuing the game port overhaul: added support for Super I/O game ports not being broken out --- src/game/gameport.c | 19 +++++++++++++++---- src/include/86box/gameport.h | 2 ++ src/include/86box/machine.h | 1 + src/machine/machine.c | 1 + src/machine/machine_table.c | 2 +- src/sio/sio_um8669f.c | 4 ++-- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/game/gameport.c b/src/game/gameport.c index d7f399ab3..2c56f13b8 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -119,7 +119,7 @@ static const isapnp_device_config_t gameport_pnp_defaults[] = { const device_t *standalone_gameport_type; -static int gameport_instance_id = 0; +int gameport_instance_id = 0; /* Linked list of active game ports. Only the top port responds to reads or writes, and ports at the standard 200h location are prioritized. */ static gameport_t *active_gameports = NULL; @@ -356,8 +356,10 @@ gameport_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pr void * gameport_add(const device_t *gameport_type) { - /* Prevent a standalone game port from being added later on. */ - standalone_gameport_type = NULL; + /* Prevent a standalone game port from being added later on, unless this + is an unused Super I/O game port (no MACHINE_GAMEPORT machine flag). */ + if (!(gameport_type->local & 0x10000) || (machines[machine].flags & MACHINE_GAMEPORT)) + standalone_gameport_type = NULL; /* Add game port device. */ return device_add_inst(gameport_type, gameport_instance_id++); @@ -399,7 +401,7 @@ gameport_init(const device_t *info) dev->joystick = joystick_instance; /* Map game port to the default address. Not applicable on PnP-only ports. */ - gameport_remap(dev, info->local); + gameport_remap(dev, info->local & 0xffff); /* Register ISAPnP if this is a standard game port card. */ if (info->local == 0x200) @@ -455,3 +457,12 @@ const device_t gameport_pnp_device = { NULL, { NULL }, NULL, NULL }; + +const device_t gameport_sio_device = { + "Game port (Super I/O)", + 0, 0x10000, + gameport_init, + gameport_close, + NULL, { NULL }, NULL, + NULL +}; diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index 406234f45..9f5da7f00 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -108,9 +108,11 @@ extern "C" { extern const device_t gameport_device; extern const device_t gameport_201_device; extern const device_t gameport_pnp_device; +extern const device_t gameport_sio_device; extern const device_t *standalone_gameport_type; #endif +extern int gameport_instance_id; extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; extern joystick_t joystick_state[MAX_JOYSTICKS]; extern int joysticks_present; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 9e627a7e7..677dc7027 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -61,6 +61,7 @@ #define MACHINE_SOUND 0x00008000 /* sys has int sound */ #define MACHINE_FDC 0x00010000 /* sys has int FDC */ #define MACHINE_NIC 0x00020000 /* sys has int NIC */ +#define MACHINE_GAMEPORT 0x00040000 /* sys has int game port */ /* Combined flags. */ #define MACHINE_VIDEO_FIXED 0x00003000 /* sys has fixed int video */ /* Feature flags for internal storage controllers. */ diff --git a/src/machine/machine.c b/src/machine/machine.c index e3f2ef600..ae731e522 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -76,6 +76,7 @@ machine_init_ex(int m) is_vpc = 0; standalone_gameport_type = NULL; + gameport_instance_id = 0; /* Set up the architecture flags. */ AT = IS_AT(machine); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d33ffd2a3..117afc4d4 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -340,7 +340,7 @@ const machine_t machines[] = { { "[i430VX] HP Brio 80xx", "brio80xx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 2200, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_brio80xx_init, NULL }, { "[i430VX] Packard Bell PB680", "pb680", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_pb680_init, NULL }, { "[i430VX] PC Partner MB520N", "mb520n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2600, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mb520n_init, NULL }, - { "[i430VX] Shuttle HOT-557", "430vx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_i430vx_init, NULL }, + { "[i430VX] Shuttle HOT-557", "430vx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_GAMEPORT, 8192, 131072, 8192, 127, machine_at_i430vx_init, NULL }, /* 430TX */ { "[i430TX] ADLink NuPRO-592", "nupro592", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 1900, 2800, 1.5, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_nupro592_init, NULL }, diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index 5087c7439..516685629 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -89,7 +89,7 @@ static const isapnp_device_config_t um8669f_pnp_defaults[] = { }, { .activate = 0 }, { - .activate = 1, + .activate = 0, .io = { { .base = 0x200 }, } } }; @@ -287,7 +287,7 @@ um8669f_init(const device_t *info) dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); - dev->gameport = gameport_add(&gameport_pnp_device); + dev->gameport = gameport_add(&gameport_sio_device); io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, dev); From 80fb5775e45102b2c19c14cfad1d7405eb8688a7 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 00:58:59 -0300 Subject: [PATCH 21/59] LM78 no longer needs to be a PCI device with the TRC change --- src/device/hwm_lm78.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index 3cc5812e6..e849190cf 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -776,7 +776,7 @@ lm78_init(const device_t *info) /* National Semiconductor LM78 on ISA and SMBus. */ const device_t lm78_device = { "National Semiconductor LM78 Hardware Monitor", - DEVICE_ISA | DEVICE_PCI, + DEVICE_ISA, 0x290 | LM78_I2C, lm78_init, lm78_close, lm78_reset, { NULL }, NULL, NULL, @@ -787,7 +787,7 @@ const device_t lm78_device = { /* Winbond W83781D on ISA and SMBus. */ const device_t w83781d_device = { "Winbond W83781D Hardware Monitor", - DEVICE_ISA | DEVICE_PCI, + DEVICE_ISA, 0x290 | LM78_I2C | LM78_W83781D, lm78_init, lm78_close, lm78_reset, { NULL }, NULL, NULL, @@ -799,7 +799,7 @@ const device_t w83781d_device = { I2C-only W83781D clone with additional voltages, GPIOs and fan control. */ const device_t as99127f_device = { "ASUS AS99127F Rev. 1 Hardware Monitor", - DEVICE_ISA | DEVICE_PCI, + DEVICE_ISA, LM78_I2C | LM78_AS99127F_REV1, lm78_init, lm78_close, lm78_reset, { NULL }, NULL, NULL, @@ -810,7 +810,7 @@ const device_t as99127f_device = { /* Rev. 2 is manufactured by Winbond and differs only in GPI registers. */ const device_t as99127f_rev2_device = { "ASUS AS99127F Rev. 2 Hardware Monitor", - DEVICE_ISA | DEVICE_PCI, + DEVICE_ISA, LM78_I2C | LM78_AS99127F_REV2, lm78_init, lm78_close, lm78_reset, { NULL }, NULL, NULL, @@ -821,7 +821,7 @@ const device_t as99127f_rev2_device = { /* Winbond W83782D on ISA and SMBus. */ const device_t w83782d_device = { "Winbond W83782D Hardware Monitor", - DEVICE_ISA | DEVICE_PCI, + DEVICE_ISA, 0x290 | LM78_I2C | LM78_W83782D, lm78_init, lm78_close, lm78_reset, { NULL }, NULL, NULL, From dfd6d4e2df6f22bdd18c0c40c422db5b4f97c25a Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 01:14:48 -0300 Subject: [PATCH 22/59] Add game port device with 6 I/O ports for the Crystal CS4237/8B --- src/game/gameport.c | 25 ++++++++++++++++++------- src/include/86box/gameport.h | 1 + src/sound/snd_cs423x.c | 7 ++++--- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/game/gameport.c b/src/game/gameport.c index 2c56f13b8..d33efb897 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -45,6 +45,7 @@ typedef struct { typedef struct _gameport_ { uint16_t addr; + uint8_t len; struct _joystick_instance_ *joystick; struct _gameport_ *next; } gameport_t; @@ -314,7 +315,7 @@ gameport_remap(void *priv, uint16_t address) } } - io_removehandler(dev->addr, (dev->addr & 1) ? 1 : 8, + io_removehandler(dev->addr, dev->len, gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev); } @@ -334,7 +335,7 @@ gameport_remap(void *priv, uint16_t address) other_dev->next = dev; } - io_sethandler(dev->addr, (dev->addr & 1) ? 1 : 8, + io_sethandler(dev->addr, dev->len, gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev); } } @@ -358,7 +359,7 @@ gameport_add(const device_t *gameport_type) { /* Prevent a standalone game port from being added later on, unless this is an unused Super I/O game port (no MACHINE_GAMEPORT machine flag). */ - if (!(gameport_type->local & 0x10000) || (machines[machine].flags & MACHINE_GAMEPORT)) + if (!(gameport_type->local & 0x1000000) || (machines[machine].flags & MACHINE_GAMEPORT)) standalone_gameport_type = NULL; /* Add game port device. */ @@ -401,6 +402,7 @@ gameport_init(const device_t *info) dev->joystick = joystick_instance; /* Map game port to the default address. Not applicable on PnP-only ports. */ + dev->len = (info->local >> 16) & 0xff; gameport_remap(dev, info->local & 0xffff); /* Register ISAPnP if this is a standard game port card. */ @@ -433,7 +435,7 @@ gameport_close(void *priv) const device_t gameport_device = { "Game port", - 0, 0x200, + 0, 0x080200, gameport_init, gameport_close, NULL, { NULL }, NULL, @@ -442,7 +444,7 @@ const device_t gameport_device = { const device_t gameport_201_device = { "Game port (port 201h only)", - 0, 0x201, + 0, 0x010201, gameport_init, gameport_close, NULL, { NULL }, NULL, @@ -451,7 +453,16 @@ const device_t gameport_201_device = { const device_t gameport_pnp_device = { "Game port (Plug and Play only)", - 0, 0, + 0, 0x080000, + gameport_init, + gameport_close, + NULL, { NULL }, NULL, + NULL +}; + +const device_t gameport_pnp_6io_device = { + "Game port (Plug and Play only, 6 I/O ports)", + 0, 0x060000, gameport_init, gameport_close, NULL, { NULL }, NULL, @@ -460,7 +471,7 @@ const device_t gameport_pnp_device = { const device_t gameport_sio_device = { "Game port (Super I/O)", - 0, 0x10000, + 0, 0x1080000, gameport_init, gameport_close, NULL, { NULL }, NULL, diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index 9f5da7f00..be8eec813 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -108,6 +108,7 @@ extern "C" { extern const device_t gameport_device; extern const device_t gameport_201_device; extern const device_t gameport_pnp_device; +extern const device_t gameport_pnp_6io_device; extern const device_t gameport_sio_device; extern const device_t *standalone_gameport_type; diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 57bf083ca..fbc8595b1 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -720,6 +720,10 @@ cs423x_init(const device_t *info) break; } + /* Initialize game port. The '7B and '8B game port only responds to 6 I/O ports; the remaining + 2 ports are reserved on those chips, and probably connected to the Digital Assist feature. */ + dev->gameport = gameport_add((dev->type == CRYSTAL_CS4236B) ? &gameport_pnp_device : &gameport_pnp_6io_device); + break; } @@ -731,9 +735,6 @@ cs423x_init(const device_t *info) cs423x_reset(dev); sound_add_handler(cs423x_get_buffer, dev); - /* Initialize game port. */ - dev->gameport = gameport_add(&gameport_pnp_device); - /* Initialize I2C bus for the EEPROM. */ dev->i2c = i2c_gpio_init("nvr_cs423x"); From ce7db25d7c9bc2c3ea49f406cc9d533badd7c1f3 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 01:15:23 -0300 Subject: [PATCH 23/59] Add hidden CS4237B and CS4238B devices --- src/include/86box/sound.h | 2 ++ src/sound/snd_cs423x.c | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index d280460e5..b15724cdd 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -126,6 +126,8 @@ extern const device_t ncr_business_audio_device; /* Crystal CS423x */ extern const device_t cs4236b_device; +extern const device_t cs4237b_device; +extern const device_t cs4238b_device; #endif #endif /*EMU_SOUND_H*/ diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index fbc8595b1..c900fb994 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -784,3 +784,27 @@ const device_t cs4236b_device = NULL, NULL }; + +const device_t cs4237b_device = +{ + "Crystal CS4237B", + DEVICE_ISA | DEVICE_AT, + CRYSTAL_CS4237B, + cs423x_init, cs423x_close, cs423x_reset, + { NULL }, + cs423x_speed_changed, + NULL, + NULL +}; + +const device_t cs4238b_device = +{ + "Crystal CS4238B", + DEVICE_ISA | DEVICE_AT, + CRYSTAL_CS4238B, + cs423x_init, cs423x_close, cs423x_reset, + { NULL }, + cs423x_speed_changed, + NULL, + NULL +}; From ea3d8448268355fb4e0ec4b8c736491292f54b7d Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 01:16:18 -0300 Subject: [PATCH 24/59] Add missing NULL check to CS423x game port. --- src/sound/snd_cs423x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index c900fb994..e11acc88b 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -618,7 +618,8 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv break; case 1: /* Game Port */ - gameport_remap(dev->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); + if (dev->gameport) + gameport_remap(dev->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); break; case 2: /* Control Registers */ From ff46734e5eb8d38267f72cdc4138c6c0cd67b635 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 14:18:21 -0300 Subject: [PATCH 25/59] Preserve logical device configuration on ISAPnP ROM update --- src/device/isapnp.c | 55 +++++++++++++++++++++++++++--------------- src/sound/snd_cs423x.c | 19 +++++++-------- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index 44885f837..62abb3202 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -53,7 +53,7 @@ static const uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 }; static const device_t isapnp_device; - +#define ENABLE_ISAPNP_LOG 1 #ifdef ENABLE_ISAPNP_LOG int isapnp_do_log = ENABLE_ISAPNP_LOG; @@ -717,17 +717,15 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) isapnp_log("ISAPnP: Parsing ROM resources for card %c%c%c%02X%02X (serial %08X)\n", '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[2], card->rom[3], (card->rom[7] << 24) | (card->rom[6] << 16) | (card->rom[5] << 8) | card->rom[4]); #endif uint16_t i = 9, j; - uint8_t ldn = 0, res, in_df = 0; + uint8_t existing = 0, ldn = 0, res, in_df = 0; uint8_t irq = 0, io = 0, mem_range = 0, mem_range_32 = 0, irq_df = 0, io_df = 0, mem_range_df = 0, mem_range_32_df = 0; uint32_t len; - isapnp_device_t *ld = card->first_ld, *prev_ld = NULL; + isapnp_device_t *ld = NULL, *prev_ld = NULL; - /* Clear any existing logical devices. */ - while (ld) { - prev_ld = ld->next; - free(ld); - ld = prev_ld; - } + /* Check if this is an existing card which already has logical devices. + Any new logical devices will be added to the list after existing ones. + Removed LDs are not flushed as we may end up with an invalid ROM. */ + existing = !!card->first_ld; /* Iterate through ROM resources. */ while (i < card->rom_size) { @@ -805,22 +803,39 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) #endif /* We're done with the previous logical device. */ - if (ld) { - prev_ld = ld; + if (ld && !existing) isapnp_reset_ld_regs(ld); + + /* Look for an existing logical device with this number, + and create one if none exist. */ + if (existing) { + ld = card->first_ld; + while (ld && (ld->number != ldn)) + ld = ld->next; + } + if (ld) { + /* Reset some logical device state. */ + ld->mem_upperlimit = ld->io_16bit = ld->irq_types = 0; + memset(ld->io_len, 0, sizeof(ld->io_len)); + } else { + /* Create logical device. */ + ld = (isapnp_device_t *) malloc(sizeof(isapnp_device_t)); + memset(ld, 0, sizeof(isapnp_device_t)); + + /* Add to end of list. */ + prev_ld = card->first_ld; + if (prev_ld) { + while (prev_ld->next) + prev_ld = prev_ld->next; + prev_ld->next = ld; + } else { + card->first_ld = ld; + } } - /* Create logical device. */ - ld = (isapnp_device_t *) malloc(sizeof(isapnp_device_t)); - memset(ld, 0, sizeof(isapnp_device_t)); - + /* Set and increment logical device number. */ ld->number = ldn++; - if (prev_ld) - prev_ld->next = ld; - else - card->first_ld = ld; - /* Start the position counts over. */ irq = io = mem_range = mem_range_32 = irq_df = io_df = mem_range_df = mem_range_32_df = 0; diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index e11acc88b..d8a8c1eee 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -302,7 +302,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) if (!val) { dev->ram_dl = 0; - /* Update PnP resource data and state. */ + /* Update PnP state and resource data. */ cs423x_pnp_enable(dev, 1); } break; @@ -728,14 +728,6 @@ cs423x_init(const device_t *info) break; } - /* Initialize SBPro codec first to get the correct CD audio filter for the default - context, which is SBPro. The WSS codec is initialized later by cs423x_reset */ - dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); - - /* Initialize RAM, registers and WSS codec. */ - cs423x_reset(dev); - sound_add_handler(cs423x_get_buffer, dev); - /* Initialize I2C bus for the EEPROM. */ dev->i2c = i2c_gpio_init("nvr_cs423x"); @@ -745,7 +737,14 @@ cs423x_init(const device_t *info) /* Initialize ISAPnP. */ dev->pnp_card = isapnp_add_card(NULL, 0, cs423x_pnp_config_changed, NULL, NULL, NULL, dev); - cs423x_pnp_enable(dev, 1); + + /* Initialize SBPro codec first to get the correct CD audio filter for the default + context, which is SBPro. The WSS codec is initialized later by cs423x_reset */ + dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device); + + /* Initialize RAM, registers and WSS codec. */ + cs423x_reset(dev); + sound_add_handler(cs423x_get_buffer, dev); return dev; } From 915981582334b7b035febb9feb2249943c3c1fac Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 15:30:52 -0300 Subject: [PATCH 26/59] CS423x: Implement internal FM control and analog power down --- src/sound/snd_cs423x.c | 137 +++++++++++++++++++++++------------------ src/sound/snd_sb.c | 2 +- 2 files changed, 79 insertions(+), 60 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index d8a8c1eee..0f70c2f8d 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -133,7 +133,8 @@ typedef struct cs423x_t void *i2c, *eeprom; uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11; - uint8_t type, ad1848_type, pnp_offset, regs[8], indirect_regs[16], eeprom_data[2048], ram_data[384], ram_dl; + uint8_t type, ad1848_type, pnp_offset, regs[8], indirect_regs[16], + eeprom_data[2048], ram_data[384], ram_dl: 2, opl_wss: 1; uint8_t pnp_enable: 1, key_pos: 5, slam_enable: 1, slam_state: 2, slam_ld, slam_reg; isapnp_device_config_t *slam_config; @@ -141,8 +142,7 @@ typedef struct cs423x_t static void cs423x_slam_enable(cs423x_t *dev, uint8_t enable); -static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom); -static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv); +static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig); static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); @@ -166,7 +166,7 @@ cs423x_read(uint16_t addr, void *priv) case 5: /* Control/RAM Access */ /* Reading RAM is undocumented; the WDM driver does so. */ - if (dev->ram_dl) { + if (dev->ram_dl == 3) { if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) /* chip configuration and PnP resources */ ret = dev->ram_data[dev->ram_addr & 0x01ff]; else @@ -249,7 +249,11 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) case 8: /* CS9236 Wavetable Control */ val &= 0x0f; - cs423x_pnp_enable(dev, 0); /* update WTEN bit */ + cs423x_pnp_enable(dev, 0, 0); + + /* Update WTEN state on the WSS codec. */ + dev->ad1848.wten = !!(val & 0x08); + ad1848_updatevolmask(&dev->ad1848); break; } dev->indirect_regs[dev->regs[3]] = val; @@ -264,7 +268,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) /* fall-through */ case 0x5a: /* Update Hardware Configuration Data */ - cs423x_pnp_enable(dev, 0); + cs423x_pnp_enable(dev, 0, 1); break; case 0x56: /* Disable Crystal Key */ @@ -303,7 +307,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) dev->ram_dl = 0; /* Update PnP state and resource data. */ - cs423x_pnp_enable(dev, 1); + cs423x_pnp_enable(dev, 1, 0); } break; @@ -455,32 +459,26 @@ cs423x_slam_enable(cs423x_t *dev, uint8_t enable) } -static uint8_t -cs423x_ctxswitch_read(uint16_t addr, void *priv) -{ - cs423x_ctxswitch_write(addr, 0, priv); - return 0xff; /* don't interfere with the actual handlers */ -} - - static void cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) { cs423x_t *dev = (cs423x_t *) priv; + uint8_t ctx = (dev->regs[7] & 0x80), + enable_opl = (dev->ad1848.xregs[4] & 0x10) && !(dev->indirect_regs[2] & 0x85); - /* Check if a context switch (WSS=1 <-> SBPro=0) occurred through the address being read/written. */ + /* Check if a context switch (WSS=1 <-> SBPro=0) occurred through the address being written. */ if ((dev->regs[7] & 0x80) ? ((addr & 0xfff0) == dev->sb_base) : ((addr & 0xfffc) == dev->wss_base)) { /* Flip context bit. */ dev->regs[7] ^= 0x80; + ctx ^= 0x80; - /* Switch OPL ownership and CD audio filter. + /* Update CD audio filter. FIXME: not thread-safe: filter function TOCTTOU in sound_cd_thread! */ - dev->sb->opl_enabled = !(dev->regs[7] & 0x80); sound_set_cd_audio_filter(NULL, NULL); - if (dev->sb->opl_enabled) /* SBPro */ - sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb); - else /* WSS */ + if (ctx) /* WSS */ sound_set_cd_audio_filter(ad1848_filter_cd_audio, &dev->ad1848); + else /* SBPro */ + sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb); /* Fire a context switch interrupt if enabled. */ if ((dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) { @@ -488,6 +486,11 @@ cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv) picint(1 << dev->ad1848.irq); /* control device shares IRQ with WSS and SBPro */ } } + + /* Update OPL ownership and state regardless of context switch, + to trap writes to other registers which may disable the OPL. */ + dev->sb->opl_enabled = !ctx && enable_opl; + dev->opl_wss = ctx && enable_opl; } @@ -495,21 +498,24 @@ static void cs423x_get_buffer(int32_t *buffer, int len, void *priv) { cs423x_t *dev = (cs423x_t *) priv; - int c, opl_wss = !dev->sb->opl_enabled; + int c, opl_wss = dev->opl_wss; - /* Output audio from the WSS codec, and also the OPL if we're in WSS mode. */ + /* Output audio from the WSS codec, and also the OPL if we're in charge of it. */ ad1848_update(&dev->ad1848); if (opl_wss) opl3_update(&dev->sb->opl); - for (c = 0; c < len * 2; c += 2) { - if (opl_wss) { - buffer[c] += (dev->sb->opl.buffer[c] * dev->ad1848.fm_vol_l) >> 16; - buffer[c + 1] += (dev->sb->opl.buffer[c + 1] * dev->ad1848.fm_vol_r) >> 16; - } + /* Don't output anything if the analog section is powered down. */ + if (!(dev->indirect_regs[2] & 0xa4)) { + for (c = 0; c < len * 2; c += 2) { + if (opl_wss) { + buffer[c] += (dev->sb->opl.buffer[c] * dev->ad1848.fm_vol_l) >> 16; + buffer[c + 1] += (dev->sb->opl.buffer[c + 1] * dev->ad1848.fm_vol_r) >> 16; + } - buffer[c] += dev->ad1848.buffer[c] / 2; - buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2; + buffer[c] += dev->ad1848.buffer[c] / 2; + buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2; + } } dev->ad1848.pos = 0; @@ -519,35 +525,49 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv) static void -cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom) +cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig) { uint8_t enable = ISAPNP_CARD_ENABLE; - /* Hide PnP card if the PKD bit is set, or if PnP was disabled by command 0x55. */ - if ((dev->ram_data[2] & 0x20) || !dev->pnp_enable) - enable = ISAPNP_CARD_DISABLE; + if (dev->pnp_card) { + /* Hide PnP card if the PKD bit is set, or if PnP was disabled by command 0x55. */ + if ((dev->ram_data[2] & 0x20) || !dev->pnp_enable) + enable = ISAPNP_CARD_DISABLE; - /* Update PnP resource data if requested. */ - if (update_rom) - isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], sizeof(dev->ram_data) - dev->pnp_offset); + /* Update PnP resource data if requested. */ + if (update_rom) + isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], sizeof(dev->ram_data) - dev->pnp_offset); - /* Update PnP state. */ - isapnp_enable_card(dev->pnp_card, enable); - - /* While we're here, update FM and wavetable enable bits based on the config data in RAM. */ - if (dev->ram_data[3] & 0x08) { - dev->indirect_regs[8] |= 0x08; - dev->ad1848.wten = 1; - } else { - dev->indirect_regs[8] &= ~0x08; - dev->ad1848.wten = 0; + /* Update PnP state. */ + isapnp_enable_card(dev->pnp_card, enable); } - if (dev->ram_data[3] & 0x80) - dev->ad1848.xregs[4] |= 0x10; - else - dev->ad1848.xregs[4] &= ~0x10; - ad1848_updatevolmask(&dev->ad1848); + /* Update some register bits based on the config data in RAM if requested. */ + if (update_hwconfig) { + /* Update WTEN. */ + if (dev->ram_data[3] & 0x08) { + dev->indirect_regs[8] |= 0x08; + dev->ad1848.wten = 1; + } else { + dev->indirect_regs[8] &= ~0x08; + dev->ad1848.wten = 0; + } + + /* Update SPS. */ + if (dev->ram_data[3] & 0x04) + dev->indirect_regs[8] |= 0x04; + else + dev->indirect_regs[8] &= ~0x04; + + /* Update IFM. */ + if (dev->ram_data[3] & 0x80) + dev->ad1848.xregs[4] |= 0x10; + else + dev->ad1848.xregs[4] &= ~0x10; + + /* Inform WSS codec of the changes. */ + ad1848_updatevolmask(&dev->ad1848); + } } @@ -560,7 +580,7 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv case 0: /* WSS, OPL3 and SBPro */ if (dev->wss_base) { io_removehandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848); - io_removehandler(dev->wss_base, 4, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + io_removehandler(dev->wss_base, 4, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); dev->wss_base = 0; } @@ -574,7 +594,7 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv io_removehandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); io_removehandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); io_removehandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); - io_removehandler(dev->sb_base, 16, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + io_removehandler(dev->sb_base, 16, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); dev->sb_base = 0; } @@ -588,7 +608,7 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv if (config->io[0].base != ISAPNP_IO_DISABLED) { dev->wss_base = config->io[0].base; io_sethandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848); - io_sethandler(dev->wss_base, 4, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + io_sethandler(dev->wss_base, 4, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); } if (config->io[1].base != ISAPNP_IO_DISABLED) { @@ -602,7 +622,7 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv io_sethandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); io_sethandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl); io_sethandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb); - io_sethandler(dev->sb_base, 16, cs423x_ctxswitch_read, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + io_sethandler(dev->sb_base, 16, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); } if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) { @@ -674,10 +694,9 @@ cs423x_reset(void *priv) /* Reset PnP resource data, state and logical devices. */ dev->pnp_enable = 1; - if (dev->pnp_card) { - cs423x_pnp_enable(dev, 1); + cs423x_pnp_enable(dev, 1, 1); + if (dev->pnp_card) isapnp_reset_card(dev->pnp_card); - } /* Reset SLAM. */ cs423x_slam_enable(dev, 1); diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index aa00b33a4..8e1ea61a4 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1630,7 +1630,7 @@ sb_pro_cs423x_init(const device_t *info) sb_t *sb = malloc(sizeof(sb_t)); memset(sb, 0, sizeof(sb_t)); - sb->opl_enabled = 1; /* WSS can disable this to take ownership of the OPL */ + sb->opl_enabled = 0; /* updated by cs423x code */ opl3_init(&sb->opl); sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); From 5cd255a0e0e576db3346c2932d98c895be098865 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 15:31:10 -0300 Subject: [PATCH 27/59] Fix CS4236 codec remapped register reads --- src/sound/snd_ad1848.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 176da40da..ff4c0be83 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -135,9 +135,9 @@ ad1848_read(uint16_t addr, void *priv) case 18: case 19: if (ad1848->type == AD1848_TYPE_CS4236) { - if (ad1848->xregs[4] & 0x04) /* FM remapping */ + if ((ad1848->xregs[4] & 0x14) == 0x14) /* FM remapping */ ret = ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */ - else if (ad1848->xregs[4] & 0x08) /* wavetable remapping */ + else if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) /* wavetable remapping */ ret = ad1848->xregs[ad1848->index - 2]; /* real wavetable volume on registers 16 and 17 */ } break; From 62afe317570662a7831d1ca632d9d404f32a8fd1 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 16:02:04 -0300 Subject: [PATCH 28/59] Remove EBGA368 due to poor research (CPUs are Samuel 2 and newer only) --- src/cpu/cpu.c | 55 ---------------------------- src/cpu/cpu.h | 7 ++-- src/cpu/cpu_table.c | 11 ------ src/include/86box/machine.h | 4 --- src/machine/CMakeLists.txt | 3 +- src/machine/m_at_ebga368.c | 71 ------------------------------------- src/machine/machine_table.c | 5 --- src/win/Makefile.mingw | 1 - 8 files changed, 4 insertions(+), 153 deletions(-) delete mode 100644 src/machine/m_at_ebga368.c diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 34d3db534..62e497578 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -1278,7 +1278,6 @@ cpu_set(void) break; case CPU_CYRIX3S: - case CPU_EDEN: /* This until proper timings get discovered */ #ifdef USE_DYNAREC x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f); #else @@ -2015,58 +2014,6 @@ cpu_CPUID(void) break; } break; - - case CPU_EDEN: - switch (EAX) { - case 0: - EAX = 1; - if (msr.fcr2 & (1 << 14)) { - EBX = msr.fcr3 >> 32; - ECX = msr.fcr3 & 0xffffffff; - EDX = msr.fcr2 >> 32; - } else { - EBX = 0x746e6543; /* CentaurHauls */ - ECX = 0x736c7561; - EDX = 0x48727561; - } - break; - case 1: - EAX = CPUID; - EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MMX | CPUID_MTRR; - if (cpu_has_feature(CPU_FEATURE_CX8)) - EDX |= CPUID_CMPXCHG8B; - break; - case 0x80000000: - EAX = 0x80000006; - break; - case 0x80000001: - EAX = CPUID; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MMX | CPUID_MTRR | CPUID_3DNOW; - if (cpu_has_feature(CPU_FEATURE_CX8)) - EDX |= CPUID_CMPXCHG8B; - break; - case 0x80000002: /* Processor name string */ - case 0x80000003: - case 0x80000004: - EAX = 0x20414956; /* VIA Samuel 2 */ - EBX = 0x756d6153; - ECX = 0x32206c65; - EDX = 0x00000000; - break; - case 0x80000005: /* Cache information */ - EBX = 0x08800880; /* TLBs */ - ECX = 0x40040120; /* L1 data cache */ - EDX = 0x40020120; /* L1 instruction cache */ - break; - case 0x80000006: - ECX = 0x40040120; /* L2 data cache */ - break; - default: - EAX = EBX = ECX = EDX = 0; - break; - } - break; } } @@ -2157,7 +2104,6 @@ cpu_RDMSR(void) break; case CPU_CYRIX3S: - case CPU_EDEN: EAX = EDX = 0; switch (ECX) { case 0x10: @@ -2609,7 +2555,6 @@ cpu_WRMSR(void) break; case CPU_CYRIX3S: - case CPU_EDEN: switch (ECX) { case 0x10: tsc = EAX | ((uint64_t)EDX << 32); diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 35209bc1a..d336b9a26 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -76,7 +76,6 @@ enum { CPU_K6_2P, CPU_K6_3P, CPU_CYRIX3S, - CPU_EDEN, CPU_PENTIUMPRO, /* 686 class CPUs */ CPU_PENTIUM2, CPU_PENTIUM2D @@ -247,7 +246,7 @@ typedef struct { uint64_t ia32_pmc[8]; /* 0x000000c1 - 0x000000c8 */ uint64_t mtrr_cap; /* 0x000000fe */ - /* IDT WinChip and WinChip 2 MSR's that are also on the VIA Cyrix III and Eden */ + /* IDT WinChip and WinChip 2 MSR's that are also on the VIA Cyrix III */ uint32_t fcr; /* 0x00000107 (IDT), 0x00001107 (VIA) */ uint64_t fcr2, fcr3; /* 0x00000108 (IDT), 0x00001108 (VIA) */ @@ -266,7 +265,7 @@ typedef struct { uint64_t ecx1e0; /* 0x000001e0 */ /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's that are also - on the VIA Cyrix III and Eden */ + on the VIA Cyrix III */ uint64_t mtrr_physbase[8]; /* 0x00000200 - 0x0000020f */ uint64_t mtrr_physmask[8]; /* 0x00000200 - 0x0000020f (ECX & 1) */ uint64_t mtrr_fix64k_8000; /* 0x00000250 */ @@ -278,7 +277,7 @@ typedef struct { uint64_t pat; /* 0x00000277 */ /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's that are also - on the VIA Cyrix III and Eden */ + on the VIA Cyrix III */ uint64_t mtrr_deftype; /* 0x000002ff */ /* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */ diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 9f8d94ca4..fca0d60e3 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -1036,17 +1036,6 @@ const cpu_family_t cpu_families[] = { {"733", CPU_CYRIX3S, fpus_internal, 733333333, 5.5, 2050, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 66, 66, 18, 18, 88}, {"", 0} } - }, { - .package = CPU_PKG_EBGA368, - .manufacturer = "VIA", - .name = "Eden Model 7", - .internal_name = "c3_eden", - .cpus = (const CPU[]) { - {"66", CPU_EDEN, fpus_internal, 66666666, 1.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 6, 6, 3, 3, 8}, /* out of spec */ - {"100", CPU_EDEN, fpus_internal, 100000000, 1.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 9, 9, 4, 4, 12}, /* out of spec */ - {"400", CPU_EDEN, fpus_internal, 400000000, 6.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 36, 36, 17, 17, 48}, - {"600", CPU_EDEN, fpus_internal, 600000000, 6.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 54, 54, 18, 18, 72}, - } }, { .package = 0, } diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 677dc7027..5c6ee5567 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -111,7 +111,6 @@ enum { MACHINE_TYPE_SLOT1_2, MACHINE_TYPE_SLOT2, MACHINE_TYPE_SOCKET370, - MACHINE_TYPE_EBGA368, MACHINE_TYPE_MISC, MACHINE_TYPE_MAX }; @@ -565,9 +564,6 @@ extern int machine_at_603tcf_init(const machine_t *); extern int machine_at_trinity371_init(const machine_t *); extern int machine_at_p6bap_init(const machine_t *); -/* m_at_ebga368.c */ -extern int machine_at_arb9673_init(const machine_t *); - /* m_at_misc.c */ extern int machine_at_vpc2007_init(const machine_t *); diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 6c1745ea8..9b16413f6 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -20,8 +20,7 @@ add_library(mch OBJECT machine.c machine_table.c m_xt.c m_xt_compaq.c m_at_t3100e.c m_at_t3100e_vid.c m_ps1.c m_ps1_hdc.c m_ps2_isa.c m_ps2_mca.c m_at_compaq.c m_at_286_386sx.c m_at_386dx_486.c m_at_socket4_5.c m_at_socket7.c m_at_sockets7.c m_at_socket8.c - m_at_slot1.c m_at_slot2.c m_at_socket370.c m_at_ebga368.c - m_at_misc.c) + m_at_slot1.c m_at_slot2.c m_at_socket370.c m_at_misc.c) if(HEDAKA) target_compile_definitions(mch PRIVATE USE_HEDAKA) diff --git a/src/machine/m_at_ebga368.c b/src/machine/m_at_ebga368.c deleted file mode 100644 index 48f19390f..000000000 --- a/src/machine/m_at_ebga368.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of VIA EBGA368 Based Single Board Computers. - * - * Note: 86Box doesn't emulate all the components a SBC may have. - * - * Authors: Miran Grca, - * Tiseno100 - * - * Copyright 2016-2019 Miran Grca. - * Copyright 2021 Tiseno100. - */ -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/mem.h> -#include <86box/io.h> -#include <86box/rom.h> -#include <86box/pci.h> -#include <86box/device.h> -#include <86box/chipset.h> -#include <86box/hdc.h> -#include <86box/hdc_ide.h> -#include <86box/keyboard.h> -#include <86box/flash.h> -#include <86box/sio.h> -#include <86box/hwm.h> -#include <86box/spd.h> -#include <86box/video.h> -#include "cpu.h" -#include <86box/machine.h> - -int -machine_at_arb9673_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/arb9673/W9673.v12", - 0x00080000, 524288, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); - device_add(&via_vt8601_device); - device_add(&via_vt82c686b_device); - device_add(&via_vt82c686_sio_device); - device_add(&via_vt82c686_hwm_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&sst_flash_39sf040_device); - spd_register(SPD_TYPE_SDRAM, 0xf, 32); - - - return ret; -} diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 117afc4d4..a1487d534 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -54,7 +54,6 @@ const machine_type_t machine_types[] = { { "Slot 1/2", MACHINE_TYPE_SLOT1_2 }, { "Slot 2", MACHINE_TYPE_SLOT2 }, { "Socket 370", MACHINE_TYPE_SOCKET370 }, - { "EBGA 368", MACHINE_TYPE_EBGA368 }, { "Miscellaneous", MACHINE_TYPE_MISC } }; @@ -464,10 +463,6 @@ const machine_t machines[] = { { "[VIA Apollo Pro133A] Acorp 6VIA90AP", "6via90ap", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, MACHINE_MULTIPLIER_FIXED, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1572864, 8192, 255, machine_at_6via90ap_init, NULL }, { "[VIA Apollo ProMedia] Jetway 603TCF", "603tcf", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_603tcf_init, NULL }, - /* EBGA368 machines */ - /* VIA Apollo Pro */ - { "[VIA Apollo ProMedia] Acrosser AR-B9673","arb9673", MACHINE_TYPE_EBGA368, CPU_PKG_EBGA368, 0, 100000000, 133333333, 2050, 2050, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 131072, 131072, 0, 31, machine_at_arb9673_init, NULL }, - /* Miscellaneous/Fake/Hypervisor machines */ { "[i440BX] Microsoft Virtual PC 2007", "vpc2007", MACHINE_TYPE_MISC, CPU_PKG_SLOT1, CPU_BLOCK(CPU_PENTIUM2, CPU_CYRIX3S), 0, 0, 0, 0, 0, 0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_vpc2007_init, NULL }, diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 79ee75f06..258dec2bc 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -634,7 +634,6 @@ MCHOBJ := machine.o machine_table.o \ m_at_286_386sx.o m_at_386dx_486.o \ m_at_socket4_5.o m_at_socket7.o m_at_sockets7.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \ - m_at_ebga368.o \ m_at_misc.o DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ From 2b692640e128bc68689ba88c0885c224ffbf98ae Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 16:02:15 -0300 Subject: [PATCH 29/59] Disable ISAPnP logging --- src/device/isapnp.c | 2 +- src/game/gameport.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index 62abb3202..69da4ca13 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -53,7 +53,7 @@ static const uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 }; static const device_t isapnp_device; -#define ENABLE_ISAPNP_LOG 1 + #ifdef ENABLE_ISAPNP_LOG int isapnp_do_log = ENABLE_ISAPNP_LOG; diff --git a/src/game/gameport.c b/src/game/gameport.c index d33efb897..ce9e4b086 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -272,6 +272,7 @@ timer_over(void *priv) axis->joystick->state &= ~(1 << axis->axis_nr); + /* Notify the joystick when the first axis' period is finished. */ if (axis == &axis->joystick->axis[0]) axis->joystick->intf->a0_over(axis->joystick->dat); } From dc4906a23fa591ec58cd71bf15274c2459fce9b1 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 17:30:50 -0300 Subject: [PATCH 30/59] Fix ISAPnP logical devices going missing --- src/device/isapnp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index 69da4ca13..e948d97f9 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -813,7 +813,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) while (ld && (ld->number != ldn)) ld = ld->next; } - if (ld) { + if (ld && (ld->number == ldn)) { /* Reset some logical device state. */ ld->mem_upperlimit = ld->io_16bit = ld->irq_types = 0; memset(ld->io_len, 0, sizeof(ld->io_len)); @@ -960,7 +960,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) } /* We're done with the last logical device. */ - if (ld) + if (ld && !existing) isapnp_reset_ld_regs(ld); } From 15888eeff87cb8362ee7cdc3d4269e7091e2cca1 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 3 Jun 2021 17:40:54 -0300 Subject: [PATCH 31/59] Add snd_cs423x.c to CMake list --- src/sound/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 32d72a34f..d991e5cc2 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -16,8 +16,8 @@ add_library(snd OBJECT sound.c openal.c snd_opl.c snd_opl_nuked.c snd_resid.cc midi.c midi_system.c snd_speaker.c snd_pssj.c snd_lpt_dac.c snd_lpt_dss.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c - snd_azt2316a.c snd_cms.c snd_gus.c snd_sb.c snd_sb_dsp.c snd_emu8k.c - snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c) + snd_azt2316a.c snd_cms.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c + snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c) if(FLUIDSYNTH) target_compile_definitions(snd PRIVATE USE_FLUIDSYNTH) From 368c92780a3c81b93b1871e47dbd7bc2b5be9046 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 3 Jun 2021 23:15:34 +0200 Subject: [PATCH 32/59] Added a version of the Winbond W83787F Super I/O chip with IDE enabled by default, fixes IDE on the Flytech 386. --- src/include/86box/sio.h | 1 + src/machine/m_at_286_386sx.c | 2 +- src/sio/sio_w83787f.c | 23 ++++++++++++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index f1e6cf82d..bf9f5526c 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -67,6 +67,7 @@ extern const device_t um8669f_device; extern const device_t via_vt82c686_sio_device; extern const device_t w83787f_device; extern const device_t w83787f_ide_device; +extern const device_t w83787f_ide_en_device; extern const device_t w83787f_ide_sec_device; extern const device_t w83877f_device; extern const device_t w83877f_president_device; diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index c920ee531..1e7ec471a 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -644,7 +644,7 @@ machine_at_flytech386_init(const machine_t *model) machine_at_common_init(model); device_add(&ali1217_device); - device_add(&w83787f_ide_device); + device_add(&w83787f_ide_en_device); device_add(&keyboard_ps2_device); if (gfxcard == VID_INTERNAL) diff --git a/src/sio/sio_w83787f.c b/src/sio/sio_w83787f.c index e95d77035..ca0bfcc49 100644 --- a/src/sio/sio_w83787f.c +++ b/src/sio/sio_w83787f.c @@ -78,7 +78,8 @@ typedef struct { uint16_t reg_init; int locked, rw_locked, cur_reg, - key, ide_function; + key, ide_function, + ide_start; fdc_t *fdc; serial_t *uart[2]; } w83787f_t; @@ -260,6 +261,7 @@ w83787f_write(uint16_t port, uint8_t val, void *priv) switch (dev->cur_reg) { case 0: + pclog("REG 00: %02X\n", val); if ((valxor & 0xc0) && (HAS_IDE_FUNCTIONALITY)) w83787f_ide_handler(dev); if (valxor & 0x30) @@ -376,6 +378,14 @@ w83787f_reset(w83787f_t *dev) ide_set_base(0, 0x1f0); ide_set_side(0, 0x3f6); } + + if (dev->ide_start) { + dev->regs[0x00] &= 0x7f; + if (dev->ide_function & 0x20) + ide_sec_enable(); + else + ide_pri_enable(); + } } else dev->regs[0x00] = 0xd0; @@ -426,6 +436,8 @@ w83787f_init(const device_t *info) if ((dev->ide_function & 0x30) == 0x10) device_add(&ide_isa_device); + dev->ide_start = !!(info->local & 0x40); + dev->reg_init = info->local & 0x0f; w83787f_reset(dev); @@ -451,6 +463,15 @@ const device_t w83787f_ide_device = { NULL }; +const device_t w83787f_ide_en_device = { + "Winbond W83787F/IF Super I/O (With IDE Enabled)", + 0, + 0x59, + w83787f_init, w83787f_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + const device_t w83787f_ide_sec_device = { "Winbond W83787F/IF Super I/O (With Secondary IDE)", 0, From e240342c4bd4bba0bf32a5eb0746468ad95a7f50 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 3 Jun 2021 23:18:43 +0200 Subject: [PATCH 33/59] Implemented packed Chain 4 support on the Voodoo Banshee and 3. --- src/video/vid_voodoo_banshee.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 7083c10ee..bd9c32688 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -664,6 +664,7 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) banshee->vgaInit1 = val; svga->write_bank = (val & 0x3ff) << 15; svga->read_bank = ((val >> 10) & 0x3ff) << 15; + svga->packed_chain4 = !!(svga->chain4 && 0x00100000); break; case PLL_pllCtrl0: From 9161f9a071b3562160a5e3051b870c70f09be329 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 3 Jun 2021 23:54:12 +0200 Subject: [PATCH 34/59] Slight fix. --- src/video/vid_voodoo_banshee.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index bd9c32688..04ccff237 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -664,7 +664,7 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) banshee->vgaInit1 = val; svga->write_bank = (val & 0x3ff) << 15; svga->read_bank = ((val >> 10) & 0x3ff) << 15; - svga->packed_chain4 = !!(svga->chain4 && 0x00100000); + svga->packed_chain4 = !!(val && 0x00100000); break; case PLL_pllCtrl0: From eef77b7c869f87e3da302becaa376e3266696e24 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 4 Jun 2021 02:41:13 +0200 Subject: [PATCH 35/59] Added a way to force legacy mode as a temporary fix for the Voodoo Banshee/3 until there's a proper fix. --- src/include/86box/vid_svga.h | 3 +++ src/include/86box/vid_svga_render_remap.h | 2 +- src/video/vid_voodoo_banshee.c | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 73c176742..776799e4b 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -154,6 +154,9 @@ typedef struct svga_t /*Force CRTC to dword mode, regardless of CR14/CR17. Required for S3 enhanced mode*/ int force_dword_mode; + /*Force CRTC to legacy mode. Required for Voodoo Banshee/3 until there's a proper fix*/ + int force_legacy_mode; + int remap_required; uint32_t (*remap_func)(struct svga_t *svga, uint32_t in_addr); diff --git a/src/include/86box/vid_svga_render_remap.h b/src/include/86box/vid_svga_render_remap.h index c2e48f1b2..6fdcd2928 100644 --- a/src/include/86box/vid_svga_render_remap.h +++ b/src/include/86box/vid_svga_render_remap.h @@ -101,7 +101,7 @@ void svga_recalc_remap_func(svga_t *svga) { int func_nr; - if (svga->fb_only) + if (svga->fb_only || svga->force_legacy_mode) func_nr = 0; else { if (svga->force_dword_mode) diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 04ccff237..a3ff5c164 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -485,9 +485,11 @@ static void banshee_recalctimings(svga_t *svga) // banshee_log("svga->hdisp=%i\n", svga->hdisp); svga->interlace = 0; + svga->force_legacy_mode = 0; if (banshee->vgaInit0 & VGAINIT0_EXTENDED_SHIFT_OUT) { + svga->force_legacy_mode = 1; switch (VIDPROCCFG_DESKTOP_PIX_FORMAT) { case PIX_FORMAT_8: @@ -664,7 +666,7 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) banshee->vgaInit1 = val; svga->write_bank = (val & 0x3ff) << 15; svga->read_bank = ((val >> 10) & 0x3ff) << 15; - svga->packed_chain4 = !!(val && 0x00100000); + svga->packed_chain4 = !!(val & 0x00100000); break; case PLL_pllCtrl0: From f870f3439ce5fa46ee5d27201889c6e3529ab4d4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 4 Jun 2021 02:46:41 +0200 Subject: [PATCH 36/59] Fixed the Shuttle HOT-539 segmentation fault. --- src/game/gameport.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/game/gameport.c b/src/game/gameport.c index ce9e4b086..a3ebd3a99 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -331,9 +331,10 @@ gameport_remap(void *priv, uint16_t address) } else { /* Port at other addresses: add to bottom. */ other_dev = active_gameports; - while (other_dev->next) + while (other_dev && other_dev->next) other_dev = other_dev->next; - other_dev->next = dev; + if (other_dev) + other_dev->next = dev; } io_sethandler(dev->addr, dev->len, From b4d35af1498af35924ccf0ece243cba930b54aca Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 5 Jun 2021 20:24:51 +0200 Subject: [PATCH 37/59] ICS 53xx/GENDAC/SDAC RAMDAC fixes. --- src/video/vid_sdac_ramdac.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/video/vid_sdac_ramdac.c b/src/video/vid_sdac_ramdac.c index 78f0bfd86..221cee342 100644 --- a/src/video/vid_sdac_ramdac.c +++ b/src/video/vid_sdac_ramdac.c @@ -167,10 +167,6 @@ sdac_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga) switch (ramdac->magic_count) { case 4: sdac_control_write(ramdac, svga, val); - if (!(ramdac->type & ICS_S3)) - ramdac->magic_count = 0; - break; - case 5: ramdac->magic_count = 0; break; default: @@ -215,21 +211,15 @@ sdac_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga) switch (rs) { case 0x02: switch (ramdac->magic_count) { - case 1: - case 2: case 3: + case 1: case 2: temp = 0x00; ramdac->magic_count++; break; - case 4: - if (ramdac->type & ICS_S3) { - temp = 0x70; /* SDAC ID */ - ramdac->magic_count++; - } else { - temp = ramdac->command; - ramdac->magic_count = 0; - } + case 3: + temp = (ramdac->type & ICS_S3) ? 0x70 : 0x00; + ramdac->magic_count++; break; - case 5: + case 4: temp = ramdac->command; ramdac->magic_count = 0; break; From 76271ddd08760697294ab6507fd6533e2ca7604a Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 5 Jun 2021 20:50:38 +0200 Subject: [PATCH 38/59] Fixed 256 color modes in the Oak OTI cards. Made the New MMIO-capable S3 cards behave like the ViRGE for the double word/packed chain-4 addressing. --- src/video/vid_oak_oti.c | 1 + src/video/vid_s3.c | 136 +++++++++++++++++++++++++++++----------- 2 files changed, 101 insertions(+), 36 deletions(-) diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index 7b0ba3a56..cd7d4e26e 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -405,6 +405,7 @@ oti_init(const device_t *info) oti_in, NULL, NULL, oti_out, NULL, NULL, oti); oti->svga.miscout = 1; + oti->svga.packed_chain4 = 1; return(oti); } diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index bb8474ab9..8b4b078b7 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -355,22 +355,31 @@ static void s3_pci_write(int func, int addr, uint8_t val, void *p); /*Remap address for chain-4/doubleword style layout*/ static __inline uint32_t -dword_remap(uint32_t in_addr) +dword_remap(svga_t *svga, uint32_t in_addr) { + if (svga->packed_chain4) + return in_addr; + return ((in_addr << 2) & 0x3fff0) | ((in_addr >> 14) & 0xc) | (in_addr & ~0x3fffc); } static __inline uint32_t -dword_remap_w(uint32_t in_addr) +dword_remap_w(svga_t *svga, uint32_t in_addr) { + if (svga->packed_chain4) + return in_addr; + return ((in_addr << 2) & 0x1fff8) | ((in_addr >> 14) & 0x6) | (in_addr & ~0x1fffe); } static __inline uint32_t -dword_remap_l(uint32_t in_addr) +dword_remap_l(svga_t *svga, uint32_t in_addr) { + if (svga->packed_chain4) + return in_addr; + return ((in_addr << 2) & 0xfffc) | ((in_addr >> 14) & 0x3) | (in_addr & ~0xffff); @@ -1657,7 +1666,7 @@ s3_hwcursor_draw(svga_t *svga, int displine) for (x = 0; x < 64; x += 16) { - uint32_t remapped_addr = dword_remap(svga->hwcursor_latch.addr); + uint32_t remapped_addr = dword_remap(svga, svga->hwcursor_latch.addr); dat[0] = (svga->vram[remapped_addr] << 8) | svga->vram[remapped_addr + 1]; dat[1] = (svga->vram[remapped_addr + 2] << 8) | svga->vram[remapped_addr + 3]; @@ -1938,8 +1947,9 @@ static void s3_trio64v_overlay_draw(svga_t *svga, int displine) int x_size, x_read = 4, x_write = 4; int x; uint32_t *p; - uint8_t *src = &svga->vram[svga->overlay_latch.addr]; - + uint32_t remapped_addr = dword_remap(svga, svga->overlay_latch.addr); + uint8_t *src = &svga->vram[remapped_addr]; + p = &(buffer32->line[displine][offset + svga->x_add]); if ((offset + s3->streams.sec_w) > s3->streams.pri_w) @@ -2222,6 +2232,8 @@ s3_out(uint16_t addr, uint8_t val, void *p) rs2 = !!(svga->crtc[0x43] & 0x02); else rs2 = (svga->crtc[0x55] & 0x01); + + pclog("Write RS2 enabled: crtc43 bit 1 = %02x, crtc55 bits 0-1 = %02x\n", svga->crtc[0x43] & 0x02, svga->crtc[0x55] & 0x03); if (s3->chip >= S3_TRIO32) svga_out(addr, val, svga); else if ((s3->chip == S3_VISION964 && s3->card_type != S3_ELSAWIN2KPROX_964) || (s3->chip == S3_86C928)) { @@ -2264,7 +2276,8 @@ s3_out(uint16_t addr, uint8_t val, void *p) { case 0x31: s3->ma_ext = (s3->ma_ext & 0x1c) | ((val & 0x30) >> 4); - svga->force_dword_mode = val & 0x08; + if (!svga->packed_chain4) + svga->force_dword_mode = !!(val & 0x08); break; case 0x32: if (svga->crtc[0x31] & 0x30) @@ -2528,8 +2541,19 @@ s3_in(uint16_t addr, void *p) case 0x6a: return s3->bank; /* Phoenix S3 video BIOS'es seem to expect CRTC registers 6B and 6C to be mirrors of 59 and 5A. */ - case 0x6b: return (s3->chip >= S3_TRIO64V) ? (svga->crtc[0x59] & 0xfc) : ((s3->chip == S3_VISION968 || s3->chip == S3_VISION868) ? (svga->crtc[0x59] & 0xfe) : svga->crtc[0x59]); - case 0x6c: return (s3->chip >= S3_TRIO64V || s3->chip == S3_VISION968 || s3->chip == S3_VISION868) ? 0 : (svga->crtc[0x5a] & 0x80); + case 0x6b: + if (svga->crtc[0x53] & 0x08) { + return (s3->chip >= S3_TRIO64V) ? (svga->crtc[0x59] & 0xfc) : (svga->crtc[0x59] & 0xfe); + } else { + return svga->crtc[0x59]; + } + break; + case 0x6c: + if (svga->crtc[0x53] & 0x08) + return 0x00; + else + return (svga->crtc[0x5a] & 0x80); + break; } return svga->crtc[svga->crtcreg]; } @@ -2591,7 +2615,7 @@ static void s3_recalctimings(svga_t *svga) if (s3->width == 2048 || s3->width == 1280 || s3->width == 1600) svga->hdisp *= 2; } else if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805) && (s3->chip != S3_TRIO32) && - (s3->chip != S3_TRIO64) && (s3->chip != S3_TRIO64V)) { + (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964) && (s3->chip != S3_VISION968)) { if (s3->width == 1280 || s3->width == 1600) svga->hdisp *= 2; } @@ -2608,7 +2632,7 @@ static void s3_recalctimings(svga_t *svga) svga->hdisp /= 2; } if ((s3->chip != S3_VISION868) && (s3->chip != S3_TRIO32) && - (s3->chip != S3_TRIO64) && (s3->chip != S3_TRIO64V)) { + (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964)) { if (s3->width == 1280 || s3->width == 1600) svga->hdisp *= 2; } @@ -2624,7 +2648,7 @@ static void s3_recalctimings(svga_t *svga) svga->hdisp /= 2; } if ((s3->chip != S3_VISION868) && (s3->chip != S3_TRIO32) && - (s3->chip != S3_TRIO64) && (s3->chip != S3_TRIO64V)) { + (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964)) { if (s3->width == 1280 || s3->width == 1600) svga->hdisp *= 2; } @@ -2684,7 +2708,8 @@ static void s3_trio64v_recalctimings(svga_t *svga) if (svga->crtc[0x51] & 0x30) svga->rowoffset |= (svga->crtc[0x51] & 0x30) << 4; else if (svga->crtc[0x43] & 0x04) svga->rowoffset |= 0x100; if (!svga->rowoffset) svga->rowoffset = 256; - + + svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) { switch (svga->bpp) { case 8: @@ -2828,7 +2853,6 @@ s3_updatemapping(s3_t *s3) case S3_TRIO64V: case S3_TRIO64V2: case S3_86C928: - case S3_VISION868: s3->linear_size = 0x400000; break; default: @@ -2852,9 +2876,10 @@ s3_updatemapping(s3_t *s3) s3->linear_base &= 0xfe000000; mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); } - } else + } else { mem_mapping_disable(&s3->linear_mapping); - + } + /* Memory mapped I/O. */ if ((svga->crtc[0x53] & 0x10) || (s3->accel.advfunc_cntl & 0x20)) { mem_mapping_disable(&svga->mapping); @@ -2863,18 +2888,16 @@ s3_updatemapping(s3_t *s3) mem_mapping_set_addr(&s3->mmio_mapping, 0xb8000, 0x8000); else mem_mapping_set_addr(&s3->mmio_mapping, 0xa0000, 0x10000); - } else { + } else mem_mapping_enable(&s3->mmio_mapping); - } } else mem_mapping_disable(&s3->mmio_mapping); /* New MMIO. */ - if (svga->crtc[0x53] & 0x08) { + if (svga->crtc[0x53] & 0x08) mem_mapping_set_addr(&s3->new_mmio_mapping, s3->linear_base + 0x1000000, 0x20000); - } else { + else mem_mapping_disable(&s3->new_mmio_mapping); - } } } @@ -3258,45 +3281,59 @@ s3_accel_in(uint16_t port, void *p) break; case 0xd148: case 0xd2e8: + s3_wait_fifo_idle(s3); return s3->accel.ropmix & 0xff; case 0xd149: case 0xd2e9: + s3_wait_fifo_idle(s3); return s3->accel.ropmix >> 8; case 0xe548: case 0xe6e8: + s3_wait_fifo_idle(s3); return s3->accel.pat_bg_color & 0xff; case 0xe549: case 0xe6e9: + s3_wait_fifo_idle(s3); return s3->accel.pat_bg_color >> 8; case 0xe54a: case 0xe6ea: + s3_wait_fifo_idle(s3); return s3->accel.pat_bg_color >> 16; case 0xe54b: case 0xe6eb: + s3_wait_fifo_idle(s3); return s3->accel.pat_bg_color >> 24; case 0xe948: case 0xeae8: + s3_wait_fifo_idle(s3); return s3->accel.pat_y & 0xff; case 0xe949: case 0xeae9: + s3_wait_fifo_idle(s3); return s3->accel.pat_y >> 8; case 0xe94a: case 0xeaea: + s3_wait_fifo_idle(s3); return s3->accel.pat_x & 0xff; case 0xe94b: case 0xeaeb: + s3_wait_fifo_idle(s3); return s3->accel.pat_x >> 8; case 0xed48: case 0xeee8: + s3_wait_fifo_idle(s3); return s3->accel.pat_fg_color & 0xff; case 0xed49: case 0xeee9: + s3_wait_fifo_idle(s3); return s3->accel.pat_fg_color >> 8; case 0xed4a: case 0xeeea: + s3_wait_fifo_idle(s3); return s3->accel.pat_fg_color >> 16; case 0xed4b: case 0xeeeb: + s3_wait_fifo_idle(s3); return s3->accel.pat_fg_color >> 24; case 0xe148: case 0xe2e8: @@ -3723,9 +3760,9 @@ polygon_setup(s3_t *s3) } -#define READ(addr, dat) if (s3->bpp == 0) dat = svga->vram[dword_remap(addr) & s3->vram_mask]; \ - else if (s3->bpp == 1) dat = vram_w[dword_remap_w(addr) & (s3->vram_mask >> 1)]; \ - else dat = vram_l[dword_remap_l(addr) & (s3->vram_mask >> 2)]; +#define READ(addr, dat) if (s3->bpp == 0) dat = svga->vram[dword_remap(svga, addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[dword_remap_w(svga, addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[dword_remap_l(svga, addr) & (s3->vram_mask >> 2)]; #define MIX_READ { \ switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \ @@ -4030,18 +4067,18 @@ polygon_setup(s3_t *s3) #define WRITE(addr, dat) if (s3->bpp == 0) \ { \ - svga->vram[dword_remap(addr) & s3->vram_mask] = dat; \ - svga->changedvram[(dword_remap(addr) & s3->vram_mask) >> 12] = changeframecount; \ + svga->vram[dword_remap(svga, addr) & s3->vram_mask] = dat; \ + svga->changedvram[(dword_remap(svga, addr) & s3->vram_mask) >> 12] = changeframecount; \ } \ else if (s3->bpp == 1) \ { \ - vram_w[dword_remap_w(addr) & (s3->vram_mask >> 1)] = dat; \ - svga->changedvram[(dword_remap_w(addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount; \ + vram_w[dword_remap_w(svga, addr) & (s3->vram_mask >> 1)] = dat; \ + svga->changedvram[(dword_remap_w(svga, addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount; \ } \ else \ { \ - vram_l[dword_remap_l(addr) & (s3->vram_mask >> 2)] = dat; \ - svga->changedvram[(dword_remap_l(addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \ + vram_l[dword_remap_l(svga, addr) & (s3->vram_mask >> 2)] = dat; \ + svga->changedvram[(dword_remap_l(svga, addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \ } @@ -5525,6 +5562,7 @@ s3_pci_read(int func, int addr, void *p) { s3_t *s3 = (s3_t *)p; svga_t *svga = &s3->svga; + switch (addr) { case 0x00: return 0x33; /*'S3'*/ @@ -5560,9 +5598,21 @@ s3_pci_read(int func, int addr, void *p) case 0x10: return 0x00; /*Linear frame buffer address*/ case 0x11: return 0x00; - case 0x12: return (s3->chip >= S3_TRIO64V || s3->chip == S3_VISION968 || s3->chip == S3_VISION868) ? 0 : (svga->crtc[0x5a] & 0x80); - case 0x13: return (s3->chip >= S3_TRIO64V) ? (svga->crtc[0x59] & 0xfc) : ((s3->chip == S3_VISION968 || s3->chip == S3_VISION868) ? (svga->crtc[0x59] & 0xfe) : svga->crtc[0x59]); - + case 0x12: + if (svga->crtc[0x53] & 0x08) + return 0x00; + else + return (svga->crtc[0x5a] & 0x80); + break; + + case 0x13: + if (svga->crtc[0x53] & 0x08) { + return (s3->chip >= S3_TRIO64V) ? (svga->crtc[0x59] & 0xfc) : (svga->crtc[0x59] & 0xfe); + } else { + return svga->crtc[0x59]; + } + break; + case 0x30: return s3->has_bios ? (s3->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ case 0x31: return 0x00; case 0x32: return s3->has_bios ? s3->pci_regs[0x32] : 0x00; @@ -5591,14 +5641,18 @@ s3_pci_write(int func, int addr, uint8_t val, void *p) break; case 0x12: - if (s3->chip != S3_TRIO64V && s3->chip != S3_TRIO64V2 && s3->chip != S3_VISION968 && s3->chip != S3_VISION868) { + if (!(svga->crtc[0x53] & 0x08)) { svga->crtc[0x5a] = (svga->crtc[0x5a] & 0x7f) | (val & 0x80); s3_updatemapping(s3); } break; case 0x13: - svga->crtc[0x59] = (s3->chip >= S3_TRIO64V) ? (val & 0xfc) : ((s3->chip == S3_VISION968 || s3->chip == S3_VISION868) ? (val & 0xfe) : val); + if (svga->crtc[0x53] & 0x08) { + svga->crtc[0x59] = (s3->chip >= S3_TRIO64V) ? (val & 0xfc) : (val & 0xfe); + } else { + svga->crtc[0x59] = val; + } s3_updatemapping(s3); break; @@ -6059,6 +6113,7 @@ static void *s3_init(const device_t *info) svga->crtc[0x59] = 0x00; svga->crtc[0x5a] = 0x0a; } + svga->packed_chain4 = 1; svga->ramdac = device_add(&ibm_rgb528_ramdac_device); svga->clock_gen = device_add(&icd2061_device); @@ -6066,7 +6121,7 @@ static void *s3_init(const device_t *info) break; case S3_PHOENIX_VISION868: - svga->decode_mask = (4 << 20) - 1; + svga->decode_mask = (8 << 20) - 1; s3->id = 0xe1; /*Vision868*/ s3->id_ext = 0x90; s3->id_ext_pci = 0x80; @@ -6082,6 +6137,7 @@ static void *s3_init(const device_t *info) svga->crtc[0x59] = 0x00; svga->crtc[0x5a] = 0x0a; } + svga->packed_chain4 = 1; svga->ramdac = device_add(&sdac_ramdac_device); svga->clock_gen = svga->ramdac; @@ -6114,6 +6170,12 @@ static void *s3_init(const device_t *info) s3->id_ext = s3->id_ext_pci = 0x11; s3->packed_mmio = 1; + if (info->local == S3_PHOENIX_TRIO64VPLUS || info->local == S3_PHOENIX_TRIO64VPLUS_ONBOARD) { + if (s3->pci) + svga->crtc[0x53] = 0x08; + svga->packed_chain4 = 1; + } + svga->clock_gen = s3; svga->getclock = s3_trio64_getclock; break; @@ -6123,7 +6185,9 @@ static void *s3_init(const device_t *info) s3->id = 0xe1; /*Trio64V2/DX*/ s3->id_ext = s3->id_ext_pci = 0x01; s3->packed_mmio = 1; + svga->crtc[0x53] = 0x08; svga->crtc[0x6c] = 1; + svga->packed_chain4 = 1; svga->clock_gen = s3; svga->getclock = s3_trio64_getclock; From c3c8da49dbe07fcb779df0732ca04b7865aa5409 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 5 Jun 2021 20:52:10 +0200 Subject: [PATCH 39/59] Removed log excess. --- src/video/vid_s3.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 8b4b078b7..9752c708c 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -2232,8 +2232,6 @@ s3_out(uint16_t addr, uint8_t val, void *p) rs2 = !!(svga->crtc[0x43] & 0x02); else rs2 = (svga->crtc[0x55] & 0x01); - - pclog("Write RS2 enabled: crtc43 bit 1 = %02x, crtc55 bits 0-1 = %02x\n", svga->crtc[0x43] & 0x02, svga->crtc[0x55] & 0x03); if (s3->chip >= S3_TRIO32) svga_out(addr, val, svga); else if ((s3->chip == S3_VISION964 && s3->card_type != S3_ELSAWIN2KPROX_964) || (s3->chip == S3_86C928)) { From 50af9387f84d56fa3c279afb51cb5257077b3095 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 6 Jun 2021 23:56:21 +0200 Subject: [PATCH 40/59] Makes PIIX board configuration registers work again - fixes deep beeps on Intel Advanced/ATX. --- src/chipset/intel_piix.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 6dc76615b..96d34d7d4 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -921,8 +921,7 @@ board_read(uint16_t port, void *priv) uint8_t ret = 0x64; if (port == 0x0078) - ret = 0x00; - // ret = dev->board_config[0]; + ret = dev->board_config[0]; else if (port == 0x0079) ret = dev->board_config[1]; else if (port == 0x00e0) From 493867f4763738d5726afd9e8f9ef5db7e63ee43 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 6 Jun 2021 23:57:26 +0200 Subject: [PATCH 41/59] Minor AT NVR fixes, fixes deep beeps on the Intel Premiere/PCI. --- src/nvr_at.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/nvr_at.c b/src/nvr_at.c index 160f2bd90..419da7c79 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -427,7 +427,7 @@ check_alarm_via(nvr_t *nvr, int8_t addr, int8_t addr_2) return((nvr->regs[addr_2] == nvr->regs[addr]) || ((nvr->regs[addr_2] & AL_DONTCARE) == AL_DONTCARE)); } else - return 0; + return 1; } @@ -456,9 +456,9 @@ timer_update(void *priv) check_alarm(nvr, RTC_MINUTES) && check_alarm(nvr, RTC_HOURS) && check_alarm_via(nvr, RTC_DOM, RTC_ALDAY) && - check_alarm_via(nvr, RTC_MONTH, RTC_ALMONTH) && + check_alarm_via(nvr, RTC_MONTH, RTC_ALMONTH)/* && check_alarm_via(nvr, RTC_DOM, RTC_ALDAY_SIS) && - check_alarm_via(nvr, RTC_MONTH, RTC_ALMONT_SIS)) { + check_alarm_via(nvr, RTC_MONTH, RTC_ALMONT_SIS)*/) { nvr->regs[RTC_REGC] |= REGC_AF; if (nvr->regs[RTC_REGB] & REGB_AIE) { nvr->regs[RTC_REGC] |= REGC_IRQF; @@ -996,8 +996,10 @@ nvr_at_init(const device_t *info) /* Set up the I/O handler for this device. */ io_sethandler(0x0070, 2, nvr_read,NULL,NULL, nvr_write,NULL,NULL, nvr); + if (info->local & 8) { io_sethandler(0x0072, 2, nvr_read,NULL,NULL, nvr_write,NULL,NULL, nvr); + } nvr_at_inited = 1; } From 32dff0b5a1f0b6fceea9e3963d3f559297b53bbe Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 6 Jun 2021 23:58:12 +0200 Subject: [PATCH 42/59] OPTi 283 rewrite. --- src/chipset/opti283.c | 242 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 195 insertions(+), 47 deletions(-) diff --git a/src/chipset/opti283.c b/src/chipset/opti283.c index be2343bff..1e48975b7 100644 --- a/src/chipset/opti283.c +++ b/src/chipset/opti283.c @@ -8,12 +8,11 @@ * * Implementation of the OPTi 82C283 chipset. * + * Authors: Tiseno100, + * Miran Grca, * - * - * Authors: Tiseno100 - * - * Copyright 2021 Tiseno100 - * + * Copyright 2021 Tiseno100. + * Copyright 2021 Miran Grca. */ #include @@ -31,8 +30,10 @@ #include <86box/mem.h> #include <86box/chipset.h> + #ifdef ENABLE_OPTI283_LOG int opti283_do_log = ENABLE_OPTI283_LOG; + static void opti283_log(const char *fmt, ...) { @@ -49,72 +50,200 @@ opti283_log(const char *fmt, ...) #define opti283_log(fmt, ...) #endif + typedef struct { - uint8_t index, - regs[256]; + uint32_t phys, virt; +} mem_remapping_t; + + +typedef struct +{ + uint8_t index, shadow_high, + regs[256]; + mem_remapping_t mem_remappings[2]; + mem_mapping_t mem_mappings[2]; } opti283_t; -static void opti283_shadow_recalc(opti283_t *dev) + +static uint8_t +opti283_read_remapped_ram(uint32_t addr, void *priv) { - mem_set_mem_state_both(0xf0000, 0x10000, (dev->regs[0x11] & 0x80) ? (MEM_READ_EXTANY | MEM_WRITE_INTERNAL) : (MEM_READ_INTERNAL | ((dev->regs[0x14] & 0x80) ? MEM_WRITE_INTERNAL : MEM_WRITE_DISABLED))); + mem_remapping_t *dev = (mem_remapping_t *) priv; - for (uint32_t i = 0; i < 4; i++) - { - if (dev->regs[0x11] & 0x40) - mem_set_mem_state_both(0xe0000 + (i << 14), 0x4000, (dev->regs[0x12] & (1 << (4 + i))) ? (MEM_READ_INTERNAL | ((dev->regs[0x11] & 4) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL)) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); - mem_set_mem_state_both(0xe0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + return mem_read_ram((addr - dev->virt) + dev->phys, priv); +} - if (dev->regs[0x11] & 0x20) - mem_set_mem_state_both(0xd0000 + (i << 14), 0x4000, (dev->regs[0x12] & (1 << i)) ? (MEM_READ_INTERNAL | ((dev->regs[0x11] & 2) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL)) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); - else - mem_set_mem_state_both(0xd0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - if (dev->regs[0x11] & 0x10) - mem_set_mem_state_both(0xc0000 + (i << 14), 0x4000, (dev->regs[0x13] & (1 << (4 + i))) ? (MEM_READ_INTERNAL | ((dev->regs[0x11] & 1) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL)) : (MEM_READ_EXTANY | MEM_WRITE_EXTANY)); - else - mem_set_mem_state_both(0xc0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); +static uint16_t +opti283_read_remapped_ramw(uint32_t addr, void *priv) +{ + mem_remapping_t *dev = (mem_remapping_t *) priv; + + return mem_read_ramw((addr - dev->virt) + dev->phys, priv); +} + + +static uint32_t +opti283_read_remapped_raml(uint32_t addr, void *priv) +{ + mem_remapping_t *dev = (mem_remapping_t *) priv; + + return mem_read_raml((addr - dev->virt) + dev->phys, priv); +} + + +static void +opti283_write_remapped_ram(uint32_t addr, uint8_t val, void *priv) +{ + mem_remapping_t *dev = (mem_remapping_t *) priv; + + mem_write_ram((addr - dev->virt) + dev->phys, val, priv); +} + + +static void +opti283_write_remapped_ramw(uint32_t addr, uint16_t val, void *priv) +{ + mem_remapping_t *dev = (mem_remapping_t *) priv; + + mem_write_ramw((addr - dev->virt) + dev->phys, val, priv); +} + + +static void +opti283_write_remapped_raml(uint32_t addr, uint32_t val, void *priv) +{ + mem_remapping_t *dev = (mem_remapping_t *) priv; + + mem_write_raml((addr - dev->virt) + dev->phys, val, priv); +} + + +static void +opti283_shadow_recalc(opti283_t *dev) +{ + uint32_t i, base; + uint32_t rbase; + uint8_t sh_enable, sh_mode; + uint8_t rom, sh_copy; + + shadowbios = shadowbios_write = 0; + dev->shadow_high = 0; + + if (dev->regs[0x11] & 0x80) { + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + shadowbios_write = 1; + } else { + shadowbios = 1; + if (dev->regs[0x14] & 0x80) { + mem_set_mem_state_both(0xf0000, 0x01000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + shadowbios_write = 1; + } else + mem_set_mem_state_both(0xf0000, 0x01000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + + mem_set_mem_state_both(0xf1000, 0x0f000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + } + + sh_copy = dev->regs[0x11] & 0x08; + for (i = 0; i < 12; i++) { + base = 0xc0000 + (i << 14); + if (i >= 4) + sh_enable = dev->regs[0x12] & (1 << (i - 4)); + else + sh_enable = dev->regs[0x13] & (1 << (i + 4)); + sh_mode = dev->regs[0x11] & (1 << (i >> 2)); + rom = dev->regs[0x11] & (1 << ((i >> 2) + 4)); + pclog("OPTI 283: %i/%08X: %i, %i, %i\n", i, base, (i >= 4) ? (1 << (i - 4)) : (1 << (i + 4)), (1 << (i >> 2)), (1 << ((i >> 2) + 4))); + + if (sh_enable && rom) { + if (base >= 0x000e0000) + shadowbios |= 1; + if (base >= 0x000d0000) + dev->shadow_high |= 1; + + if (sh_mode) { + if (base >= 0x000e0000) + shadowbios_write |= 1; + + if (sh_copy) + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + } else + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + } else { + if (base >= 0xe0000) + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_DISABLED); + else + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_DISABLED); + } + } + + rbase = ((uint32_t) (dev->regs[0x13] & 0x0f)) << 20; + + if (rbase > 0) { + dev->mem_remappings[0].virt = rbase; + mem_mapping_set_addr(&dev->mem_mappings[0], rbase, 0x00020000); + + if (!dev->shadow_high) { + rbase += 0x00020000; + dev->mem_remappings[1].virt = rbase; + mem_mapping_set_addr(&dev->mem_mappings[1], rbase , 0x00020000); + } else + mem_mapping_disable(&dev->mem_mappings[1]); + } else { + mem_mapping_disable(&dev->mem_mappings[0]); + mem_mapping_disable(&dev->mem_mappings[1]); } } + static void opti283_write(uint16_t addr, uint8_t val, void *priv) { opti283_t *dev = (opti283_t *)priv; - switch (addr) - { - case 0x22: - dev->index = val; - break; - case 0x24: - opti283_log("OPTi 283: dev->regs[%02x] = %02x\n", dev->index, val); + switch (addr) { + case 0x22: + dev->index = val; + break; - switch (dev->index) - { - case 0x10: - dev->regs[dev->index] = val; - break; + case 0x24: + opti283_log("OPTi 283: dev->regs[%02x] = %02x\n", dev->index, val); - case 0x11: - case 0x12: - case 0x13: - case 0x14: - dev->regs[dev->index] = val; - opti283_shadow_recalc(dev); - break; - } - break; + switch (dev->index) { + case 0x10: + dev->regs[dev->index] = val; + break; + + case 0x14: + reset_on_hlt = !!(val & 0x40); + /* FALLTHROUGH */ + case 0x11: case 0x12: + case 0x13: + dev->regs[dev->index] = val; + opti283_shadow_recalc(dev); + break; + } + break; } } + static uint8_t opti283_read(uint16_t addr, void *priv) { opti283_t *dev = (opti283_t *)priv; - return (addr == 0x24) ? dev->regs[dev->index] : 0xff; + uint8_t ret = 0xff; + + if (addr == 0x24) + ret = dev->regs[dev->index]; + + return ret; } + static void opti283_close(void *priv) { @@ -123,22 +252,40 @@ opti283_close(void *priv) free(dev); } + static void * opti283_init(const device_t *info) { opti283_t *dev = (opti283_t *)malloc(sizeof(opti283_t)); - memset(dev, 0, sizeof(opti283_t)); + memset(dev, 0x00, sizeof(opti283_t)); io_sethandler(0x0022, 0x0001, opti283_read, NULL, NULL, opti283_write, NULL, NULL, dev); io_sethandler(0x0024, 0x0001, opti283_read, NULL, NULL, opti283_write, NULL, NULL, dev); dev->regs[0x10] = 0x3f; dev->regs[0x11] = 0xf0; + + dev->mem_remappings[0].phys = 0x000a0000; + dev->mem_remappings[1].phys = 0x000d0000; + + mem_mapping_add(&dev->mem_mappings[0], 0, 0x00020000, + opti283_read_remapped_ram, opti283_read_remapped_ramw, opti283_read_remapped_raml, + opti283_write_remapped_ram, opti283_write_remapped_ramw, opti283_write_remapped_raml, + &ram[dev->mem_remappings[0].phys], MEM_MAPPING_INTERNAL, &dev->mem_remappings[0]); + mem_mapping_disable(&dev->mem_mappings[0]); + + mem_mapping_add(&dev->mem_mappings[1], 0, 0x00020000, + opti283_read_remapped_ram, opti283_read_remapped_ramw, opti283_read_remapped_raml, + opti283_write_remapped_ram, opti283_write_remapped_ramw, opti283_write_remapped_raml, + &ram[dev->mem_remappings[1].phys], MEM_MAPPING_INTERNAL, &dev->mem_remappings[1]); + mem_mapping_disable(&dev->mem_mappings[1]); + opti283_shadow_recalc(dev); return dev; } + const device_t opti283_device = { "OPTi 82C283", 0, @@ -146,7 +293,8 @@ const device_t opti283_device = { opti283_init, opti283_close, NULL, - {NULL}, + { NULL }, NULL, NULL, - NULL}; + NULL +}; From 59d1469a0768421e31dd4cbc7dbdd1883b8b3bca Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 6 Jun 2021 23:59:05 +0200 Subject: [PATCH 43/59] Intel 420EX fixes. --- src/chipset/intel_420ex.c | 78 +++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/src/chipset/intel_420ex.c b/src/chipset/intel_420ex.c index 6885bf9d3..f0511d0e8 100644 --- a/src/chipset/intel_420ex.c +++ b/src/chipset/intel_420ex.c @@ -43,7 +43,7 @@ typedef struct { - uint8_t id, smram_locked, + uint8_t has_ide, smram_locked, regs[256]; uint16_t timer_base, @@ -165,10 +165,6 @@ i420ex_write(int func, int addr, uint8_t val, void *priv) if (((addr >= 0x0f) && (addr < 0x4c)) && (addr != 0x40)) return; - /* The IB (original) variant of the I420EX has no PCI IRQ steering. */ - if ((addr >= 0x60) && (addr <= 0x63) && (dev->id < 0x03)) - return; - switch (addr) { case 0x05: dev->regs[addr] = (val & 0x01); @@ -186,21 +182,21 @@ i420ex_write(int func, int addr, uint8_t val, void *priv) break; case 0x48: dev->regs[addr] = (val & 0x3f); -#ifdef USE_420EX_IDE - ide_pri_disable(); - switch (val & 0x03) { - case 0x01: - ide_set_base(0, 0x01f0); - ide_set_side(0, 0x03f6); - ide_pri_enable(); - break; - case 0x02: - ide_set_base(0, 0x0170); - ide_set_side(0, 0x0376); - ide_pri_enable(); - break; + if (dev->has_ide) { + ide_pri_disable(); + switch (val & 0x03) { + case 0x01: + ide_set_base(0, 0x01f0); + ide_set_side(0, 0x03f6); + ide_pri_enable(); + break; + case 0x02: + ide_set_base(0, 0x0170); + ide_set_side(0, 0x0376); + ide_pri_enable(); + break; + } } -#endif break; case 0x49: case 0x53: dev->regs[addr] = (val & 0x1f); @@ -385,7 +381,6 @@ i420ex_reset_hard(void *priv) dev->regs[0x02] = 0x86; dev->regs[0x03] = 0x04; /*82378IB (I420EX)*/ dev->regs[0x04] = 0x07; dev->regs[0x07] = 0x02; - dev->regs[0x08] = dev->id; dev->regs[0x4c] = 0x4d; dev->regs[0x4e] = 0x03; @@ -404,8 +399,9 @@ i420ex_reset_hard(void *priv) pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + if (dev->has_ide) + ide_pri_disable(); } @@ -442,6 +438,8 @@ i420ex_reset(void *p) i420ex_t *dev = (i420ex_t *) p; int i; + i420ex_write(0, 0x48, 0x00, p); + for (i = 0; i < 7; i++) i420ex_write(0, 0x59 + i, 0x00, p); @@ -488,13 +486,11 @@ i420ex_speed_changed(void *priv) if (te) timer_set_delay_u64(&dev->timer, ((uint64_t) dev->timer_latch) * TIMER_USEC); - if (dev->id == 0x03) { - te = timer_is_enabled(&dev->fast_off_timer); + te = timer_is_enabled(&dev->fast_off_timer); - timer_stop(&dev->fast_off_timer); - if (te) - timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); - } + timer_stop(&dev->fast_off_timer); + if (te) + timer_on_auto(&dev->fast_off_timer, dev->fast_off_period); } @@ -508,12 +504,10 @@ i420ex_init(const device_t *info) pci_add_card(PCI_ADD_NORTHBRIDGE, i420ex_read, i420ex_write, dev); - dev->id = info->local; + dev->has_ide = info->local; timer_add(&dev->fast_off_timer, i420ex_fast_off_count, dev, 0); - i420ex_reset_hard(dev); - cpu_fast_off_flags = 0x00000000; cpu_fast_off_val = dev->regs[0xa8]; @@ -527,12 +521,9 @@ i420ex_init(const device_t *info) dma_alias_set(); -#ifdef USE_420EX_IDE - device_add(&ide_pci_device); - ide_pri_disable(); -#else device_add(&ide_pci_2ch_device); -#endif + + i420ex_reset_hard(dev); return dev; } @@ -551,3 +542,18 @@ const device_t i420ex_device = NULL, NULL }; + + +const device_t i420ex_ide_device = +{ + "Intel 82420EX (With IDE)", + DEVICE_PCI, + 0x01, + i420ex_init, + i420ex_close, + i420ex_reset, + { NULL }, + i420ex_speed_changed, + NULL, + NULL +}; From 166f64d422006fcffa8c9d7abd2bdfa42dbfbc28 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:06:17 +0200 Subject: [PATCH 44/59] Some CPU fixes, should fix compiling. --- src/cpu/cpu.c | 2 ++ src/cpu/cpu.h | 4 ++++ src/cpu/x86.c | 30 +++++++++++++++++++++++++----- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 62e497578..290c14a86 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -358,6 +358,8 @@ cpu_set(void) acycs = 0; #endif + soft_reset_pci = 0; + cpu_alt_reset = 0; unmask_a20_in_smm = 0; diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index d336b9a26..2aecdf13e 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -698,6 +698,10 @@ typedef struct extern uint32_t addr64, addr64_2; extern uint32_t addr64a[8], addr64a_2[8]; +extern int soft_reset_pci; + +extern int reset_on_hlt, hlt_reset_pending; + extern cyrix_t cyrix; extern void (*cpu_exec)(int cycs); diff --git a/src/cpu/x86.c b/src/cpu/x86.c index 539cea550..e652c5d27 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -31,6 +31,7 @@ #include <86box/rom.h> #include <86box/nmi.h> #include <86box/pic.h> +#include <86box/pci.h> #include <86box/ppi.h> #include <86box/timer.h> @@ -56,7 +57,7 @@ uint64_t xt_cpu_multi; int nmi = 0, nmi_auto_clear = 0; /* Was the CPU ever reset? */ -int x86_was_reset = 0; +int x86_was_reset = 0, soft_reset_pci = 0; /* Is the TRAP flag on? */ int trap = 0; @@ -64,6 +65,9 @@ int trap = 0; /* The current effective address's segment. */ uint32_t easeg; +/* This is for the OPTI 283 special reset handling mode. */ +int reset_on_hlt, hlt_reset_pending; + #ifdef ENABLE_X86_LOG void dumpregs(int); @@ -216,15 +220,28 @@ makeznptable(void) static void reset_common(int hard) { - /* Make sure to gracefully leave SMM. */ - if (in_smm) - leave_smm(); - #ifdef ENABLE_808X_LOG if (hard) x808x_log("x86 reset\n"); #endif + if (!hard && reset_on_hlt) { + hlt_reset_pending++; + pclog("hlt_reset_pending = %i\n", hlt_reset_pending); + if (hlt_reset_pending == 2) + hlt_reset_pending = 0; + else + return; + } + + /* Make sure to gracefully leave SMM. */ + if (in_smm) + leave_smm(); + + /* Needed for the ALi M1533. */ + if (soft_reset_pci && !hard) + pci_reset(); + use32 = 0; cpu_cur_status = 0; stack32 = 0; @@ -290,6 +307,9 @@ reset_common(int hard) shadowbios = shadowbios_write = 0; alt_access = cpu_end_block_after_ins = 0; + if (hard) + reset_on_hlt = hlt_reset_pending = 0; + if (!is286) reset_808x(hard); } From 40b0db4162eea647af7315d2946fdfc170819cca Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:07:27 +0200 Subject: [PATCH 45/59] And another CPU change. --- src/cpu/x86_ops_misc.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cpu/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index a64a3edbb..a6e7e9193 100644 --- a/src/cpu/x86_ops_misc.h +++ b/src/cpu/x86_ops_misc.h @@ -627,6 +627,9 @@ static int opHLT(uint32_t fetchdat) CPU_BLOCK_END(); PREFETCH_RUN(100, 1, -1, 0,0,0,0, 0); + if (hlt_reset_pending) + softresetx86(); + return 0; } From 195ebd66a58d6b474936219a94efd2c837724fa1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:10:05 +0200 Subject: [PATCH 46/59] Removed a thing in nvr.h. --- src/include/86box/nvr.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/include/86box/nvr.h b/src/include/86box/nvr.h index 9dc054b22..3df78de6e 100644 --- a/src/include/86box/nvr.h +++ b/src/include/86box/nvr.h @@ -81,7 +81,6 @@ typedef struct _nvr_ { void (*ven_save)(void); uint8_t regs[NVR_MAXSIZE]; /* these are the registers */ - uint8_t apc_regs[4]; /* AND THIS! IS THE APC MADAFAKA :b */ } nvr_t; From 80a6f81a97e0ab28cccb723d9a6efb3cbaee62b2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:10:56 +0200 Subject: [PATCH 47/59] SM(S)C FDC37M60x Super I/O chip rewrite. --- src/sio/sio_fdc37m60x.c | 305 +++++++++++++++++++++------------------- 1 file changed, 163 insertions(+), 142 deletions(-) diff --git a/src/sio/sio_fdc37m60x.c b/src/sio/sio_fdc37m60x.c index ca0111405..b98801ff2 100644 --- a/src/sio/sio_fdc37m60x.c +++ b/src/sio/sio_fdc37m60x.c @@ -31,24 +31,27 @@ #include <86box/fdc.h> #include <86box/sio.h> -#define SIO_INDEX_PORT dev->sio_index_port -#define INDEX dev->index +#define SIO_INDEX_PORT dev->sio_index_port +#define INDEX dev->index /* Current Logical Device Number */ -#define CURRENT_LOGICAL_DEVICE dev->regs[0x07] +#define CURRENT_LOGICAL_DEVICE dev->regs[0x07] /* Global Device Configuration */ -#define ENABLED dev->device_regs[CURRENT_LOGICAL_DEVICE][0x30] -#define BASE_ADDRESS ((dev->device_regs[CURRENT_LOGICAL_DEVICE][0x60] << 8) | (dev->device_regs[CURRENT_LOGICAL_DEVICE][0x61])) -#define IRQ dev->device_regs[CURRENT_LOGICAL_DEVICE][0x70] -#define DMA dev->device_regs[CURRENT_LOGICAL_DEVICE][0x74] +#define ENABLED(ld) dev->device_regs[ld][0x30] +#define BASE_ADDRESS(ld) ((dev->device_regs[ld][0x60] << 8) | \ + (dev->device_regs[ld][0x61])) +#define IRQ(ld) dev->device_regs[ld][0x70] +#define DMA(ld) dev->device_regs[ld][0x74] /* Miscellaneous Chip Functionality */ -#define SOFT_RESET (val & 0x01) -#define POWER_CONTROL dev->regs[0x22] +#define SOFT_RESET (val & 0x01) +#define POWER_CONTROL dev->regs[0x22] + #ifdef ENABLE_FDC37M60X_LOG int fdc37m60x_do_log = ENABLE_FDC37M60X_LOG; + static void fdc37m60x_log(const char *fmt, ...) { @@ -65,196 +68,217 @@ fdc37m60x_log(const char *fmt, ...) #define fdc37m60x_log(fmt, ...) #endif + typedef struct { - uint8_t index, regs[256], device_regs[10][256], cfg_lock, ide_function; - uint16_t sio_index_port; + uint8_t index, regs[256], device_regs[10][256], cfg_lock, ide_function; + uint16_t sio_index_port; - fdc_t *fdc_controller; - serial_t *uart[2]; + fdc_t * fdc; + serial_t * uart[2]; } fdc37m60x_t; -void fdc37m60x_fdc_handler(fdc37m60x_t *dev); -void fdc37m60x_uart_handler(uint8_t num, fdc37m60x_t *dev); -void fdc37m60x_lpt_handler(fdc37m60x_t *dev); -void fdc37m60x_logical_device_handler(fdc37m60x_t *dev); -static void fdc37m60x_reset(void *priv); + +static void fdc37m60x_fdc_handler(fdc37m60x_t *dev); +static void fdc37m60x_uart_handler(uint8_t num, fdc37m60x_t *dev); +static void fdc37m60x_lpt_handler(fdc37m60x_t *dev); +static void fdc37m60x_logical_device_handler(fdc37m60x_t *dev); +static void fdc37m60x_reset(void *priv); + static void fdc37m60x_write(uint16_t addr, uint8_t val, void *priv) { fdc37m60x_t *dev = (fdc37m60x_t *)priv; - switch (addr) - { - case 0x3f0: - case 0x370: - INDEX = val; + if (addr & 1) { + if (!dev->cfg_lock) { + switch (INDEX) { + /* Global Configuration */ + case 0x02: + dev->regs[INDEX] = val; + if (SOFT_RESET) + fdc37m60x_reset(dev); + break; - /* Enter/Escape Configuration Mode */ - if (val == 0x55) - dev->cfg_lock = 0; - else if (val == 0xaa) - dev->cfg_lock = 1; - break; + case 0x07: + CURRENT_LOGICAL_DEVICE = val; + break; - case 0x3f1: - case 0x371: - if (!dev->cfg_lock) - { - switch (INDEX) - { - /* Global Configuration */ - case 0x02: - dev->regs[INDEX] = val; - if (SOFT_RESET) - fdc37m60x_reset(dev); - break; + case 0x22: + POWER_CONTROL = val & 0x3f; + break; - case 0x07: - CURRENT_LOGICAL_DEVICE = (val & 0x0f); - break; + case 0x23: + dev->regs[INDEX] = val & 0x3f; + break; - case 0x22: - POWER_CONTROL = val & 0x3f; - break; + case 0x24: + dev->regs[INDEX] = val & 0x4e; + break; - case 0x23: - dev->regs[INDEX] = val & 0x3f; - break; + case 0x2b: case 0x2c: case 0x2d: case 0x2e: + case 0x2f: + dev->regs[INDEX] = val; + break; - case 0x24: - dev->regs[INDEX] = val & 0xce; - break; - - /* Device Configuration */ - case 0x30: - case 0x60: - case 0x61: - case 0x70: - case 0x74: - if(CURRENT_LOGICAL_DEVICE <= 0x81) /* Avoid Overflow */ - dev->device_regs[CURRENT_LOGICAL_DEVICE][INDEX] = (INDEX == 0x30) ? (val & 1) : val; - fdc37m60x_logical_device_handler(dev); - break; - } + /* Device Configuration */ + case 0x30: + case 0x60: case 0x61: + case 0x70: + case 0x74: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + if (CURRENT_LOGICAL_DEVICE <= 0x81) /* Avoid Overflow */ + dev->device_regs[CURRENT_LOGICAL_DEVICE][INDEX] = (INDEX == 0x30) ? (val & 1) : val; + fdc37m60x_logical_device_handler(dev); + break; + } } - break; + } else { + /* Enter/Escape Configuration Mode */ + if (val == 0x55) + dev->cfg_lock = 0; + else if (!dev->cfg_lock && (val == 0xaa)) + dev->cfg_lock = 1; + else if (!dev->cfg_lock) + INDEX = val; } } + static uint8_t fdc37m60x_read(uint16_t addr, void *priv) { fdc37m60x_t *dev = (fdc37m60x_t *)priv; + uint8_t ret = 0xff; - return (INDEX >= 0x30) ? dev->device_regs[CURRENT_LOGICAL_DEVICE][INDEX] : dev->regs[INDEX]; + if (addr & 1) + ret = (INDEX >= 0x30) ? dev->device_regs[CURRENT_LOGICAL_DEVICE][INDEX] : dev->regs[INDEX]; + + return ret; } -void fdc37m60x_fdc_handler(fdc37m60x_t *dev) + +static void +fdc37m60x_fdc_handler(fdc37m60x_t *dev) { - fdc_remove(dev->fdc_controller); - if(ENABLED || (POWER_CONTROL & 0x01)) + fdc_remove(dev->fdc); + + if (ENABLED(0) || (POWER_CONTROL & 0x01)) { - fdc_set_base(dev->fdc_controller, BASE_ADDRESS); - fdc_set_irq(dev->fdc_controller, IRQ & 0xf); - fdc_set_dma_ch(dev->fdc_controller, DMA & 0x07); - fdc37m60x_log("SMC60x-FDC: BASE %04x IRQ %d DMA %d\n", BASE_ADDRESS, IRQ & 0xf, DMA & 0x07); + fdc_set_base(dev->fdc, BASE_ADDRESS(0)); + fdc_set_irq(dev->fdc, IRQ(0) & 0xf); + fdc_set_dma_ch(dev->fdc, DMA(0) & 0x07); + fdc37m60x_log("SMC60x-FDC: BASE %04x IRQ %d DMA %d\n", BASE_ADDRESS(0), IRQ(0) & 0xf, DMA(0) & 0x07); } + + fdc_update_enh_mode(dev->fdc, dev->device_regs[0][0xf0] & 0x01); + + fdc_update_densel_force(dev->fdc, (dev->device_regs[0][0xf1] & 0xc) >> 2); + + fdc_update_rwc(dev->fdc, 3, (dev->device_regs[0][0xf2] & 0xc0) >> 6); + fdc_update_rwc(dev->fdc, 2, (dev->device_regs[0][0xf2] & 0x30) >> 4); + fdc_update_rwc(dev->fdc, 1, (dev->device_regs[0][0xf2] & 0x0c) >> 2); + fdc_update_rwc(dev->fdc, 0, (dev->device_regs[0][0xf2] & 0x03)); + + fdc_update_drvrate(dev->fdc, 0, (dev->device_regs[0][0xf4] & 0x18) >> 3); + fdc_update_drvrate(dev->fdc, 1, (dev->device_regs[0][0xf5] & 0x18) >> 3); + fdc_update_drvrate(dev->fdc, 2, (dev->device_regs[0][0xf6] & 0x18) >> 3); + fdc_update_drvrate(dev->fdc, 3, (dev->device_regs[0][0xf7] & 0x18) >> 3); } -void fdc37m60x_uart_handler(uint8_t num, fdc37m60x_t *dev) + +static void +fdc37m60x_uart_handler(uint8_t num, fdc37m60x_t *dev) { serial_remove(dev->uart[num & 1]); - if(!(num & 1) ? (ENABLED || (POWER_CONTROL & 0x10)) : (ENABLED || (POWER_CONTROL & 0x20))) + + if (ENABLED(4 + (num & 1)) || (POWER_CONTROL & (1 << (4 + (num & 1))))) { - serial_setup(dev->uart[num & 1], BASE_ADDRESS, IRQ & 0xf); - fdc37m60x_log("SMC60x-UART%d: BASE %04x IRQ %d\n", num & 1, BASE_ADDRESS, IRQ & 0xf); + serial_setup(dev->uart[num & 1], BASE_ADDRESS(4 + (num & 1)), IRQ(4 + (num & 1)) & 0xf); + fdc37m60x_log("SMC60x-UART%d: BASE %04x IRQ %d\n", num & 1, BASE_ADDRESS(4 + (num & 1)), IRQ(4 + (num & 1)) & 0xf); } } + void fdc37m60x_lpt_handler(fdc37m60x_t *dev) { lpt1_remove(); - if(ENABLED || (POWER_CONTROL & 0x80)) - { - lpt1_init(BASE_ADDRESS); - lpt1_irq(IRQ & 0xf); - fdc37m60x_log("SMC60x-LPT: BASE %04x IRQ %d\n", BASE_ADDRESS, IRQ & 0xf); + + if (ENABLED(3) || (POWER_CONTROL & 0x08)) { + lpt1_init(BASE_ADDRESS(3)); + lpt1_irq(IRQ(3) & 0xf); + fdc37m60x_log("SMC60x-LPT: BASE %04x IRQ %d\n", BASE_ADDRESS(3), IRQ(3) & 0xf); } } + void fdc37m60x_logical_device_handler(fdc37m60x_t *dev) { -/* -Register 07h: -Device 0: FDC -Device 3: LPT -Device 4: UART1 -Device 5: UART2 -*/ - switch (CURRENT_LOGICAL_DEVICE) - { - case 0x00: - fdc37m60x_fdc_handler(dev); - break; + /* Register 07h: + Device 0: FDC + Device 3: LPT + Device 4: UART1 + Device 5: UART2 + */ - case 0x03: - fdc37m60x_lpt_handler(dev); - break; + switch (CURRENT_LOGICAL_DEVICE) { + case 0x00: + fdc37m60x_fdc_handler(dev); + break; - case 0x04: - fdc37m60x_uart_handler(0, dev); - break; + case 0x03: + fdc37m60x_lpt_handler(dev); + break; - case 0x05: - fdc37m60x_uart_handler(1, dev); - break; + case 0x04: + fdc37m60x_uart_handler(0, dev); + break; + + case 0x05: + fdc37m60x_uart_handler(1, dev); + break; } } + static void fdc37m60x_reset(void *priv) { - fdc37m60x_t *dev = (fdc37m60x_t *)priv; + fdc37m60x_t *dev = (fdc37m60x_t *) priv; + uint8_t i; - CURRENT_LOGICAL_DEVICE = 0x00; - dev->regs[0x22] = 0x00; + memset(dev->regs, 0, sizeof(dev->regs)); + for (i = 0; i < 10; i++) + memset(dev->device_regs[i], 0, sizeof(dev->device_regs[i])); + + dev->regs[0x20] = 0x47; + dev->regs[0x24] = 0x04; dev->regs[0x26] = SIO_INDEX_PORT & 0xf; dev->regs[0x27] = (SIO_INDEX_PORT >> 4) & 0xf; /* FDC Registers */ - dev->device_regs[0][0x30] = 0x00; dev->device_regs[0][0x60] = 0x03; /* Base Address */ dev->device_regs[0][0x61] = 0xf0; - dev->device_regs[0][0x70] = 0x06; dev->device_regs[0][0x74] = 0x02; + dev->device_regs[0][0xf0] = 0x0e; + dev->device_regs[0][0xf2] = 0xff; /* LPT Port */ - dev->device_regs[3][0x30] = 0x00; - dev->device_regs[3][0x60] = 0x00; /* Base Address */ - dev->device_regs[3][0x61] = 0x00; - - dev->device_regs[3][0x64] = 0x04; + dev->device_regs[3][0x74] = 0x04; + dev->device_regs[3][0xf0] = 0x3c; /* UART1 */ - dev->device_regs[4][0x30] = 0x00; - dev->device_regs[4][0x60] = 0x00; /* Base Address */ - dev->device_regs[4][0x61] = 0x00; - - dev->device_regs[4][0x70] = 0x00; - - /* UART2 */ - dev->device_regs[5][0x30] = 0x00; - dev->device_regs[5][0x60] = 0x00; /* Base Address */ - dev->device_regs[5][0x61] = 0x00; - - dev->device_regs[5][0x70] = 0x00; + dev->device_regs[4][0x74] = 0x04; + dev->device_regs[4][0xf1] = 0x02; + dev->device_regs[4][0xf2] = 0x03; /* AUX */ - dev->device_regs[8][0x30] = 0x00; + dev->device_regs[8][0xc0] = 0x06; + dev->device_regs[8][0xc1] = 0x03; fdc37m60x_fdc_handler(dev); fdc37m60x_uart_handler(0, dev); @@ -262,6 +286,7 @@ fdc37m60x_reset(void *priv) fdc37m60x_lpt_handler(dev); } + static void fdc37m60x_close(void *priv) { @@ -270,6 +295,7 @@ fdc37m60x_close(void *priv) free(dev); } + static void * fdc37m60x_init(const device_t *info) { @@ -277,25 +303,18 @@ fdc37m60x_init(const device_t *info) memset(dev, 0, sizeof(fdc37m60x_t)); SIO_INDEX_PORT = info->local; - dev->regs[0x20] = 0x47; - dev->regs[0x24] = 0x04; - dev->device_regs[0][0xf0] = 0x0e; - dev->device_regs[0][0xf2] = 0xff; - dev->device_regs[3][0xf0] = 0x3c; - dev->device_regs[4][0xf1] = 0x02; - dev->device_regs[4][0xf2] = 0x03; - dev->device_regs[8][0xc0] = 0x06; - dev->device_regs[8][0xc1] = 0x03; - - dev->fdc_controller = device_add(&fdc_at_smc_device); + dev->fdc = device_add(&fdc_at_smc_device); dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); io_sethandler(SIO_INDEX_PORT, 0x0002, fdc37m60x_read, NULL, NULL, fdc37m60x_write, NULL, NULL, dev); + fdc37m60x_reset(dev); + return dev; } + const device_t fdc37m60x_device = { "SMSC FDC37M60X", 0, @@ -303,10 +322,11 @@ const device_t fdc37m60x_device = { fdc37m60x_init, fdc37m60x_close, NULL, - {NULL}, + { NULL }, NULL, NULL, - NULL}; + NULL +}; const device_t fdc37m60x_370_device = { "SMSC FDC37M60X with 10K Pull Up Resistor", @@ -315,7 +335,8 @@ const device_t fdc37m60x_370_device = { fdc37m60x_init, fdc37m60x_close, NULL, - {NULL}, + { NULL }, NULL, NULL, - NULL}; + NULL +}; From dc6e07a1628a07054451d5af777f977d3f177102 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:11:45 +0200 Subject: [PATCH 48/59] SMC FDC73C93x Super I/O chip fixes. --- src/sio/sio_fdc37c93x.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sio/sio_fdc37c93x.c b/src/sio/sio_fdc37c93x.c index a0f0a2135..35cfe862b 100644 --- a/src/sio/sio_fdc37c93x.c +++ b/src/sio/sio_fdc37c93x.c @@ -478,17 +478,17 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) break; case 0xF1: if (valxor & 0xC) - fdc_update_densel_force(dev->fdc, (val & 0xC) >> 2); + fdc_update_densel_force(dev->fdc, (val & 0xc) >> 2); break; case 0xF2: if (valxor & 0xC0) - fdc_update_rwc(dev->fdc, 3, (valxor & 0xC0) >> 6); + fdc_update_rwc(dev->fdc, 3, (val & 0xc0) >> 6); if (valxor & 0x30) - fdc_update_rwc(dev->fdc, 2, (valxor & 0x30) >> 4); + fdc_update_rwc(dev->fdc, 2, (val & 0x30) >> 4); if (valxor & 0x0C) - fdc_update_rwc(dev->fdc, 1, (valxor & 0x0C) >> 2); + fdc_update_rwc(dev->fdc, 1, (val & 0x0c) >> 2); if (valxor & 0x03) - fdc_update_rwc(dev->fdc, 0, (valxor & 0x03)); + fdc_update_rwc(dev->fdc, 0, (val & 0x03)); break; case 0xF4: if (valxor & 0x18) From f0da82fa2b18e126279098a188ad9b087695ac66 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:12:53 +0200 Subject: [PATCH 49/59] The LG Prime3C no longer calls the IDE handler on register write if it is the variant without IDE. --- src/sio/sio_prime3c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sio/sio_prime3c.c b/src/sio/sio_prime3c.c index b18e274fa..2d2d0435e 100644 --- a/src/sio/sio_prime3c.c +++ b/src/sio/sio_prime3c.c @@ -127,7 +127,8 @@ prime3c_write(uint16_t addr, uint8_t val, void *priv) case 0xc5: IDE_SIDE_ADDRESS = (val & 0xfc) | 0x02; - prime3c_ide_handler(dev); + if (HAS_IDE_FUNCTIONALITY) + prime3c_ide_handler(dev); break; case 0xc6: From 63a5c3a281d68c7c1b250c66adc704dac94d63e5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:15:09 +0200 Subject: [PATCH 50/59] Some indentation changes in 86box.c and added a fatal_ex() function. --- src/86box.c | 111 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/src/86box.c b/src/86box.c index 4d1e64782..b51fb4763 100644 --- a/src/86box.c +++ b/src/86box.c @@ -208,34 +208,32 @@ void pclog_ex(const char *fmt, va_list ap) { #ifndef RELEASE_BUILD - char temp[1024]; + char temp[1024]; - if (strcmp(fmt, "") == 0) + if (strcmp(fmt, "") == 0) return; - if (stdlog == NULL) { + if (stdlog == NULL) { if (log_path[0] != '\0') { stdlog = plat_fopen(log_path, "w"); if (stdlog == NULL) stdlog = stdout; - } else { + } else stdlog = stdout; - } - } + } - vsprintf(temp, fmt, ap); - if (suppr_seen && ! strcmp(buff, temp)) { + vsprintf(temp, fmt, ap); + if (suppr_seen && ! strcmp(buff, temp)) seen++; - } else { - if (suppr_seen && seen) { + else { + if (suppr_seen && seen) fprintf(stdlog, "*** %d repeats ***\n", seen); - } seen = 0; strcpy(buff, temp); - fprintf(stdlog, temp, ap); - } + fprintf(stdlog, "%s", temp); + } - fflush(stdlog); + fflush(stdlog); #endif } @@ -267,47 +265,86 @@ pclog(const char *fmt, ...) void fatal(const char *fmt, ...) { - char temp[1024]; - va_list ap; - char *sp; + char temp[1024]; + va_list ap; + char *sp; - va_start(ap, fmt); + va_start(ap, fmt); - if (stdlog == NULL) { + if (stdlog == NULL) { if (log_path[0] != '\0') { stdlog = plat_fopen(log_path, "w"); if (stdlog == NULL) stdlog = stdout; - } else { + } else stdlog = stdout; - } - } + } - vsprintf(temp, fmt, ap); - fprintf(stdlog, "%s", temp); - fflush(stdlog); - va_end(ap); + vsprintf(temp, fmt, ap); + fprintf(stdlog, "%s", temp); + fflush(stdlog); + va_end(ap); - nvr_save(); + nvr_save(); - config_save(); + config_save(); #ifdef ENABLE_808X_LOG - dumpregs(1); + dumpregs(1); #endif - /* Make sure the message does not have a trailing newline. */ - if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0'; + /* Make sure the message does not have a trailing newline. */ + if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0'; - /* Cleanly terminate all of the emulator's components so as - to avoid things like threads getting stuck. */ - do_stop(); + /* Cleanly terminate all of the emulator's components so as + to avoid things like threads getting stuck. */ + do_stop(); - ui_msgbox(MBX_ERROR | MBX_FATAL | MBX_ANSI, temp); + ui_msgbox(MBX_ERROR | MBX_FATAL | MBX_ANSI, temp); - fflush(stdlog); + fflush(stdlog); - exit(-1); + exit(-1); +} + + +void +fatal_ex(const char *fmt, va_list ap) +{ + char temp[1024]; + char *sp; + + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } + + vsprintf(temp, fmt, ap); + fprintf(stdlog, "%s", temp); + fflush(stdlog); + + nvr_save(); + + config_save(); + +#ifdef ENABLE_808X_LOG + dumpregs(1); +#endif + + /* Make sure the message does not have a trailing newline. */ + if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0'; + + /* Cleanly terminate all of the emulator's components so as + to avoid things like threads getting stuck. */ + do_stop(); + + ui_msgbox(MBX_ERROR | MBX_FATAL | MBX_ANSI, temp); + + fflush(stdlog); } From 7d3ed9b39706a40ab3452af3627fccb90367a69a Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:15:52 +0200 Subject: [PATCH 51/59] Added the fatal_ex() function to 86box.h. --- src/include/86box/86box.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index e7f79b36f..20e5b151b 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -152,6 +152,7 @@ extern int config_changed; /* config has changed */ /* Function prototypes. */ #ifdef HAVE_STDARG_H extern void pclog_ex(const char *fmt, va_list); +extern void fatal_ex(const char *fmt, va_list); #endif extern void pclog_toggle_suppr(void); extern void pclog(const char *fmt, ...); From 149ecab64a8d7f5afb98346380cab484d390ea90 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:17:03 +0200 Subject: [PATCH 52/59] New logging system, currently not used by anything. --- src/include/86box/log.h | 46 ++++++++++++ src/log.c | 162 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 src/include/86box/log.h create mode 100644 src/log.c diff --git a/src/include/86box/log.h b/src/include/86box/log.h new file mode 100644 index 000000000..210f2c5a7 --- /dev/null +++ b/src/include/86box/log.h @@ -0,0 +1,46 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Main include file for the application. + * + * + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2021 Miran Grca. + * Copyright 2021 Fred N. van Kempen. + */ +#ifndef EMU_LOG_H +# define EMU_LOG_H + +#ifndef RELEASE_BUILD + +#ifdef __cplusplus +extern "C" { +#endif + +/* Function prototypes. */ +extern void log_set_suppr_seen(void *priv, int suppr_seen); +extern void log_set_dev_name(void *priv, char *dev_name); +#ifdef HAVE_STDARG_H +extern void log_out(void *priv, const char *fmt, va_list); +extern void log_fatal(void *priv, const char *fmt, ...); +#endif +extern void * log_open(char *dev_name); +extern void log_close(void *priv); + +#ifdef __cplusplus +} +#endif + +#else +#define log_fatal(priv, fmt, ...) fatal(fmt, ...) +#endif /*RELEASE_BUILD*/ + +#endif /*EMU_LOG_H*/ diff --git a/src/log.c b/src/log.c new file mode 100644 index 000000000..a20a8d520 --- /dev/null +++ b/src/log.c @@ -0,0 +1,162 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * The handler of the new logging system. + * + * + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2021 Miran Grca. + * Copyright 2021 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/config.h> +#include <86box/mem.h> +#include "cpu.h" +#include <86box/plat.h> +#include <86box/version.h> +#include <86box/log.h> + + +#ifndef RELEASE_BUILD +typedef struct +{ + char buff[1024], *dev_name; + int seen, suppr_seen; +} log_t; + + +void +log_set_suppr_seen(void *priv, int suppr_seen) +{ + log_t *log = (log_t *) priv; + + log->suppr_seen = suppr_seen; +} + + +void +log_set_dev_name(void *priv, char *dev_name) +{ + log_t *log = (log_t *) priv; + + log->dev_name = dev_name; +} + + +static void +log_copy(log_t *log, char *dest, const char *src, size_t dest_size) +{ + memset(dest, 0x00, dest_size * sizeof(char)); + if (log && log->dev_name && strcmp(log->dev_name, "")) { + strcat(dest, log->dev_name); + strcat(dest, ": "); + } + strcat(dest, src); +} + + +/* + * Log something to the logfile or stdout. + * + * To avoid excessively-large logfiles because some + * module repeatedly logs, we keep track of what is + * being logged, and catch repeating entries. + */ +void +log_out(void *priv, const char *fmt, va_list ap) +{ + log_t *log = (log_t *) priv; + char temp[1024], fmt2[1024]; + + if (log == NULL) + return; + + if (strcmp(fmt, "") == 0) + return; + + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } + + vsprintf(temp, fmt, ap); + if (log->suppr_seen && ! strcmp(log->buff, temp)) + log->seen++; + else { + if (log->suppr_seen && log->seen) { + log_copy(log, fmt2, "*** %d repeats ***\n", 1024); + fprintf(stdlog, fmt2, log->seen); + } + log->seen = 0; + strcpy(log->buff, temp); + log_copy(log, fmt2, temp, 1024); + fprintf(stdlog, fmt2, ap); + } + + fflush(stdlog); +} + + +void +log_fatal(void *priv, const char *fmt, ...) +{ + log_t *log = (log_t *) priv; + char temp[1024], fmt2[1024]; + va_list ap; + + if (log == NULL) + return; + + va_start(ap, fmt); + log_copy(log, fmt2, fmt, 1024); + vsprintf(temp, fmt2, ap); + fatal_ex(fmt2, ap); + va_end(ap); + exit(-1); +} + + +void * +log_open(char *dev_name) +{ + log_t *log = malloc(sizeof(log_t)); + + memset(log, 0, sizeof(log_t)); + + log->dev_name = dev_name; + log->suppr_seen = 1; + + return (void *) log; +} + + +void +log_close(void *priv) +{ + log_t *log = (log_t *) priv; + + free(log); +} +#endif From 51b88518b88a547258ffe1e97744a870a35137bf Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:17:29 +0200 Subject: [PATCH 53/59] Some mem.c reset organization. --- src/mem/mem.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/mem/mem.c b/src/mem/mem.c index 374062c1b..cac528a59 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2585,7 +2585,24 @@ mem_reset(void) memset(page_ff, 0xff, sizeof(page_ff)); - m = 1024UL * mem_size; +#ifdef USE_NEW_DYNAREC + if (byte_dirty_mask) { + free(byte_dirty_mask); + byte_dirty_mask = NULL; + } + + if (byte_code_present_mask) { + free(byte_code_present_mask); + byte_code_present_mask = NULL; + } +#endif + + /* Free the old pages array, if necessary. */ + if (pages) { + free(pages); + pages = NULL; + } + if (ram != NULL) { free(ram); ram = NULL; @@ -2596,9 +2613,12 @@ mem_reset(void) ram2 = NULL; } #endif + if (mem_size > 2097152) fatal("Attempting to use more than 2 GB of emulated RAM\n"); + m = 1024UL * mem_size; + #if (!(defined __amd64__ || defined _M_X64)) if (mem_size > 1048576) { ram = (uint8_t *)malloc(1 << 30); /* allocate and clear the RAM block of the first 1 GB */ @@ -2655,16 +2675,9 @@ mem_reset(void) /* * Allocate and initialize the (new) page table. - * We only do this if the size of the page table has changed. */ - if (pages_sz != m) { - pages_sz = m; - if (pages) { - free(pages); - pages = NULL; - } - pages = (page_t *)malloc(m*sizeof(page_t)); - } + pages_sz = m; + pages = (page_t *)malloc(m*sizeof(page_t)); memset(page_lookup, 0x00, (1 << 20) * sizeof(page_t *)); memset(page_lookupp, 0x04, (1 << 20) * sizeof(uint8_t)); @@ -2672,17 +2685,9 @@ mem_reset(void) memset(pages, 0x00, pages_sz*sizeof(page_t)); #ifdef USE_NEW_DYNAREC - if (byte_dirty_mask) { - free(byte_dirty_mask); - byte_dirty_mask = NULL; - } byte_dirty_mask = malloc((mem_size * 1024) / 8); memset(byte_dirty_mask, 0, (mem_size * 1024) / 8); - if (byte_code_present_mask) { - free(byte_code_present_mask); - byte_code_present_mask = NULL; - } byte_code_present_mask = malloc((mem_size * 1024) / 8); memset(byte_code_present_mask, 0, (mem_size * 1024) / 8); #endif From cc310d663fd71fb8f5b98f56413ce6bc35da2bf7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:18:33 +0200 Subject: [PATCH 54/59] Slight GC100 rework. --- src/chipset/gc100.c | 196 +++++++++++++++++++++----------------------- 1 file changed, 95 insertions(+), 101 deletions(-) diff --git a/src/chipset/gc100.c b/src/chipset/gc100.c index 97c944f74..79182a380 100644 --- a/src/chipset/gc100.c +++ b/src/chipset/gc100.c @@ -7,15 +7,14 @@ * This file is part of the 86Box distribution. * * Implementation of the G2 GC100/GC100A chipset. - * NOTE: As documentation is currently available only for the - * CG100 chipset, the GC100A chipset has been reverese-engineered. - * Thus, its behavior may not be fully accurate. + * NOTE: As documentation is currently available only for the + * CG100 chipset, the GC100A chipset has been reverese-engineered. + * Thus, its behavior may not be fully accurate. * - * Authors: EngiNerd + * Authors: EngiNerd, * - * Copyright 2020-2021 EngiNerd + * Copyright 2020-2021 EngiNerd. */ - #include #include #include @@ -42,15 +41,16 @@ #include <86box/io.h> #include <86box/video.h> + typedef struct { uint8_t reg[0x10]; } gc100_t; -#define ENABLE_GC100_LOG 1 #ifdef ENABLE_GC100_LOG int gc100_do_log = ENABLE_GC100_LOG; + static void gc100_log(const char *fmt, ...) { @@ -66,136 +66,130 @@ gc100_log(const char *fmt, ...) #define gc100_log(fmt, ...) #endif + static uint8_t -get_fdd_switch_settings(){ - +get_fdd_switch_settings(void) +{ int i, fdd_count = 0; for (i = 0; i < FDD_NUM; i++) { - if (fdd_get_flags(i)) - fdd_count++; + if (fdd_get_flags(i)) + fdd_count++; } if (!fdd_count) return 0x00; else return ((fdd_count - 1) << 6) | 0x01; - } + static uint8_t -get_videomode_switch_settings(){ - +get_videomode_switch_settings(void) +{ if (video_is_mda()) - return 0x30; + return 0x30; else if (video_is_cga()) - return 0x20; /* 0x10 would be 40x25 */ + return 0x20; /* 0x10 would be 40x25 */ else - return 0x00; - + return 0x00; } + static void gc100_write(uint16_t port, uint8_t val, void *priv) { gc100_t *dev = (gc100_t *) priv; - uint16_t addr = port & 0xf; dev->reg[addr] = val; - switch (addr) - { - /* addr 0x2 - * bits 5-7: not used - * bit 4: intenal memory wait states - * bits 2-3: external memory wait states - * bits 0-1: i/o access wait states - */ - case 0x2: - break; - - /* addr 0x3 - * bits 1-7: not used - * bit 0: turbo 0 xt 1 - */ - case 0x3: - if (val & 0x1) - cpu_dynamic_switch(0); - else - cpu_dynamic_switch(cpu); - break; - - /* addr 0x5 - * programmable dip-switches - * bits 6-7: floppy drive number - * bits 4-5: video mode - * bits 2-3: memory size - * bit 1: fpu - * bit 0: not used - */ - - /* addr 0x6 */ - - /* addr 0x7 */ + switch (addr) { + /* addr 0x2 + * bits 5-7: not used + * bit 4: intenal memory wait states + * bits 2-3: external memory wait states + * bits 0-1: i/o access wait states + */ + case 2: + break; + + /* addr 0x3 + * bits 1-7: not used + * bit 0: turbo 0 xt 1 + */ + case 3: + if (val & 1) + cpu_dynamic_switch(0); + else + cpu_dynamic_switch(cpu); + break; + /* addr 0x5 + * programmable dip-switches + * bits 6-7: floppy drive number + * bits 4-5: video mode + * bits 2-3: memory size + * bit 1: fpu + * bit 0: not used + */ + + /* addr 0x6 */ + + /* addr 0x7 */ } - + gc100_log("GC100: Write %02x at %02x\n", val, port); - } + static uint8_t gc100_read(uint16_t port, void *priv) { gc100_t *dev = (gc100_t *) priv; uint8_t ret = 0xff; - uint16_t addr = port & 0xf; ret = dev->reg[addr]; - + gc100_log("GC100: Read %02x at %02x\n", ret, port); - switch (addr) - { - /* addr 0x2 - * bits 5-7: not used - * bit 4: intenal memory wait states - * bits 2-3: external memory wait states - * bits 0-1: i/o access wait states - */ - case 0x2: - break; - - /* addr 0x3 - * bits 1-7: not used - * bit 0: turbo 0 xt 1 - */ - case 0x3: - break; - - /* addr 0x5 - * programmable dip-switches - * bits 6-7: floppy drive number - * bits 4-5: video mode - * bits 2-3: memory size - * bit 1: fpu - * bit 0: not used - */ - case 0x5: - ret = ret & 0x0c; - ret |= get_fdd_switch_settings(); - ret |= get_videomode_switch_settings(); - if (hasfpu) - ret |= 0x02; + switch (addr) { + /* addr 0x2 + * bits 5-7: not used + * bit 4: intenal memory wait states + * bits 2-3: external memory wait states + * bits 0-1: i/o access wait states + */ + case 0x2: + break; - break; - - /* addr 0x6 */ - - /* addr 0x7 */ - + /* addr 0x3 + * bits 1-7: not used + * bit 0: turbo 0 xt 1 + */ + case 0x3: + break; + + /* addr 0x5 + * programmable dip-switches + * bits 6-7: floppy drive number + * bits 4-5: video mode + * bits 2-3: memory size + * bit 1: fpu + * bit 0: not used + */ + case 0x5: + ret = ret & 0x0c; + ret |= get_fdd_switch_settings(); + ret |= get_videomode_switch_settings(); + if (hasfpu) + ret |= 0x02; + break; + + /* addr 0x6 */ + + /* addr 0x7 */ } return ret; @@ -210,6 +204,7 @@ gc100_close(void *priv) free(dev); } + static void * gc100_init(const device_t *info) { @@ -222,13 +217,12 @@ gc100_init(const device_t *info) dev->reg[0x6] = 0x0; dev->reg[0x7] = 0x0; - /* GC100A */ - if(info->local) { + if (info->local) { + /* GC100A */ io_sethandler(0x0c2, 0x02, gc100_read, NULL, NULL, gc100_write, NULL, NULL, dev); io_sethandler(0x0c5, 0x03, gc100_read, NULL, NULL, gc100_write, NULL, NULL, dev); - } - /* GC100 */ - else { + } else { + /* GC100 */ io_sethandler(0x022, 0x02, gc100_read, NULL, NULL, gc100_write, NULL, NULL, dev); io_sethandler(0x025, 0x01, gc100_read, NULL, NULL, gc100_write, NULL, NULL, dev); } @@ -236,6 +230,7 @@ gc100_init(const device_t *info) return dev; } + const device_t gc100_device = { "G2 GC100", 0, @@ -253,4 +248,3 @@ const device_t gc100a_device = { { NULL }, NULL, NULL, NULL }; - From bfbb4b9655da48f84b9ec6bbce6e728a867c1819 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:20:04 +0200 Subject: [PATCH 55/59] PCI now supports a fourth MIRQ. --- src/include/86box/pci.h | 1 + src/pci.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/include/86box/pci.h b/src/include/86box/pci.h index e59268742..210ff1d4e 100644 --- a/src/include/86box/pci.h +++ b/src/include/86box/pci.h @@ -44,6 +44,7 @@ #define PCI_MIRQ0 0 #define PCI_MIRQ1 1 #define PCI_MIRQ2 2 +#define PCI_MIRQ3 3 #define PCI_IRQ_DISABLED -1 diff --git a/src/pci.c b/src/pci.c index a8c76b003..5f1c48f50 100644 --- a/src/pci.c +++ b/src/pci.c @@ -59,7 +59,7 @@ static uint8_t pci_pmc = 0, last_pci_card = 0, last_normal_pci_card = 0, last_p static uint8_t pci_card_to_slot_mapping[256][32], pci_bus_number_to_index_mapping[256]; static uint8_t pci_irqs[16], pci_irq_level[16]; static uint64_t pci_irq_hold[16]; -static pci_mirq_t pci_mirqs[3]; +static pci_mirq_t pci_mirqs[4]; static int pci_type, pci_switch, pci_index, @@ -446,7 +446,7 @@ pci_set_irq(uint8_t card, uint8_t pci_int) } else pci_log("pci_set_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); - if (picint_is_level(irq_line) && (pci_irq_hold[irq_line] & (1ULL << slot))) { + if (level && (pci_irq_hold[irq_line] & (1ULL << slot))) { /* IRQ already held, do nothing. */ pci_log("pci_set_irq(%02X, %02X): Card is already holding the IRQ\n", card, pci_int); return; From 4be8bbb7043318883ba40db76931ebf3f7005807 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Jun 2021 00:22:12 +0200 Subject: [PATCH 56/59] Some changes to io.c/h. --- src/include/86box/io.h | 38 ++++++++- src/io.c | 172 +++++++++++++++++++++-------------------- 2 files changed, 125 insertions(+), 85 deletions(-) diff --git a/src/include/86box/io.h b/src/include/86box/io.h index 7ec808abf..6112ea8e4 100644 --- a/src/include/86box/io.h +++ b/src/include/86box/io.h @@ -23,6 +23,33 @@ extern void io_init(void); +extern void io_sethandler_common(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv, int step); + +extern void io_removehandler_common(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv, int step); + +extern void io_handler_common(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv, int step); + extern void io_sethandler(uint16_t base, int size, uint8_t (*inb)(uint16_t addr, void *priv), uint16_t (*inw)(uint16_t addr, void *priv), @@ -50,7 +77,6 @@ extern void io_handler(int set, uint16_t base, int size, void (*outl)(uint16_t addr, uint32_t val, void *priv), void *priv); -#ifdef PC98 extern void io_sethandler_interleaved(uint16_t base, int size, uint8_t (*inb)(uint16_t addr, void *priv), uint16_t (*inw)(uint16_t addr, void *priv), @@ -68,7 +94,15 @@ extern void io_removehandler_interleaved(uint16_t base, int size, void (*outw)(uint16_t addr, uint16_t val, void *priv), void (*outl)(uint16_t addr, uint32_t val, void *priv), void *priv); -#endif + +extern void io_handler_interleaved(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); extern uint8_t inb(uint16_t port); extern void outb(uint16_t port, uint8_t val); diff --git a/src/io.c b/src/io.c index 0930da37d..2751cc639 100644 --- a/src/io.c +++ b/src/io.c @@ -104,19 +104,19 @@ io_init(void) void -io_sethandler(uint16_t base, int size, +io_sethandler_common(uint16_t base, int size, uint8_t (*inb)(uint16_t addr, void *priv), uint16_t (*inw)(uint16_t addr, void *priv), uint32_t (*inl)(uint16_t addr, void *priv), void (*outb)(uint16_t addr, uint8_t val, void *priv), void (*outw)(uint16_t addr, uint16_t val, void *priv), void (*outl)(uint16_t addr, uint32_t val, void *priv), - void *priv) + void *priv, int step) { int c; io_t *p, *q = NULL; - for (c = 0; c < size; c++) { + for (c = 0; c < size; c += step) { p = io_last[base + c]; q = (io_t *) malloc(sizeof(io_t)); memset(q, 0, sizeof(io_t)); @@ -145,19 +145,19 @@ io_sethandler(uint16_t base, int size, void -io_removehandler(uint16_t base, int size, - uint8_t (*inb)(uint16_t addr, void *priv), - uint16_t (*inw)(uint16_t addr, void *priv), - uint32_t (*inl)(uint16_t addr, void *priv), - void (*outb)(uint16_t addr, uint8_t val, void *priv), - void (*outw)(uint16_t addr, uint16_t val, void *priv), - void (*outl)(uint16_t addr, uint32_t val, void *priv), - void *priv) +io_removehandler_common(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv, int step) { int c; io_t *p, *q; - for (c = 0; c < size; c++) { + for (c = 0; c < size; c += step) { p = io[base + c]; if (!p) continue; @@ -185,6 +185,51 @@ io_removehandler(uint16_t base, int size, } +void +io_handler_common(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv, int step) +{ + if (set) + io_sethandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, step); + else + io_removehandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, step); +} + + +void +io_sethandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + io_sethandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, 1); +} + + +void +io_removehandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + io_removehandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, 1); +} + + void io_handler(int set, uint16_t base, int size, uint8_t (*inb)(uint16_t addr, void *priv), @@ -195,89 +240,50 @@ io_handler(int set, uint16_t base, int size, void (*outl)(uint16_t addr, uint32_t val, void *priv), void *priv) { - if (set) - io_sethandler(base, size, inb, inw, inl, outb, outw, outl, priv); - else - io_removehandler(base, size, inb, inw, inl, outb, outw, outl, priv); + io_handler_common(set, base, size, inb, inw, inl, outb, outw, outl, priv, 1); } -#ifdef PC98 void -io_sethandler_interleaved(uint16_t base, int size, - uint8_t (*inb)(uint16_t addr, void *priv), - uint16_t (*inw)(uint16_t addr, void *priv), - uint32_t (*inl)(uint16_t addr, void *priv), - void (*outb)(uint16_t addr, uint8_t val, void *priv), - void (*outw)(uint16_t addr, uint16_t val, void *priv), - void (*outl)(uint16_t addr, uint32_t val, void *priv), - void *priv) +io_sethandler_interleaved(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) { - int c; - io_t *p, *q; - - size <<= 2; - for (c=0; cnext = q; - q->prev = p; - } else { - io[base + c] = q; - q->prev = NULL; - } - - q->inb = inb; - q->inw = inw; - q->inl = inl; - - q->outb = outb; - q->outw = outw; - q->outl = outl; - - q->priv = priv; - } + io_sethandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, 2); } void io_removehandler_interleaved(uint16_t base, int size, - uint8_t (*inb)(uint16_t addr, void *priv), - uint16_t (*inw)(uint16_t addr, void *priv), - uint32_t (*inl)(uint16_t addr, void *priv), - void (*outb)(uint16_t addr, uint8_t val, void *priv), - void (*outw)(uint16_t addr, uint16_t val, void *priv), - void (*outl)(uint16_t addr, uint32_t val, void *priv), - void *priv) + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) { - int c; - io_t *p, *q; - - size <<= 2; - for (c = 0; c < size; c += 2) { - p = io[base + c]; - if (!p) - return; - while(p) { - q = p->next; - if ((p->inb == inb) && (p->inw == inw) && - (p->inl == inl) && (p->outb == outb) && - (p->outw == outw) && (p->outl == outl) && - (p->priv == priv)) { - if (p->prev) - p->prev->next = p->next; - if (p->next) - p->next->prev = p->prev; - free(p); - break; - } - p = q; - } - } + io_removehandler_common(base, size, inb, inw, inl, outb, outw, outl, priv, 2); +} + + +void +io_handler_interleaved(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + io_handler_common(set, base, size, inb, inw, inl, outb, outw, outl, priv, 2); } -#endif uint8_t From 29018a35d8f93a7306f7e8b8c9883c0f3e07608b Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 8 Jun 2021 07:33:29 +0200 Subject: [PATCH 57/59] Fixed 512k Intel Flash chips. --- src/mem/intel_flash.c | 189 +++++++++++++++++++++--------------------- 1 file changed, 94 insertions(+), 95 deletions(-) diff --git a/src/mem/intel_flash.c b/src/mem/intel_flash.c index cf166c663..b96becc2d 100644 --- a/src/mem/intel_flash.c +++ b/src/mem/intel_flash.c @@ -74,7 +74,7 @@ typedef struct flash_t block_start[BLOCKS_NUM], block_end[BLOCKS_NUM], block_len[BLOCKS_NUM]; - mem_mapping_t mapping[4], mapping_h[8]; + mem_mapping_t mapping[4], mapping_h[16]; } flash_t; @@ -298,14 +298,13 @@ intel_flash_add_mappings(flash_t *dev) uint32_t base, fbase; uint32_t sub = 0x20000; - if (biosmask == 0x7ffff) { + if (biosmask == 0x7ffff) { sub = 0x80000; max = 8; - } - else if (biosmask == 0x3ffff) { + } else if (biosmask == 0x3ffff) { sub = 0x40000; max = 4; - } + } for (i = 0; i < max; i++) { if (biosmask == 0x7ffff) @@ -331,7 +330,7 @@ intel_flash_add_mappings(flash_t *dev) flash_read, flash_readw, flash_readl, flash_write, flash_writew, flash_writel, dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); - mem_mapping_add(&(dev->mapping_h[i + 4]), (base | 0xfff00000), 0x10000, + mem_mapping_add(&(dev->mapping_h[i + (max >> 1)]), (base | 0xfff00000), 0x10000, flash_read, flash_readw, flash_readl, flash_write, flash_writew, flash_writel, dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); @@ -415,101 +414,101 @@ intel_flash_init(const device_t *info) dev->block_end[BLOCK_DATA2] = 0x7bfff; dev->block_start[BLOCK_BOOT] = 0x7c000; /* BOOT BLOCK */ dev->block_end[BLOCK_BOOT] = 0x7ffff; - } - break; + } + break; - case 0x3ffff: - if (dev->flags & FLAG_WORD) - dev->flash_id = (dev->flags & FLAG_BXB) ? 0x2275 : 0x2274; - else - dev->flash_id = (dev->flags & FLAG_BXB) ? 0x7D : 0x7C; + case 0x3ffff: + if (dev->flags & FLAG_WORD) + dev->flash_id = (dev->flags & FLAG_BXB) ? 0x2275 : 0x2274; + else + dev->flash_id = (dev->flags & FLAG_BXB) ? 0x7D : 0x7C; - /* The block lengths are the same both flash types. */ - dev->block_len[BLOCK_MAIN1] = 0x20000; - dev->block_len[BLOCK_MAIN2] = 0x18000; - dev->block_len[BLOCK_MAIN3] = 0x00000; - dev->block_len[BLOCK_MAIN4] = 0x00000; - dev->block_len[BLOCK_DATA1] = 0x02000; - dev->block_len[BLOCK_DATA2] = 0x02000; - dev->block_len[BLOCK_BOOT] = 0x04000; + /* The block lengths are the same both flash types. */ + dev->block_len[BLOCK_MAIN1] = 0x20000; + dev->block_len[BLOCK_MAIN2] = 0x18000; + dev->block_len[BLOCK_MAIN3] = 0x00000; + dev->block_len[BLOCK_MAIN4] = 0x00000; + dev->block_len[BLOCK_DATA1] = 0x02000; + dev->block_len[BLOCK_DATA2] = 0x02000; + dev->block_len[BLOCK_BOOT] = 0x04000; - if (dev->flags & FLAG_BXB) { /* 28F002BX-B/28F200BX-B */ - dev->block_start[BLOCK_MAIN1] = 0x20000; /* MAIN BLOCK 1 */ - dev->block_end[BLOCK_MAIN1] = 0x3ffff; - dev->block_start[BLOCK_MAIN2] = 0x08000; /* MAIN BLOCK 2 */ - dev->block_end[BLOCK_MAIN2] = 0x1ffff; - dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ - dev->block_end[BLOCK_MAIN3] = 0xfffff; - dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ - dev->block_end[BLOCK_MAIN4] = 0xfffff; - dev->block_start[BLOCK_DATA1] = 0x06000; /* DATA AREA 1 BLOCK */ - dev->block_end[BLOCK_DATA1] = 0x07fff; - dev->block_start[BLOCK_DATA2] = 0x04000; /* DATA AREA 2 BLOCK */ - dev->block_end[BLOCK_DATA2] = 0x05fff; - dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ - dev->block_end[BLOCK_BOOT] = 0x03fff; - } else { /* 28F002BX-T/28F200BX-T */ - dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ - dev->block_end[BLOCK_MAIN1] = 0x1ffff; - dev->block_start[BLOCK_MAIN2] = 0x20000; /* MAIN BLOCK 2 */ - dev->block_end[BLOCK_MAIN2] = 0x37fff; - dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ - dev->block_end[BLOCK_MAIN3] = 0xfffff; - dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ - dev->block_end[BLOCK_MAIN4] = 0xfffff; - dev->block_start[BLOCK_DATA1] = 0x38000; /* DATA AREA 1 BLOCK */ - dev->block_end[BLOCK_DATA1] = 0x39fff; - dev->block_start[BLOCK_DATA2] = 0x3a000; /* DATA AREA 2 BLOCK */ - dev->block_end[BLOCK_DATA2] = 0x3bfff; - dev->block_start[BLOCK_BOOT] = 0x3c000; /* BOOT BLOCK */ - dev->block_end[BLOCK_BOOT] = 0x3ffff; - } - break; + if (dev->flags & FLAG_BXB) { /* 28F002BX-B/28F200BX-B */ + dev->block_start[BLOCK_MAIN1] = 0x20000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x3ffff; + dev->block_start[BLOCK_MAIN2] = 0x08000; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0x1ffff; + dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ + dev->block_end[BLOCK_MAIN3] = 0xfffff; + dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ + dev->block_end[BLOCK_MAIN4] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x06000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x07fff; + dev->block_start[BLOCK_DATA2] = 0x04000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x05fff; + dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x03fff; + } else { /* 28F002BX-T/28F200BX-T */ + dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1ffff; + dev->block_start[BLOCK_MAIN2] = 0x20000; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0x37fff; + dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ + dev->block_end[BLOCK_MAIN3] = 0xfffff; + dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ + dev->block_end[BLOCK_MAIN4] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x38000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x39fff; + dev->block_start[BLOCK_DATA2] = 0x3a000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x3bfff; + dev->block_start[BLOCK_BOOT] = 0x3c000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x3ffff; + } + break; - default: - dev->flash_id = (type & FLAG_BXB) ? 0x95 : 0x94; + default: + dev->flash_id = (type & FLAG_BXB) ? 0x95 : 0x94; - /* The block lengths are the same both flash types. */ - dev->block_len[BLOCK_MAIN1] = 0x1c000; - dev->block_len[BLOCK_MAIN2] = 0x00000; - dev->block_len[BLOCK_MAIN3] = 0x00000; - dev->block_len[BLOCK_MAIN4] = 0x00000; - dev->block_len[BLOCK_DATA1] = 0x01000; - dev->block_len[BLOCK_DATA2] = 0x01000; - dev->block_len[BLOCK_BOOT] = 0x02000; + /* The block lengths are the same both flash types. */ + dev->block_len[BLOCK_MAIN1] = 0x1c000; + dev->block_len[BLOCK_MAIN2] = 0x00000; + dev->block_len[BLOCK_MAIN3] = 0x00000; + dev->block_len[BLOCK_MAIN4] = 0x00000; + dev->block_len[BLOCK_DATA1] = 0x01000; + dev->block_len[BLOCK_DATA2] = 0x01000; + dev->block_len[BLOCK_BOOT] = 0x02000; - if (dev->flags & FLAG_BXB) { /* 28F001BX-B/28F100BX-B */ - dev->block_start[BLOCK_MAIN1] = 0x04000; /* MAIN BLOCK 1 */ - dev->block_end[BLOCK_MAIN1] = 0x1ffff; - dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ - dev->block_end[BLOCK_MAIN2] = 0xfffff; - dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ - dev->block_end[BLOCK_MAIN3] = 0xfffff; - dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ - dev->block_end[BLOCK_MAIN4] = 0xfffff; - dev->block_start[BLOCK_DATA1] = 0x02000; /* DATA AREA 1 BLOCK */ - dev->block_end[BLOCK_DATA1] = 0x02fff; - dev->block_start[BLOCK_DATA2] = 0x03000; /* DATA AREA 2 BLOCK */ - dev->block_end[BLOCK_DATA2] = 0x03fff; - dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ - dev->block_end[BLOCK_BOOT] = 0x01fff; - } else { /* 28F001BX-T/28F100BX-T */ - dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ - dev->block_end[BLOCK_MAIN1] = 0x1bfff; - dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ - dev->block_end[BLOCK_MAIN2] = 0xfffff; - dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ - dev->block_end[BLOCK_MAIN3] = 0xfffff; - dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ - dev->block_end[BLOCK_MAIN4] = 0xfffff; - dev->block_start[BLOCK_DATA1] = 0x1c000; /* DATA AREA 1 BLOCK */ - dev->block_end[BLOCK_DATA1] = 0x1cfff; - dev->block_start[BLOCK_DATA2] = 0x1d000; /* DATA AREA 2 BLOCK */ - dev->block_end[BLOCK_DATA2] = 0x1dfff; - dev->block_start[BLOCK_BOOT] = 0x1e000; /* BOOT BLOCK */ - dev->block_end[BLOCK_BOOT] = 0x1ffff; - } - break; + if (dev->flags & FLAG_BXB) { /* 28F001BX-B/28F100BX-B */ + dev->block_start[BLOCK_MAIN1] = 0x04000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1ffff; + dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0xfffff; + dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ + dev->block_end[BLOCK_MAIN3] = 0xfffff; + dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ + dev->block_end[BLOCK_MAIN4] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x02000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x02fff; + dev->block_start[BLOCK_DATA2] = 0x03000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x03fff; + dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x01fff; + } else { /* 28F001BX-T/28F100BX-T */ + dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1bfff; + dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0xfffff; + dev->block_start[BLOCK_MAIN3] = 0xfffff; /* MAIN BLOCK 3 */ + dev->block_end[BLOCK_MAIN3] = 0xfffff; + dev->block_start[BLOCK_MAIN4] = 0xfffff; /* MAIN BLOCK 4 */ + dev->block_end[BLOCK_MAIN4] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x1c000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x1cfff; + dev->block_start[BLOCK_DATA2] = 0x1d000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x1dfff; + dev->block_start[BLOCK_BOOT] = 0x1e000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x1ffff; + } + break; } intel_flash_add_mappings(dev); From 0ecbb8f7d6d0c17886c7c788bbdc5a22e195bbeb Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 8 Jun 2021 20:33:22 +0200 Subject: [PATCH 58/59] Fixed a small mess-up that messed up all Intel Flash chips, the Bora Pro should now work again. --- src/mem/intel_flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mem/intel_flash.c b/src/mem/intel_flash.c index b96becc2d..cd064ddee 100644 --- a/src/mem/intel_flash.c +++ b/src/mem/intel_flash.c @@ -330,7 +330,7 @@ intel_flash_add_mappings(flash_t *dev) flash_read, flash_readw, flash_readl, flash_write, flash_writew, flash_writel, dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); - mem_mapping_add(&(dev->mapping_h[i + (max >> 1)]), (base | 0xfff00000), 0x10000, + mem_mapping_add(&(dev->mapping_h[i + max]), (base | 0xfff00000), 0x10000, flash_read, flash_readw, flash_readl, flash_write, flash_writew, flash_writel, dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM|MEM_MAPPING_ROMCS, (void *) dev); From 73bdd27ba85d508125c3770d012ecc75ac5ea52d Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 10 Jun 2021 05:07:32 +0200 Subject: [PATCH 59/59] Fixed PIIX MIRQ routing so MIRQ1 routing is no longer incorrectly applied to MIRQ0. --- src/chipset/intel_piix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 96d34d7d4..2c3e0fa89 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -396,9 +396,9 @@ piix_write(int func, int addr, uint8_t val, void *priv) else fregs[addr] = val & 0xcf; if (val & 0x80) - pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); + pci_set_mirq_routing(PCI_MIRQ0 + (addr & 0x01), PCI_IRQ_DISABLED); else - pci_set_mirq_routing(PCI_MIRQ0, val & 0xf); + pci_set_mirq_routing(PCI_MIRQ0 + (addr & 0x01), val & 0xf); piix_log("MIRQ%i is %s\n", addr & 0x01, (val & 0x20) ? "disabled" : "enabled"); } break;