diff options
author | Angelo Salese <angelosa@users.noreply.github.com> | 2021-10-20 03:28:43 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-19 21:28:43 -0400 |
commit | b3e20002b716b75887214acc38c00b989942a633 (patch) | |
tree | 59d8464937c4cdcd88614fa5d4f35c4f03dd035f /src/devices/machine | |
parent | 4e74debb69abecb4f8f2b654040f56f768de9653 (diff) |
First pass in improving Amiga SW compatibility (#8722)
* amiga.cpp: connect missing DSKINDEX signal from FDC to CIA-B ICR bit 4
* amigafdc.cpp: workaround live_counter > 8 to reset, makes abreed to boot to gameplay
* 8364_paula.cpp: fix output channel of irq delegation, and throw one when a DMA reaches the end of a stream. Fixes asparmgp/gpmaster BGMs at very least
* mos6526.cpp: guard against resetting IRQs when none is chained
* makes timer B polling reads to actually work in barb2paln4, fixing booting
* amigafdc.cpp: start adding logmacros
* amigafdc.cpp: fix DMAON readback, giving logica2 diag BIOS the chance to print extensive floppy test info
* 8364_paula.cpp: avoid reading audio DMA buffers outside the allocated ranges, fixes sound buzzing/aliasing bug
* alg.cpp: standardize title metadatas
* amigaocs_flop.xml: QA, consistent XML titles, consistent ids of virus plagued disks (additional field plus mark these as baddump)
* amigaocs_flop.xml: mark the failures on mount and bulk test with ATK
* 8364_paula.cpp: fix DMA reload behaviour (fixes BGMs in Ocean games), add live logging, misc
* amiga.cpp: ignore bit 0 with BPLxMOD writes, fixes hpoker/hpokera GFXs
* amigaocs_flop.xml: misc QA notes
Diffstat (limited to 'src/devices/machine')
-rw-r--r-- | src/devices/machine/8364_paula.cpp | 125 | ||||
-rw-r--r-- | src/devices/machine/8364_paula.h | 7 | ||||
-rw-r--r-- | src/devices/machine/amigafdc.cpp | 64 | ||||
-rw-r--r-- | src/devices/machine/mos6526.cpp | 5 |
4 files changed, 165 insertions, 36 deletions
diff --git a/src/devices/machine/8364_paula.cpp b/src/devices/machine/8364_paula.cpp index 6869ffb3395..83c4f033661 100644 --- a/src/devices/machine/8364_paula.cpp +++ b/src/devices/machine/8364_paula.cpp @@ -2,22 +2,36 @@ // copyright-holders: Aaron Giles, Dirk Best /*************************************************************************** - Commodore 8364 "Paula" + MOS Technology 8364 "Paula" + + TODO: + - Inherit FDC, serial and irq controller to here; + - Move Agnus "location" logic from here; + - low-pass filter; + - convert volume values to non-linear dB scale (cfr. ) + - Verify ADKCON modulation; + - Verify manual mode; + - When a DMA stop occurs, is the correlated channel playback stopped + at the end of the current cycle or as soon as possible like current + implementation? ***************************************************************************/ #include "emu.h" #include "8364_paula.h" +#define LIVE_AUDIO_VIEW 0 + //#define VERBOSE 1 #include "logmacro.h" +#include <cstring> //************************************************************************** // DEVICE DEFINITIONS //************************************************************************** -DEFINE_DEVICE_TYPE(PAULA_8364, paula_8364_device, "paula_8364", "8364 Paula") +DEFINE_DEVICE_TYPE(PAULA_8364, paula_8364_device, "paula_8364", "MOS 8364 \"Paula\"") //************************************************************************* @@ -51,9 +65,6 @@ void paula_8364_device::device_start() for (int i = 0; i < 4; i++) { m_channel[i].index = i; - m_channel[i].curticks = 0; - m_channel[i].manualmode = false; - m_channel[i].curlocation = 0; m_channel[i].irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(paula_8364_device::signal_irq), this)); } @@ -61,6 +72,24 @@ void paula_8364_device::device_start() m_stream = stream_alloc(0, 4, clock() / CLOCK_DIVIDER); } +void paula_8364_device::device_reset() +{ + m_dmacon = 0; + m_adkcon = 0; + for (auto &chan : m_channel) + { + chan.loc = 0; + chan.len = 0; + chan.per = 0; + chan.vol = 0; + chan.curticks = 0; + chan.manualmode = false; + chan.curlocation = 0; + chan.curlength = 0; + chan.dma_enabled = false; + } +} + //------------------------------------------------- // update - stream updater //------------------------------------------------- @@ -99,6 +128,18 @@ void paula_8364_device::reg_w(offs_t offset, uint16_t data) case REG_DMACON: m_stream->update(); m_dmacon = (data & 0x8000) ? (m_dmacon | (data & 0x021f)) : (m_dmacon & ~(data & 0x021f)); // only bits 15, 9 and 5 to 0 + // update the DMA latches on each channel and reload if fresh + // This holds true particularly for Ocean games (bchvolly, lostpatr, pang) and waylildr: + // they sets a DMA length for a channel then enable DMA then resets that length to 1 + // after a short delay loop. + for (int channum = 0; channum < 4; channum++) + { + audio_channel *chan = &m_channel[channum]; + if (!chan->dma_enabled && ((m_dmacon >> channum) & 1)) + dma_reload(chan, true); + + chan->dma_enabled = BIT(m_dmacon, channum); + } break; case REG_ADKCON: @@ -106,7 +147,7 @@ void paula_8364_device::reg_w(offs_t offset, uint16_t data) m_adkcon = (data & 0x8000) ? (m_adkcon | (data & 0x7fff)) : (m_adkcon & ~(data & 0x7fff)); break; - // to be moved + // FIXME: location belongs to Agnus case REG_AUD0LCL: m_channel[CHAN_0].loc = (m_channel[CHAN_0].loc & 0xffff0000) | ((data & 0xfffe) << 0); break; // 15-bit case REG_AUD0LCH: m_channel[CHAN_0].loc = (m_channel[CHAN_0].loc & 0x0000ffff) | ((data & 0x001f) << 16); break; // 3-bit on ocs, 5-bit ecs case REG_AUD1LCL: m_channel[CHAN_1].loc = (m_channel[CHAN_1].loc & 0xffff0000) | ((data & 0xfffe) << 0); break; // 15-bit @@ -119,19 +160,19 @@ void paula_8364_device::reg_w(offs_t offset, uint16_t data) // audio data case REG_AUD0LEN: m_channel[CHAN_0].len = data; break; case REG_AUD0PER: m_channel[CHAN_0].per = data; break; - case REG_AUD0VOL: m_channel[CHAN_0].vol = data; break; + case REG_AUD0VOL: m_channel[CHAN_0].vol = data & 0x7f; break; case REG_AUD0DAT: m_channel[CHAN_0].dat = data; m_channel[CHAN_0].manualmode = true; break; case REG_AUD1LEN: m_channel[CHAN_1].len = data; break; case REG_AUD1PER: m_channel[CHAN_1].per = data; break; - case REG_AUD1VOL: m_channel[CHAN_1].vol = data; break; + case REG_AUD1VOL: m_channel[CHAN_1].vol = data & 0x7f; break; case REG_AUD1DAT: m_channel[CHAN_1].dat = data; m_channel[CHAN_1].manualmode = true; break; case REG_AUD2LEN: m_channel[CHAN_2].len = data; break; case REG_AUD2PER: m_channel[CHAN_2].per = data; break; - case REG_AUD2VOL: m_channel[CHAN_2].vol = data; break; + case REG_AUD2VOL: m_channel[CHAN_2].vol = data & 0x7f; break; case REG_AUD2DAT: m_channel[CHAN_2].dat = data; m_channel[CHAN_2].manualmode = true; break; case REG_AUD3LEN: m_channel[CHAN_3].len = data; break; case REG_AUD3PER: m_channel[CHAN_3].per = data; break; - case REG_AUD3VOL: m_channel[CHAN_3].vol = data; break; + case REG_AUD3VOL: m_channel[CHAN_3].vol = data & 0x7f; break; case REG_AUD3DAT: m_channel[CHAN_3].dat = data; m_channel[CHAN_3].manualmode = true; break; } } @@ -142,20 +183,51 @@ void paula_8364_device::reg_w(offs_t offset, uint16_t data) TIMER_CALLBACK_MEMBER( paula_8364_device::signal_irq ) { - m_int_w(param); + m_int_w(param, 1); } //------------------------------------------------- // dma_reload //------------------------------------------------- -void paula_8364_device::dma_reload(audio_channel *chan) +void paula_8364_device::dma_reload(audio_channel *chan, bool startup) { chan->curlocation = chan->loc; + // TODO: how to treat length == 0? chan->curlength = chan->len; - chan->irq_timer->adjust(attotime::from_hz(15750), chan->index); // clock() / 227 + // TODO: on startup=false irq should be delayed two cycles + if (startup) + chan->irq_timer->adjust(attotime::from_hz(15750), chan->index); // clock() / 227 + else + signal_irq(nullptr, chan->index); - LOG("dma_reload(%d): offs=%05X len=%04X\n", chan->index, chan->curlocation, chan->curlength); + LOG("dma_reload(%d): offs=%06X len=%04X\n", chan->index, chan->curlocation, chan->curlength); +} + +std::string paula_8364_device::print_audio_state() +{ + std::ostringstream outbuffer; + + util::stream_format(outbuffer, "DMACON: %04x (%d) ADKCON %04x\n", m_dmacon, BIT(m_dmacon, 9), m_adkcon); + for (auto &chan : m_channel) + { + util::stream_format(outbuffer, "%d (%d) (%d%d) REGS: %06x %04x %03x %02x %d LIVE: %06x %04x %d\n" + , chan.index + , BIT(m_dmacon, chan.index) + , BIT(m_adkcon, chan.index+4) + , BIT(m_adkcon, chan.index) + , chan.loc + , chan.len + , chan.per + , chan.vol + , chan.manualmode + , chan.curlocation + , chan.curlength + , chan.dma_enabled + ); + } + + return outbuffer.str(); } //------------------------------------------------- @@ -182,15 +254,8 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, std::vector<re int samples = outputs[0].samples() * CLOCK_DIVIDER; - // update the DMA states on each channel and reload if fresh - for (channum = 0; channum < 4; channum++) - { - audio_channel *chan = &m_channel[channum]; - if (!chan->dma_enabled && ((m_dmacon >> channum) & 1)) - dma_reload(chan); - - chan->dma_enabled = BIT(m_dmacon, channum); - } + if (LIVE_AUDIO_VIEW) + popmessage(print_audio_state()); // loop until done while (samples > 0) @@ -219,6 +284,7 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, std::vector<re int i; // normalize the volume value + // FIXME: definitely not linear volume = (volume & 0x40) ? 64 : (volume & 0x3f); volume *= 4; @@ -268,9 +334,18 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, std::vector<re if (chan->curlength != 0) chan->curlength--; - // if we run out of data, reload the dma + // if we run out of data, reload the dma and signal an IRQ, + // gpmaster/asparmgp definitely expects this + // (uses channel 3 as a sequencer, changing the start address on the fly) if (chan->curlength == 0) - dma_reload(chan); + { + dma_reload(chan, false); + // reload the data pointer, otherwise aliasing / buzzing outside the given buffer will be heard + // For example: Xenon 2 sets up location=0x63298 length=0x20 + // for silencing channels on-the-fly without relying on irqs. + // Without this the location will read at 0x632d8 (data=0x7a7d), causing annoying buzzing. + chan->dat = m_mem_r(chan->curlocation); + } } // latch the next byte of the sample diff --git a/src/devices/machine/8364_paula.h b/src/devices/machine/8364_paula.h index 9fa7a6ebf38..0596cd6d4a1 100644 --- a/src/devices/machine/8364_paula.h +++ b/src/devices/machine/8364_paula.h @@ -66,6 +66,7 @@ public: protected: // device-level overrides virtual void device_start() override; + virtual void device_reset() override; // sound stream update overrides virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override; @@ -133,11 +134,11 @@ private: uint16_t dat; }; - void dma_reload(audio_channel *chan); + void dma_reload(audio_channel *chan, bool startup); // callbacks devcb_read16 m_mem_r; - devcb_write_line m_int_w; + devcb_write8 m_int_w; // internal state uint16_t m_dmacon; @@ -147,6 +148,8 @@ private: sound_stream *m_stream; TIMER_CALLBACK_MEMBER( signal_irq ); + + std::string print_audio_state(); }; // device type definition diff --git a/src/devices/machine/amigafdc.cpp b/src/devices/machine/amigafdc.cpp index 4452af43493..ad83a268039 100644 --- a/src/devices/machine/amigafdc.cpp +++ b/src/devices/machine/amigafdc.cpp @@ -12,6 +12,18 @@ #include "formats/ipf_dsk.h" #include "amigafdc.h" +#define LOG_WARN (1U << 1) // Show warnings +#define LOG_DMA (1U << 2) // Show DMA setups +#define LOG_SYNC (1U << 3) // Show sync block setups + +#define VERBOSE (LOG_WARN | LOG_DMA | LOG_SYNC) + +#include "logmacro.h" + +#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__) +#define LOGDMA(...) LOGMASKED(LOG_DMA, __VA_ARGS__) +#define LOGSYNC(...) LOGMASKED(LOG_SYNC, __VA_ARGS__) + DEFINE_DEVICE_TYPE(AMIGA_FDC, amiga_fdc_device, "amiga_fdc", "Amiga FDC") void amiga_fdc_device::floppy_formats(format_registration &fr) @@ -210,7 +222,12 @@ void amiga_fdc_device::live_run(const attotime &limit) } if(cur_live.bit_counter > 8) - fatalerror("amiga_fdc_device::live_run - cur_live.bit_counter > 8\n"); + { + // CHECKME: abreed, ghoulsvf Ghouls'n Goblins and lastnin2 at very least throws this + // is it a side effect of something else not happening at the right time or the assumption is right? + cur_live.bit_counter = 0; + LOGWARN("%s: live_run - cur_live.bit_counter > 8\n", machine().describe_context()); + } if(cur_live.bit_counter == 8) { live_delay(RUNNING_SYNCPOINT); @@ -233,7 +250,10 @@ void amiga_fdc_device::live_run(const attotime &limit) return; cur_live.bit_counter++; if(cur_live.bit_counter > 8) - fatalerror("amiga_fdc_device::live_run - cur_live.bit_counter > 8\n"); + { + cur_live.bit_counter = 0; + LOGWARN("%s: live_run - cur_live.bit_counter > 8\n", machine().describe_context()); + } if(cur_live.bit_counter == 8) { live_delay(RUNNING_SYNCPOINT); @@ -247,6 +267,14 @@ void amiga_fdc_device::live_run(const attotime &limit) if(!(dskbyt & 0x2000)) { if(cur_live.shift_reg == dsksync) { if(adkcon & 0x0400) { + // FIXME: exact dsksync behaviour + // - Some games currently writes two dsksync to the buffer (marked as "[FDC] dsksync"), + // removing one will make most of them happy. + // This is reported as 0-lower cylinder good and everything else as bad in the ATK suite; + // - Some games trashes memory, mostly the ones with "[FDC] dsksync bootblock": + // they attempt to load the tracks in AmigaDOS in the same way that's done by the + // Kickstart to check if the disk is bootable. + // This is reported as 0-upper cylinder bad in the ATK suite; if(dma_state == DMA_WAIT_START) { cur_live.bit_counter = 0; @@ -257,16 +285,22 @@ void amiga_fdc_device::live_run(const attotime &limit) cur_live.bit_counter = 0; dma_value = dma_read(); - } else + } else { + LOGSYNC("%s: DSKSYNC on %06x %d\n", this->tag(), dskpt, dma_state); dma_write(dsksync); + } } else if(dma_state != DMA_IDLE) { + LOGSYNC("%s: DSKSYNC on %06x %d\n", this->tag(), dskpt, dma_state); dma_write(dsksync); cur_live.bit_counter = 0; } else if(cur_live.bit_counter != 8) cur_live.bit_counter = 0; } + //else + // LOGSYNC("%s: no DSKSYNC\n", this->tag()); + dskbyt |= 0x1000; m_write_dsksyn(1); } else @@ -332,6 +366,11 @@ void amiga_fdc_device::dma_check() bool was_writing = dskbyt & 0x2000; dskbyt &= 0x9fff; if(dma_enabled()) { + LOGDMA("%s: DMA start dskpt=%08x dsklen=%04x dir=%s adkcon=%04x dsksync=%04x\n", + machine().describe_context(), + dskpt, dsklen & 0x3fff, BIT(dsklen, 14) ? "RAM->disk" : "disk->RAM", adkcon, dsksync + ); + if(dma_state == IDLE) { dma_state = adkcon & 0x0400 ? DMA_WAIT_START : DMA_RUNNING_BYTE_0; if(dma_state == DMA_RUNNING_BYTE_0) { @@ -344,7 +383,6 @@ void amiga_fdc_device::dma_check() } } } else { - dskbyt |= 0x4000; if(dsklen & 0x4000) dskbyt |= 0x2000; } @@ -355,7 +393,6 @@ void amiga_fdc_device::dma_check() cur_live.pll.stop_writing(floppy, cur_live.tm); if(!was_writing && (dskbyt & 0x2000)) cur_live.pll.start_writing(cur_live.tm); - } void amiga_fdc_device::adkcon_set(uint16_t data) @@ -409,6 +446,7 @@ uint16_t amiga_fdc_device::dskptl_r() void amiga_fdc_device::dsksync_w(uint16_t data) { live_sync(); + LOGSYNC("%s: DSKSYNC %04x\n", machine().describe_context(), data); dsksync = data; live_run(); } @@ -416,6 +454,7 @@ void amiga_fdc_device::dsksync_w(uint16_t data) void amiga_fdc_device::dmacon_set(uint16_t data) { live_sync(); + LOGDMA("%s: DMACON set DSKEN %d DMAEN %d (%04x)\n", machine().describe_context(), BIT(data, 4), BIT(data, 9), data); dmacon = data; dma_check(); live_run(); @@ -423,8 +462,15 @@ void amiga_fdc_device::dmacon_set(uint16_t data) uint16_t amiga_fdc_device::dskbytr_r() { - uint16_t res = dskbyt; - dskbyt &= 0x7fff; + uint16_t res = (dskbyt & ~0x4000); + // check if DMA is on + // logica2 diagnostic BIOS floppy test requires this + bool dmaon = (dma_state != DMA_IDLE) && ((dmacon & 0x0210) == 0x0210); + res |= dmaon << 14; + + // reset DSKBYT ready on read + if (!machine().side_effects_disabled()) + dskbyt &= 0x7fff; return res; } @@ -454,6 +500,7 @@ void amiga_fdc_device::ciaaprb_w(uint8_t data) live_sync(); + // FIXME: several sources claims that multiple drive selects is really possible if(!(data & 0x08)) floppy = floppy_devices[0]; else if(!(data & 0x10)) @@ -494,7 +541,8 @@ uint8_t amiga_fdc_device::ciaapra_r() { uint8_t ret = 0x3c; if(floppy) { - //if(!floppy->ready_r()) fixit: seems to not work well with multiple disk drives + // FIXME: seems to not work well with multiple disk drives + //if(!floppy->ready_r()) ret &= ~0x20; if(!floppy->trk00_r()) ret &= ~0x10; diff --git a/src/devices/machine/mos6526.cpp b/src/devices/machine/mos6526.cpp index e1f40b109c1..55368e33e86 100644 --- a/src/devices/machine/mos6526.cpp +++ b/src/devices/machine/mos6526.cpp @@ -902,7 +902,10 @@ uint8_t mos6526_device::read(offs_t offset) case ICR: data = (m_ir1 << 7) | m_icr; - if (machine().side_effects_disabled()) + // Do not reset irqs unless one is effectively issued. + // cfr. amigaocs_flop.xml barb2paln4 that polls for Timer B status + // until it expires at PC=7821c and other places. + if (machine().side_effects_disabled() || !m_icr) return data; m_icr_read = true; |