summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/sa1111.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/sa1111.cpp')
-rw-r--r--src/devices/machine/sa1111.cpp690
1 files changed, 565 insertions, 125 deletions
diff --git a/src/devices/machine/sa1111.cpp b/src/devices/machine/sa1111.cpp
index 1c062dd1a55..a74e3400082 100644
--- a/src/devices/machine/sa1111.cpp
+++ b/src/devices/machine/sa1111.cpp
@@ -21,19 +21,24 @@
#define LOG_GPIO (1 << 10)
#define LOG_INTC (1 << 11)
#define LOG_CARD (1 << 12)
+#define LOG_AUDIO_DMA (1 << 13)
#define LOG_ALL (LOG_UNKNOWN | LOG_SBI | LOG_SK | LOG_USB | LOG_AUDIO | LOG_SSP | LOG_TRACK | LOG_MOUSE | LOG_GPIO | LOG_INTC | LOG_CARD)
-#define VERBOSE (0) // (LOG_ALL)
+#define VERBOSE (0)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(SA1111, sa1111_device, "sa1111", "Intel SA1111 Microprocessor Companion Chip")
sa1111_device::sa1111_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SA1111, tag, owner, clock)
+ , m_maincpu(*this, finder_base::DUMMY_TAG)
+ , m_audio_codec(*this, finder_base::DUMMY_TAG)
+ , m_irq_out(*this)
, m_gpio_out(*this)
, m_ssp_out(*this)
, m_l3_addr_out(*this)
, m_l3_data_out(*this)
+ , m_i2s_out(*this)
{
}
@@ -188,12 +193,25 @@ void sa1111_device::skcr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
LOGMASKED(LOG_SBI, "%s: Enable Scan Test: %d\n", machine().describe_context(), BIT(data, SKCR_SCANTST_BIT));
LOGMASKED(LOG_SBI, "%s: Enable Clock Test: %d\n", machine().describe_context(), BIT(data, SKCR_CLKTST_BIT));
LOGMASKED(LOG_SBI, "%s: Enable RDY Response: %d\n", machine().describe_context(), BIT(data, SKCR_RDY_BIT));
- LOGMASKED(LOG_SBI, "%s: Audio Feature Select: %s\n", machine().describe_context(), BIT(data, SKCR_SLAC_BIT) ? "AC Link" : "I2S");
+ LOGMASKED(LOG_SBI, "%s: Audio Feature Select: %s\n", machine().describe_context(), BIT(data, SKCR_SACMDSL_BIT) ? "AC Link" : "I2S");
LOGMASKED(LOG_SBI, "%s: Out-Only Pad Control: %d\n", machine().describe_context(), BIT(data, SKCR_OPPC_BIT));
LOGMASKED(LOG_SBI, "%s: Enable PII Test: %d\n", machine().describe_context(), BIT(data, SKCR_PII_BIT));
LOGMASKED(LOG_SBI, "%s: USB IO Cell Test: %d\n", machine().describe_context(), BIT(data, SKCR_UIOTEN_BIT));
LOGMASKED(LOG_SBI, "%s: Enable /OE on SDRAM DMA Read Cycles: %d\n", machine().describe_context(), 1 - BIT(data, SKCR_OEEN_BIT));
- COMBINE_DATA(&m_sbi_regs.skcr);
+ const bool audio_mode_changed = BIT(m_sbi_regs.skcr ^ ((m_sbi_regs.skcr & ~mem_mask) | (data & mem_mask)), SKCR_SACMDSL_BIT);
+ const bool audio_enabled = BIT(m_audio_regs.sacr0, SACR0_ENB_BIT);
+ if (audio_mode_changed && audio_enabled)
+ {
+ // If we're changing audio output modes while the audio interface is active, bring it down in the old mode,
+ // then bring it back up in the new mode.
+ audio_set_enabled(false);
+ COMBINE_DATA(&m_sbi_regs.skcr);
+ audio_set_enabled(true);
+ }
+ else
+ {
+ COMBINE_DATA(&m_sbi_regs.skcr);
+ }
}
void sa1111_device::smcr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
@@ -296,9 +314,13 @@ void sa1111_device::skcdr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
void sa1111_device::skaud_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
+ const uint32_t audio_divider = ((data & SKAUD_ACD_MASK) >> SKAUD_ACD_BIT) + 1;
LOGMASKED(LOG_SK, "%s: skaud_w: Audio Clock Divider Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- LOGMASKED(LOG_SK, "%s: Audio Clock Divider: %02x\n", machine().describe_context(), ((data & SKAUD_ACD_MASK) >> SKAUD_ACD_BIT) + 1);
+ LOGMASKED(LOG_SK, "%s: Audio Clock Divider: %02x\n", machine().describe_context(), audio_divider);
COMBINE_DATA(&m_sk_regs.skaud);
+ const uint32_t pll_clock = clock() * 39;
+ if (m_audio_codec)
+ m_audio_codec->set_unscaled_clock(pll_clock / audio_divider);
}
void sa1111_device::skpmc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
@@ -442,12 +464,310 @@ WRITE_LINE_MEMBER(sa1111_device::l3wd_in)
m_audio_regs.sasr0 |= (1 << SASR0_L3WD_BIT);
}
+TIMER_CALLBACK_MEMBER(sa1111_device::audio_rx_dma_callback)
+{
+ // TODO: Audio input
+}
+
TIMER_CALLBACK_MEMBER(sa1111_device::audio_rx_callback)
{
+ // TODO: Audio input
+}
+
+TIMER_CALLBACK_MEMBER(sa1111_device::audio_tx_dma_callback)
+{
+ const uint32_t buf = BIT(m_audio_regs.sadtcs, SADTCS_TBIU_BIT);
+ const uint32_t remaining = m_audio_regs.sadtcc >> 2;
+ const uint32_t avail = ARRAY_LENGTH(m_audio_regs.tx_fifo) - m_audio_regs.tx_fifo_count;
+ if (remaining == 0 || avail == 0)
+ return;
+
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ uint32_t count;
+ for (count = 0; count < remaining && count < avail; count++)
+ {
+ const uint32_t data = space.read_dword(m_audio_regs.sadta);
+ LOGMASKED(LOG_AUDIO_DMA, "audio_tx_dma_callback: read data %08x from %08x, pushing to FIFO\n", data, m_audio_regs.sadta);
+ audio_tx_fifo_push(data);
+ m_audio_regs.sadta += 4;
+ }
+
+ m_audio_regs.sadtcc = (remaining - count) << 2;
+ if (!m_audio_regs.sadtcc)
+ {
+ static const uint32_t s_start_masks[2] = { (1 << SADTCS_TDSTA_BIT), (1 << SADTCS_TDSTB_BIT) };
+ static const uint32_t s_done_masks[2] = { (1 << SADTCS_TDBDA_BIT), (1 << SADTCS_TDBDB_BIT) };
+ static const uint32_t s_done_ints[2] = { INT_AUDTXA, INT_AUDTXB };
+ m_audio_regs.sadtcs &= ~s_start_masks[buf];
+ m_audio_regs.sadtcs |= s_done_masks[buf];
+ set_irq_line(s_done_ints[buf], 1);
+ m_audio_regs.sadtcs ^= (1 << SADTCS_TBIU_BIT);
+ m_audio_regs.sadta = m_audio_regs.sadts[1 - buf];
+ m_audio_regs.sadtcc = m_audio_regs.sadtc[1 - buf];
+ }
}
TIMER_CALLBACK_MEMBER(sa1111_device::audio_tx_callback)
{
+ const uint32_t data = audio_tx_fifo_pop();
+ LOGMASKED(LOG_AUDIO_DMA, "audio_tx_callback: obtained data %08x, passing to codec\n", data);
+ m_i2s_out(data);
+}
+
+void sa1111_device::audio_update_mode()
+{
+ audio_set_enabled(BIT(m_audio_regs.sacr0, SACR0_ENB_BIT));
+}
+
+void sa1111_device::audio_clear_interrupts()
+{
+ set_irq_line(INT_AUDTXA, 0);
+ set_irq_line(INT_AUDRXA, 0);
+ set_irq_line(INT_AUDTXB, 0);
+ set_irq_line(INT_AUDRXB, 0);
+ set_irq_line(INT_AUDTFS, 0);
+ set_irq_line(INT_AUDRFS, 0);
+ set_irq_line(INT_AUDTUR, 0);
+ set_irq_line(INT_AUDROR, 0);
+ set_irq_line(INT_AUDDTS, 0);
+ set_irq_line(INT_AUDRDD, 0);
+ set_irq_line(INT_AUDSTO, 0);
+}
+
+void sa1111_device::audio_controller_reset()
+{
+ m_audio_regs.rx_fifo_read_idx = 0;
+ m_audio_regs.rx_fifo_write_idx = 0;
+ m_audio_regs.rx_fifo_count = 0;
+ m_audio_regs.tx_fifo_read_idx = 0;
+ m_audio_regs.tx_fifo_write_idx = 0;
+ m_audio_regs.tx_fifo_count = 0;
+}
+
+void sa1111_device::audio_set_enabled(bool enabled)
+{
+ if (enabled)
+ {
+ audio_set_tx_dma_enabled(BIT(m_audio_regs.sadtcs, SADTCS_TDEN_BIT));
+ audio_set_rx_dma_enabled(BIT(m_audio_regs.sadrcs, SADRCS_RDEN_BIT));
+ audio_update_tx_fifo_levels();
+ audio_update_rx_fifo_levels();
+ audio_update_busy_flag();
+
+ uint32_t *status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? &m_audio_regs.sasr1 : &m_audio_regs.sasr0;
+ set_irq_line(INT_AUDTUR, BIT(*status, SASR_TUR_BIT));
+ set_irq_line(INT_AUDROR, BIT(*status, SASR_ROR_BIT));
+ set_irq_line(INT_AUDDTS, BIT(*status, SASR_SEND_BIT));
+ set_irq_line(INT_AUDRDD, BIT(*status, SASR_RECV_BIT ));
+ set_irq_line(INT_AUDSTO, BIT(m_audio_regs.sasr1, SASR1_RSTO_BIT));
+ }
+ else
+ {
+ audio_set_tx_dma_enabled(false);
+ audio_set_rx_dma_enabled(false);
+ audio_clear_interrupts();
+ }
+}
+
+void sa1111_device::audio_set_tx_dma_enabled(bool enabled)
+{
+ LOGMASKED(LOG_AUDIO_DMA, "audio_set_tx_dma_enabled: %d\n", enabled);
+ if (enabled)
+ {
+ if (m_audio_regs.tx_dma_timer->remaining() == attotime::never)
+ {
+ const uint32_t buf = BIT(m_audio_regs.sadtcs, SADTCS_TBIU_BIT);
+ if ((buf == 0 && BIT(m_audio_regs.sadtcs, SADTCS_TDSTA_BIT)) || (buf == 1 && BIT(m_audio_regs.sadtcs, SADTCS_TDSTB_BIT)))
+ {
+ LOGMASKED(LOG_AUDIO_DMA, "audio_set_tx_dma_enabled, starting Tx DMA from buffer %d\n", buf);
+ audio_start_tx_dma(buf);
+ }
+ }
+ }
+ else
+ {
+ m_audio_regs.tx_timer->adjust(attotime::never);
+ m_audio_regs.tx_dma_timer->adjust(attotime::never);
+ }
+}
+
+void sa1111_device::audio_set_rx_dma_enabled(bool enabled)
+{
+ if (enabled)
+ {
+ if (m_audio_regs.rx_dma_timer->remaining() == attotime::never)
+ {
+ const uint32_t buf = BIT(m_audio_regs.sadrcs, SADRCS_RBIU_BIT);
+ if ((buf == 0 && BIT(m_audio_regs.sadrcs, SADRCS_RDSTA_BIT)) || (buf == 1 && BIT(m_audio_regs.sadrcs, SADRCS_RDSTB_BIT)))
+ {
+ audio_start_rx_dma(buf);
+ }
+ }
+ }
+ else
+ {
+ m_audio_regs.rx_timer->adjust(attotime::never);
+ m_audio_regs.rx_dma_timer->adjust(attotime::never);
+ }
+}
+
+void sa1111_device::audio_start_tx_dma(const uint32_t buf)
+{
+ if (!m_audio_codec)
+ return;
+
+ m_audio_regs.sadta = m_audio_regs.sadts[buf];
+ m_audio_regs.sadtcc = m_audio_regs.sadtc[buf];
+
+ const uint32_t divisor = ((m_sk_regs.skaud & SKAUD_ACD_MASK) >> SKAUD_ACD_BIT) + 1;
+ const uint32_t pll_clock = clock() * 39;
+ attotime clock_period = attotime::from_ticks(divisor * 256, pll_clock);
+ m_audio_regs.tx_dma_timer->adjust(clock_period, 0, clock_period);
+
+ LOGMASKED(LOG_AUDIO_DMA, "audio_start_tx_dma, setting start address to %08x, Tx clock to %d / %d\n", m_audio_regs.sadta, pll_clock, divisor);
+}
+
+void sa1111_device::audio_start_rx_dma(const uint32_t buf)
+{
+ if (!m_audio_codec)
+ return;
+
+ m_audio_regs.sadra = m_audio_regs.sadrs[buf];
+
+ const uint32_t divisor = ((m_sk_regs.skaud & SKAUD_ACD_MASK) >> SKAUD_ACD_BIT) + 1;
+ const uint32_t pll_clock = clock() * 39;
+ attotime clock_period = attotime::from_ticks(divisor * 256, pll_clock);
+ m_audio_regs.rx_dma_timer->adjust(clock_period, 0, clock_period);
+}
+
+void sa1111_device::audio_update_tx_fifo_levels()
+{
+ uint32_t *status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? &m_audio_regs.sasr1 : &m_audio_regs.sasr0;
+ if (m_audio_regs.tx_fifo_count < ARRAY_LENGTH(m_audio_regs.tx_fifo))
+ *status |= (1 << SASR_TNF_BIT);
+ else
+ *status &= ~(1 << SASR_TNF_BIT);
+
+ const uint32_t tfl = ((m_audio_regs.tx_fifo_count == ARRAY_LENGTH(m_audio_regs.tx_fifo)) ? (m_audio_regs.tx_fifo_count - 1) : m_audio_regs.tx_fifo_count);
+ *status &= ~SASR_TFL_MASK;
+ *status |= (tfl << SASR_TFL_BIT);
+
+ const uint32_t tfth = ((m_audio_regs.sacr0 & SACR0_TFTH_MASK) >> SACR0_TFTH_BIT) + 1;
+ if (tfl <= tfth)
+ {
+ *status |= (1 << SASR_TFS_BIT);
+ set_irq_line(INT_AUDTFS, 1);
+ }
+ else
+ {
+ *status &= ~(1 << SASR_TFS_BIT);
+ set_irq_line(INT_AUDTFS, 0);
+ }
+}
+
+void sa1111_device::audio_update_rx_fifo_levels()
+{
+ uint32_t *status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? &m_audio_regs.sasr1 : &m_audio_regs.sasr0;
+ if (m_audio_regs.rx_fifo_count != 0)
+ *status |= (1 << SASR_RNE_BIT);
+ else
+ *status &= ~(1 << SASR_RNE_BIT);
+
+ const uint32_t rfl = ((m_audio_regs.rx_fifo_count == ARRAY_LENGTH(m_audio_regs.rx_fifo)) ? (m_audio_regs.rx_fifo_count - 1) : m_audio_regs.rx_fifo_count);
+ *status &= ~SASR_RFL_MASK;
+ *status |= (rfl << SASR_RFL_BIT);
+
+ const uint32_t rfth = ((m_audio_regs.sacr0 & SACR0_RFTH_MASK) >> SACR0_RFTH_BIT) + 1;
+ if (rfl >= rfth)
+ {
+ *status |= (1 << SASR_RFS_BIT);
+ set_irq_line(INT_AUDRFS, 1);
+ }
+ else
+ {
+ *status &= ~(1 << SASR_RFS_BIT);
+ set_irq_line(INT_AUDRFS, 0);
+ }
+}
+
+void sa1111_device::audio_update_busy_flag()
+{
+ uint32_t *status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? &m_audio_regs.sasr1 : &m_audio_regs.sasr0;
+ if (m_audio_regs.rx_fifo_count > 0 || m_audio_regs.tx_fifo_count > 0)
+ *status |= (1 << SASR_BSY_BIT);
+ else
+ *status &= ~(1 << SASR_BSY_BIT);
+}
+
+void sa1111_device::audio_tx_fifo_push(uint32_t data)
+{
+ if (m_audio_regs.tx_fifo_count < ARRAY_LENGTH(m_audio_regs.tx_fifo))
+ {
+ m_audio_regs.tx_fifo[m_audio_regs.tx_fifo_write_idx] = data;
+ m_audio_regs.tx_fifo_write_idx = (m_audio_regs.tx_fifo_write_idx + 1) % ARRAY_LENGTH(m_audio_regs.tx_fifo);
+ m_audio_regs.tx_fifo_count++;
+ audio_update_tx_fifo_levels();
+ if (m_audio_regs.tx_timer->remaining() == attotime::never)
+ {
+ const uint32_t divisor = ((m_sk_regs.skaud & SKAUD_ACD_MASK) >> SKAUD_ACD_BIT) + 1;
+ const uint32_t pll_clock = clock() * 39;
+ attotime clock_period = attotime::from_ticks(divisor * 256, pll_clock);
+ m_audio_regs.tx_timer->adjust(clock_period, 0, clock_period);
+ }
+ }
+}
+
+uint32_t sa1111_device::audio_tx_fifo_pop()
+{
+ if (m_audio_regs.tx_fifo_count > 0)
+ {
+ const uint32_t data = m_audio_regs.tx_fifo[m_audio_regs.tx_fifo_read_idx];
+ m_audio_regs.tx_fifo_read_idx = (m_audio_regs.tx_fifo_read_idx + 1) % ARRAY_LENGTH(m_audio_regs.tx_fifo);
+ m_audio_regs.tx_fifo_count--;
+ audio_update_tx_fifo_levels();
+ if (m_audio_regs.tx_fifo_count == 0)
+ {
+ m_audio_regs.tx_timer->adjust(attotime::never);
+ }
+ return data;
+ }
+ else
+ {
+ uint32_t *status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? &m_audio_regs.sasr1 : &m_audio_regs.sasr0;
+ *status |= (1 << SASR_TUR_BIT);
+ set_irq_line(INT_AUDTUR, 1);
+ return m_audio_regs.tx_fifo[m_audio_regs.tx_fifo_read_idx];
+ }
+}
+
+void sa1111_device::audio_rx_fifo_push(uint32_t data)
+{
+ if (m_audio_regs.rx_fifo_count < ARRAY_LENGTH(m_audio_regs.rx_fifo))
+ {
+ m_audio_regs.rx_fifo[m_audio_regs.rx_fifo_write_idx] = data;
+ m_audio_regs.rx_fifo_write_idx = (m_audio_regs.rx_fifo_write_idx + 1) % ARRAY_LENGTH(m_audio_regs.rx_fifo);
+ m_audio_regs.rx_fifo_count++;
+ audio_update_rx_fifo_levels();
+ }
+ else
+ {
+ uint32_t *status = BIT(m_sbi_regs.skcr, SKCR_SACMDSL_BIT) ? &m_audio_regs.sasr1 : &m_audio_regs.sasr0;
+ *status |= (1 << SASR_ROR_BIT);
+ set_irq_line(INT_AUDROR, 1);
+ }
+}
+
+uint32_t sa1111_device::audio_rx_fifo_pop()
+{
+ if (m_audio_regs.rx_fifo_count > 0)
+ {
+ const uint32_t data = m_audio_regs.rx_fifo[m_audio_regs.rx_fifo_read_idx];
+ m_audio_regs.rx_fifo_read_idx = (m_audio_regs.rx_fifo_read_idx + 1) % ARRAY_LENGTH(m_audio_regs.rx_fifo);
+ m_audio_regs.rx_fifo_count--;
+ audio_update_rx_fifo_levels();
+ return data;
+ }
+ return m_audio_regs.rx_fifo[m_audio_regs.rx_fifo_read_idx];
}
uint32_t sa1111_device::sacr0_r(offs_t offset, uint32_t mem_mask)
@@ -472,15 +792,15 @@ uint32_t sa1111_device::sasr0_r(offs_t offset, uint32_t mem_mask)
{
const uint32_t data = m_audio_regs.sasr0;
LOGMASKED(LOG_AUDIO, "%s: sasr0_r: Serial Audio Status Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask);
- LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Not Full: %d\n", machine().describe_context(), BIT(data, SASR0_TNF_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Not Empty: %d\n", machine().describe_context(), BIT(data, SASR0_RNE_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Serial Audio Controller Busy: %d\n", machine().describe_context(), BIT(data, SASR0_BSY_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR0_TFS_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR0_RFS_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Underrun: %d\n", machine().describe_context(), BIT(data, SASR0_TUR_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Overrun: %d\n", machine().describe_context(), BIT(data, SASR0_ROR_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Level: %02x\n", machine().describe_context(), (data & SASR0_TFL_MASK) >> SASR0_TFL_BIT);
- LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Level: %02x\n", machine().describe_context(), (data & SASR0_RFL_MASK) >> SASR0_RFL_BIT);
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Not Full: %d\n", machine().describe_context(), BIT(data, SASR_TNF_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Not Empty: %d\n", machine().describe_context(), BIT(data, SASR_RNE_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Serial Audio Controller Busy: %d\n", machine().describe_context(), BIT(data, SASR_BSY_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR_TFS_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR_RFS_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Underrun: %d\n", machine().describe_context(), BIT(data, SASR_TUR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Overrun: %d\n", machine().describe_context(), BIT(data, SASR_ROR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Level: %02x\n", machine().describe_context(), (data & SASR_TFL_MASK) >> SASR_TFL_BIT);
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Level: %02x\n", machine().describe_context(), (data & SASR_RFL_MASK) >> SASR_RFL_BIT);
LOGMASKED(LOG_AUDIO, "%s: L3 Control Bus Data Write Done: %d\n", machine().describe_context(), BIT(data, SASR0_L3WD_BIT));
LOGMASKED(LOG_AUDIO, "%s: L3 Control Bus Data Read Done: %d\n", machine().describe_context(), BIT(data, SASR0_L3RD_BIT));
return data;
@@ -490,15 +810,15 @@ uint32_t sa1111_device::sasr1_r(offs_t offset, uint32_t mem_mask)
{
const uint32_t data = m_audio_regs.sasr1;
LOGMASKED(LOG_AUDIO, "%s: sasr1_r: Serial Audio Status Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask);
- LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Not Full: %d\n", machine().describe_context(), BIT(data, SASR1_TNF_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Not Empty: %d\n", machine().describe_context(), BIT(data, SASR1_RNE_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Serial Audio Controller Busy: %d\n", machine().describe_context(), BIT(data, SASR1_BSY_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR1_TFS_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR1_RFS_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Underrun: %d\n", machine().describe_context(), BIT(data, SASR1_TUR_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Overrun: %d\n", machine().describe_context(), BIT(data, SASR1_ROR_BIT));
- LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Level: %02x\n", machine().describe_context(), (data & SASR1_TFL_MASK) >> SASR1_TFL_BIT);
- LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Level: %02x\n", machine().describe_context(), (data & SASR1_RFL_MASK) >> SASR1_RFL_BIT);
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Not Full: %d\n", machine().describe_context(), BIT(data, SASR_TNF_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Not Empty: %d\n", machine().describe_context(), BIT(data, SASR_RNE_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Serial Audio Controller Busy: %d\n", machine().describe_context(), BIT(data, SASR_BSY_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR_TFS_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Service Request: %d\n", machine().describe_context(), BIT(data, SASR_RFS_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Underrun: %d\n", machine().describe_context(), BIT(data, SASR_TUR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Overrun: %d\n", machine().describe_context(), BIT(data, SASR_ROR_BIT));
+ LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Level: %02x\n", machine().describe_context(), (data & SASR_TFL_MASK) >> SASR_TFL_BIT);
+ LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Level: %02x\n", machine().describe_context(), (data & SASR_RFL_MASK) >> SASR_RFL_BIT);
LOGMASKED(LOG_AUDIO, "%s: AC-Link Command Address and Data Transmitted: %d\n", machine().describe_context(), BIT(data, SASR1_CADT_BIT));
LOGMASKED(LOG_AUDIO, "%s: AC-Link Status Address and Data Received: %d\n", machine().describe_context(), BIT(data, SASR1_SADR_BIT));
LOGMASKED(LOG_AUDIO, "%s: Read Status Time-Out: %d\n", machine().describe_context(), BIT(data, SASR1_RSTO_BIT));
@@ -553,26 +873,26 @@ uint32_t sa1111_device::sadtcs_r(offs_t offset, uint32_t mem_mask)
uint32_t sa1111_device::sadtsa_r(offs_t offset, uint32_t mem_mask)
{
- LOGMASKED(LOG_AUDIO, "%s: sadtsa_r: Serial Audio DMA Transmit Buffer Start Address Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadtsa, mem_mask);
- return m_audio_regs.sadtsa;
+ LOGMASKED(LOG_AUDIO, "%s: sadtsa_r: Serial Audio DMA Transmit Buffer Start Address Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadts[0], mem_mask);
+ return m_audio_regs.sadts[0];
}
uint32_t sa1111_device::sadtca_r(offs_t offset, uint32_t mem_mask)
{
- LOGMASKED(LOG_AUDIO, "%s: sadtca_r: Serial Audio DMA Transmit Buffer Count Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadtca, mem_mask);
- return m_audio_regs.sadtca;
+ LOGMASKED(LOG_AUDIO, "%s: sadtca_r: Serial Audio DMA Transmit Buffer Count Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadtc[0], mem_mask);
+ return m_audio_regs.sadtc[0];
}
uint32_t sa1111_device::sadtsb_r(offs_t offset, uint32_t mem_mask)
{
- LOGMASKED(LOG_AUDIO, "%s: sadtsb_r: Serial Audio DMA Transmit Buffer Start Address Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadtsb, mem_mask);
- return m_audio_regs.sadtsb;
+ LOGMASKED(LOG_AUDIO, "%s: sadtsb_r: Serial Audio DMA Transmit Buffer Start Address Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadts[1], mem_mask);
+ return m_audio_regs.sadts[1];
}
uint32_t sa1111_device::sadtcb_r(offs_t offset, uint32_t mem_mask)
{
- LOGMASKED(LOG_AUDIO, "%s: sadtcb_r: Serial Audio DMA Transmit Buffer Count Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadtcb, mem_mask);
- return m_audio_regs.sadtcb;
+ LOGMASKED(LOG_AUDIO, "%s: sadtcb_r: Serial Audio DMA Transmit Buffer Count Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadtc[1], mem_mask);
+ return m_audio_regs.sadtc[1];
}
uint32_t sa1111_device::sadrcs_r(offs_t offset, uint32_t mem_mask)
@@ -583,32 +903,33 @@ uint32_t sa1111_device::sadrcs_r(offs_t offset, uint32_t mem_mask)
uint32_t sa1111_device::sadrsa_r(offs_t offset, uint32_t mem_mask)
{
- LOGMASKED(LOG_AUDIO, "%s: sadrsa_r: Serial Audio DMA Receive Buffer Start Address Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrsa, mem_mask);
- return m_audio_regs.sadrsa;
+ LOGMASKED(LOG_AUDIO, "%s: sadrsa_r: Serial Audio DMA Receive Buffer Start Address Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrs[0], mem_mask);
+ return m_audio_regs.sadrs[0];
}
uint32_t sa1111_device::sadrca_r(offs_t offset, uint32_t mem_mask)
{
- LOGMASKED(LOG_AUDIO, "%s: sadrca_r: Serial Audio DMA Receive Buffer Count Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrca, mem_mask);
- return m_audio_regs.sadrca;
+ LOGMASKED(LOG_AUDIO, "%s: sadrca_r: Serial Audio DMA Receive Buffer Count Register A: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrc[0], mem_mask);
+ return m_audio_regs.sadrc[0];
}
uint32_t sa1111_device::sadrsb_r(offs_t offset, uint32_t mem_mask)
{
- LOGMASKED(LOG_AUDIO, "%s: sadrsb_r: Serial Audio DMA Receive Buffer Start Address Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrsb, mem_mask);
- return m_audio_regs.sadrsb;
+ LOGMASKED(LOG_AUDIO, "%s: sadrsb_r: Serial Audio DMA Receive Buffer Start Address Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrs[1], mem_mask);
+ return m_audio_regs.sadrs[1];
}
uint32_t sa1111_device::sadrcb_r(offs_t offset, uint32_t mem_mask)
{
- LOGMASKED(LOG_AUDIO, "%s: sadrcb_r: Serial Audio DMA Receive Buffer Count Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrcb, mem_mask);
- return m_audio_regs.sadrcb;
+ LOGMASKED(LOG_AUDIO, "%s: sadrcb_r: Serial Audio DMA Receive Buffer Count Register B: %08x & %08x\n", machine().describe_context(), m_audio_regs.sadrc[1], mem_mask);
+ return m_audio_regs.sadrc[1];
}
uint32_t sa1111_device::sadr_r(offs_t offset, uint32_t mem_mask)
{
- LOGMASKED(LOG_AUDIO, "%s: sadr_r: Serial Audio Data Register: %08x & %08x\n", machine().describe_context(), m_audio_regs.rx_fifo[m_audio_regs.rx_fifo_read_idx], mem_mask);
- return m_audio_regs.rx_fifo[m_audio_regs.rx_fifo_read_idx];
+ const uint32_t data = audio_rx_fifo_pop();
+ LOGMASKED(LOG_AUDIO, "%s: sadr_r: Serial Audio Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask);
+ return data;
}
void sa1111_device::sacr0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
@@ -619,7 +940,25 @@ void sa1111_device::sacr0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
LOGMASKED(LOG_AUDIO, "%s: Reset SAC Control and FIFOs: %d\n", machine().describe_context(), BIT(data, SACR0_RST_BIT));
LOGMASKED(LOG_AUDIO, "%s: Transmit FIFO Threshold: %02x\n", machine().describe_context(), (data & SACR0_TFTH_MASK) >> SACR0_TFTH_BIT);
LOGMASKED(LOG_AUDIO, "%s: Receive FIFO Threshold: %02x\n", machine().describe_context(), (data & SACR0_RFTH_MASK) >> SACR0_RFTH_BIT);
+
+ const uint32_t old = m_audio_regs.sacr0;
COMBINE_DATA(&m_audio_regs.sacr0);
+ const uint32_t changed = old ^ m_audio_regs.sacr0;
+
+ if (BIT(m_audio_regs.sacr0, SACR0_RST_BIT))
+ audio_controller_reset();
+
+ if (BIT(changed, SACR0_ENB_BIT))
+ {
+ audio_set_enabled(BIT(m_audio_regs.sacr0, SACR0_ENB_BIT));
+ }
+ else
+ {
+ if (changed & SACR0_TFTH_MASK)
+ audio_update_tx_fifo_levels();
+ if (changed & SACR0_RFTH_MASK)
+ audio_update_rx_fifo_levels();
+ }
}
void sa1111_device::sacr1_w(offs_t offset, uint32_t data, uint32_t mem_mask)
@@ -658,26 +997,33 @@ void sa1111_device::sascr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
if (BIT(data, SASCR_TUR_BIT))
{
- m_audio_regs.sasr0 &= ~(1 << SASR0_TUR_BIT);
- m_audio_regs.sasr1 &= ~(1 << SASR1_TUR_BIT);
+ m_audio_regs.sasr0 &= ~(1 << SASR_TUR_BIT);
+ m_audio_regs.sasr1 &= ~(1 << SASR_TUR_BIT);
+ set_irq_line(INT_AUDTUR, 0);
}
if (BIT(data, SASCR_ROR_BIT))
{
- m_audio_regs.sasr0 &= ~(1 << SASR0_ROR_BIT);
- m_audio_regs.sasr1 &= ~(1 << SASR1_ROR_BIT);
+ m_audio_regs.sasr0 &= ~(1 << SASR_ROR_BIT);
+ m_audio_regs.sasr1 &= ~(1 << SASR_ROR_BIT);
+ set_irq_line(INT_AUDROR, 0);
}
if (BIT(data, SASCR_DTS_BIT))
{
m_audio_regs.sasr0 &= ~(1 << SASR0_L3WD_BIT);
m_audio_regs.sasr1 &= ~(1 << SASR1_CADT_BIT);
+ set_irq_line(INT_AUDDTS, 0);
}
if (BIT(data, SASCR_RDD_BIT))
{
m_audio_regs.sasr0 &= ~(1 << SASR0_L3RD_BIT);
m_audio_regs.sasr1 &= ~(1 << SASR1_SADR_BIT);
+ set_irq_line(INT_AUDRDD, 0);
}
if (BIT(data, SASCR_STO_BIT))
+ {
m_audio_regs.sasr1 &= ~(1 << SASR1_RSTO_BIT);
+ set_irq_line(INT_AUDSTO, 0);
+ }
}
void sa1111_device::l3car_w(offs_t offset, uint32_t data, uint32_t mem_mask)
@@ -727,51 +1073,60 @@ void sa1111_device::sadtcs_w(offs_t offset, uint32_t data, uint32_t mem_mask)
LOGMASKED(LOG_AUDIO, "%s: Clear Serial Audio DMA Transmit Buffer Done B: %d\n", machine().describe_context(), BIT(data, SADTCS_TDBDB_BIT));
LOGMASKED(LOG_AUDIO, "%s: Serial Audio DMA Transmit Buffer Start Transfer B: %d\n", machine().describe_context(), BIT(data, SADTCS_TDSTB_BIT));
- m_audio_regs.sadtcs &= ~(1 << SADTCS_TDEN_BIT);
- m_audio_regs.sadtcs |= data & (1 << SADTCS_TDEN_BIT);
+ const uint32_t old = m_audio_regs.sadtcs;
+
+ static const uint32_t start_mask = (1 << SADTCS_TDSTA_BIT) | (1 << SADTCS_TDSTB_BIT);
+ static const uint32_t write_mask = (1 << SADTCS_TDEN_BIT) | start_mask;
+ m_audio_regs.sadtcs &= ~write_mask;
+ m_audio_regs.sadtcs |= data & write_mask & mem_mask;
- if (BIT(data, SADTCS_TDBDA_BIT))
+ if (BIT(data, SADTCS_TDBDA_BIT) || BIT(data, SADTCS_TDSTA_BIT))
+ {
+ LOGMASKED(LOG_AUDIO_DMA, "%s: sadtcs_w: Clearing done A bit, lowering AUDTXA IRQ\n");
m_audio_regs.sadtcs &= ~(1 << SADTCS_TDBDA_BIT);
- if (BIT(data, SADTCS_TDBDB_BIT))
+ set_irq_line(INT_AUDTXA, 0);
+ }
+ if (BIT(data, SADTCS_TDBDB_BIT) || BIT(data, SADTCS_TDSTB_BIT))
+ {
+ LOGMASKED(LOG_AUDIO_DMA, "%s: sadtcs_w: Clearing done B bit, lowering AUDTXB IRQ\n");
m_audio_regs.sadtcs &= ~(1 << SADTCS_TDBDB_BIT);
+ set_irq_line(INT_AUDTXB, 0);
+ }
+
+ const uint32_t changed = old ^ m_audio_regs.sadtcs;
- if (BIT(m_audio_regs.sadtcs, SADTCS_TDEN_BIT))
+ if (BIT(changed, SADTCS_TDEN_BIT))
{
- if (BIT(data, SADTCS_TDSTA_BIT))
- {
- m_audio_regs.sadtcs &= ~(1 << SADTCS_TDBDA_BIT);
- // TODO: Begin DMA transmit of Buffer A
- }
- if (BIT(data, SADTCS_TDSTB_BIT))
- {
- m_audio_regs.sadtcs &= ~(1 << SADTCS_TDBDB_BIT);
- // TODO: Begin DMA transmit of Buffer B
- }
+ audio_set_tx_dma_enabled(BIT(changed, SADTCS_TDEN_BIT));
+ }
+ else if (BIT(m_audio_regs.sadtcs, SADTCS_TDEN_BIT) && (changed & start_mask))
+ {
+ audio_set_tx_dma_enabled(true);
}
}
void sa1111_device::sadtsa_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_AUDIO, "%s: sadtsa_w: Serial Audio DMA Transmit Buffer Start Address Register A = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_audio_regs.sadtsa);
+ COMBINE_DATA(&m_audio_regs.sadts[0]);
}
void sa1111_device::sadtca_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_AUDIO, "%s: sadtca_w: Serial Audio DMA Transmit Buffer Count Register A = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_audio_regs.sadtca);
+ COMBINE_DATA(&m_audio_regs.sadtc[0]);
}
void sa1111_device::sadtsb_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_AUDIO, "%s: sadtsb_w: Serial Audio DMA Transmit Buffer Start Address Register B = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_audio_regs.sadtsb);
+ COMBINE_DATA(&m_audio_regs.sadts[1]);
}
void sa1111_device::sadtcb_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_AUDIO, "%s: sadtcb_w: Serial Audio DMA Transmit Buffer Count Register B = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_audio_regs.sadtcb);
+ COMBINE_DATA(&m_audio_regs.sadtc[1]);
}
void sa1111_device::sadrcs_w(offs_t offset, uint32_t data, uint32_t mem_mask)
@@ -783,51 +1138,58 @@ void sa1111_device::sadrcs_w(offs_t offset, uint32_t data, uint32_t mem_mask)
LOGMASKED(LOG_AUDIO, "%s: Clear Serial Audio DMA Receive Buffer Done B: %d\n", machine().describe_context(), BIT(data, SADRCS_RDBDB_BIT));
LOGMASKED(LOG_AUDIO, "%s: Serial Audio DMA Receive Buffer Start Transfer B: %d\n", machine().describe_context(), BIT(data, SADRCS_RDSTB_BIT));
- m_audio_regs.sadrcs &= ~(1 << SADRCS_RDEN_BIT);
- m_audio_regs.sadrcs |= data & (1 << SADRCS_RDEN_BIT);
+ const uint32_t old = m_audio_regs.sadrcs;
+
+ static const uint32_t start_mask = (1 << SADRCS_RDSTA_BIT) | (1 << SADRCS_RDSTB_BIT);
+ static const uint32_t write_mask = (1 << SADRCS_RDEN_BIT) | start_mask;
+ m_audio_regs.sadrcs &= ~write_mask;
+ m_audio_regs.sadrcs |= data & write_mask & mem_mask;
if (BIT(data, SADRCS_RDBDA_BIT))
+ {
m_audio_regs.sadrcs &= ~(1 << SADRCS_RDBDA_BIT);
+ set_irq_line(INT_AUDRXA, 0);
+ }
if (BIT(data, SADRCS_RDBDB_BIT))
+ {
m_audio_regs.sadrcs &= ~(1 << SADRCS_RDBDB_BIT);
+ set_irq_line(INT_AUDRXB, 0);
+ }
+
+ const uint32_t changed = old ^ m_audio_regs.sadrcs;
- if (BIT(m_audio_regs.sadrcs, SADRCS_RDEN_BIT))
+ if (BIT(changed, SADRCS_RDEN_BIT))
{
- if (BIT(data, SADRCS_RDSTA_BIT))
- {
- m_audio_regs.sadrcs &= ~(1 << SADRCS_RDBDA_BIT);
- // TODO: Begin DMA receive of Buffer A
- }
- if (BIT(data, SADRCS_RDSTB_BIT))
- {
- m_audio_regs.sadrcs &= ~(1 << SADRCS_RDBDB_BIT);
- // TODO: Begin DMA receive of Buffer B
- }
+ audio_set_rx_dma_enabled(BIT(changed, SADRCS_RDEN_BIT));
+ }
+ else if (BIT(m_audio_regs.sadrcs, SADRCS_RDEN_BIT) && (changed & start_mask))
+ {
+ audio_set_rx_dma_enabled(true);
}
}
void sa1111_device::sadrsa_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_AUDIO, "%s: sadrsa_w: Serial Audio DMA Receive Buffer Start Address Register A = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_audio_regs.sadrsa);
+ COMBINE_DATA(&m_audio_regs.sadrs[0]);
}
void sa1111_device::sadrca_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_AUDIO, "%s: sadrca_w: Serial Audio DMA Receive Buffer Count Register A = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_audio_regs.sadrca);
+ COMBINE_DATA(&m_audio_regs.sadrc[0]);
}
void sa1111_device::sadrsb_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_AUDIO, "%s: sadrsb_w: Serial Audio DMA Receive Buffer Start Address Register B = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_audio_regs.sadrsb);
+ COMBINE_DATA(&m_audio_regs.sadrs[1]);
}
void sa1111_device::sadrcb_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_AUDIO, "%s: sadrcb_w: Serial Audio DMA Receive Buffer Count Register B = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- COMBINE_DATA(&m_audio_regs.sadrcb);
+ COMBINE_DATA(&m_audio_regs.sadrc[1]);
}
void sa1111_device::saitr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
@@ -849,7 +1211,7 @@ void sa1111_device::saitr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
void sa1111_device::sadr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_AUDIO, "%s: sadr_w: Serial Audio Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
- // TODO: Push into audio FIFO
+ audio_tx_fifo_push(data);
}
/*
@@ -1283,41 +1645,62 @@ void sa1111_device::gpio_in(const uint32_t line, const int state)
void sa1111_device::gpio_update_direction(const uint32_t block, const uint32_t old_dir)
{
+ const uint32_t new_outputs = old_dir & ~m_gpio_regs.ddr[block];
+ if (new_outputs)
+ {
+ for (uint32_t line = 0; line < 8; line++)
+ {
+ if (BIT(new_outputs, line))
+ {
+ m_gpio_out[block * 8 + line](BIT(m_gpio_regs.out_latch[block], line));
+ }
+ }
+ }
}
-void sa1111_device::gpio_update_outputs(const uint32_t block, const uint32_t old_latch)
+void sa1111_device::gpio_update_outputs(const uint32_t block, const uint32_t changed)
{
+ uint32_t remaining_changed = changed;
+
+ for (uint32_t line = 0; line < 8 && remaining_changed != 0; line++)
+ {
+ if (BIT(remaining_changed, line))
+ {
+ m_gpio_out[block * 8 + line](BIT(m_gpio_regs.level[block], line));
+ remaining_changed &= ~(1 << line);
+ }
+ }
}
-template <unsigned Block>
+template <int Block>
uint32_t sa1111_device::ddr_r(offs_t offset, uint32_t mem_mask)
{
LOGMASKED(LOG_GPIO, "%s: ddr_r: GPIO Block %c Data Direction: %08x & %08x\n", machine().describe_context(), 'A' + Block, m_gpio_regs.ddr[Block], mem_mask);
return m_gpio_regs.ddr[Block];
}
-template <unsigned Block>
+template <int Block>
uint32_t sa1111_device::drr_r(offs_t offset, uint32_t mem_mask)
{
LOGMASKED(LOG_GPIO, "%s: drr_r: GPIO Block %c Data Value Register: %08x & %08x\n", machine().describe_context(), 'A' + Block, m_gpio_regs.level[Block], mem_mask);
return m_gpio_regs.level[Block];
}
-template <unsigned Block>
+template <int Block>
uint32_t sa1111_device::sdr_r(offs_t offset, uint32_t mem_mask)
{
LOGMASKED(LOG_GPIO, "%s: sdr_r: GPIO Block %c Sleep Direction: %08x & %08x\n", machine().describe_context(), 'A' + Block, m_gpio_regs.sdr[Block], mem_mask);
return m_gpio_regs.sdr[Block];
}
-template <unsigned Block>
+template <int Block>
uint32_t sa1111_device::ssr_r(offs_t offset, uint32_t mem_mask)
{
LOGMASKED(LOG_GPIO, "%s: ssr_r: GPIO Block %c Sleep State: %08x & %08x\n", machine().describe_context(), 'A' + Block, m_gpio_regs.ssr[Block], mem_mask);
return m_gpio_regs.ssr[Block];
}
-template <unsigned Block>
+template <int Block>
void sa1111_device::ddr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_GPIO, "%s: ddr_w: GPIO Block %c Data Direction = %08x & %08x\n", machine().describe_context(), 'A' + Block, data, mem_mask);
@@ -1327,24 +1710,25 @@ void sa1111_device::ddr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
gpio_update_direction(Block, old);
}
-template <unsigned Block>
+template <int Block>
void sa1111_device::dwr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_GPIO, "%s: dwr_w: GPIO Block %c Data Value Register = %08x & %08x\n", machine().describe_context(), 'A' + Block, data, mem_mask);
- const uint32_t old = m_gpio_regs.out_latch[Block];
+ const uint32_t old = m_gpio_regs.level[Block];
COMBINE_DATA(&m_gpio_regs.out_latch[Block]);
- if (old != m_gpio_regs.out_latch[Block])
- gpio_update_outputs(Block, old);
+ m_gpio_regs.level[Block] = (m_gpio_regs.ddr[Block] & m_gpio_regs.in_latch[Block]) | (~m_gpio_regs.ddr[Block] & m_gpio_regs.out_latch[Block]);
+ if (old != m_gpio_regs.level[Block])
+ gpio_update_outputs(Block, old ^ m_gpio_regs.level[Block]);
}
-template <unsigned Block>
+template <int Block>
void sa1111_device::sdr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_GPIO, "%s: sdr_w: GPIO Block %c Sleep Direction = %08x & %08x\n", machine().describe_context(), 'A' + Block, data, mem_mask);
COMBINE_DATA(&m_gpio_regs.sdr[Block]);
}
-template <unsigned Block>
+template <int Block>
void sa1111_device::ssr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_GPIO, "%s: ssr_w: GPIO Block %c Sleep State = %08x & %08x\n", machine().describe_context(), 'A' + Block, data, mem_mask);
@@ -1359,7 +1743,40 @@ void sa1111_device::ssr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
*/
-template <unsigned Set>
+void sa1111_device::set_irq_line(uint32_t line, int state)
+{
+ const uint32_t set = BIT(line, 5);
+ const uint32_t local_bit = line & 0x1f;
+ const uint32_t mask = (1 << local_bit);
+ const uint32_t old_raw = BIT(m_intc_regs.intraw[set], local_bit);
+ //LOGMASKED(LOG_INTC, "Setting IRQ line %d to state %d. Current intraw[%d] state %08x, bit state %d\n", line, state, set, m_intc_regs.intraw[set], old_raw);
+ if (old_raw == state)
+ return;
+
+ m_intc_regs.intraw[set] &= ~mask;
+ m_intc_regs.intraw[set] |= (state << local_bit);
+
+ const uint32_t falling_edge = BIT(m_intc_regs.intpol[set], local_bit);
+ const bool new_rising = (!old_raw && state && !falling_edge);
+ const bool new_falling = (old_raw && !state && falling_edge);
+
+ if (new_rising || new_falling)
+ m_intc_regs.intstat[set] |= mask;
+
+ if (BIT(m_intc_regs.inten[set], local_bit))
+ {
+ LOGMASKED(LOG_INTC, "IRQ line %d is enabled, updating interrupts\n", line);
+ update_interrupts();
+ }
+}
+
+void sa1111_device::update_interrupts()
+{
+ const bool any_interrupt = (m_intc_regs.intstat[0] & m_intc_regs.inten[0]) || (m_intc_regs.intstat[1] & m_intc_regs.inten[1]);
+ m_irq_out(any_interrupt);
+}
+
+template <int Set>
uint32_t sa1111_device::inttest_r(offs_t offset, uint32_t mem_mask)
{
if (Set == 0)
@@ -1375,14 +1792,14 @@ uint32_t sa1111_device::inttest_r(offs_t offset, uint32_t mem_mask)
}
}
-template <unsigned Set>
+template <int Set>
uint32_t sa1111_device::inten_r(offs_t offset, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: inten_r: Interrupt Enable Register %d: %08x & %08x\n", machine().describe_context(), Set, m_intc_regs.inten[Set], mem_mask);
return m_intc_regs.inten[Set];
}
-template <unsigned Set>
+template <int Set>
uint32_t sa1111_device::intpol_r(offs_t offset, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: intpol_r: Interrupt Polarity Register %d: %08x & %08x\n", machine().describe_context(), Set, m_intc_regs.intpol[Set], mem_mask);
@@ -1395,42 +1812,47 @@ uint32_t sa1111_device::inttstsel_r(offs_t offset, uint32_t mem_mask)
return m_intc_regs.inttstsel;
}
-template <unsigned Set>
+template <int Set>
uint32_t sa1111_device::intstat_r(offs_t offset, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: intstat_r: Interrupt Status Register %d: %08x & %08x\n", machine().describe_context(), Set, m_intc_regs.intstat[Set], mem_mask);
return m_intc_regs.intstat[Set];
}
-template <unsigned Set>
+template <int Set>
uint32_t sa1111_device::wake_en_r(offs_t offset, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: wake_en_r: Interrupt Wake-Up Enable Register %d: %08x & %08x\n", machine().describe_context(), Set, m_intc_regs.wake_en[Set], mem_mask);
return m_intc_regs.wake_en[Set];
}
-template <unsigned Set>
+template <int Set>
uint32_t sa1111_device::wake_pol_r(offs_t offset, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: wake_pol_r: Interrupt Wake-Up Polarity Register %d: %08x & %08x\n", machine().describe_context(), Set, m_intc_regs.wake_pol[Set], mem_mask);
return m_intc_regs.wake_pol[Set];
}
-template <unsigned Set>
+template <int Set>
void sa1111_device::inttest_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: inttest_w: Interrupt Test Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
COMBINE_DATA(&m_intc_regs.inttest[Set]);
}
-template <unsigned Set>
+template <int Set>
void sa1111_device::inten_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: inten_w: Interrupt Enable Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
+ const uint32_t old = m_intc_regs.inten[Set];
COMBINE_DATA(&m_intc_regs.inten[Set]);
+ if (old != m_intc_regs.inten[Set] && (m_intc_regs.intstat[Set] & old) != 0)
+ {
+ update_interrupts();
+ }
}
-template <unsigned Set>
+template <int Set>
void sa1111_device::intpol_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: intc_w: Interrupt Polarity Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
@@ -1443,28 +1865,38 @@ void sa1111_device::inttstsel_w(offs_t offset, uint32_t data, uint32_t mem_mask)
COMBINE_DATA(&m_intc_regs.inttstsel);
}
-template <unsigned Set>
+template <int Set>
void sa1111_device::intclr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: intc_w: Interrupt Clear Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
+ const uint32_t old = m_intc_regs.intstat[Set];
m_intc_regs.intstat[Set] &= ~(data & mem_mask);
+ if (old != m_intc_regs.intstat[Set] && (old & m_intc_regs.inten[Set]) != 0)
+ {
+ update_interrupts();
+ }
}
-template <unsigned Set>
+template <int Set>
void sa1111_device::intset_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: intset_w: Interrupt Set Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
+ const uint32_t old = m_intc_regs.intstat[Set];
m_intc_regs.intstat[Set] |= (data & mem_mask);
+ if (old != m_intc_regs.intstat[Set] && (m_intc_regs.intstat[Set] & m_intc_regs.inten[Set]) != 0)
+ {
+ update_interrupts();
+ }
}
-template <unsigned Set>
+template <int Set>
void sa1111_device::wake_en_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: wake_en_w: Interrupt Wake-Up Enable Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
COMBINE_DATA(&m_intc_regs.wake_en[Set]);
}
-template <unsigned Set>
+template <int Set>
void sa1111_device::wake_pol_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
LOGMASKED(LOG_INTC, "%s: wake_pol_w: Interrupt Wake-Up Polarity Register %d = %08x & %08x\n", machine().describe_context(), Set, data, mem_mask);
@@ -1568,15 +2000,15 @@ void sa1111_device::device_start()
save_item(NAME(m_audio_regs.acsar));
save_item(NAME(m_audio_regs.acsdr));
save_item(NAME(m_audio_regs.sadtcs));
- save_item(NAME(m_audio_regs.sadtsa));
- save_item(NAME(m_audio_regs.sadtca));
- save_item(NAME(m_audio_regs.sadtsb));
- save_item(NAME(m_audio_regs.sadtcb));
+ save_item(NAME(m_audio_regs.sadts));
+ save_item(NAME(m_audio_regs.sadtc));
+ save_item(NAME(m_audio_regs.sadta));
+ save_item(NAME(m_audio_regs.sadtcc));
save_item(NAME(m_audio_regs.sadrcs));
- save_item(NAME(m_audio_regs.sadrsa));
- save_item(NAME(m_audio_regs.sadrca));
- save_item(NAME(m_audio_regs.sadrsb));
- save_item(NAME(m_audio_regs.sadrcb));
+ save_item(NAME(m_audio_regs.sadrs));
+ save_item(NAME(m_audio_regs.sadrc));
+ save_item(NAME(m_audio_regs.sadra));
+ save_item(NAME(m_audio_regs.sadrcc));
save_item(NAME(m_audio_regs.saitr));
save_item(NAME(m_audio_regs.rx_fifo));
save_item(NAME(m_audio_regs.rx_fifo_read_idx));
@@ -1630,21 +2062,26 @@ void sa1111_device::device_start()
save_item(NAME(m_intc_regs.intstat));
save_item(NAME(m_intc_regs.wake_en));
save_item(NAME(m_intc_regs.wake_pol));
+ save_item(NAME(m_intc_regs.intraw));
save_item(NAME(m_card_regs.pccr));
save_item(NAME(m_card_regs.pcssr));
save_item(NAME(m_card_regs.pcsr));
m_audio_regs.rx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sa1111_device::audio_rx_callback), this));
+ m_audio_regs.rx_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sa1111_device::audio_rx_dma_callback), this));
m_audio_regs.tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sa1111_device::audio_tx_callback), this));
+ m_audio_regs.tx_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sa1111_device::audio_tx_dma_callback), this));
m_ssp_regs.rx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sa1111_device::ssp_rx_callback), this));
m_ssp_regs.tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sa1111_device::ssp_tx_callback), this));
+ m_irq_out.resolve_safe();
m_gpio_out.resolve_all_safe();
m_ssp_out.resolve_safe();
m_l3_addr_out.resolve_safe();
m_l3_data_out.resolve_safe();
+ m_i2s_out.resolve_safe();
}
void sa1111_device::device_reset()
@@ -1681,26 +2118,28 @@ void sa1111_device::device_reset()
m_audio_regs.acsar = 0;
m_audio_regs.acsdr = 0;
m_audio_regs.sadtcs = 0;
- m_audio_regs.sadtsa = 0;
- m_audio_regs.sadtca = 0;
- m_audio_regs.sadtsb = 0;
- m_audio_regs.sadtcb = 0;
+ memset(m_audio_regs.sadts, 0, sizeof(uint32_t) * 2);
+ memset(m_audio_regs.sadtc, 0, sizeof(uint32_t) * 2);
+ m_audio_regs.sadta = 0;
+ m_audio_regs.sadtcc = 0;
m_audio_regs.sadrcs = 0;
- m_audio_regs.sadrsa = 0;
- m_audio_regs.sadrca = 0;
- m_audio_regs.sadrsb = 0;
- m_audio_regs.sadrcb = 0;
+ memset(m_audio_regs.sadrs, 0, sizeof(uint32_t) * 2);
+ memset(m_audio_regs.sadrc, 0, sizeof(uint32_t) * 2);
+ m_audio_regs.sadra = 0;
+ m_audio_regs.sadrcc = 0;
m_audio_regs.saitr = 0;
- memset(m_audio_regs.rx_fifo, 0, sizeof(uint16_t) * ARRAY_LENGTH(m_audio_regs.rx_fifo));
+ memset(m_audio_regs.rx_fifo, 0, sizeof(uint32_t) * ARRAY_LENGTH(m_audio_regs.rx_fifo));
m_audio_regs.rx_fifo_read_idx = 0;
m_audio_regs.rx_fifo_write_idx = 0;
m_audio_regs.rx_fifo_count = 0;
m_audio_regs.rx_timer->adjust(attotime::never);
- memset(m_audio_regs.tx_fifo, 0, sizeof(uint16_t) * ARRAY_LENGTH(m_audio_regs.tx_fifo));
+ m_audio_regs.rx_dma_timer->adjust(attotime::never);
+ memset(m_audio_regs.tx_fifo, 0, sizeof(uint32_t) * ARRAY_LENGTH(m_audio_regs.tx_fifo));
m_audio_regs.tx_fifo_read_idx = 0;
m_audio_regs.tx_fifo_write_idx = 0;
m_audio_regs.tx_fifo_count = 0;
m_audio_regs.tx_timer->adjust(attotime::never);
+ m_audio_regs.tx_dma_timer->adjust(attotime::never);
m_ssp_regs.sspcr0 = 0;
m_ssp_regs.sspcr1 = (0x7 << SSPCR1_RFT_BIT) | (0x7 << SSPCR1_TFT_BIT);
@@ -1734,10 +2173,11 @@ void sa1111_device::device_reset()
memset(m_intc_regs.intstat, 0, sizeof(uint32_t) * ARRAY_LENGTH(m_intc_regs.intstat));
memset(m_intc_regs.wake_en, 0, sizeof(uint32_t) * ARRAY_LENGTH(m_intc_regs.wake_en));
memset(m_intc_regs.wake_pol, 0, sizeof(uint32_t) * ARRAY_LENGTH(m_intc_regs.wake_pol));
+ memset(m_intc_regs.intraw, 0, sizeof(uint32_t) * ARRAY_LENGTH(m_intc_regs.intraw));
m_card_regs.pccr = 0;
m_card_regs.pcssr = 0;
- m_card_regs.pcsr = 0x0000000c;
+ m_card_regs.pcsr = 0x000000fc;
}
void sa1111_device::device_add_mconfig(machine_config &config)