summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine
diff options
context:
space:
mode:
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
commitb3e20002b716b75887214acc38c00b989942a633 (patch)
tree59d8464937c4cdcd88614fa5d4f35c4f03dd035f /src/devices/machine
parent4e74debb69abecb4f8f2b654040f56f768de9653 (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.cpp125
-rw-r--r--src/devices/machine/8364_paula.h7
-rw-r--r--src/devices/machine/amigafdc.cpp64
-rw-r--r--src/devices/machine/mos6526.cpp5
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;