mirror of
https://github.com/86Box/86Box.git
synced 2026-02-23 01:48:21 -07:00
Merge branch 'master' of https://github.com/starfrost013/86box
This commit is contained in:
@@ -239,7 +239,7 @@ typedef struct neat_t {
|
||||
ram_page_t shadow[32]; /* Shadow RAM pages */
|
||||
} neat_t;
|
||||
|
||||
static uint8_t defaults[16] = { 0x0a, 0x45, 0xfc, 0x00, 0x00, 0x7f, 0x00, 0x00,
|
||||
static uint8_t defaults[16] = { 0x0a, 0x45, 0xfc, 0x00, 0x00, 0xfe, 0x00, 0x00,
|
||||
0x00, 0x00, 0xa0, 0x63, 0x10, 0x00, 0x00, 0x12 };
|
||||
|
||||
static uint8_t masks[4] = { RB10_P0EXT, RB10_P1EXT, RB10_P2EXT, RB10_P3EXT };
|
||||
@@ -924,6 +924,16 @@ neat_init(UNUSED(const device_t *info))
|
||||
|
||||
mem_mapping_disable(&ram_mid_mapping);
|
||||
|
||||
for (int i = 0; i < 24; i++) {
|
||||
if (i >= 20)
|
||||
neat_mem_update_state(dev, 0x000a0000 + (i * EMS_PGSIZE), EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_SHADOW);
|
||||
else {
|
||||
/* This is needed to actually trigger an update. */
|
||||
dev->mem_flags[i + 8] = MEM_FLAG_ROMCS;
|
||||
neat_mem_update_state(dev, 0x000a0000 + (i * EMS_PGSIZE), EMS_PGSIZE, 0x00, MEM_FMASK_SHADOW);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For each supported page (we can have a maximum of 4),
|
||||
* create, initialize and disable the mappings, and set
|
||||
@@ -1096,7 +1106,7 @@ neat_init(UNUSED(const device_t *info))
|
||||
neat_log("NEAT: **INVALID DRAM SIZE %iKB !**\n", mem_size);
|
||||
}
|
||||
if (dram_mode > 0) {
|
||||
neat_log("NEAT: using DRAM mode #%i (mem=%iKB)\n", i, mem_size);
|
||||
neat_log("NEAT: using DRAM mode #%i (mem=%iKB)\n", dram_mode, mem_size);
|
||||
}
|
||||
|
||||
/* Set up an I/O handler for the chipset. */
|
||||
|
||||
@@ -268,7 +268,8 @@ exec386_2386(int32_t cycs)
|
||||
} else {
|
||||
CHECK_READ_CS(MIN(ol, 4));
|
||||
}
|
||||
ins_fetch_fault = cpu_386_check_instruction_fault();
|
||||
if (is386)
|
||||
ins_fetch_fault = cpu_386_check_instruction_fault();
|
||||
|
||||
/* Breakpoint fault has priority over other faults. */
|
||||
if (ins_fetch_fault) {
|
||||
@@ -336,6 +337,14 @@ exec386_2386(int32_t cycs)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else if (new_ne) {
|
||||
flags_rebuild();
|
||||
new_ne = 0;
|
||||
#ifndef USE_NEW_DYNAREC
|
||||
oldcs = CS;
|
||||
#endif
|
||||
cpu_state.oldpc = cpu_state.pc;
|
||||
x86_int(16);
|
||||
} else if (trap) {
|
||||
flags_rebuild();
|
||||
if (trap & 2) dr[6] |= 0x8000;
|
||||
|
||||
@@ -72,6 +72,7 @@ extern uint8_t *pccache2;
|
||||
extern int optype;
|
||||
extern uint32_t pccache;
|
||||
|
||||
int new_ne = 0;
|
||||
int in_sys = 0;
|
||||
int unmask_a20_in_smm = 0;
|
||||
uint32_t old_rammask = 0xffffffff;
|
||||
|
||||
@@ -357,6 +357,8 @@ exec386_dynarec_int(void)
|
||||
CPU_BLOCK_END();
|
||||
if (smi_line)
|
||||
CPU_BLOCK_END();
|
||||
else if (new_ne)
|
||||
CPU_BLOCK_END();
|
||||
else if (trap)
|
||||
CPU_BLOCK_END();
|
||||
else if (nmi && nmi_enable && nmi_mask)
|
||||
@@ -366,7 +368,7 @@ exec386_dynarec_int(void)
|
||||
}
|
||||
|
||||
block_ended:
|
||||
if (!cpu_state.abrt && trap) {
|
||||
if (!cpu_state.abrt && !new_ne && trap) {
|
||||
# ifdef USE_DEBUG_REGS_486
|
||||
//pclog("Debug trap 0x%X\n", trap);
|
||||
if (trap & 2) dr[6] |= 0x8000;
|
||||
@@ -602,6 +604,8 @@ exec386_dynarec_dyn(void)
|
||||
if (cpu_init)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (new_ne)
|
||||
CPU_BLOCK_END();
|
||||
if ((cpu_state.flags & T_FLAG) || (trap == 2))
|
||||
CPU_BLOCK_END();
|
||||
if (smi_line)
|
||||
@@ -626,7 +630,7 @@ exec386_dynarec_dyn(void)
|
||||
|
||||
cpu_end_block_after_ins = 0;
|
||||
|
||||
if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !x86_was_reset)
|
||||
if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !new_ne && !x86_was_reset)
|
||||
codegen_block_end_recompile(block);
|
||||
|
||||
if (x86_was_reset)
|
||||
@@ -702,6 +706,8 @@ exec386_dynarec_dyn(void)
|
||||
if (cpu_init)
|
||||
CPU_BLOCK_END();
|
||||
|
||||
if (new_ne)
|
||||
CPU_BLOCK_END();
|
||||
if (cpu_state.flags & T_FLAG)
|
||||
CPU_BLOCK_END();
|
||||
if (smi_line)
|
||||
@@ -726,7 +732,7 @@ exec386_dynarec_dyn(void)
|
||||
|
||||
cpu_end_block_after_ins = 0;
|
||||
|
||||
if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !x86_was_reset)
|
||||
if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !new_ne && !x86_was_reset)
|
||||
codegen_block_end();
|
||||
|
||||
if (x86_was_reset)
|
||||
@@ -809,6 +815,15 @@ exec386_dynarec(int32_t cycs)
|
||||
}
|
||||
}
|
||||
|
||||
if (new_ne) {
|
||||
# ifndef USE_NEW_DYNAREC
|
||||
oldcs = CS;
|
||||
# endif
|
||||
cpu_state.oldpc = cpu_state.pc;
|
||||
new_ne = 0;
|
||||
x86_int(16);
|
||||
}
|
||||
|
||||
if (smi_line)
|
||||
enter_smm_check(0);
|
||||
else if (nmi && nmi_enable && nmi_mask) {
|
||||
@@ -977,6 +992,15 @@ block_ended:
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else if (new_ne) {
|
||||
flags_rebuild();
|
||||
|
||||
new_ne = 0;
|
||||
#ifndef USE_NEW_DYNAREC
|
||||
oldcs = CS;
|
||||
#endif
|
||||
cpu_state.oldpc = cpu_state.pc;
|
||||
x86_int(16);
|
||||
} else if (trap) {
|
||||
flags_rebuild();
|
||||
#ifdef USE_DEBUG_REGS_486
|
||||
|
||||
@@ -814,6 +814,8 @@ extern int lock_legal_80[8];
|
||||
extern int lock_legal_f6[8];
|
||||
extern int lock_legal_fe[8];
|
||||
|
||||
extern int new_ne;
|
||||
|
||||
extern int in_lock;
|
||||
extern int cpu_override_interpreter;
|
||||
|
||||
|
||||
@@ -271,6 +271,7 @@ reset_common(int hard)
|
||||
stack32 = 0;
|
||||
msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21);
|
||||
msw = 0;
|
||||
new_ne = 0;
|
||||
if (hascache)
|
||||
cr0 = 1 << 30;
|
||||
else
|
||||
|
||||
@@ -99,8 +99,8 @@ opWAIT(uint32_t fetchdat)
|
||||
|
||||
if (fpu_softfloat) {
|
||||
if (fpu_state.swd & FPU_SW_Summary) {
|
||||
if (is486 && (cr0 & 0x20))
|
||||
x86_int(16);
|
||||
if (cr0 & 0x20)
|
||||
new_ne = 1;
|
||||
else
|
||||
picint(1 << 13);
|
||||
return 1;
|
||||
|
||||
@@ -99,7 +99,10 @@ opWAIT(uint32_t fetchdat)
|
||||
|
||||
if (fpu_softfloat) {
|
||||
if (fpu_state.swd & FPU_SW_Summary) {
|
||||
picint(1 << 13);
|
||||
if (cr0 & 0x20)
|
||||
new_ne = 1;
|
||||
else
|
||||
picint(1 << 13);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,10 +355,10 @@ FPU_exception(uint32_t fetchdat, uint16_t exceptions, int store)
|
||||
nmi = 1;
|
||||
}
|
||||
#else
|
||||
if (is486 && (cr0 & 0x20))
|
||||
x86_int(16);
|
||||
else
|
||||
picint(1 << 13);
|
||||
if (cr0 & 0x20)
|
||||
new_ne = 1;
|
||||
else
|
||||
picint(1 << 13);
|
||||
#endif // FPU_8087
|
||||
}
|
||||
return unmasked;
|
||||
|
||||
@@ -228,8 +228,8 @@ FPU_save_regi_tag(extFloat80_t reg, int tag, int stnr)
|
||||
#define FPU_check_pending_exceptions() \
|
||||
do { \
|
||||
if (fpu_state.swd & FPU_SW_Summary) { \
|
||||
if (is486 && (cr0 & 0x20)) \
|
||||
x86_int(16); \
|
||||
if (cr0 & 0x20) \
|
||||
new_ne = 1; \
|
||||
else \
|
||||
picint(1 << 13); \
|
||||
return 1; \
|
||||
|
||||
@@ -99,8 +99,8 @@ typedef union {
|
||||
dst = src1 / (double) src2; \
|
||||
else { \
|
||||
fpu_log("FPU : divide by zero\n"); \
|
||||
if (is486 && (cr0 & 0x20)) \
|
||||
x86_int(16); \
|
||||
if (cr0 & 0x20) \
|
||||
new_ne = 1; \
|
||||
else \
|
||||
picint(1 << 13); \
|
||||
return 1; \
|
||||
|
||||
@@ -121,6 +121,25 @@ typedef struct {
|
||||
isapnp_device_t *current_ld;
|
||||
} isapnp_t;
|
||||
|
||||
static isapnp_device_t *
|
||||
isapnp_create_ld(isapnp_card_t *card)
|
||||
{
|
||||
/* Allocate logical device. */
|
||||
isapnp_device_t *ld = calloc(1, sizeof(isapnp_device_t));
|
||||
|
||||
/* Add to the end of the card's logical device list. */
|
||||
isapnp_device_t *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;
|
||||
}
|
||||
|
||||
return ld;
|
||||
}
|
||||
|
||||
static void
|
||||
isapnp_device_config_changed(isapnp_card_t *card, isapnp_device_t *ld)
|
||||
{
|
||||
@@ -532,8 +551,12 @@ isapnp_write_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uin
|
||||
ld = ld->next;
|
||||
}
|
||||
|
||||
if (!ld)
|
||||
isapnp_log("ISAPnP: CSN %02X has no device %02X\n", card->csn, val);
|
||||
if (!ld) {
|
||||
isapnp_log("ISAPnP: CSN %02X has no device %02X, creating one\n", card->csn, val);
|
||||
dev->current_ld_card = card;
|
||||
dev->current_ld = isapnp_create_ld(card);
|
||||
dev->current_ld->number = val;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -763,8 +786,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size)
|
||||
uint8_t mem_range_df = 0;
|
||||
uint8_t mem_range_32_df = 0;
|
||||
uint32_t len;
|
||||
isapnp_device_t *ld = NULL;
|
||||
isapnp_device_t *prev_ld = NULL;
|
||||
isapnp_device_t *ld = NULL;
|
||||
|
||||
/* 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.
|
||||
@@ -912,18 +934,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size)
|
||||
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;
|
||||
}
|
||||
ld = isapnp_create_ld(card);
|
||||
}
|
||||
|
||||
/* Set and increment logical device number. */
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* Copyright 2008-2020 Sarah Walker.
|
||||
* Copyright 2018-2020 TheCollector1995.
|
||||
* Copyright 2021 RichardG.
|
||||
* Copyright 2021-2025 RichardG.
|
||||
*/
|
||||
|
||||
#ifndef SOUND_AD1848_H
|
||||
@@ -26,8 +26,10 @@ enum {
|
||||
AD1848_TYPE_DEFAULT = 0,
|
||||
AD1848_TYPE_CS4248 = 1,
|
||||
AD1848_TYPE_CS4231 = 2,
|
||||
AD1848_TYPE_CS4235 = 3,
|
||||
AD1848_TYPE_CS4236 = 4
|
||||
AD1848_TYPE_CS4232 = 3,
|
||||
AD1848_TYPE_CS4236 = 4,
|
||||
AD1848_TYPE_CS4236B = 5,
|
||||
AD1848_TYPE_CS4235 = 6
|
||||
};
|
||||
|
||||
typedef struct ad1848_t {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* Copyright 2008-2020 Sarah Walker.
|
||||
* Copyright 2018-2020 TheCollector1995.
|
||||
* Copyright 2021-2022 RichardG.
|
||||
* Copyright 2021-2025 RichardG.
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <86box/plat_fallthrough.h>
|
||||
|
||||
#define CS4231 0x80
|
||||
#define CS4232 0x02
|
||||
#define CS4236 0x03
|
||||
|
||||
static int ad1848_vols_7bits[128];
|
||||
@@ -57,10 +58,10 @@ ad1848_setdma(ad1848_t *ad1848, int newdma)
|
||||
void
|
||||
ad1848_updatevolmask(ad1848_t *ad1848)
|
||||
{
|
||||
if ((ad1848->type >= AD1848_TYPE_CS4235) && ((ad1848->xregs[4] & 0x10) || ad1848->wten))
|
||||
ad1848->wave_vol_mask = 0x3f;
|
||||
else
|
||||
if ((ad1848->type == AD1848_TYPE_CS4236B) && !(ad1848->xregs[4] & 0x10) && !ad1848->wten)
|
||||
ad1848->wave_vol_mask = 0x7f;
|
||||
else
|
||||
ad1848->wave_vol_mask = 0x3f;
|
||||
}
|
||||
|
||||
static double
|
||||
@@ -106,8 +107,8 @@ ad1848_updatefreq(ad1848_t *ad1848)
|
||||
{
|
||||
double freq;
|
||||
|
||||
if (ad1848->type >= AD1848_TYPE_CS4235) {
|
||||
if (ad1848->xregs[11] & 0x20) {
|
||||
if (ad1848->type >= AD1848_TYPE_CS4232) {
|
||||
if (ad1848->xregs[11] & 0x20) { /* CS4236B+ only */
|
||||
freq = 16934400.0;
|
||||
switch (ad1848->xregs[13]) {
|
||||
default:
|
||||
@@ -182,7 +183,7 @@ ad1848_read(uint16_t addr, void *priv)
|
||||
|
||||
case 18:
|
||||
case 19:
|
||||
if (ad1848->type >= AD1848_TYPE_CS4235) {
|
||||
if (ad1848->type >= AD1848_TYPE_CS4236B) {
|
||||
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->wten && !(ad1848->xregs[4] & 0x08)) /* wavetable remapping */
|
||||
@@ -192,13 +193,13 @@ ad1848_read(uint16_t addr, void *priv)
|
||||
|
||||
case 20:
|
||||
case 21:
|
||||
/* Backdoor to the Control/RAM registers on CS4235. */
|
||||
if ((ad1848->type == AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80))
|
||||
/* Backdoor to the Control/RAM registers on CS4235+. */
|
||||
if ((ad1848->type >= AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80))
|
||||
ret = ad1848->cram_read(ad1848->index - 15, ad1848->cram_priv);
|
||||
break;
|
||||
|
||||
case 23:
|
||||
if ((ad1848->type >= AD1848_TYPE_CS4235) && (ad1848->regs[23] & 0x08)) {
|
||||
if ((ad1848->type >= AD1848_TYPE_CS4236B) && (ad1848->regs[23] & 0x08)) {
|
||||
if ((ad1848->xindex & 0xfe) == 0x00) /* remapped line volume */
|
||||
ret = ad1848->regs[18 + ad1848->xindex];
|
||||
else
|
||||
@@ -235,7 +236,7 @@ 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? */
|
||||
if (ad1848->type >= AD1848_TYPE_CS4235)
|
||||
if (ad1848->type >= AD1848_TYPE_CS4236B)
|
||||
ad1848->regs[23] &= ~0x08; /* clear XRAE */
|
||||
ad1848->trd = val & 0x20;
|
||||
ad1848->mce = val & 0x40;
|
||||
@@ -244,7 +245,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv)
|
||||
case 1:
|
||||
switch (ad1848->index) {
|
||||
case 10:
|
||||
if (ad1848->type < AD1848_TYPE_CS4235)
|
||||
if (ad1848->type < AD1848_TYPE_CS4232)
|
||||
break;
|
||||
fallthrough;
|
||||
|
||||
@@ -282,13 +283,13 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv)
|
||||
|
||||
case 17:
|
||||
/* Enable additional data formats on modes 2 and 3 where supported. */
|
||||
if ((ad1848->type == AD1848_TYPE_CS4231) || (ad1848->type == AD1848_TYPE_CS4236))
|
||||
if ((ad1848->type == AD1848_TYPE_CS4231) || (ad1848->type == AD1848_TYPE_CS4236B))
|
||||
ad1848->fmt_mask = (val & 0x40) ? 0xf0 : 0x70;
|
||||
break;
|
||||
|
||||
case 18:
|
||||
case 19:
|
||||
if (ad1848->type >= AD1848_TYPE_CS4235) {
|
||||
if (ad1848->type >= AD1848_TYPE_CS4236B) {
|
||||
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;
|
||||
@@ -332,8 +333,8 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv)
|
||||
|
||||
case 20:
|
||||
case 21:
|
||||
/* Backdoor to the Control/RAM registers on CS4235. */
|
||||
if ((ad1848->type == AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80)) {
|
||||
/* Backdoor to the Control/RAM registers on CS4235+. */
|
||||
if ((ad1848->type >= AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80)) {
|
||||
ad1848->cram_write(ad1848->index - 15, val, ad1848->cram_priv);
|
||||
val = ad1848->regs[ad1848->index];
|
||||
}
|
||||
@@ -344,7 +345,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv)
|
||||
break;
|
||||
|
||||
case 23:
|
||||
if ((ad1848->type >= AD1848_TYPE_CS4235) && ((ad1848->regs[12] & 0x60) == 0x60)) {
|
||||
if ((ad1848->type >= AD1848_TYPE_CS4236B) && ((ad1848->regs[12] & 0x60) == 0x60)) {
|
||||
if (!(ad1848->regs[23] & 0x08)) { /* existing (not new) XRAE is clear */
|
||||
ad1848->xindex = ((val & 0x04) << 2) | (val >> 4);
|
||||
break;
|
||||
@@ -401,7 +402,11 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv)
|
||||
case 25:
|
||||
return;
|
||||
case 27:
|
||||
if (ad1848->type != AD1848_TYPE_DEFAULT)
|
||||
if ((ad1848->type != AD1848_TYPE_CS4232) && (ad1848->type != AD1848_TYPE_CS4236))
|
||||
return;
|
||||
break;
|
||||
case 29:
|
||||
if ((ad1848->type != AD1848_TYPE_CS4232) && (ad1848->type != AD1848_TYPE_CS4236))
|
||||
return;
|
||||
break;
|
||||
|
||||
@@ -456,17 +461,13 @@ ad1848_process_mulaw(uint8_t byte)
|
||||
{
|
||||
byte = ~byte;
|
||||
int temp = (((byte & 0x0f) << 3) + 0x84);
|
||||
int16_t dec;
|
||||
temp <<= ((byte & 0x70) >> 4);
|
||||
temp = (byte & 0x80) ? (0x84 - temp) : (temp - 0x84);
|
||||
if (temp > 32767)
|
||||
dec = 32767;
|
||||
return 32767;
|
||||
else if (temp < -32768)
|
||||
dec = -32768;
|
||||
else
|
||||
dec = (int16_t) temp;
|
||||
|
||||
return dec;
|
||||
return -32768;
|
||||
return (int16_t) temp;
|
||||
}
|
||||
|
||||
static int16_t
|
||||
@@ -489,8 +490,7 @@ ad1848_process_alaw(uint8_t byte)
|
||||
dec |= 0x108;
|
||||
break;
|
||||
}
|
||||
dec = (byte & 0x80) ? dec : -dec;
|
||||
return (int16_t) dec;
|
||||
return (int16_t) ((byte & 0x80) ? dec : -dec);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
@@ -704,10 +704,7 @@ ad1848_init(ad1848_t *ad1848, uint8_t 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) || (type >= AD1848_TYPE_CS4235))
|
||||
ad1848->regs[12] = 0x8a;
|
||||
else
|
||||
ad1848->regs[12] = 0xa;
|
||||
ad1848->regs[12] = (type >= AD1848_TYPE_CS4248) ? 0x8a : 0xa;
|
||||
ad1848->regs[13] = 0;
|
||||
ad1848->regs[14] = ad1848->regs[15] = 0;
|
||||
|
||||
@@ -719,27 +716,29 @@ ad1848_init(ad1848_t *ad1848, uint8_t type)
|
||||
ad1848->regs[25] = CS4231;
|
||||
ad1848->regs[26] = 0x80;
|
||||
ad1848->regs[29] = 0x80;
|
||||
} else if (type >= AD1848_TYPE_CS4235) {
|
||||
} else if (type >= AD1848_TYPE_CS4232) {
|
||||
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[25] = (type == AD1848_TYPE_CS4232) ? CS4232 : CS4236;
|
||||
ad1848->regs[26] = 0xa0;
|
||||
ad1848->regs[27] = ad1848->regs[29] = 0;
|
||||
ad1848->regs[30] = ad1848->regs[31] = 0;
|
||||
|
||||
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;
|
||||
if (type >= AD1848_TYPE_CS4236B) {
|
||||
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_updatefreq(ad1848);
|
||||
@@ -747,7 +746,7 @@ ad1848_init(ad1848_t *ad1848, uint8_t type)
|
||||
ad1848->out_l = ad1848->out_r = 0;
|
||||
ad1848->fm_vol_l = ad1848->fm_vol_r = 65536;
|
||||
ad1848_updatevolmask(ad1848);
|
||||
if (type == AD1848_TYPE_CS4235)
|
||||
if (type >= AD1848_TYPE_CS4235)
|
||||
ad1848->fmt_mask = 0x50;
|
||||
else
|
||||
ad1848->fmt_mask = 0x70;
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
* Copyright 2021-2022 RichardG.
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/dma.h>
|
||||
@@ -46,10 +47,19 @@
|
||||
#define CRYSTAL_NOEEPROM 0x100
|
||||
|
||||
enum {
|
||||
CRYSTAL_CS4235 = 0xdd,
|
||||
CRYSTAL_CS4236B = 0xcb,
|
||||
CRYSTAL_CS4232 = 0x32, /* no chip ID; dummy value */
|
||||
CRYSTAL_CS4236 = 0x36, /* no chip ID; dummy value */
|
||||
CRYSTAL_CS4236B = 0xab, /* report an older revision ID to make the values nice and incremental */
|
||||
CRYSTAL_CS4237B = 0xc8,
|
||||
CRYSTAL_CS4238B = 0xc9
|
||||
CRYSTAL_CS4238B = 0xc9,
|
||||
CRYSTAL_CS4235 = 0xdd,
|
||||
CRYSTAL_CS4239 = 0xde
|
||||
};
|
||||
enum {
|
||||
CRYSTAL_RAM_CMD = 0,
|
||||
CRYSTAL_RAM_ADDR_LO = 1,
|
||||
CRYSTAL_RAM_ADDR_HI = 2,
|
||||
CRYSTAL_RAM_DATA = 3
|
||||
};
|
||||
enum {
|
||||
CRYSTAL_SLAM_NONE = 0,
|
||||
@@ -58,15 +68,31 @@ enum {
|
||||
CRYSTAL_SLAM_BYTE2 = 3
|
||||
};
|
||||
|
||||
#ifdef ENABLE_CS423X_LOG
|
||||
int cs423x_do_log = ENABLE_CS423X_LOG;
|
||||
|
||||
static void
|
||||
cs423x_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (cs423x_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define cs423x_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
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 cs4236b_eeprom[8224] = {
|
||||
static const uint8_t cs4236b_default[] = {
|
||||
// clang-format off
|
||||
/* Chip configuration */
|
||||
0x55, 0xbb, /* magic */
|
||||
0x00, 0x00, /* length */
|
||||
0x00, 0x03, /* CD-ROM and modem decode */
|
||||
0x80, /* misc. config */
|
||||
0x80, /* global config */
|
||||
@@ -77,8 +103,8 @@ static const uint8_t cs4236b_eeprom[8224] = {
|
||||
0x75, 0xb9, 0xfc, /* IRQ routing */
|
||||
0x10, 0x03, /* DMA routing */
|
||||
|
||||
/* PnP resources */
|
||||
0x00
|
||||
/* Default PnP data */
|
||||
0x0e, 0x63, 0x42, 0x35, 0xff, 0xff, 0xff, 0xff, 0x00 /* hinted by documentation to be just the header */
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
@@ -97,6 +123,7 @@ typedef struct cs423x_t {
|
||||
uint16_t ram_addr;
|
||||
uint16_t eeprom_size : 11;
|
||||
uint16_t pnp_offset;
|
||||
uint16_t pnp_size;
|
||||
uint8_t type;
|
||||
uint8_t ad1848_type;
|
||||
uint8_t regs[8];
|
||||
@@ -119,6 +146,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, uint8_t update_hwconfig);
|
||||
static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv);
|
||||
static void cs423x_reset(void *priv);
|
||||
|
||||
static void
|
||||
cs423x_nvram(cs423x_t *dev, uint8_t save)
|
||||
@@ -130,6 +158,8 @@ cs423x_nvram(cs423x_t *dev, uint8_t save)
|
||||
else
|
||||
(void) !fread(dev->eeprom_data, sizeof(dev->eeprom_data), 1, fp);
|
||||
fclose(fp);
|
||||
} else {
|
||||
cs423x_log("CS423x: EEPROM data %s failed\n", save ? "save" : "load");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,17 +177,32 @@ cs423x_read(uint16_t addr, void *priv)
|
||||
ret |= 0x04;
|
||||
break;
|
||||
|
||||
case 4: /* Control Indirect Data Register */
|
||||
ret = dev->indirect_regs[dev->regs[3]];
|
||||
case 3: /* Control Indirect Access Register (CS4236B+) */
|
||||
/* Intel VS440FX BIOS tells CS4236 from CS4232 through the upper bits. Setting them is enough. */
|
||||
if (dev->type >= CRYSTAL_CS4236)
|
||||
ret |= 0xf0;
|
||||
break;
|
||||
|
||||
case 4: /* Control Indirect Data Register (CS4236B+) / Control Data Register (CS4236) */
|
||||
if (dev->type >= CRYSTAL_CS4236B)
|
||||
ret = dev->indirect_regs[dev->regs[3]];
|
||||
break;
|
||||
|
||||
case 5: /* Control/RAM Access */
|
||||
/* Reading RAM is undocumented; the Windows drivers do so. */
|
||||
if (dev->ram_dl == 3)
|
||||
ret = dev->ram_data[dev->ram_addr++];
|
||||
/* Reading RAM is undocumented, but performed by:
|
||||
- Windows drivers (unknown purpose)
|
||||
- Intel VS440FX BIOS (PnP ROM checksum recalculation) */
|
||||
if (dev->ram_dl == CRYSTAL_RAM_DATA) {
|
||||
ret = dev->ram_data[dev->ram_addr];
|
||||
cs423x_log("CS423x: RAM read(%04X) = %02X\n", dev->ram_addr, ret);
|
||||
dev->ram_addr++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: /* Global Status */
|
||||
case 7: /* Global Status (CS4236+) */
|
||||
if (dev->type < CRYSTAL_CS4236)
|
||||
break;
|
||||
|
||||
/* Context switching: take active context and interrupt flag, then clear interrupt flag. */
|
||||
ret &= 0xc0;
|
||||
dev->regs[7] &= 0x80;
|
||||
@@ -175,6 +220,8 @@ cs423x_read(uint16_t addr, void *priv)
|
||||
break;
|
||||
}
|
||||
|
||||
cs423x_log("CS423x: read(%X) = %02X\n", reg, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -182,53 +229,80 @@ static void
|
||||
cs423x_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
cs423x_t *dev = (cs423x_t *) priv;
|
||||
uint8_t reg = addr & 0x07;
|
||||
uint8_t reg = addr & 7;
|
||||
|
||||
cs423x_log("CS423x: write(%X, %02X)\n", reg, val);
|
||||
|
||||
switch (reg) {
|
||||
case 0: /* Joystick and Power Control */
|
||||
if (dev->type <= CRYSTAL_CS4232)
|
||||
val &= 0xeb;
|
||||
break;
|
||||
|
||||
case 1: /* EEPROM Interface */
|
||||
if (dev->type <= CRYSTAL_CS4232)
|
||||
val &= 0x37;
|
||||
if (val & 0x04)
|
||||
i2c_gpio_set(dev->i2c, val & 0x01, val & 0x02);
|
||||
break;
|
||||
|
||||
case 3: /* Control Indirect Access Register */
|
||||
case 2: /* Block Power Down (CS4236+) */
|
||||
if (dev->type < CRYSTAL_CS4236)
|
||||
return;
|
||||
break;
|
||||
|
||||
case 3: /* Control Indirect Access Register (CS4236B+) */
|
||||
if (dev->type < CRYSTAL_CS4236B)
|
||||
return;
|
||||
val &= 0x0f;
|
||||
break;
|
||||
|
||||
case 4: /* Control Indirect Data Register */
|
||||
case 4: /* Control Indirect Data Register (CS4236B+) / Control Data Register (CS4236) */
|
||||
if (dev->type < CRYSTAL_CS4236) {
|
||||
return;
|
||||
} else if (dev->type == CRYSTAL_CS4236) {
|
||||
val &= 0x40;
|
||||
break;
|
||||
}
|
||||
switch (dev->regs[3] & 0x0f) {
|
||||
case 0: /* WSS Master Control */
|
||||
if (val & 0x80)
|
||||
if ((dev->type < CRYSTAL_CS4235) && (val & 0x80))
|
||||
ad1848_init(&dev->ad1848, dev->ad1848_type);
|
||||
val = 0x00;
|
||||
break;
|
||||
|
||||
case 1: /* Version / Chip ID */
|
||||
case 7: /* Reserved */
|
||||
case 9 ... 15: /* unspecified */
|
||||
case 1: /* Version / Chip ID */
|
||||
case 7: /* Reserved */
|
||||
case 10 ... 15: /* unspecified */
|
||||
return;
|
||||
|
||||
case 2: /* 3D Space and {Center|Volume} */
|
||||
case 6: /* Upper Channel Status */
|
||||
case 2: /* 3D Space and {Center|Volume} (CS4237B+) */
|
||||
if (dev->type < CRYSTAL_CS4237B)
|
||||
return;
|
||||
break;
|
||||
|
||||
case 3: /* 3D Enable */
|
||||
case 3: /* 3D Enable (CS4237B+) */
|
||||
if (dev->type < CRYSTAL_CS4237B)
|
||||
return;
|
||||
val &= 0xe0;
|
||||
break;
|
||||
|
||||
case 4: /* Consumer Serial Port Enable */
|
||||
case 4: /* Consumer Serial Port Enable (CS423[78]B, unused on CS4235+) */
|
||||
if (dev->type < CRYSTAL_CS4237B)
|
||||
return;
|
||||
val &= 0xf0;
|
||||
break;
|
||||
|
||||
case 5: /* Lower Channel Status */
|
||||
case 5: /* Lower Channel Status (CS423[78]B, unused on CS4235+) */
|
||||
if (dev->type < CRYSTAL_CS4237B)
|
||||
return;
|
||||
if (dev->type < CRYSTAL_CS4235) /* bit 0 changed from reserved to unused on CS4235 */
|
||||
val &= 0xfe;
|
||||
break;
|
||||
|
||||
case 6: /* Upper Channel Status (CS423[78]B, unused on CS4235+) */
|
||||
if (dev->type < CRYSTAL_CS4237B)
|
||||
return;
|
||||
val &= 0xfe;
|
||||
break;
|
||||
|
||||
case 8: /* CS9236 Wavetable Control */
|
||||
@@ -240,6 +314,16 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv)
|
||||
ad1848_updatevolmask(&dev->ad1848);
|
||||
break;
|
||||
|
||||
case 9: /* Power Management (CS4235+) */
|
||||
if (dev->type < CRYSTAL_CS4235)
|
||||
return;
|
||||
if ((dev->indirect_regs[dev->regs[3]] & 0x80) && !(val & 0x80)) {
|
||||
cs423x_reset(dev);
|
||||
return;
|
||||
}
|
||||
val &= 0x83;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -248,7 +332,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv)
|
||||
|
||||
case 5: /* Control/RAM Access */
|
||||
switch (dev->ram_dl) {
|
||||
case 0: /* commands */
|
||||
case CRYSTAL_RAM_CMD: /* commands */
|
||||
switch (val) {
|
||||
case 0x55: /* Disable PnP Key */
|
||||
dev->pnp_enable = 0;
|
||||
@@ -266,7 +350,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv)
|
||||
break;
|
||||
|
||||
case 0xaa: /* Download RAM */
|
||||
dev->ram_dl = 1;
|
||||
dev->ram_dl = CRYSTAL_RAM_ADDR_LO;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -274,17 +358,19 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv)
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: /* low address byte */
|
||||
case CRYSTAL_RAM_ADDR_LO: /* low address byte */
|
||||
dev->ram_addr = val;
|
||||
dev->ram_dl++;
|
||||
dev->ram_dl = CRYSTAL_RAM_ADDR_HI;
|
||||
break;
|
||||
|
||||
case 2: /* high address byte */
|
||||
dev->ram_addr |= (val << 8);
|
||||
dev->ram_dl++;
|
||||
case CRYSTAL_RAM_ADDR_HI: /* high address byte */
|
||||
dev->ram_addr |= val << 8;
|
||||
dev->ram_dl = CRYSTAL_RAM_DATA;
|
||||
cs423x_log("CS423x: RAM start(%04X)\n", dev->ram_addr);
|
||||
break;
|
||||
|
||||
case 3: /* data */
|
||||
case CRYSTAL_RAM_DATA: /* data */
|
||||
cs423x_log("CS423x: RAM write(%04X, %02X)\n", dev->ram_addr, val);
|
||||
dev->ram_data[dev->ram_addr++] = val;
|
||||
break;
|
||||
|
||||
@@ -296,14 +382,16 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv)
|
||||
case 6: /* RAM Access End */
|
||||
/* TriGem Delhi-III BIOS writes undocumented value 0x40 instead of 0x00. */
|
||||
if ((val == 0x00) || (val == 0x40)) {
|
||||
dev->ram_dl = 0;
|
||||
cs423x_log("CS423x: RAM end\n");
|
||||
dev->ram_dl = CRYSTAL_RAM_CMD;
|
||||
|
||||
/* Update PnP state and resource data. */
|
||||
dev->pnp_size = 384; /* we don't know the length */
|
||||
cs423x_pnp_enable(dev, 1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: /* Global Status */
|
||||
case 7: /* Global Status (CS4236+) */
|
||||
return;
|
||||
|
||||
default:
|
||||
@@ -319,6 +407,9 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv)
|
||||
cs423x_t *dev = (cs423x_t *) priv;
|
||||
uint8_t idx;
|
||||
|
||||
if ((dev->slam_state != CRYSTAL_SLAM_NONE) || (val == slam_init_key[dev->key_pos])) /* cut down on ISAPnP-related noise */
|
||||
cs423x_log("CS423x: slam_write(%02X)\n", val);
|
||||
|
||||
switch (dev->slam_state) {
|
||||
case CRYSTAL_SLAM_NONE:
|
||||
/* Not in SLAM: read and compare Crystal key. */
|
||||
@@ -333,6 +424,7 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv)
|
||||
}
|
||||
|
||||
/* Enter SLAM. */
|
||||
cs423x_log("CS423x: SLAM unlocked\n");
|
||||
dev->slam_state = CRYSTAL_SLAM_INDEX;
|
||||
}
|
||||
} else {
|
||||
@@ -343,6 +435,8 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv)
|
||||
case CRYSTAL_SLAM_INDEX:
|
||||
/* Intercept the Activate Audio Device command. */
|
||||
if (val == 0x79) {
|
||||
cs423x_log("CS423x: Exiting SLAM\n");
|
||||
|
||||
/* Apply the last logical device's configuration. */
|
||||
if (dev->slam_config) {
|
||||
cs423x_pnp_config_changed(dev->slam_ld, dev->slam_config, dev);
|
||||
@@ -363,6 +457,7 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv)
|
||||
case CRYSTAL_SLAM_BYTE1:
|
||||
case CRYSTAL_SLAM_BYTE2:
|
||||
/* Write register value: two bytes for I/O ports, single byte otherwise. */
|
||||
cs423x_log("CS423x: SLAM write(%02X, %02X)\n", dev->slam_reg, val);
|
||||
switch (dev->slam_reg) {
|
||||
case 0x06: /* Card Select Number */
|
||||
isapnp_set_csn(dev->pnp_card, val);
|
||||
@@ -433,7 +528,7 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Prepare for the next register, unless a two-byte read returns above. */
|
||||
/* Prepare for the next register, unless a two-byte write returns above. */
|
||||
dev->slam_state = CRYSTAL_SLAM_INDEX;
|
||||
break;
|
||||
|
||||
@@ -454,8 +549,11 @@ cs423x_slam_enable(cs423x_t *dev, uint8_t enable)
|
||||
|
||||
/* Enable SLAM if the CKD bit is not set. */
|
||||
if (enable && !(dev->ram_data[0x4002] & 0x10)) {
|
||||
cs423x_log("CS423x: Enabling SLAM\n");
|
||||
dev->slam_enable = 1;
|
||||
io_sethandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev);
|
||||
} else {
|
||||
cs423x_log("CS423x: Disabling SLAM\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,6 +569,7 @@ cs423x_ctxswitch_write(uint16_t addr, UNUSED(uint8_t val), void *priv)
|
||||
/* Flip context bit. */
|
||||
dev->regs[7] ^= 0x80;
|
||||
ctx ^= 0x80;
|
||||
cs423x_log("CS423x: Context switch to %s\n", ctx ? "WSS" : "SBPro");
|
||||
|
||||
/* Update CD audio filter.
|
||||
FIXME: not thread-safe: filter function TOCTTOU in sound_cd_thread! */
|
||||
@@ -502,7 +601,7 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv)
|
||||
ad1848_update(&dev->ad1848);
|
||||
|
||||
/* Don't output anything if the analog section is powered down. */
|
||||
if (!(dev->indirect_regs[2] & 0xa4)) {
|
||||
if (!(dev->indirect_regs[2] & 0xa4) && !(dev->indirect_regs[9] & 0x04)) {
|
||||
for (int c = 0; c < len * 2; c += 2) {
|
||||
buffer[c] += dev->ad1848.buffer[c] / 2;
|
||||
buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2;
|
||||
@@ -515,35 +614,33 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv)
|
||||
static void
|
||||
cs423x_get_music_buffer(int32_t *buffer, int len, void *priv)
|
||||
{
|
||||
cs423x_t *dev = (cs423x_t *) priv;
|
||||
int opl_wss = dev->opl_wss;
|
||||
const int32_t *opl_buf = NULL;
|
||||
cs423x_t *dev = (cs423x_t *) priv;
|
||||
|
||||
/* Output audio from the WSS codec, and also the OPL if we're in charge of it. */
|
||||
if (opl_wss)
|
||||
opl_buf = dev->sb->opl.update(dev->sb->opl.priv);
|
||||
if (dev->opl_wss) {
|
||||
const int32_t *opl_buf = dev->sb->opl.update(dev->sb->opl.priv);
|
||||
|
||||
/* Don't output anything if the analog section is powered down. */
|
||||
if (!(dev->indirect_regs[2] & 0xa4)) {
|
||||
for (int c = 0; c < len * 2; c += 2) {
|
||||
if (opl_wss) {
|
||||
/* Don't output anything if the analog section or DAC2 (CS4235+) is powered down. */
|
||||
if (!(dev->indirect_regs[2] & 0xa4) && !(dev->indirect_regs[9] & 0x06)) {
|
||||
for (int c = 0; c < len * 2; c += 2) {
|
||||
buffer[c] += (opl_buf[c] * dev->ad1848.fm_vol_l) >> 16;
|
||||
buffer[c + 1] += (opl_buf[c + 1] * dev->ad1848.fm_vol_r) >> 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opl_wss)
|
||||
dev->sb->opl.reset_buffer(dev->sb->opl.priv);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig)
|
||||
{
|
||||
cs423x_log("CS423x: Updating PnP ROM=%d hwconfig=%d\n", update_rom, update_hwconfig);
|
||||
|
||||
if (dev->pnp_card) {
|
||||
/* Update PnP resource data if requested. */
|
||||
if (update_rom)
|
||||
isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], 384);
|
||||
isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], dev->pnp_size);
|
||||
|
||||
/* Disable PnP key if the PKD bit is set, or if it was disabled by command 0x55. */
|
||||
/* But wait! The TriGem Delhi-III BIOS sends command 0x55, and its behavior doesn't
|
||||
@@ -568,7 +665,7 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig)
|
||||
}
|
||||
|
||||
/* Update SPS. */
|
||||
if (dev->type != CRYSTAL_CS4235) {
|
||||
if ((dev->type >= CRYSTAL_CS4236B) && (dev->type <= CRYSTAL_CS4238B)) {
|
||||
if (dev->ram_data[0x4003] & 0x04)
|
||||
dev->indirect_regs[8] |= 0x04;
|
||||
else
|
||||
@@ -581,6 +678,14 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig)
|
||||
else
|
||||
dev->ad1848.xregs[4] &= ~0x10;
|
||||
|
||||
/* Update VCEN. */
|
||||
if (dev->type == CRYSTAL_CS4236) {
|
||||
if (dev->ram_data[0x4002] & 0x04)
|
||||
dev->regs[4] |= 0x40;
|
||||
else
|
||||
dev->regs[4] &= ~0x40;
|
||||
}
|
||||
|
||||
/* Inform WSS codec of the changes. */
|
||||
ad1848_updatevolmask(&dev->ad1848);
|
||||
}
|
||||
@@ -697,9 +802,21 @@ cs423x_reset(void *priv)
|
||||
/* Clear RAM. */
|
||||
memset(dev->ram_data, 0, sizeof(dev->ram_data));
|
||||
|
||||
/* Load default configuration data to RAM. */
|
||||
memcpy(&dev->ram_data[0x4000], cs4236b_default, sizeof(cs4236b_default));
|
||||
dev->pnp_size = 9;
|
||||
|
||||
if (dev->eeprom) {
|
||||
/* Load EEPROM data to RAM. */
|
||||
memcpy(&dev->ram_data[0x4000], &dev->eeprom_data[4], MIN(384, ((dev->eeprom_data[2] << 8) | dev->eeprom_data[3]) - 4));
|
||||
/* Load EEPROM data to RAM if the magic bytes are present. */
|
||||
if ((dev->eeprom_data[0] == 0x55) && (dev->eeprom_data[1] == 0xbb)) {
|
||||
cs423x_log("CS423x: EEPROM data valid, loading to RAM\n");
|
||||
dev->pnp_size = (dev->eeprom_data[2] << 8) | dev->eeprom_data[3];
|
||||
if (dev->pnp_size > 384)
|
||||
dev->pnp_size = 384;
|
||||
memcpy(&dev->ram_data[0x4000], &dev->eeprom_data[4], sizeof(dev->eeprom_data) - 4);
|
||||
} else {
|
||||
cs423x_log("CS423x: EEPROM data invalid, ignoring\n");
|
||||
}
|
||||
|
||||
/* Save EEPROM contents to file. */
|
||||
cs423x_nvram(dev, 1);
|
||||
@@ -734,6 +851,7 @@ cs423x_init(const device_t *info)
|
||||
|
||||
/* Initialize model-specific data. */
|
||||
dev->type = info->local & 0xff;
|
||||
cs423x_log("CS423x: init(%02X)\n", dev->type);
|
||||
switch (dev->type) {
|
||||
case CRYSTAL_CS4235:
|
||||
case CRYSTAL_CS4236B:
|
||||
@@ -743,30 +861,41 @@ cs423x_init(const device_t *info)
|
||||
dev->ad1848_type = (dev->type == CRYSTAL_CS4235) ? AD1848_TYPE_CS4235 : AD1848_TYPE_CS4236;
|
||||
dev->pnp_offset = 0x4013;
|
||||
|
||||
/* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init */
|
||||
/* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init. */
|
||||
dev->ad1848.xregs[25] = dev->type;
|
||||
|
||||
if (!(info->local & CRYSTAL_NOEEPROM)) {
|
||||
/* Load EEPROM contents from template. */
|
||||
memcpy(dev->eeprom_data, cs4236b_eeprom, sizeof(cs4236b_eeprom));
|
||||
/* Copy default configuration data. */
|
||||
memcpy(&dev->eeprom_data[4], cs4236b_default, sizeof(cs4236b_default));
|
||||
|
||||
/* Load PnP resource data ROM. */
|
||||
FILE *fp = rom_fopen(PNP_ROM_CS4236B, "rb");
|
||||
if (fp) {
|
||||
(void) !fread(&(dev->eeprom_data[23]), 1, 8201, fp);
|
||||
uint16_t eeprom_pnp_offset = (dev->pnp_offset & 0x1ff) + 4;
|
||||
/* This is wrong. The header field only indicates PnP resource data length, and real chips use
|
||||
it to locate the firmware patch area, but we don't need any of that, so we can get away
|
||||
with pretending the whole ROM is PnP data, at least until we can get full EEPROM dumps. */
|
||||
dev->pnp_size = fread(&dev->eeprom_data[eeprom_pnp_offset], 1, sizeof(dev->eeprom_data) - eeprom_pnp_offset, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/* Set content size. */
|
||||
dev->eeprom_data[2] = sizeof(cs4236b_eeprom) >> 8;
|
||||
dev->eeprom_data[3] = sizeof(cs4236b_eeprom) & 0xff;
|
||||
/* Populate EEPROM header if the PnP ROM was loaded. */
|
||||
if (dev->pnp_size) {
|
||||
dev->eeprom_data[0] = 0x55;
|
||||
dev->eeprom_data[1] = 0xbb;
|
||||
dev->eeprom_data[2] = dev->pnp_size >> 8;
|
||||
dev->eeprom_data[3] = dev->pnp_size;
|
||||
}
|
||||
|
||||
/* Set PnP card ID and EEPROM file name. */
|
||||
/* Patch PnP ROM and set EEPROM file name. */
|
||||
switch (dev->type) {
|
||||
case CRYSTAL_CS4235:
|
||||
dev->eeprom_data[8] = 0x05;
|
||||
dev->eeprom_data[16] = 0x08;
|
||||
dev->eeprom_data[26] = 0x25;
|
||||
dev->eeprom_data[44] = '5';
|
||||
if (dev->pnp_size) {
|
||||
dev->eeprom_data[8] = 0x05;
|
||||
dev->eeprom_data[16] = 0x08;
|
||||
dev->eeprom_data[26] = 0x25;
|
||||
dev->eeprom_data[44] = '5';
|
||||
}
|
||||
dev->nvr_path = "cs4235.nvr";
|
||||
break;
|
||||
|
||||
@@ -775,14 +904,18 @@ cs423x_init(const device_t *info)
|
||||
break;
|
||||
|
||||
case CRYSTAL_CS4237B:
|
||||
dev->eeprom_data[26] = 0x37;
|
||||
dev->eeprom_data[44] = '7';
|
||||
if (dev->pnp_size) {
|
||||
dev->eeprom_data[26] = 0x37;
|
||||
dev->eeprom_data[44] = '7';
|
||||
}
|
||||
dev->nvr_path = "cs4237b.nvr";
|
||||
break;
|
||||
|
||||
case CRYSTAL_CS4238B:
|
||||
dev->eeprom_data[26] = 0x38;
|
||||
dev->eeprom_data[44] = '8';
|
||||
if (dev->pnp_size) {
|
||||
dev->eeprom_data[26] = 0x38;
|
||||
dev->eeprom_data[44] = '8';
|
||||
}
|
||||
dev->nvr_path = "cs4238b.nvr";
|
||||
break;
|
||||
|
||||
@@ -794,9 +927,9 @@ cs423x_init(const device_t *info)
|
||||
cs423x_nvram(dev, 0);
|
||||
}
|
||||
|
||||
/* 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_CS4235) || (dev->type == CRYSTAL_CS4236B)) ? &gameport_pnp_device : &gameport_pnp_6io_device);
|
||||
/* Initialize game port. The game port on all B chips only
|
||||
responds to 6 I/O ports; the remaining 2 are reserved. */
|
||||
dev->gameport = gameport_add((dev->type == CRYSTAL_CS4235) ? &gameport_pnp_device : &gameport_pnp_6io_device);
|
||||
|
||||
break;
|
||||
|
||||
@@ -807,8 +940,8 @@ cs423x_init(const device_t *info)
|
||||
/* Initialize I2C bus for the EEPROM. */
|
||||
dev->i2c = i2c_gpio_init("nvr_cs423x");
|
||||
|
||||
/* Initialize I2C EEPROM if the contents are valid. */
|
||||
if ((dev->eeprom_data[0] == 0x55) && (dev->eeprom_data[1] == 0xbb))
|
||||
/* Initialize I2C EEPROM if enabled. */
|
||||
if (!(info->local & CRYSTAL_NOEEPROM))
|
||||
dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->eeprom_data, sizeof(dev->eeprom_data), 1);
|
||||
|
||||
/* Initialize ISAPnP. */
|
||||
@@ -836,6 +969,8 @@ cs423x_close(void *priv)
|
||||
{
|
||||
cs423x_t *dev = (cs423x_t *) priv;
|
||||
|
||||
cs423x_log("CS423x: close()\n");
|
||||
|
||||
/* Save EEPROM contents to file. */
|
||||
if (dev->eeprom) {
|
||||
cs423x_nvram(dev, 1);
|
||||
|
||||
Reference in New Issue
Block a user