mirror of
https://github.com/holub/mame
synced 2025-06-06 04:43:45 +03:00
am9516: general improvements
This commit is contained in:
parent
a5af13e008
commit
c6e5d0c324
@ -16,13 +16,9 @@
|
||||
* - Personal Computer Products Data Book, © 1989 Advanced Micro Devices
|
||||
*
|
||||
* TODO:
|
||||
* - start after chaining
|
||||
* - software request
|
||||
* - single operation
|
||||
* - second interrupt handling
|
||||
* - search modes
|
||||
* - chain load abort
|
||||
* - wait states
|
||||
* - hardware masks
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
@ -32,10 +28,9 @@
|
||||
#define LOG_REGR (1U << 1)
|
||||
#define LOG_REGW (1U << 2)
|
||||
#define LOG_COMMAND (1U << 3)
|
||||
#define LOG_STATE (1U << 4)
|
||||
#define LOG_DMA (1U << 5)
|
||||
#define LOG_DMA (1U << 4)
|
||||
|
||||
//#define VERBOSE (LOG_GENERAL|LOG_REGR|LOG_REGW|LOG_COMMAND)
|
||||
//#define VERBOSE (LOG_GENERAL|LOG_REGR|LOG_REGW|LOG_COMMAND|LOG_DMA)
|
||||
#include "logmacro.h"
|
||||
|
||||
enum master_mode_mask : u8
|
||||
@ -84,12 +79,20 @@ enum status_mask : u16
|
||||
|
||||
enum cmh_mask : u16
|
||||
{
|
||||
CMH_MCF = 0x0003, // match control
|
||||
CMH_DACK = 0x0004, // dack control
|
||||
CMH_MASK = 0x0008, // hardware mask
|
||||
CMH_SRQ = 0x0010, // software request
|
||||
CMH_MC = 0x0003, // match control
|
||||
CMH_DC = 0x0004, // dack control
|
||||
CMH_HM = 0x0008, // hardware mask
|
||||
CMH_SR = 0x0010, // software request
|
||||
|
||||
CMH_WM = 0x001f,
|
||||
CMH_WM = 0x001f,
|
||||
};
|
||||
|
||||
enum cmh_mc_mask : u16
|
||||
{
|
||||
MC_00 = 0x0000, // stop on no match
|
||||
MC_01 = 0x0020, // stop on no match
|
||||
MC_10 = 0x0040, // stop on word match
|
||||
MC_11 = 0x0060, // stop on byte match
|
||||
};
|
||||
|
||||
enum cml_mask : u16
|
||||
@ -108,6 +111,14 @@ enum cml_mask : u16
|
||||
CML_CTC = 0x8000, // chain enable - terminal count
|
||||
};
|
||||
|
||||
enum cml_tt_mask : u16
|
||||
{
|
||||
TT_00 = 0x0000, // single transfer
|
||||
TT_01 = 0x0020, // demand dedicated bus hold
|
||||
TT_10 = 0x0040, // demand dedicated bus release
|
||||
TT_11 = 0x0060, // demand interleave
|
||||
};
|
||||
|
||||
enum aru_mask : u16
|
||||
{
|
||||
ARU_WC = 0x0006, // wait control
|
||||
@ -166,8 +177,7 @@ void am9516_device::device_start()
|
||||
save_item(NAME(m_eop_out_state));
|
||||
save_item(NAME(m_eop_in_state));
|
||||
|
||||
save_item(NAME(m_master_mode));
|
||||
save_item(NAME(m_chain_control));
|
||||
save_item(NAME(m_mode));
|
||||
save_item(NAME(m_pointer));
|
||||
save_item(NAME(m_temporary));
|
||||
|
||||
@ -200,17 +210,18 @@ void am9516_device::device_start()
|
||||
ch.flyby_byte_w.resolve_safe();
|
||||
ch.flyby_word_r.resolve_safe(0);
|
||||
ch.flyby_word_w.resolve_safe();
|
||||
|
||||
ch.run = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(am9516_device::operate), this));
|
||||
}
|
||||
|
||||
m_channel[0].is = 0;
|
||||
m_channel[1].is = IS_CHN;
|
||||
|
||||
m_channel[0].run = timer_alloc(timer_expired_delegate(FUNC(am9516_device::operate<0>), this));
|
||||
m_channel[1].run = timer_alloc(timer_expired_delegate(FUNC(am9516_device::operate<1>), this));
|
||||
}
|
||||
|
||||
void am9516_device::device_reset()
|
||||
{
|
||||
m_master_mode = 0;
|
||||
m_mode = 0;
|
||||
|
||||
for (channel &ch : m_channel)
|
||||
{
|
||||
@ -280,7 +291,7 @@ u16 am9516_device::data_r()
|
||||
case 0x34: return m_channel[1].boc;
|
||||
case 0x36: return m_channel[0].boc;
|
||||
// master mode
|
||||
case 0x38: return m_master_mode;
|
||||
case 0x38: return m_mode;
|
||||
// pattern
|
||||
case 0x48: return m_channel[1].pattern;
|
||||
case 0x4a: return m_channel[0].pattern;
|
||||
@ -297,7 +308,7 @@ u16 am9516_device::data_r()
|
||||
case 0x5a: return m_channel[0].iv;
|
||||
|
||||
default:
|
||||
LOG("data_r undefined register 0x%02 (%s)\n",
|
||||
LOG("undefined register 0x%02 (%s)\n",
|
||||
m_pointer, machine().describe_context());
|
||||
return 0;
|
||||
}
|
||||
@ -344,9 +355,9 @@ void am9516_device::data_w(u16 data)
|
||||
case 0x36: m_channel[0].boc = data; break;
|
||||
// master mode
|
||||
case 0x38:
|
||||
LOGMASKED(LOG_REGW, "data_w master mode 0x%04x (%s)\n",
|
||||
LOGMASKED(LOG_REGW, "master mode 0x%04x (%s)\n",
|
||||
data, machine().describe_context());
|
||||
m_master_mode = data & 0xf;
|
||||
m_mode = data & 0xf;
|
||||
return;
|
||||
// pattern
|
||||
case 0x48: m_channel[1].pattern = data; break;
|
||||
@ -355,14 +366,14 @@ void am9516_device::data_w(u16 data)
|
||||
case 0x4c: m_channel[1].mask = data; break;
|
||||
case 0x4e: m_channel[0].mask = data; break;
|
||||
// channel mode
|
||||
case 0x50: m_channel[1].cml = data; break;
|
||||
case 0x52: m_channel[0].cml = data; break;
|
||||
case 0x50: m_channel[1].cml = data; m_channel[1].log_mode(LOG_GENERAL); break;
|
||||
case 0x52: m_channel[0].cml = data; m_channel[0].log_mode(LOG_GENERAL); break;
|
||||
// interrupt vector
|
||||
case 0x58: m_channel[1].iv = data; break;
|
||||
case 0x5a: m_channel[0].iv = data; break;
|
||||
|
||||
default:
|
||||
LOG("data_w undefined register 0x%02 data 0x%04x (%s)\n",
|
||||
LOG("undefined register 0x%02 data 0x%04x (%s)\n",
|
||||
m_pointer, data, machine().describe_context());
|
||||
return;
|
||||
}
|
||||
@ -384,7 +395,7 @@ void am9516_device::data_w(u16 data)
|
||||
"interrupt vector", nullptr,
|
||||
};
|
||||
|
||||
LOGMASKED(LOG_REGW, "data_w channel %d %s 0x%04x (%s)\n",
|
||||
LOGMASKED(LOG_REGW, "channel %d %s 0x%04x (%s)\n",
|
||||
!(m_pointer & 2), reg_name[m_pointer >> 2], data, machine().describe_context());
|
||||
}
|
||||
}
|
||||
@ -426,9 +437,12 @@ void am9516_device::command(u8 data)
|
||||
BIT(data, 0), BIT(data, 1) ? "set" : "clear", machine().describe_context());
|
||||
|
||||
if (BIT(data, 1))
|
||||
ch.cmh |= CMH_SRQ;
|
||||
{
|
||||
ch.cmh |= CMH_SR;
|
||||
ch.run->adjust(attotime::zero);
|
||||
}
|
||||
else
|
||||
ch.cmh &= ~CMH_SRQ;
|
||||
ch.cmh &= ~CMH_SR;
|
||||
break;
|
||||
|
||||
case 0x60: // set/clear flip bit
|
||||
@ -446,16 +460,16 @@ void am9516_device::command(u8 data)
|
||||
BIT(data, 0), BIT(data, 1) ? "set" : "clear", machine().describe_context());
|
||||
|
||||
if (BIT(data, 1))
|
||||
ch.cmh |= CMH_MASK;
|
||||
ch.cmh |= CMH_HM;
|
||||
else
|
||||
ch.cmh &= ~CMH_MASK;
|
||||
ch.cmh &= ~CMH_HM;
|
||||
break;
|
||||
|
||||
case 0xa0: // start chain
|
||||
LOGMASKED(LOG_COMMAND, "channel %d start chain (%s)\n",
|
||||
BIT(data, 0), machine().describe_context());
|
||||
|
||||
chain(BIT(data, 0));
|
||||
ch.chain();
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -465,161 +479,23 @@ void am9516_device::command(u8 data)
|
||||
}
|
||||
}
|
||||
|
||||
void am9516_device::chain(unsigned const c)
|
||||
{
|
||||
channel &ch = m_channel[c];
|
||||
address_space &s(space(SYSTEM_MEM));
|
||||
|
||||
// TODO: abort on EOP
|
||||
|
||||
// fetch reload word
|
||||
u32 chain_address = ch.address(ch.cau, ch.cal);
|
||||
m_chain_control = s.read_word(chain_address) & CC_WM;
|
||||
LOGMASKED(LOG_REGW, "chain address 0x%06x reload word 0x%04x\n", chain_address, m_chain_control);
|
||||
chain_address += 2;
|
||||
|
||||
// current address a
|
||||
if (m_chain_control & CC_CAA)
|
||||
{
|
||||
ch.caau = s.read_word(chain_address + 0) & ARU_WM;
|
||||
ch.caal = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "current address a 0x%04x 0x%04x\n", ch.caau, ch.caal);
|
||||
|
||||
m_chain_control &= ~CC_CAA;
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// current address b
|
||||
if (m_chain_control & CC_CAB)
|
||||
{
|
||||
ch.cabu = s.read_word(chain_address + 0) & ARU_WM;
|
||||
ch.cabl = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "current address b 0x%04x 0x%04x\n", ch.cabu, ch.cabl);
|
||||
|
||||
m_chain_control &= ~CC_CAB;
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// current operation count
|
||||
if (m_chain_control & CC_COC)
|
||||
{
|
||||
ch.coc = s.read_word(chain_address);
|
||||
|
||||
LOGMASKED(LOG_REGW, "current operation count 0x%04x\n", ch.coc);
|
||||
|
||||
m_chain_control &= ~CC_COC;
|
||||
chain_address += 2;
|
||||
}
|
||||
|
||||
// base address a
|
||||
if (m_chain_control & CC_BAA)
|
||||
{
|
||||
ch.baau = s.read_word(chain_address + 0) & ARU_WM;
|
||||
ch.baal = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "base address a 0x%04x 0x%04x\n", ch.baau, ch.baal);
|
||||
|
||||
m_chain_control &= ~CC_BAA;
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// base address b
|
||||
if (m_chain_control & CC_BAB)
|
||||
{
|
||||
ch.babu = s.read_word(chain_address + 0) & ARU_WM;
|
||||
ch.babl = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "base address b 0x%04x 0x%04x\n", ch.babu, ch.babl);
|
||||
|
||||
m_chain_control &= ~CC_BAB;
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// base operation count
|
||||
if (m_chain_control & CC_BOC)
|
||||
{
|
||||
ch.boc = s.read_word(chain_address);
|
||||
|
||||
LOGMASKED(LOG_REGW, "base operation count 0x%04x\n", ch.boc);
|
||||
|
||||
m_chain_control &= ~CC_BOC;
|
||||
chain_address += 2;
|
||||
}
|
||||
|
||||
// pattern and mask
|
||||
if (m_chain_control & CC_PM)
|
||||
{
|
||||
ch.pattern = s.read_word(chain_address + 0);
|
||||
ch.mask = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "pattern 0x%04x mask %04x\n", ch.pattern, ch.mask);
|
||||
|
||||
m_chain_control &= ~CC_PM;
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// interrupt vector
|
||||
if (m_chain_control & CC_IV)
|
||||
{
|
||||
ch.iv = s.read_word(chain_address);
|
||||
|
||||
LOGMASKED(LOG_REGW, "interrupt vector 0x%04x\n", ch.iv);
|
||||
|
||||
m_chain_control &= ~CC_IV;
|
||||
chain_address += 2;
|
||||
}
|
||||
|
||||
// channel mode
|
||||
if (m_chain_control & CC_CM)
|
||||
{
|
||||
ch.cmh = s.read_word(chain_address + 0) & CMH_WM;
|
||||
ch.cml = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "channel mode 0x%04x %04x\n", ch.cmh, ch.cml);
|
||||
|
||||
m_chain_control &= ~CC_CM;
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// chain address
|
||||
if (m_chain_control & CC_CA)
|
||||
{
|
||||
ch.cau = s.read_word(chain_address + 0) & (ARU_UA | ARU_WC);
|
||||
ch.cal = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "chain address 0x%04x %04x\n", ch.cau, ch.cal);
|
||||
|
||||
m_chain_control &= ~CC_CA;
|
||||
chain_address += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// update chain address register
|
||||
ch.cau = ((chain_address >> 8) & ARU_UA) | u8(ch.cau);
|
||||
ch.cal = u16(chain_address);
|
||||
}
|
||||
|
||||
ch.status &= ~(S_CA | S_NAC);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(am9516_device::eop_w)
|
||||
{
|
||||
LOGMASKED(LOG_DMA, "eop %s\n", state ? "cleared" : "asserted");
|
||||
m_eop_in_state = !state;
|
||||
}
|
||||
|
||||
template <unsigned Channel> WRITE_LINE_MEMBER(am9516_device::dreq_w)
|
||||
{
|
||||
LOGMASKED(LOG_DMA, "dreq_w<%d> %d\n", Channel, state);
|
||||
LOGMASKED(LOG_DMA, "channel %d dreq %s\n", Channel, state ? "cleared" : "asserted");
|
||||
channel &ch = m_channel[Channel];
|
||||
|
||||
if (!state)
|
||||
{
|
||||
ch.status |= S_HRQ;
|
||||
|
||||
if (!(ch.status & S_HM))
|
||||
ch.run->adjust(attotime::zero, Channel);
|
||||
if (!(ch.status & S_HM) && ch.run->expire().is_never())
|
||||
ch.run->adjust(attotime::zero);
|
||||
}
|
||||
else
|
||||
ch.status &= ~S_HRQ;
|
||||
@ -628,70 +504,89 @@ template <unsigned Channel> WRITE_LINE_MEMBER(am9516_device::dreq_w)
|
||||
template void am9516_device::dreq_w<0>(int state);
|
||||
template void am9516_device::dreq_w<1>(int state);
|
||||
|
||||
void am9516_device::operate(s32 param)
|
||||
template <unsigned Channel> void am9516_device::operate(s32 param)
|
||||
{
|
||||
channel &ch = m_channel[param];
|
||||
channel &ch = m_channel[Channel];
|
||||
|
||||
if (!(m_mode & MM0) || (ch.status & S_SIP))
|
||||
{
|
||||
LOGMASKED(LOG_DMA, "channel %d bus access disabled\n", Channel);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(ch.status & S_HRQ) && !(ch.cmh & CMH_SR))
|
||||
{
|
||||
LOGMASKED(LOG_DMA, "channel %d no request pending\n", Channel);
|
||||
return;
|
||||
}
|
||||
|
||||
u16 status = 0;
|
||||
unsigned cycles = 0;
|
||||
|
||||
switch (ch.cml & CML_OPER)
|
||||
{
|
||||
// transfer
|
||||
case 0x1:
|
||||
// byte/byte flowthru
|
||||
m_temporary = ch.read_byte(ch.cml & CML_FLIP);
|
||||
ch.write_byte(u8(m_temporary), ch.cml & CML_FLIP);
|
||||
cycles = 6;
|
||||
m_temporary = ch.read_byte(cycles, ch.cml & CML_FLIP);
|
||||
ch.write_byte(u8(m_temporary), cycles, ch.cml & CML_FLIP);
|
||||
|
||||
ch.coc--;
|
||||
break;
|
||||
case 0x8:
|
||||
case 0x9:
|
||||
cycles = 9;
|
||||
if (ch.cml & CML_FLIP)
|
||||
{
|
||||
// word/byte flowthru
|
||||
m_temporary = ch.read_word(ch.cml & CML_FLIP);
|
||||
m_temporary = ch.read_word(cycles, ch.cml & CML_FLIP);
|
||||
|
||||
unsigned const shift = ch.cabu & AC_DEC;
|
||||
ch.write_byte(u8(m_temporary >> (8 - shift)), ch.cml & CML_FLIP);
|
||||
ch.write_byte(u8(m_temporary >> shift), ch.cml & CML_FLIP);
|
||||
ch.write_byte(u8(m_temporary >> (8 - shift)), cycles, ch.cml & CML_FLIP);
|
||||
ch.write_byte(u8(m_temporary >> shift), cycles, ch.cml & CML_FLIP);
|
||||
}
|
||||
else
|
||||
{
|
||||
// byte/word flowthru
|
||||
unsigned const shift = ch.cabu & AC_DEC;
|
||||
m_temporary = u16(ch.read_byte(ch.cml & CML_FLIP)) << (8 - shift);
|
||||
m_temporary |= u16(ch.read_byte(ch.cml & CML_FLIP)) << shift;
|
||||
m_temporary = u16(ch.read_byte(cycles, ch.cml & CML_FLIP)) << (8 - shift);
|
||||
m_temporary |= u16(ch.read_byte(cycles, ch.cml & CML_FLIP)) << shift;
|
||||
|
||||
ch.write_word(m_temporary, ch.cml & CML_FLIP);
|
||||
ch.write_word(m_temporary, cycles, ch.cml & CML_FLIP);
|
||||
}
|
||||
|
||||
ch.coc--;
|
||||
break;
|
||||
case 0x0:
|
||||
// word/word flowthru
|
||||
m_temporary = ch.read_word(ch.cml & CML_FLIP);
|
||||
ch.write_word(m_temporary, ch.cml & CML_FLIP);
|
||||
cycles = 6;
|
||||
m_temporary = ch.read_word(cycles, ch.cml & CML_FLIP);
|
||||
ch.write_word(m_temporary, cycles, ch.cml & CML_FLIP);
|
||||
|
||||
ch.coc--;
|
||||
break;
|
||||
case 0x3:
|
||||
// byte/byte flyby
|
||||
cycles = 3;
|
||||
if (ch.cml & CML_FLIP)
|
||||
// from flyby to arb
|
||||
ch.write_byte(ch.flyby_byte_r());
|
||||
ch.write_byte(ch.flyby_byte_r(), cycles);
|
||||
else
|
||||
// from ara to flyby
|
||||
ch.flyby_byte_w(ch.read_byte());
|
||||
ch.flyby_byte_w(ch.read_byte(cycles));
|
||||
|
||||
ch.coc--;
|
||||
break;
|
||||
case 0x2:
|
||||
// word/word flyby
|
||||
cycles = 3;
|
||||
if (ch.cml & CML_FLIP)
|
||||
// from flyby to arb
|
||||
ch.write_word(ch.flyby_word_r());
|
||||
ch.write_word(ch.flyby_word_r(), cycles);
|
||||
else
|
||||
// from ara to flyby
|
||||
ch.flyby_word_w(ch.read_word());
|
||||
ch.flyby_word_w(ch.read_word(cycles));
|
||||
|
||||
ch.coc--;
|
||||
break;
|
||||
@ -737,6 +632,8 @@ void am9516_device::operate(s32 param)
|
||||
|
||||
if (status & (S_MC | S_EOP | S_TC))
|
||||
complete(param, status);
|
||||
else if (ch.cml & CML_TT)
|
||||
ch.run->adjust(attotime::from_ticks(cycles, clock()));
|
||||
}
|
||||
|
||||
void am9516_device::complete(unsigned const c, u16 status)
|
||||
@ -746,6 +643,8 @@ void am9516_device::complete(unsigned const c, u16 status)
|
||||
ch.status &= ~(S_MCH | S_MCL | S_MC | S_EOP | S_TC);
|
||||
ch.status |= status | S_NAC;
|
||||
|
||||
LOGMASKED(LOG_DMA, "channel %d complete status 0x%04x\n", c, ch.status);
|
||||
|
||||
m_eop(0);
|
||||
m_eop(1);
|
||||
|
||||
@ -754,38 +653,13 @@ void am9516_device::complete(unsigned const c, u16 status)
|
||||
|| ((ch.status & S_EOP) && (ch.cml & CML_IEOP))
|
||||
|| ((ch.status & S_MC) && (ch.cml & CML_IMC)))
|
||||
{
|
||||
LOG("completion interrupt channel %d\n", c);
|
||||
ch.interrupt(true);
|
||||
|
||||
interrupt();
|
||||
}
|
||||
|
||||
// FIXME: depending on bus mode and interrupt state, reloading
|
||||
// may be delayed until interrupt is acknowledged
|
||||
|
||||
// reload base to current
|
||||
if (((ch.status & S_TC) && (ch.cml & CML_RTC))
|
||||
|| ((ch.status & S_EOP) && (ch.cml & CML_REOP))
|
||||
|| ((ch.status & S_MC) && (ch.cml & CML_RMC)))
|
||||
{
|
||||
LOG("reload base to current channel %d\n", c);
|
||||
ch.caau = ch.baau;
|
||||
ch.caal = ch.baal;
|
||||
ch.cabu = ch.babu;
|
||||
ch.cabl = ch.babl;
|
||||
ch.coc = ch.boc;
|
||||
|
||||
ch.status &= ~S_NAC;
|
||||
}
|
||||
|
||||
// reload chain
|
||||
if (((ch.status & S_TC) && (ch.cml & CML_CTC))
|
||||
|| ((ch.status & S_EOP) && (ch.cml & CML_CEOP))
|
||||
|| ((ch.status & S_MC) && (ch.cml & CML_CMC)))
|
||||
{
|
||||
LOG("reload chain channel %d\n", c);
|
||||
chain(c);
|
||||
}
|
||||
if (!(ch.status & S_SIP))
|
||||
ch.reload();
|
||||
}
|
||||
|
||||
void am9516_device::interrupt()
|
||||
@ -796,6 +670,7 @@ void am9516_device::interrupt()
|
||||
|
||||
if (m_int_state != int_state)
|
||||
{
|
||||
LOG("interrupt %s\n", int_state ? "asserted" : "cleared");
|
||||
m_int_state = int_state;
|
||||
m_int(!m_int_state);
|
||||
}
|
||||
@ -807,7 +682,7 @@ u16 am9516_device::acknowledge()
|
||||
{
|
||||
if ((ch.status & S_CIE) && (ch.status & S_IP))
|
||||
{
|
||||
u16 const data = (m_master_mode & MM3) ? 0 : ch.is;
|
||||
u16 const data = (m_mode & MM3) ? 0 : ch.is;
|
||||
|
||||
ch.interrupt(false);
|
||||
interrupt();
|
||||
@ -819,6 +694,9 @@ u16 am9516_device::acknowledge()
|
||||
fatalerror("%s: interrupt acknowledge with no pending interrupts\n", tag());
|
||||
}
|
||||
|
||||
#undef LOG_OUTPUT_FUNC
|
||||
#define LOG_OUTPUT_FUNC udc.logerror
|
||||
|
||||
u32 am9516_device::channel::address(u16 &aru, u16 &arl, int delta)
|
||||
{
|
||||
u32 const current = u32(aru & ARU_UA) << 8 | arl;
|
||||
@ -840,35 +718,43 @@ u32 am9516_device::channel::address(u16 &aru, u16 &arl, int delta)
|
||||
return current;
|
||||
}
|
||||
|
||||
u8 am9516_device::channel::read_byte(bool flip)
|
||||
u8 am9516_device::channel::read_byte(unsigned &cycles, bool flip)
|
||||
{
|
||||
u16 &cau = flip ? cabu : caau;
|
||||
u16 &cal = flip ? cabl : caal;
|
||||
|
||||
cycles += wait_states[BIT(cau, 1, 2)];
|
||||
|
||||
return udc.space((cau & ARU_AR) >> 6).read_byte(address(cau, cal, 1));
|
||||
}
|
||||
|
||||
void am9516_device::channel::write_byte(u8 data, bool flip)
|
||||
void am9516_device::channel::write_byte(u8 data, unsigned &cycles, bool flip)
|
||||
{
|
||||
u16 &cau = flip ? caau : cabu;
|
||||
u16 &cal = flip ? caal : cabl;
|
||||
|
||||
cycles += wait_states[BIT(cau, 1, 2)];
|
||||
|
||||
udc.space((cau & ARU_AR) >> 6).write_byte(address(cau, cal, 1), data);
|
||||
}
|
||||
|
||||
u16 am9516_device::channel::read_word(bool flip)
|
||||
u16 am9516_device::channel::read_word(unsigned &cycles, bool flip)
|
||||
{
|
||||
u16 &cau = flip ? cabu : caau;
|
||||
u16 &cal = flip ? cabl : caal;
|
||||
|
||||
cycles += wait_states[BIT(cau, 1, 2)];
|
||||
|
||||
return udc.space((cau & ARU_AR) >> 6).read_word(address(cau, cal, 2));
|
||||
}
|
||||
|
||||
void am9516_device::channel::write_word(u16 data, bool flip)
|
||||
void am9516_device::channel::write_word(u16 data, unsigned &cycles, bool flip)
|
||||
{
|
||||
u16 &cau = flip ? caau : cabu;
|
||||
u16 &cal = flip ? caal : cabl;
|
||||
|
||||
cycles += wait_states[BIT(cau, 1, 2)];
|
||||
|
||||
udc.space((cau & ARU_AR) >> 6).write_word(address(cau, cal, 2), data);
|
||||
}
|
||||
|
||||
@ -876,6 +762,7 @@ void am9516_device::channel::interrupt(bool assert)
|
||||
{
|
||||
if (assert && (status & S_IP))
|
||||
{
|
||||
LOG("second interrupt pending\n");
|
||||
status |= S_SIP;
|
||||
return;
|
||||
}
|
||||
@ -886,7 +773,12 @@ void am9516_device::channel::interrupt(bool assert)
|
||||
is &= IS_CHN;
|
||||
|
||||
if (status & S_SIP)
|
||||
{
|
||||
LOG("second interrupt cleared\n");
|
||||
status &= ~S_SIP;
|
||||
|
||||
reload();
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
@ -894,3 +786,232 @@ void am9516_device::channel::interrupt(bool assert)
|
||||
status |= S_IP;
|
||||
is |= bitswap<u16>(status, 5, 4, 3, 12, 2, 1, 0) << 9 | iv;
|
||||
}
|
||||
|
||||
void am9516_device::channel::reload()
|
||||
{
|
||||
// reload base to current
|
||||
if (((status & S_TC) && (cml & CML_RTC))
|
||||
|| ((status & S_EOP) && (cml & CML_REOP))
|
||||
|| ((status & S_MC) && (cml & CML_RMC)))
|
||||
{
|
||||
LOGMASKED(LOG_DMA, "reload base to current\n");
|
||||
caau = baau;
|
||||
caal = baal;
|
||||
cabu = babu;
|
||||
cabl = babl;
|
||||
coc = boc;
|
||||
|
||||
log_addr(LOG_DMA, "current address a", caau, caal);
|
||||
log_addr(LOG_DMA, "current address b", cabu, cabl);
|
||||
LOGMASKED(LOG_DMA, "current operation count 0x%04x\n", coc);
|
||||
|
||||
status &= ~S_NAC;
|
||||
}
|
||||
|
||||
// reload chain
|
||||
if (((status & S_TC) && (cml & CML_CTC))
|
||||
|| ((status & S_EOP) && (cml & CML_CEOP))
|
||||
|| ((status & S_MC) && (cml & CML_CMC)))
|
||||
{
|
||||
LOGMASKED(LOG_DMA, "reload chain\n");
|
||||
chain();
|
||||
}
|
||||
}
|
||||
|
||||
void am9516_device::channel::chain()
|
||||
{
|
||||
address_space &s(udc.space(SYSTEM_MEM));
|
||||
|
||||
// TODO: abort on EOP
|
||||
|
||||
// fetch reload word
|
||||
u32 chain_address = address(cau, cal);
|
||||
u16 reload = s.read_word(chain_address) & CC_WM;
|
||||
LOGMASKED(LOG_REGW, "chain address 0x%06x reload word 0x%04x\n", chain_address, reload);
|
||||
chain_address += 2;
|
||||
|
||||
// current address a
|
||||
if (reload & CC_CAA)
|
||||
{
|
||||
caau = s.read_word(chain_address + 0) & ARU_WM;
|
||||
caal = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "current address a 0x%04x 0x%04x\n", caau, caal);
|
||||
log_addr(LOG_DMA, "current address a", caau, caal);
|
||||
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// current address b
|
||||
if (reload & CC_CAB)
|
||||
{
|
||||
cabu = s.read_word(chain_address + 0) & ARU_WM;
|
||||
cabl = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "current address b 0x%04x 0x%04x\n", cabu, cabl);
|
||||
log_addr(LOG_DMA, "current address b", cabu, cabl);
|
||||
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// current operation count
|
||||
if (reload & CC_COC)
|
||||
{
|
||||
coc = s.read_word(chain_address);
|
||||
|
||||
LOGMASKED(LOG_DMA, "current operation count 0x%04x\n", coc);
|
||||
|
||||
chain_address += 2;
|
||||
}
|
||||
|
||||
// base address a
|
||||
if (reload & CC_BAA)
|
||||
{
|
||||
baau = s.read_word(chain_address + 0) & ARU_WM;
|
||||
baal = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "base address a 0x%04x 0x%04x\n", baau, baal);
|
||||
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// base address b
|
||||
if (reload & CC_BAB)
|
||||
{
|
||||
babu = s.read_word(chain_address + 0) & ARU_WM;
|
||||
babl = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "base address b 0x%04x 0x%04x\n", babu, babl);
|
||||
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// base operation count
|
||||
if (reload & CC_BOC)
|
||||
{
|
||||
boc = s.read_word(chain_address);
|
||||
|
||||
LOGMASKED(LOG_REGW, "base operation count 0x%04x\n", boc);
|
||||
|
||||
chain_address += 2;
|
||||
}
|
||||
|
||||
// pattern and mask
|
||||
if (reload & CC_PM)
|
||||
{
|
||||
pattern = s.read_word(chain_address + 0);
|
||||
mask = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "pattern 0x%04x mask %04x\n", pattern, mask);
|
||||
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// interrupt vector
|
||||
if (reload & CC_IV)
|
||||
{
|
||||
iv = s.read_word(chain_address);
|
||||
|
||||
LOGMASKED(LOG_REGW, "interrupt vector 0x%04x\n", iv);
|
||||
|
||||
chain_address += 2;
|
||||
}
|
||||
|
||||
// channel mode
|
||||
if (reload & CC_CM)
|
||||
{
|
||||
cmh = s.read_word(chain_address + 0) & CMH_WM;
|
||||
cml = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "channel mode 0x%04x %04x\n", cmh, cml);
|
||||
log_mode(LOG_DMA, true);
|
||||
|
||||
chain_address += 4;
|
||||
}
|
||||
|
||||
// chain address
|
||||
if (reload & CC_CA)
|
||||
{
|
||||
cau = s.read_word(chain_address + 0) & (ARU_UA | ARU_WC);
|
||||
cal = s.read_word(chain_address + 2);
|
||||
|
||||
LOGMASKED(LOG_REGW, "chain address 0x%04x %04x\n", cau, cal);
|
||||
|
||||
chain_address += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// update chain address register
|
||||
cau = ((chain_address >> 8) & ARU_UA) | u8(cau);
|
||||
cal = u16(chain_address);
|
||||
}
|
||||
|
||||
status &= ~(S_CA | S_NAC);
|
||||
|
||||
if (cmh & CMH_SR)
|
||||
run->adjust(attotime::zero);
|
||||
}
|
||||
|
||||
void am9516_device::channel::log_mode(unsigned mask, bool high) const
|
||||
{
|
||||
if (VERBOSE & mask)
|
||||
{
|
||||
static const char *const match[] =
|
||||
{
|
||||
"no match", "no match", "word match", "byte match"
|
||||
};
|
||||
static const char *const operation[] =
|
||||
{
|
||||
"transfer, word/word flowthru",
|
||||
"transfer, byte/byte flowthru",
|
||||
"transfer, word/word flyby",
|
||||
"transfer, byte/byte flyby",
|
||||
"transfer/search, word/word flowthru",
|
||||
"transfer/search, byte/byte flowthru",
|
||||
"transfer/search, word/word flyby",
|
||||
"transfer/search, byte/byte flyby",
|
||||
"transfer, byte/word flowthru",
|
||||
"transfer, byte/word flowthru",
|
||||
"illegal",
|
||||
"illegal",
|
||||
"transfer/search, byte/word flowthru",
|
||||
"transfer/search, byte/word flowthru",
|
||||
"search, word/word",
|
||||
"search, byte/byte",
|
||||
};
|
||||
static const char *const tt[] =
|
||||
{
|
||||
"single transfer", "demand dedicated/bus hold", "demand dedicated/bus release", "demand interleave"
|
||||
};
|
||||
static const char *const flags[] =
|
||||
{
|
||||
"-", "eop", "mc", "mc|eop", "tc", "tc|eop", "tc|mc", "tc|mc|eop"
|
||||
};
|
||||
|
||||
LOGMASKED(mask, "channel mode %s, %s, complete(int:%s rld:%s chn:%s)\n",
|
||||
operation[cml & CML_OPER], tt[BIT(cml, 5, 2)], flags[BIT(cml, 7, 3)], flags[BIT(cml, 10, 3)], flags[BIT(cml, 13, 3)]);
|
||||
|
||||
if (high)
|
||||
LOGMASKED(mask, "channel mode stop:%s /dack:%d hm:%d sr:%d\n",
|
||||
match[BIT(cmh, 0, 2)], BIT(cmh, 2), BIT(cmh, 3), BIT(cmh, 4));
|
||||
}
|
||||
}
|
||||
|
||||
void am9516_device::channel::log_addr(unsigned mask, const char *const name, u16 aru, u16 arl) const
|
||||
{
|
||||
if (VERBOSE & mask)
|
||||
{
|
||||
static const char *const ar[] =
|
||||
{
|
||||
"system i/o", "system mem", "normal i/o", "normal mem"
|
||||
};
|
||||
static const char *const ac[] =
|
||||
{
|
||||
"inc", "dec", "hld", "hld"
|
||||
};
|
||||
|
||||
LOGMASKED(mask, "%s %s 0x%06x %s wait:%d\n",
|
||||
name, ar[BIT(aru, 6, 2)], u32(aru & ARU_UA) << 8 | arl,
|
||||
ac[BIT(aru, 3, 2)], wait_states[BIT(aru, 1, 2)]);
|
||||
}
|
||||
}
|
||||
|
@ -52,8 +52,7 @@ protected:
|
||||
|
||||
private:
|
||||
void command(u8 data);
|
||||
void chain(unsigned const c);
|
||||
void operate(s32 param);
|
||||
template <unsigned Channel> void operate(s32 param);
|
||||
void complete(unsigned const c, u16 status);
|
||||
void interrupt();
|
||||
|
||||
@ -68,8 +67,7 @@ private:
|
||||
bool m_eop_in_state;
|
||||
|
||||
// chip-level registers
|
||||
u8 m_master_mode;
|
||||
u16 m_chain_control;
|
||||
u8 m_mode;
|
||||
u8 m_pointer;
|
||||
u16 m_temporary;
|
||||
|
||||
@ -86,12 +84,17 @@ private:
|
||||
|
||||
u32 address(u16 &aru, u16 &arl, int delta = 0);
|
||||
|
||||
u8 read_byte(bool flip = false);
|
||||
void write_byte(u8 data, bool flip = false);
|
||||
u16 read_word(bool flip = false);
|
||||
void write_word(u16 data, bool flip = false);
|
||||
u8 read_byte(unsigned &cycles, bool flip = false);
|
||||
void write_byte(u8 data, unsigned &cycles, bool flip = false);
|
||||
u16 read_word(unsigned &cycles, bool flip = false);
|
||||
void write_word(u16 data, unsigned &cycles, bool flip = false);
|
||||
|
||||
void interrupt(bool assert);
|
||||
void chain();
|
||||
void reload();
|
||||
|
||||
void log_mode(unsigned mask, bool high = false) const;
|
||||
void log_addr(unsigned mask, const char *const name, u16 aru, u16 arl) const;
|
||||
|
||||
am9516_device &udc;
|
||||
|
||||
@ -121,6 +124,8 @@ private:
|
||||
u16 cml = 0; // channel mode low
|
||||
u16 cmh = 0; // channel mode high
|
||||
u8 iv = 0; // interrupt vector
|
||||
|
||||
unsigned const wait_states[4] = { 0, 1, 2, 4 };
|
||||
}
|
||||
m_channel[2];
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user