am9516: general improvements

This commit is contained in:
Patrick Mackinlay 2022-08-01 11:33:12 +07:00
parent a5af13e008
commit c6e5d0c324
2 changed files with 355 additions and 229 deletions

View File

@ -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)]);
}
}

View File

@ -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];
};