diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index c4c8ce57edf..dc2f9864fb7 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -1721,6 +1721,18 @@ if (MACHINES["K056230"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/machine/m950x0.h,MACHINES["M950X0"] = true +--------------------------------------------------- + +if (MACHINES["M950X0"]~=null) then + files { + MAME_DIR .. "src/devices/machine/m950x0.cpp", + MAME_DIR .. "src/devices/machine/m950x0.h", + } +end + --------------------------------------------------- -- --@src/devices/machine/mm5740.h,MACHINES["MM5740"] = true diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index 4dd6fbd898c..3344c2854c0 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -558,6 +558,7 @@ MACHINES["MC68901"] = true MACHINES["MCCS1850"] = true MACHINES["M68307"] = true MACHINES["M68340"] = true +--MACHINES["M950X0"] = true MACHINES["MCF5206E"] = true MACHINES["METERS"] = true MACHINES["MICROTOUCH"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 1d967c2320b..f4d9214f320 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -569,6 +569,7 @@ MACHINES["LSI53C810"] = true MACHINES["M3002"] = true MACHINES["M68307"] = true MACHINES["M68340"] = true +MACHINES["M950X0"] = true MACHINES["M68SFDC"] = true MACHINES["M6M80011AP"] = true MACHINES["MB14241"] = true diff --git a/src/devices/machine/m950x0.cpp b/src/devices/machine/m950x0.cpp new file mode 100644 index 00000000000..b04844aefac --- /dev/null +++ b/src/devices/machine/m950x0.cpp @@ -0,0 +1,207 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/*************************************************************************** + + m950x0.cpp + + STmicro M95010/20/40 SPI-bus EEPROM + + Common characteristics: + - 16-byte page size + - Write protection selectable in quarter, half, or full sizes + + Part variants with a -DF designation have additional support for an + identification page, which is not currently emulated. + + Sizes: + M95010 - 1kbit + M95020 - 2kbit + M95040 - 4kbit, slightly altered instructions for 9th address bit + + Current issues: + - Implementation currently operates in a parallel manner, rather than + serial. + +***************************************************************************/ + +#include "emu.h" +#include "m950x0.h" + +#define VERBOSE (0) +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(M95010, m95010_device, "m95010", "STmicro M95010 1kbit SPI EEPROM") +DEFINE_DEVICE_TYPE(M95020, m95020_device, "m95020", "STmicro M95020 2kbit SPI EEPROM") +DEFINE_DEVICE_TYPE(M95040, m95040_device, "m95040", "STmicro M95040 4kbit SPI EEPROM") + +m950x0_device::m950x0_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, int capacity) + : eeprom_base_device(mconfig, type, tag, owner) + , m_check_a8(capacity > 0x100) + , m_addr_mask((uint16_t)capacity - 1) + , m_state(STATE_IDLE) +{ + size(capacity, 8); +} + +m95010_device::m95010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : m950x0_device(mconfig, M95010, tag, owner, 0x80) +{ +} + +m95020_device::m95020_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : m950x0_device(mconfig, M95010, tag, owner, 0x100) +{ +} + +m95040_device::m95040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : m950x0_device(mconfig, M95010, tag, owner, 0x200) +{ +} + +void m950x0_device::device_start() +{ + eeprom_base_device::device_start(); + + save_item(NAME(m_state)); + save_item(NAME(m_selected)); + save_item(NAME(m_status)); + save_item(NAME(m_addr)); +} + +void m950x0_device::device_reset() +{ + eeprom_base_device::device_reset(); + + m_state = STATE_IDLE; + m_selected = false; + m_status = 0xf0; + m_addr = 0; +} + +uint8_t m950x0_device::access(uint8_t data) +{ + if (!m_selected) + return 0; + + uint8_t response = 0; + + switch (m_state) + { + case STATE_IDLE: + process_instruction(data); + break; + + case STATE_RDSR: + response = m_status; + m_state = STATE_IDLE; + LOG("Status Register read, value: %02x\n", response); + break; + + case STATE_WRSR: + m_status &= 0xf0; + m_status |= data & 0x0f; + m_state = STATE_IDLE; + LOG("Status Register write, new value: %02x\n", m_status); + break; + + case STATE_READ_ADDR: + m_addr |= data; + m_state = STATE_READ_DATA; + LOG("Read command, starting address: %03x, entering read-data state\n", m_addr); + break; + + case STATE_WRITE_ADDR: + m_addr |= data; + m_state = STATE_WRITE_DATA; + LOG("Write command, starting address: %03x, entering write-data state\n", m_addr); + break; + + case STATE_READ_DATA: + response = (uint8_t)internal_read(m_addr); + LOG("Read command, data: %02x, at address %03x\n", response, m_addr); + m_addr++; + m_addr &= m_addr_mask; + break; + + case STATE_WRITE_DATA: + internal_write(m_addr, data); + LOG("Write command, data: %02x to address %03x\n", data, m_addr); + m_addr++; + m_addr &= m_addr_mask; + break; + } + + return response; +} + +void m950x0_device::process_instruction(const uint8_t insn) +{ + switch (insn) + { + case INSN_WREN0: + case INSN_WREN1: + LOG("Instruction: Write enable\n"); + m_status |= (1 << STATUS_WEL_BIT); + break; + + case INSN_WRDI0: + case INSN_WRDI1: + LOG("Instruction: Write disable\n"); + m_status &= ~(1 << STATUS_WEL_BIT); + break; + + case INSN_RDSR0: + case INSN_RDSR1: + LOG("Instruction: Read status register\n"); + m_state = STATE_RDSR; + break; + + case INSN_WRSR0: + case INSN_WRSR1: + LOG("Instruction: Write status register\n"); + m_state = STATE_WRSR; + break; + + case INSN_READ0: + LOG("Instruction: Read, A8=0\n"); + m_state = STATE_READ_ADDR; + break; + case INSN_READ1: + LOG("Instruction: Read, A8=1\n"); + m_state = STATE_READ_ADDR; + if (m_check_a8) + m_addr |= 0x100; + break; + + case INSN_WRITE0: + LOG("Instruction: Write, A8=0\n"); + m_state = STATE_WRITE_ADDR; + break; + case INSN_WRITE1: + LOG("Instruction: Write, A8=1\n"); + m_state = STATE_WRITE_ADDR; + if (m_check_a8) + m_addr |= 0x100; + break; + + default: + LOG("Unrecognized instruction byte: %02x, deselecting\n", insn); + m_selected = false; + break; + } +} + +void m950x0_device::select_w(int selected) +{ + if (m_selected == (bool)selected) + return; + + m_selected = (bool)selected; + + if (!selected) + { + LOG("Deselected, resetting address to 0 and entering idle state.\n"); + m_state = STATE_IDLE; + m_addr = 0; + } +} diff --git a/src/devices/machine/m950x0.h b/src/devices/machine/m950x0.h new file mode 100644 index 00000000000..46fe250148a --- /dev/null +++ b/src/devices/machine/m950x0.h @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/*************************************************************************** + + m950x0.h + + STmicro M95010/20/40 SPI-bus EEPROM + +***************************************************************************/ + +#ifndef MAME_MACHINE_M950X0_H +#define MAME_MACHINE_M950X0_H + +#pragma once + +#include "machine/eeprom.h" + +class m950x0_device : public eeprom_base_device +{ +public: + uint8_t access(uint8_t data); + void select_w(int selected); + +protected: + m950x0_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, int capacity); + +private: + virtual void device_start() override; + virtual void device_reset() override; + + void process_instruction(const uint8_t insn); + + enum : uint32_t + { + STATE_IDLE, + + // Status-register accesses expect two sequential bytes (instruction + status) + STATE_RDSR, + STATE_WRSR, + + // Reads and writes expect a minimum of 3 bytes (instruction + address + data) + STATE_READ_ADDR, + STATE_READ_DATA, + STATE_WRITE_ADDR, + STATE_WRITE_DATA + }; + + enum : uint8_t + { + INSN_WRSR0 = 0x01, + INSN_WRITE0 = 0x02, + INSN_READ0 = 0x03, + INSN_WRDI0 = 0x04, + INSN_RDSR0 = 0x05, + INSN_WREN0 = 0x06, + + INSN_WRSR1 = 0x09, + INSN_WRITE1 = 0x0a, + INSN_READ1 = 0x0b, + INSN_WRDI1 = 0x0c, + INSN_RDSR1 = 0x0d, + INSN_WREN1 = 0x0e, + + STATUS_WEL_BIT = 1 + }; + + const bool m_check_a8; + const uint16_t m_addr_mask; + + uint32_t m_state; + bool m_selected; + uint8_t m_status; + uint16_t m_addr; +}; + +class m95010_device : public m950x0_device +{ +public: + m95010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); +}; + +class m95020_device : public m950x0_device +{ +public: + m95020_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); +}; + +class m95040_device : public m950x0_device +{ +public: + m95040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); +}; + +DECLARE_DEVICE_TYPE(M95010, m95010_device) +DECLARE_DEVICE_TYPE(M95020, m95020_device) +DECLARE_DEVICE_TYPE(M95040, m95040_device) + +#endif // MAME_MACHINE_M950X0_H \ No newline at end of file diff --git a/src/devices/machine/sa1110.cpp b/src/devices/machine/sa1110.cpp index eded21499d2..218819f44ad 100644 --- a/src/devices/machine/sa1110.cpp +++ b/src/devices/machine/sa1110.cpp @@ -10,21 +10,26 @@ #include "sa1110.h" #define LOG_UNKNOWN (1 << 1) -#define LOG_UART (1 << 2) -#define LOG_UART_HF (1 << 3) -#define LOG_MCP (1 << 4) -#define LOG_SSP (1 << 5) -#define LOG_OSTIMER (1 << 6) -#define LOG_OSTIMER_HF (1 << 7) -#define LOG_RTC (1 << 8) -#define LOG_POWER (1 << 9) -#define LOG_RESET (1 << 10) -#define LOG_GPIO (1 << 11) -#define LOG_GPIO_HF (1 << 12) -#define LOG_INTC (1 << 13) -#define LOG_ALL (LOG_UNKNOWN | LOG_UART | LOG_MCP | LOG_SSP | LOG_OSTIMER | LOG_RTC | LOG_POWER | LOG_RESET | LOG_GPIO | LOG_INTC) +#define LOG_ICP (1 << 2) +#define LOG_UART3 (1 << 3) +#define LOG_UART3_HF (1 << 4) +#define LOG_MCP (1 << 5) +#define LOG_SSP (1 << 6) +#define LOG_OSTIMER (1 << 7) +#define LOG_OSTIMER_HF (1 << 8) +#define LOG_RTC (1 << 9) +#define LOG_RTC_HF (1 << 10) +#define LOG_POWER (1 << 11) +#define LOG_POWER_HF (1 << 12) +#define LOG_RESET (1 << 13) +#define LOG_GPIO (1 << 14) +#define LOG_GPIO_HF (1 << 15) +#define LOG_INTC (1 << 16) +#define LOG_PPC (1 << 17) +#define LOG_DMA (1 << 18) +#define LOG_ALL (LOG_UNKNOWN | LOG_ICP | LOG_UART3 | LOG_MCP | LOG_OSTIMER | LOG_RTC | LOG_POWER | LOG_RESET | LOG_GPIO | LOG_INTC | LOG_PPC | LOG_DMA) -#define VERBOSE (0) // (LOG_ALL) +#define VERBOSE (0) #include "logmacro.h" DEFINE_DEVICE_TYPE(SA1110_PERIPHERALS, sa1110_periphs_device, "sa1110_periphs", "Intel XScale SA1110 Peripherals") @@ -42,6 +47,252 @@ sa1110_periphs_device::sa1110_periphs_device(const machine_config &mconfig, cons { } +/* + + Intel SA-1110 ICP - Serial Port 2 + + pg. 264 to 288 Intel StrongARM SA-1110 Microprocessor Developer's Manual + +*/ + +TIMER_CALLBACK_MEMBER(sa1110_periphs_device::icp_rx_callback) +{ +} + +TIMER_CALLBACK_MEMBER(sa1110_periphs_device::icp_tx_callback) +{ +} + +TIMER_CALLBACK_MEMBER(sa1110_periphs_device::hssp_rx_callback) +{ +} + +TIMER_CALLBACK_MEMBER(sa1110_periphs_device::hssp_tx_callback) +{ +} + +void sa1110_periphs_device::icp_uart_set_receiver_enabled(bool enabled) +{ +} + +void sa1110_periphs_device::icp_uart_set_transmitter_enabled(bool enabled) +{ +} + +void sa1110_periphs_device::icp_uart_set_receive_irq_enabled(bool enabled) +{ +} + +void sa1110_periphs_device::icp_uart_set_transmit_irq_enabled(bool enabled) +{ +} + +uint8_t sa1110_periphs_device::icp_uart_read_receive_fifo() +{ + return 0; +} + +void sa1110_periphs_device::icp_uart_write_transmit_fifo(uint8_t data) +{ +} + +uint16_t sa1110_periphs_device::icp_hssp_read_receive_fifo() +{ + return 0; +} + +void sa1110_periphs_device::icp_hssp_write_transmit_fifo(uint8_t data) +{ +} + +void sa1110_periphs_device::icp_uart_set_receiver_idle() +{ +} + +void sa1110_periphs_device::icp_uart_begin_of_break() +{ +} + +void sa1110_periphs_device::icp_uart_end_of_break() +{ +} + + +uint32_t sa1110_periphs_device::icp_r(offs_t offset, uint32_t mem_mask) +{ + switch (offset) + { + case REG_UTCR0: + LOGMASKED(LOG_ICP, "%s: icp_r: UART Control Register 0: %08x & %08x\n", machine().describe_context(), m_icp_regs.uart.utcr[0], mem_mask); + return m_icp_regs.uart.utcr[0]; + case REG_UTCR1: + LOGMASKED(LOG_ICP, "%s: icp_r: UART Control Register 1: %08x & %08x\n", machine().describe_context(), m_icp_regs.uart.utcr[1], mem_mask); + return m_icp_regs.uart.utcr[1]; + case REG_UTCR2: + LOGMASKED(LOG_ICP, "%s: icp_r: UART Control Register 2: %08x & %08x\n", machine().describe_context(), m_icp_regs.uart.utcr[2], mem_mask); + return m_icp_regs.uart.utcr[2]; + case REG_UTCR3: + LOGMASKED(LOG_ICP, "%s: icp_r: UART Control Register 3: %08x & %08x\n", machine().describe_context(), m_icp_regs.uart.utcr[3], mem_mask); + return m_icp_regs.uart.utcr[3]; + case REG_UTCR4: + LOGMASKED(LOG_ICP, "%s: icp_r: UART Control Register 4: %08x & %08x\n", machine().describe_context(), m_icp_regs.utcr4, mem_mask); + return m_icp_regs.utcr4; + case REG_UTDR: + { + const uint8_t data = icp_uart_read_receive_fifo(); + LOGMASKED(LOG_ICP, "%s: icp_r: UART Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; + } + case REG_UTSR0: + LOGMASKED(LOG_ICP, "%s: icp_r: UART Status Register 0: %08x & %08x\n", machine().describe_context(), m_icp_regs.uart.utsr0, mem_mask); + return m_icp_regs.uart.utsr0; + case REG_UTSR1: + LOGMASKED(LOG_ICP, "%s: icp_r: UART Status Register 1: %08x & %08x\n", machine().describe_context(), m_icp_regs.uart.utsr1, mem_mask); + return m_icp_regs.uart.utsr1; + case REG_HSCR0: + LOGMASKED(LOG_ICP, "%s: icp_r: HSSP Control Register 0: %08x & %08x\n", machine().describe_context(), m_icp_regs.hssp.hscr0, mem_mask); + return m_icp_regs.hssp.hscr0; + case REG_HSCR1: + LOGMASKED(LOG_ICP, "%s: icp_r: HSSP Control Register 1: %08x & %08x\n", machine().describe_context(), m_icp_regs.hssp.hscr1, mem_mask); + return m_icp_regs.hssp.hscr1; + case REG_HSDR: + { + const uint16_t data = icp_hssp_read_receive_fifo(); + LOGMASKED(LOG_ICP, "%s: icp_r: HSSP Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; + } + case REG_HSSR0: + LOGMASKED(LOG_ICP, "%s: icp_r: HSSP Status Register 0: %08x & %08x\n", machine().describe_context(), m_icp_regs.hssp.hssr0, mem_mask); + return m_icp_regs.hssp.hssr0; + case REG_HSSR1: + LOGMASKED(LOG_ICP, "%s: icp_r: HSSP Status Register 1: %08x & %08x\n", machine().describe_context(), m_icp_regs.hssp.hssr1, mem_mask); + return m_icp_regs.hssp.hssr1; + default: + LOGMASKED(LOG_ICP | LOG_UNKNOWN, "%s: icp_r: Unknown address: %08x & %08x\n", machine().describe_context(), ICP_BASE_ADDR | (offset << 2), mem_mask); + return 0; + } +} + +void sa1110_periphs_device::icp_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + switch (offset) + { + case REG_UTCR0: + { + LOGMASKED(LOG_ICP, "%s: icp_w: UART Control Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_ICP, "%s: Parity Enable: %d\n", machine().describe_context(), BIT(data, 0)); + LOGMASKED(LOG_ICP, "%s: Parity Mode: %s\n", machine().describe_context(), BIT(data, 1) ? "Even" : "Odd"); + LOGMASKED(LOG_ICP, "%s: Stop Bits: %d\n", machine().describe_context(), BIT(data, 2) + 1); + LOGMASKED(LOG_ICP, "%s: Data Size: %d\n", machine().describe_context(), BIT(data, 3) ? 8 : 7); + LOGMASKED(LOG_ICP, "%s: Sample Clock: %s\n", machine().describe_context(), BIT(data, 4) ? "External" : "Internal"); + LOGMASKED(LOG_ICP, "%s: Receive Edge: %s\n", machine().describe_context(), BIT(data, 5) ? "Falling" : "Rising"); + LOGMASKED(LOG_ICP, "%s: Transmit Edge: %s\n", machine().describe_context(), BIT(data, 6) ? "Falling" : "Rising"); + + //stop_bits_t stop_bits = (BIT(data, 2) ? STOP_BITS_2 : STOP_BITS_1); + + //parity_t parity = PARITY_NONE; + //if (BIT(data, 0)) + //{ + // parity = (BIT(data, 1) ? PARITY_EVEN : PARITY_ODD); + //} + + //set_data_frame(1, BIT(data, 3) ? 8 : 7, parity, stop_bits); + //receive_register_reset(); + //transmit_register_reset(); + + COMBINE_DATA(&m_icp_regs.uart.utcr[0]); + break; + } + case REG_UTCR1: + { + LOGMASKED(LOG_ICP, "%s: icp_w: UART Control Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_ICP, "%s: Baud Rate Divisor MSB: %02x\n", machine().describe_context(), data & 0x0f); + //const uint8_t old = m_uart_regs.utcr[1] & 0x0f; + COMBINE_DATA(&m_icp_regs.uart.utcr[1]); + //if ((m_uart_regs.utcr[1] & 0x0f) != old) + // icp_uart_recalculate_divisor(); + break; + } + case REG_UTCR2: + { + LOGMASKED(LOG_ICP, "%s: icp_w: UART Control Register 2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_ICP, "%s: Baud Rate Divisor LSB: %02x\n", machine().describe_context(), (uint8_t)data); + //const uint8_t old = m_uart_regs.utcr[2] & 0xff; + COMBINE_DATA(&m_icp_regs.uart.utcr[2]); + //if ((m_uart_regs.utcr[2] & 0xff) != old) + // icp_uart_recalculate_divisor(); + break; + } + case REG_UTCR3: + { + LOGMASKED(LOG_ICP, "%s: icp_w: UART Control Register 3 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_ICP, "%s: Receive Enable: %d\n", machine().describe_context(), BIT(data, 0)); + LOGMASKED(LOG_ICP, "%s: Transmit Enable: %d\n", machine().describe_context(), BIT(data, 1)); + LOGMASKED(LOG_ICP, "%s: Send Break: %d\n", machine().describe_context(), BIT(data, 2)); + LOGMASKED(LOG_ICP, "%s: Receive FIFO IRQ Enable: %d\n", machine().describe_context(), BIT(data, 3)); + LOGMASKED(LOG_ICP, "%s: Transmit FIFO IRQ Enable: %d\n", machine().describe_context(), BIT(data, 4)); + LOGMASKED(LOG_ICP, "%s: Loopback Enable: %d\n", machine().describe_context(), BIT(data, 5)); + const uint32_t old = m_icp_regs.uart.utcr[3]; + COMBINE_DATA(&m_icp_regs.uart.utcr[3]); + const uint32_t changed = old ^ m_icp_regs.uart.utcr[3]; + if (BIT(changed, 0)) + icp_uart_set_receiver_enabled(BIT(data, 0)); + if (BIT(changed, 1)) + icp_uart_set_transmitter_enabled(BIT(data, 1)); + if (BIT(changed, 3)) + icp_uart_set_receive_irq_enabled(BIT(data, 3)); + if (BIT(changed, 4)) + icp_uart_set_transmit_irq_enabled(BIT(data, 4)); + break; + } + case REG_UTCR4: + LOGMASKED(LOG_ICP, "%s: icp_w: UART Control Register 4 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_ICP, "%s: HP-SIR enable: %d\n", machine().describe_context(), BIT(data, UTCR4_HSE_BIT), mem_mask); + LOGMASKED(LOG_ICP, "%s: Low-Power enable: %d\n", machine().describe_context(), BIT(data, UTCR4_LPM_BIT), mem_mask); + COMBINE_DATA(&m_icp_regs.utcr4); + break; + case REG_UTDR: + LOGMASKED(LOG_ICP, "%s: icp_w: UART Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); + if (data == 0x0d || data == 0x0a || (data >= 0x20 && data < 0x7f)) + { + printf("%c", (char)data); + } + icp_uart_write_transmit_fifo((uint8_t)data); + break; + case REG_UTSR0: + LOGMASKED(LOG_ICP, "%s: icp_w: UART Status Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_ICP, "%s: Receiver Idle Status: %d\n", machine().describe_context(), BIT(data, 2)); + LOGMASKED(LOG_ICP, "%s: Receiver Begin of Break Status: %d\n", machine().describe_context(), BIT(data, 3)); + LOGMASKED(LOG_ICP, "%s: Receiver End of Break Status: %d\n", machine().describe_context(), BIT(data, 4)); + if (BIT(data, 2)) + icp_uart_set_receiver_idle(); + if (BIT(data, 3)) + icp_uart_begin_of_break(); + if (BIT(data, 4)) + icp_uart_end_of_break(); + break; + case REG_HSCR0: + LOGMASKED(LOG_ICP, "%s: icp_w: HSSP Control Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_HSCR1: + LOGMASKED(LOG_ICP, "%s: icp_w: HSSP Control Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_HSDR: + LOGMASKED(LOG_ICP, "%s: icp_w: HSSP Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); + icp_hssp_write_transmit_fifo((uint8_t)data); + break; + case REG_HSSR0: + LOGMASKED(LOG_ICP, "%s: icp_w: HSSP Status Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_HSSR1: + LOGMASKED(LOG_ICP, "%s: icp_w: HSSP Status Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + default: + LOGMASKED(LOG_ICP | LOG_UNKNOWN, "%s: icp_w: Unknown address: %08x = %08x & %08x\n", machine().describe_context(), ICP_BASE_ADDR | (offset << 2), data, mem_mask); + break; + } +} + /* Intel SA-1110 Serial Port 3 - UART @@ -140,9 +391,6 @@ void sa1110_periphs_device::uart_write_receive_fifo(uint16_t data_and_flags) m_uart_regs.rx_fifo_count++; m_uart_regs.rx_fifo_write_idx = (m_uart_regs.rx_fifo_write_idx + 1) % ARRAY_LENGTH(m_uart_regs.rx_fifo); - // update receiver-not-full flag - m_uart_regs.utsr1 |= (1 << UTSR1_RNE_BIT); - // update error flags uart_update_eif_status(); @@ -163,18 +411,20 @@ uint8_t sa1110_periphs_device::uart_read_receive_fifo() m_uart_regs.utsr1 &= ~((1 << UTSR1_PRE_BIT) | (1 << UTSR1_FRE_BIT) | (1 << UTSR1_ROR_BIT)); m_uart_regs.utsr1 |= fifo_bottom_flags << UTSR1_PRE_BIT; } - else - { - m_uart_regs.utsr1 &= ~(1 << UTSR1_RNE_BIT); - } uart_update_eif_status(); } + uart_check_rx_fifo_service(); return data; } void sa1110_periphs_device::uart_check_rx_fifo_service() { - if (m_uart_regs.rx_fifo_count > 4 && BIT(m_uart_regs.utcr[3], UTCR3_RXE_BIT)) + if (m_uart_regs.rx_fifo_count != 0) + m_uart_regs.utsr1 |= (1 << UTSR1_RNE_BIT); + else + m_uart_regs.utsr1 &= ~(1 << UTSR1_RNE_BIT); + + if (m_uart_regs.rx_fifo_count > 4) { m_uart_regs.utsr0 |= (1 << UTSR0_RFS_BIT); if (BIT(m_uart_regs.utcr[3], UTCR3_RIE_BIT)) @@ -208,19 +458,18 @@ void sa1110_periphs_device::uart_write_transmit_fifo(uint8_t data) m_uart_regs.tx_fifo_count++; m_uart_regs.tx_fifo_write_idx = (m_uart_regs.tx_fifo_write_idx + 1) % ARRAY_LENGTH(m_uart_regs.tx_fifo); - // update transmitter-not-full flag - if (m_uart_regs.tx_fifo_count == ARRAY_LENGTH(m_uart_regs.tx_fifo)) - m_uart_regs.utsr1 &= ~(1 << UTSR1_TNF_BIT); - else - m_uart_regs.utsr1 |= (1 << UTSR1_TNF_BIT); - // update FIFO-service interrupt uart_check_tx_fifo_service(); } void sa1110_periphs_device::uart_check_tx_fifo_service() { - if (m_uart_regs.tx_fifo_count <= 4 && BIT(m_uart_regs.utcr[3], UTCR3_TXE_BIT)) + if (m_uart_regs.tx_fifo_count < ARRAY_LENGTH(m_uart_regs.tx_fifo)) + m_uart_regs.utsr1 |= (1 << UTSR1_TNF_BIT); + else + m_uart_regs.utsr1 &= ~(1 << UTSR1_TNF_BIT); + + if (m_uart_regs.tx_fifo_count <= 4) { m_uart_regs.utsr0 |= (1 << UTSR0_TFS_BIT); if (BIT(m_uart_regs.utcr[3], UTCR3_TIE_BIT)) @@ -268,18 +517,18 @@ void sa1110_periphs_device::uart_set_transmitter_enabled(bool enabled) { if (enabled) { - m_uart_regs.utsr0 |= (1 << UTSR0_TFS_BIT); - m_uart3_irqs->in_w(1); + //m_uart_regs.utsr0 |= (1 << UTSR0_TFS_BIT); + //m_uart3_irqs->in_w(1); - m_uart_regs.utsr1 |= (1 << UTSR1_TNF_BIT); + //m_uart_regs.utsr1 |= (1 << UTSR1_TNF_BIT); } else { - m_uart_regs.utsr0 &= ~(1 << UTSR0_TFS_BIT); - m_uart3_irqs->in_w(0); + //m_uart_regs.utsr0 &= ~(1 << UTSR0_TFS_BIT); + //m_uart3_irqs->in_w(0); - m_uart_regs.utsr1 &= ~(1 << UTSR1_TBY_BIT); - m_uart_regs.utsr1 &= ~(1 << UTSR1_TNF_BIT); + //m_uart_regs.utsr1 &= ~(1 << UTSR1_TBY_BIT); + //m_uart_regs.utsr1 &= ~(1 << UTSR1_TNF_BIT); m_uart_regs.tx_fifo_count = 0; m_uart_regs.tx_fifo_read_idx = 0; @@ -287,6 +536,8 @@ void sa1110_periphs_device::uart_set_transmitter_enabled(bool enabled) transmit_register_reset(); } + + uart_check_tx_fifo_service(); } void sa1110_periphs_device::uart_set_receive_irq_enabled(bool enabled) @@ -302,31 +553,31 @@ uint32_t sa1110_periphs_device::uart3_r(offs_t offset, uint32_t mem_mask) switch (offset) { case REG_UTCR0: - LOGMASKED(LOG_UART, "%s: uart3_r: UART Control Register 0: %08x & %08x\n", machine().describe_context(), m_uart_regs.utcr[0], mem_mask); + LOGMASKED(LOG_UART3, "%s: uart3_r: UART Control Register 0: %08x & %08x\n", machine().describe_context(), m_uart_regs.utcr[0], mem_mask); return m_uart_regs.utcr[0]; case REG_UTCR1: - LOGMASKED(LOG_UART, "%s: uart3_r: UART Control Register 1: %08x & %08x\n", machine().describe_context(), m_uart_regs.utcr[1], mem_mask); + LOGMASKED(LOG_UART3, "%s: uart3_r: UART Control Register 1: %08x & %08x\n", machine().describe_context(), m_uart_regs.utcr[1], mem_mask); return m_uart_regs.utcr[1]; case REG_UTCR2: - LOGMASKED(LOG_UART, "%s: uart3_r: UART Control Register 2: %08x & %08x\n", machine().describe_context(), m_uart_regs.utcr[2], mem_mask); + LOGMASKED(LOG_UART3, "%s: uart3_r: UART Control Register 2: %08x & %08x\n", machine().describe_context(), m_uart_regs.utcr[2], mem_mask); return m_uart_regs.utcr[2]; case REG_UTCR3: - LOGMASKED(LOG_UART, "%s: uart3_r: UART Control Register 3: %08x & %08x\n", machine().describe_context(), m_uart_regs.utcr[3], mem_mask); + LOGMASKED(LOG_UART3, "%s: uart3_r: UART Control Register 3: %08x & %08x\n", machine().describe_context(), m_uart_regs.utcr[3], mem_mask); return m_uart_regs.utcr[3]; case REG_UTDR: { const uint8_t data = uart_read_receive_fifo(); - LOGMASKED(LOG_UART, "%s: uart3_r: UART Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_UART3, "%s: uart3_r: UART Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); return data; } case REG_UTSR0: - LOGMASKED(LOG_UART_HF, "%s: uart3_r: UART Status Register 0: %08x & %08x\n", machine().describe_context(), m_uart_regs.utsr0, mem_mask); + LOGMASKED(LOG_UART3, "%s: uart3_r: UART Status Register 0: %08x & %08x\n", machine().describe_context(), m_uart_regs.utsr0, mem_mask); return m_uart_regs.utsr0; case REG_UTSR1: - LOGMASKED(LOG_UART_HF, "%s: uart3_r: UART Status Register 1: %08x & %08x\n", machine().describe_context(), m_uart_regs.utsr1, mem_mask); + LOGMASKED(LOG_UART3, "%s: uart3_r: UART Status Register 1: %08x & %08x\n", machine().describe_context(), m_uart_regs.utsr1, mem_mask); return m_uart_regs.utsr1; default: - LOGMASKED(LOG_UART | LOG_UNKNOWN, "%s: uart3_r: Unknown address: %08x & %08x\n", machine().describe_context(), UART_BASE_ADDR | (offset << 2), mem_mask); + LOGMASKED(LOG_UART3 | LOG_UNKNOWN, "%s: uart3_r: Unknown address: %08x & %08x\n", machine().describe_context(), UART_BASE_ADDR | (offset << 2), mem_mask); return 0; } } @@ -337,14 +588,14 @@ void sa1110_periphs_device::uart3_w(offs_t offset, uint32_t data, uint32_t mem_m { case REG_UTCR0: { - LOGMASKED(LOG_UART, "%s: uart3_w: UART Control Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask); - LOGMASKED(LOG_UART, "%s: Parity Enable: %d\n", machine().describe_context(), BIT(data, 0)); - LOGMASKED(LOG_UART, "%s: Parity Mode: %s\n", machine().describe_context(), BIT(data, 1) ? "Even" : "Odd"); - LOGMASKED(LOG_UART, "%s: Stop Bits: %d\n", machine().describe_context(), BIT(data, 2) + 1); - LOGMASKED(LOG_UART, "%s: Data Size: %d\n", machine().describe_context(), BIT(data, 3) ? 8 : 7); - LOGMASKED(LOG_UART, "%s: Sample Clock: %s\n", machine().describe_context(), BIT(data, 4) ? "External" : "Internal"); - LOGMASKED(LOG_UART, "%s: Receive Edge: %s\n", machine().describe_context(), BIT(data, 5) ? "Falling" : "Rising"); - LOGMASKED(LOG_UART, "%s: Transmit Edge: %s\n", machine().describe_context(), BIT(data, 6) ? "Falling" : "Rising"); + LOGMASKED(LOG_UART3, "%s: uart3_w: UART Control Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_UART3, "%s: Parity Enable: %d\n", machine().describe_context(), BIT(data, 0)); + LOGMASKED(LOG_UART3, "%s: Parity Mode: %s\n", machine().describe_context(), BIT(data, 1) ? "Even" : "Odd"); + LOGMASKED(LOG_UART3, "%s: Stop Bits: %d\n", machine().describe_context(), BIT(data, 2) + 1); + LOGMASKED(LOG_UART3, "%s: Data Size: %d\n", machine().describe_context(), BIT(data, 3) ? 8 : 7); + LOGMASKED(LOG_UART3, "%s: Sample Clock: %s\n", machine().describe_context(), BIT(data, 4) ? "External" : "Internal"); + LOGMASKED(LOG_UART3, "%s: Receive Edge: %s\n", machine().describe_context(), BIT(data, 5) ? "Falling" : "Rising"); + LOGMASKED(LOG_UART3, "%s: Transmit Edge: %s\n", machine().describe_context(), BIT(data, 6) ? "Falling" : "Rising"); stop_bits_t stop_bits = (BIT(data, 2) ? STOP_BITS_2 : STOP_BITS_1); @@ -363,8 +614,8 @@ void sa1110_periphs_device::uart3_w(offs_t offset, uint32_t data, uint32_t mem_m } case REG_UTCR1: { - LOGMASKED(LOG_UART, "%s: uart3_w: UART Control Register 1: %08x & %08x\n", machine().describe_context(), data, mem_mask); - LOGMASKED(LOG_UART, "%s: Baud Rate Divisor MSB: %02x\n", machine().describe_context(), data & 0x0f); + LOGMASKED(LOG_UART3, "%s: uart3_w: UART Control Register 1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_UART3, "%s: Baud Rate Divisor MSB: %02x\n", machine().describe_context(), data & 0x0f); const uint8_t old = m_uart_regs.utcr[1] & 0x0f; COMBINE_DATA(&m_uart_regs.utcr[1]); if ((m_uart_regs.utcr[1] & 0x0f) != old) @@ -373,8 +624,8 @@ void sa1110_periphs_device::uart3_w(offs_t offset, uint32_t data, uint32_t mem_m } case REG_UTCR2: { - LOGMASKED(LOG_UART, "%s: uart3_w: UART Control Register 2: %08x & %08x\n", machine().describe_context(), data, mem_mask); - LOGMASKED(LOG_UART, "%s: Baud Rate Divisor LSB: %02x\n", machine().describe_context(), (uint8_t)data); + LOGMASKED(LOG_UART3, "%s: uart3_w: UART Control Register 2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_UART3, "%s: Baud Rate Divisor LSB: %02x\n", machine().describe_context(), (uint8_t)data); const uint8_t old = m_uart_regs.utcr[2] & 0xff; COMBINE_DATA(&m_uart_regs.utcr[2]); if ((m_uart_regs.utcr[2] & 0xff) != old) @@ -383,13 +634,13 @@ void sa1110_periphs_device::uart3_w(offs_t offset, uint32_t data, uint32_t mem_m } case REG_UTCR3: { - LOGMASKED(LOG_UART, "%s: uart3_w: UART Control Register 3: %08x & %08x\n", machine().describe_context(), data, mem_mask); - LOGMASKED(LOG_UART, "%s: Receive Enable: %d\n", machine().describe_context(), BIT(data, 0)); - LOGMASKED(LOG_UART, "%s: Transmit Enable: %d\n", machine().describe_context(), BIT(data, 1)); - LOGMASKED(LOG_UART, "%s: Send Break: %d\n", machine().describe_context(), BIT(data, 2)); - LOGMASKED(LOG_UART, "%s: Receive FIFO IRQ Enable: %d\n", machine().describe_context(), BIT(data, 3)); - LOGMASKED(LOG_UART, "%s: Transmit FIFO IRQ Enable: %d\n", machine().describe_context(), BIT(data, 4)); - LOGMASKED(LOG_UART, "%s: Loopback Enable: %d\n", machine().describe_context(), BIT(data, 5)); + LOGMASKED(LOG_UART3, "%s: uart3_w: UART Control Register 3 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_UART3, "%s: Receive Enable: %d\n", machine().describe_context(), BIT(data, 0)); + LOGMASKED(LOG_UART3, "%s: Transmit Enable: %d\n", machine().describe_context(), BIT(data, 1)); + LOGMASKED(LOG_UART3, "%s: Send Break: %d\n", machine().describe_context(), BIT(data, 2)); + LOGMASKED(LOG_UART3, "%s: Receive FIFO IRQ Enable: %d\n", machine().describe_context(), BIT(data, 3)); + LOGMASKED(LOG_UART3, "%s: Transmit FIFO IRQ Enable: %d\n", machine().describe_context(), BIT(data, 4)); + LOGMASKED(LOG_UART3, "%s: Loopback Enable: %d\n", machine().describe_context(), BIT(data, 5)); const uint32_t old = m_uart_regs.utcr[3]; COMBINE_DATA(&m_uart_regs.utcr[3]); const uint32_t changed = old ^ m_uart_regs.utcr[3]; @@ -404,7 +655,7 @@ void sa1110_periphs_device::uart3_w(offs_t offset, uint32_t data, uint32_t mem_m break; } case REG_UTDR: - LOGMASKED(LOG_UART, "%s: uart3_w: UART Data Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_UART3, "%s: uart3_w: UART Data Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); if (data == 0x0d || data == 0x0a || (data >= 0x20 && data < 0x7f)) { printf("%c", (char)data); @@ -412,10 +663,10 @@ void sa1110_periphs_device::uart3_w(offs_t offset, uint32_t data, uint32_t mem_m uart_write_transmit_fifo((uint8_t)data); break; case REG_UTSR0: - LOGMASKED(LOG_UART, "%s: uart3_w: UART Status Register 0: %08x & %08x\n", machine().describe_context(), data, mem_mask); - LOGMASKED(LOG_UART, "%s: Receiver Idle Status: %d\n", machine().describe_context(), BIT(data, 2)); - LOGMASKED(LOG_UART, "%s: Receiver Begin of Break Status: %d\n", machine().describe_context(), BIT(data, 3)); - LOGMASKED(LOG_UART, "%s: Receiver End of Break Status: %d\n", machine().describe_context(), BIT(data, 4)); + LOGMASKED(LOG_UART3, "%s: uart3_w: UART Status Register 0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_UART3, "%s: Receiver Idle Status: %d\n", machine().describe_context(), BIT(data, 2)); + LOGMASKED(LOG_UART3, "%s: Receiver Begin of Break Status: %d\n", machine().describe_context(), BIT(data, 3)); + LOGMASKED(LOG_UART3, "%s: Receiver End of Break Status: %d\n", machine().describe_context(), BIT(data, 4)); if (BIT(data, 2)) uart_set_receiver_idle(); if (BIT(data, 3)) @@ -424,7 +675,7 @@ void sa1110_periphs_device::uart3_w(offs_t offset, uint32_t data, uint32_t mem_m uart_end_of_break(); break; default: - LOGMASKED(LOG_UART | LOG_UNKNOWN, "%s: uart3_w: Unknown address: %08x = %08x & %08x\n", machine().describe_context(), UART_BASE_ADDR | (offset << 2), data, mem_mask); + LOGMASKED(LOG_UART3 | LOG_UNKNOWN, "%s: uart3_w: Unknown address: %08x = %08x & %08x\n", machine().describe_context(), UART_BASE_ADDR | (offset << 2), data, mem_mask); break; } } @@ -1198,7 +1449,7 @@ uint32_t sa1110_periphs_device::rtc_r(offs_t offset, uint32_t mem_mask) LOGMASKED(LOG_RTC, "%s: rtc_r: RTC Alarm Register: %08x & %08x\n", machine().describe_context(), m_rtc_regs.rtar, mem_mask); return m_rtc_regs.rtar; case REG_RCNR: - LOGMASKED(LOG_RTC, "%s: rtc_r: RTC Count Register: %08x & %08x\n", machine().describe_context(), m_rtc_regs.rcnr, mem_mask); + LOGMASKED(LOG_RTC_HF, "%s: rtc_r: RTC Count Register: %08x & %08x\n", machine().describe_context(), m_rtc_regs.rcnr, mem_mask); return m_rtc_regs.rcnr; case REG_RTTR: LOGMASKED(LOG_RTC, "%s: rtc_r: RTC Timer Trim Register: %08x & %08x\n", machine().describe_context(), m_rtc_regs.rttr, mem_mask); @@ -1276,7 +1527,7 @@ uint32_t sa1110_periphs_device::power_r(offs_t offset, uint32_t mem_mask) LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Sleep Status Register: %08x & %08x\n", machine().describe_context(), m_power_regs.pssr, mem_mask); return m_power_regs.pssr; case REG_PSPR: - LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Scratch Pad Register: %08x & %08x\n", machine().describe_context(), m_power_regs.pspr, mem_mask); + LOGMASKED(LOG_POWER_HF, "%s: power_r: Power Manager Scratch Pad Register: %08x & %08x\n", machine().describe_context(), m_power_regs.pspr, mem_mask); return m_power_regs.pspr; case REG_PWER: LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Wake-up Enable Register: %08x & %08x\n", machine().describe_context(), m_power_regs.pwer, mem_mask); @@ -1312,7 +1563,7 @@ void sa1110_periphs_device::power_w(offs_t offset, uint32_t data, uint32_t mem_m m_power_regs.pssr &= ~(data & 0x0000001f); break; case REG_PSPR: - LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Scratch Pad Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_POWER_HF, "%s: power_w: Power Manager Scratch Pad Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_power_regs.pspr); break; case REG_PWER: @@ -1398,6 +1649,7 @@ void sa1110_periphs_device::gpio_in(const uint32_t line, const int state) m_gpio_regs.input_latch &= ~mask; m_gpio_regs.input_latch |= (state << line); + LOGMASKED(LOG_GPIO, "gpio_in: Line %d, state %d\n", line, state); if (old_latch != m_gpio_regs.input_latch && !BIT(m_gpio_regs.gafr, line)) { // TODO: The manual is unclear if edge detection functions on both inputs and outputs. @@ -1414,6 +1666,7 @@ void sa1110_periphs_device::gpio_in(const uint32_t line, const int state) } m_gpio_regs.gplr = (m_gpio_regs.input_latch & ~m_gpio_regs.gafr) | (m_gpio_regs.alt_input_latch & m_gpio_regs.gafr); + LOGMASKED(LOG_GPIO, "gpio_in: New GPLR: %08x\n", m_gpio_regs.gplr); } } @@ -1557,7 +1810,7 @@ void sa1110_periphs_device::gpio_w(offs_t offset, uint32_t data, uint32_t mem_ma const uint32_t old = m_gpio_regs.gedr; m_gpio_regs.gedr &= ~(data & mem_mask); if (old != m_gpio_regs.gedr) - gpio_update_interrupts(old); + gpio_update_interrupts(old ^ m_gpio_regs.gedr); break; } case REG_GAFR: @@ -1566,7 +1819,7 @@ void sa1110_periphs_device::gpio_w(offs_t offset, uint32_t data, uint32_t mem_ma const uint32_t old = m_gpio_regs.gafr; COMBINE_DATA(&m_gpio_regs.gafr); if (old != m_gpio_regs.gafr) - gpio_update_alternate_pins(old); + gpio_update_alternate_pins(old ^ m_gpio_regs.gafr); break; } default: @@ -1649,11 +1902,11 @@ void sa1110_periphs_device::intc_w(offs_t offset, uint32_t data, uint32_t mem_ma switch (offset) { case REG_ICIP: - LOGMASKED(LOG_INTC, "%s: intc_w: (Invalid Write) Interrupt Controller IRQ Pending Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_INTC, "%s: intc_w: (Invalid Write) Interrupt Controller IRQ Pending Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_ICMR: { - LOGMASKED(LOG_INTC, "%s: intc_w: Interrupt Controller Mask Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_INTC, "%s: intc_w: Interrupt Controller Mask Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); const uint32_t old = m_intc_regs.icmr; COMBINE_DATA(&m_intc_regs.icmr); if (old != m_intc_regs.icmr) @@ -1662,7 +1915,7 @@ void sa1110_periphs_device::intc_w(offs_t offset, uint32_t data, uint32_t mem_ma } case REG_ICLR: { - LOGMASKED(LOG_INTC, "%s: intc_w: Interrupt Controller Level Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_INTC, "%s: intc_w: Interrupt Controller Level Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); const uint32_t old = m_intc_regs.iclr; COMBINE_DATA(&m_intc_regs.iclr); if (old != m_intc_regs.iclr) @@ -1670,13 +1923,13 @@ void sa1110_periphs_device::intc_w(offs_t offset, uint32_t data, uint32_t mem_ma break; } case REG_ICFP: - LOGMASKED(LOG_INTC, "%s: intc_w: (Invalid Write) Interrupt Controller FIQ Pending Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_INTC, "%s: intc_w: (Invalid Write) Interrupt Controller FIQ Pending Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_ICPR: - LOGMASKED(LOG_INTC, "%s: intc_w: (Invalid Write) Interrupt Controller Pending Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_INTC, "%s: intc_w: (Invalid Write) Interrupt Controller Pending Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); break; case REG_ICCR: - LOGMASKED(LOG_INTC, "%s: intc_w: Interrupt Controller Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + LOGMASKED(LOG_INTC, "%s: intc_w: Interrupt Controller Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); m_intc_regs.iccr = BIT(data, 0); break; default: @@ -1685,8 +1938,292 @@ void sa1110_periphs_device::intc_w(offs_t offset, uint32_t data, uint32_t mem_ma } } +/* + + Intel SA-1110 Peripheral Pin Controller + + pg. 347 to 357 Intel StrongARM SA-1110 Microprocessor Developer's Manual + +*/ + +uint32_t sa1110_periphs_device::ppc_r(offs_t offset, uint32_t mem_mask) +{ + switch (offset) + { + case REG_PPDR: + LOGMASKED(LOG_PPC, "%s: ppc_r: PPC Pin Direction Register: %08x & %08x\n", machine().describe_context(), m_ppc_regs.ppdr, mem_mask); + return m_ppc_regs.ppdr; + case REG_PPSR: + LOGMASKED(LOG_PPC, "%s: ppc_r: PPC Pin State Register: %08x & %08x\n", machine().describe_context(), m_ppc_regs.ppsr, mem_mask); + return m_ppc_regs.ppsr; + case REG_PPAR: + LOGMASKED(LOG_PPC, "%s: ppc_r: PPC Pin Assignment Register: %08x & %08x\n", machine().describe_context(), m_ppc_regs.ppar, mem_mask); + return m_ppc_regs.ppar; + case REG_PSDR: + LOGMASKED(LOG_PPC, "%s: ppc_r: PPC Sleep Mode Direction Register: %08x & %08x\n", machine().describe_context(), m_ppc_regs.psdr, mem_mask); + return m_ppc_regs.psdr; + case REG_PPFR: + LOGMASKED(LOG_PPC, "%s: ppc_r: PPC Pin Flag Register: %08x & %08x\n", machine().describe_context(), m_ppc_regs.ppfr, mem_mask); + return m_ppc_regs.ppfr; + default: + LOGMASKED(LOG_PPC | LOG_UNKNOWN, "%s: ppc_r: Unknown address: %08x & %08x\n", machine().describe_context(), PPC_BASE_ADDR | (offset << 2), mem_mask); + return 0; + } +} + +void sa1110_periphs_device::ppc_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + switch (offset) + { + case REG_PPDR: + { + LOGMASKED(LOG_PPC, "%s: ppc_w: PPC Pin Direction Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); + COMBINE_DATA(&m_ppc_regs.ppdr); + //const uint32_t old_ppsr = m_ppc_regs.ppsr; + m_ppc_regs.ppsr = (m_ppc_regs.ppsr_out & m_ppc_regs.ppdr) | (m_ppc_regs.ppsr_in & ~m_ppc_regs.ppdr); + //const uint32_t changed_states = old_ppsr ^ m_ppc_regs.ppsr; + //if (changed_states) + //{ + //} + break; + } + case REG_PPSR: + { + LOGMASKED(LOG_PPC, "%s: ppc_w: PPC Pin State Register = %08x & %08x\n", machine().describe_context(), data, mem_mask); + //const uint32_t old_latch = m_ppc_regs.ppsr_out; + COMBINE_DATA(&m_ppc_regs.ppsr_out); + m_ppc_regs.ppsr = (m_ppc_regs.ppsr_out & m_ppc_regs.ppdr) | (m_ppc_regs.ppsr_in & ~m_ppc_regs.ppdr); + //const uint32_t changed_outputs = (old ^ m_ppc_regs.ppsr_out) & m_ppc_regs.ppdr; + //if (changed_outputs) + //{ + // Do stuff + //} + break; + } + case REG_PPAR: + LOGMASKED(LOG_PPC, "%s: ppc_w: PPC Pin Assignment Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + COMBINE_DATA(&m_ppc_regs.ppar); + break; + case REG_PSDR: + LOGMASKED(LOG_PPC, "%s: ppc_w: PPC Sleep Mode Direction Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + COMBINE_DATA(&m_ppc_regs.psdr); + break; + case REG_PPFR: + LOGMASKED(LOG_PPC, "%s: ppc_w: PPC Pin Flag Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); + COMBINE_DATA(&m_ppc_regs.ppfr); + break; + default: + LOGMASKED(LOG_PPC | LOG_UNKNOWN, "%s: ppc_w: Unknown address: %08x = %08x & %08x\n", machine().describe_context(), PPC_BASE_ADDR | (offset << 2), data, mem_mask); + break; + } +} + +/* + + Intel SA-1110 Peripheral Pin Controller + + pg. 186 to 194 Intel StrongARM SA-1110 Microprocessor Developer's Manual + +*/ + +void sa1110_periphs_device::dma_set_control_bits(int channel, uint32_t bits) +{ + dma_regs ®s = m_dma_regs[channel]; + const uint32_t old = regs.dsr; + regs.dsr |= bits; + const uint32_t newly_set = ~old & bits; + if (newly_set == 0) + return; + + const uint32_t irq_mask = (1 << DSR_ERROR_BIT) | (1 << DSR_DONEA_BIT) | (1 << DSR_DONEB_BIT); + + if (BIT(newly_set, DSR_RUN_BIT)) + regs.dsr &= ~(1 << DSR_ERROR_BIT); + if (BIT(newly_set, DSR_DONEA_BIT) || BIT(newly_set, DSR_STRTA_BIT)) + regs.dsr &= ~(1 << DSR_DONEA_BIT); + if (BIT(newly_set, DSR_DONEB_BIT) || BIT(newly_set, DSR_STRTB_BIT)) + regs.dsr &= ~(1 << DSR_DONEB_BIT); + + if (regs.ddar == 0x81400580 && BIT(regs.dsr, DSR_RUN_BIT)) + { + const uint32_t buf = BIT(regs.dsr, DSR_BIU_BIT); + const uint32_t count = regs.dbt[buf]; + if (count) + { + const uint32_t start_mask = (buf ? (1 << DSR_STRTB_BIT) : (1 << DSR_STRTA_BIT)); + const uint32_t done_mask = (buf ? (1 << DSR_DONEB_BIT) : (1 << DSR_DONEA_BIT)); + const uint32_t addr = regs.dbs[buf]; + address_space &space = m_maincpu->space(AS_PROGRAM); + if (regs.dsr & start_mask) + { + for (uint32_t i = 0; i < count; i++) + { + const uint8_t value = space.read_byte(addr + i); + if (value == 0x0d || value == 0x0a || (value >= 0x20 && value < 0x7f)) + { + printf("%c", (char)value); + } + } + printf("\n"); + regs.dsr &= ~start_mask; + regs.dsr |= done_mask; + regs.dsr ^= (1 << DSR_BIU_BIT); + } + } + } + + set_irq_line(INT_DMA0 + channel, (BIT(regs.dsr, DSR_IE_BIT) && (regs.dsr & irq_mask)) ? 1 : 0); +} + +void sa1110_periphs_device::dma_clear_control_bits(int channel, uint32_t bits) +{ + dma_regs ®s = m_dma_regs[channel]; + + const uint32_t irq_mask = (1 << DSR_ERROR_BIT) | (1 << DSR_DONEA_BIT) | (1 << DSR_DONEB_BIT); + + regs.dsr &= ~bits; + set_irq_line(INT_DMA0 + channel, (BIT(regs.dsr, DSR_IE_BIT) && (regs.dsr & irq_mask)) ? 1 : 0); +} + +uint32_t sa1110_periphs_device::dma_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t channel = (offset >> 3) & 7; + if (channel < 6) + { + switch (offset & 7) + { + case REG_DDAR: + LOGMASKED(LOG_DMA, "%s: dma_r: DMA%d Device Address Register: %08x & %08x\n", machine().describe_context(), channel, m_dma_regs[channel].ddar, mem_mask); + return m_dma_regs[channel].ddar; + case REG_DSSR: + case REG_DCSR: + case REG_DSR: + LOGMASKED(LOG_DMA, "%s: dma_r: DMA%d Control/Status Register: %08x & %08x\n", machine().describe_context(), channel, m_dma_regs[channel].dsr, mem_mask); + return m_dma_regs[channel].dsr; + case REG_DBSA: + LOGMASKED(LOG_DMA, "%s: dma_r: DMA%d Buffer A Start Address: %08x & %08x\n", machine().describe_context(), channel, m_dma_regs[channel].dbs[0], mem_mask); + return m_dma_regs[channel].dbs[0]; + case REG_DBTA: + LOGMASKED(LOG_DMA, "%s: dma_r: DMA%d Buffer A Transfer Count: %08x & %08x\n", machine().describe_context(), channel, m_dma_regs[channel].dbt[0], mem_mask); + return m_dma_regs[channel].dbt[0]; + case REG_DBSB: + LOGMASKED(LOG_DMA, "%s: dma_r: DMA%d Buffer B Start Address: %08x & %08x\n", machine().describe_context(), channel, m_dma_regs[channel].dbs[1], mem_mask); + return m_dma_regs[channel].dbs[1]; + case REG_DBTB: + LOGMASKED(LOG_DMA, "%s: dma_r: DMA%d Buffer B Transfer Count: %08x & %08x\n", machine().describe_context(), channel, m_dma_regs[channel].dbt[1], mem_mask); + return m_dma_regs[channel].dbt[1]; + default: + LOGMASKED(LOG_DMA | LOG_UNKNOWN, "%s: dma_r: Unknown address: %08x & %08x\n", machine().describe_context(), DMA_BASE_ADDR | (offset << 2), mem_mask); + return 0; + } + } + return 0; +} + +void sa1110_periphs_device::dma_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + uint32_t channel = (offset >> 3) & 7; + if (channel < 6) + { + switch (offset & 7) + { + case REG_DDAR: + LOGMASKED(LOG_DMA, "%s: dma_w: DMA%d Device Address Register = %08x & %08x\n", machine().describe_context(), channel, data, mem_mask); + COMBINE_DATA(&m_dma_regs[channel].ddar); + break; + case REG_DSSR: + LOGMASKED(LOG_DMA, "%s: dma_w: DMA%d Control/Status Register (1S) = %08x & %08x\n", machine().describe_context(), channel, data, mem_mask); + LOGMASKED(LOG_DMA, "%s: Run Set: %d\n", machine().describe_context(), BIT(data, DSR_RUN_BIT)); + LOGMASKED(LOG_DMA, "%s: Interrupt Enable Set: %d\n", machine().describe_context(), BIT(data, DSR_IE_BIT)); + LOGMASKED(LOG_DMA, "%s: Error Set: %d\n", machine().describe_context(), BIT(data, DSR_ERROR_BIT)); + LOGMASKED(LOG_DMA, "%s: Done A Set: %d\n", machine().describe_context(), BIT(data, DSR_DONEA_BIT)); + LOGMASKED(LOG_DMA, "%s: Start A Set: %d\n", machine().describe_context(), BIT(data, DSR_STRTA_BIT)); + LOGMASKED(LOG_DMA, "%s: Done B Set: %d\n", machine().describe_context(), BIT(data, DSR_DONEB_BIT)); + LOGMASKED(LOG_DMA, "%s: Start B Set: %d\n", machine().describe_context(), BIT(data, DSR_STRTB_BIT)); + LOGMASKED(LOG_DMA, "%s: Buffer In Use Set: %d\n", machine().describe_context(), BIT(data, DSR_BIU_BIT)); + dma_set_control_bits(channel, data & mem_mask); + break; + case REG_DCSR: + LOGMASKED(LOG_DMA, "%s: dma_w: DMA%d Control/Status Register (1C) = %08x & %08x\n", machine().describe_context(), channel, data, mem_mask); + LOGMASKED(LOG_DMA, "%s: Run Clear: %d\n", machine().describe_context(), BIT(data, DSR_RUN_BIT)); + LOGMASKED(LOG_DMA, "%s: Interrupt Enable Clear: %d\n", machine().describe_context(), BIT(data, DSR_IE_BIT)); + LOGMASKED(LOG_DMA, "%s: Error Clear: %d\n", machine().describe_context(), BIT(data, DSR_ERROR_BIT)); + LOGMASKED(LOG_DMA, "%s: Done A Clear: %d\n", machine().describe_context(), BIT(data, DSR_DONEA_BIT)); + LOGMASKED(LOG_DMA, "%s: Start A Clear: %d\n", machine().describe_context(), BIT(data, DSR_STRTA_BIT)); + LOGMASKED(LOG_DMA, "%s: Done B Clear: %d\n", machine().describe_context(), BIT(data, DSR_DONEB_BIT)); + LOGMASKED(LOG_DMA, "%s: Start B Clear: %d\n", machine().describe_context(), BIT(data, DSR_STRTB_BIT)); + LOGMASKED(LOG_DMA, "%s: Buffer In Use Clear: %d\n", machine().describe_context(), BIT(data, DSR_BIU_BIT)); + dma_clear_control_bits(channel, data & mem_mask); + break; + case REG_DSR: + LOGMASKED(LOG_DMA, "%s: dma_w: DMA%d Control/Status Register (RO) = %08x & %08x\n", machine().describe_context(), channel, data, mem_mask); + break; + case REG_DBSA: + LOGMASKED(LOG_DMA, "%s: dma_w: DMA%d Buffer A Start Address = %08x & %08x\n", machine().describe_context(), channel, data, mem_mask); + if (!BIT(m_dma_regs[channel].dsr, DSR_STRTA_BIT)) + COMBINE_DATA(&m_dma_regs[channel].dbs[0]); + break; + case REG_DBTA: + LOGMASKED(LOG_DMA, "%s: dma_w: DMA%d Buffer A Transfer Count = %08x & %08x\n", machine().describe_context(), channel, data, mem_mask); + if (!BIT(m_dma_regs[channel].dsr, DSR_STRTA_BIT)) + { + COMBINE_DATA(&m_dma_regs[channel].dbt[0]); + m_dma_regs[channel].dbt[0] &= DBT_MASK; + } + break; + case REG_DBSB: + LOGMASKED(LOG_DMA, "%s: dma_w: DMA%d Buffer B Start Address = %08x & %08x\n", machine().describe_context(), channel, data, mem_mask); + if (!BIT(m_dma_regs[channel].dsr, DSR_STRTB_BIT)) + COMBINE_DATA(&m_dma_regs[channel].dbs[1]); + break; + case REG_DBTB: + LOGMASKED(LOG_DMA, "%s: dma_w: DMA%d Buffer B Transfer Count = %08x & %08x\n", machine().describe_context(), channel, data, mem_mask); + if (!BIT(m_dma_regs[channel].dsr, DSR_STRTB_BIT)) + { + COMBINE_DATA(&m_dma_regs[channel].dbt[1]); + m_dma_regs[channel].dbt[1] &= DBT_MASK; + } + break; + default: + LOGMASKED(LOG_DMA | LOG_UNKNOWN, "%s: dma_w: Unknown address %08x = %08x & %08x\n", machine().describe_context(), DMA_BASE_ADDR | (offset << 2), data, mem_mask); + break; + } + } +} + void sa1110_periphs_device::device_start() { + save_item(NAME(m_icp_regs.uart.utcr)); + save_item(NAME(m_icp_regs.uart.utsr0)); + save_item(NAME(m_icp_regs.uart.utsr1)); + save_item(NAME(m_icp_regs.uart.rx_fifo)); + save_item(NAME(m_icp_regs.uart.rx_fifo_read_idx)); + save_item(NAME(m_icp_regs.uart.rx_fifo_write_idx)); + save_item(NAME(m_icp_regs.uart.rx_fifo_count)); + m_icp_regs.uart_rx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sa1110_periphs_device::icp_rx_callback), this)); + save_item(NAME(m_icp_regs.uart.tx_fifo)); + save_item(NAME(m_icp_regs.uart.tx_fifo_read_idx)); + save_item(NAME(m_icp_regs.uart.tx_fifo_write_idx)); + save_item(NAME(m_icp_regs.uart.tx_fifo_count)); + m_icp_regs.uart_tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sa1110_periphs_device::icp_tx_callback), this)); + save_item(NAME(m_icp_regs.uart.rx_break_interlock)); + + save_item(NAME(m_icp_regs.utcr4)); + save_item(NAME(m_icp_regs.hssp.hscr0)); + save_item(NAME(m_icp_regs.hssp.hscr1)); + save_item(NAME(m_icp_regs.hssp.hssr0)); + save_item(NAME(m_icp_regs.hssp.hssr1)); + save_item(NAME(m_icp_regs.hssp.rx_fifo)); + save_item(NAME(m_icp_regs.hssp.rx_fifo_read_idx)); + save_item(NAME(m_icp_regs.hssp.rx_fifo_write_idx)); + save_item(NAME(m_icp_regs.hssp.rx_fifo_count)); + m_icp_regs.hssp.rx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sa1110_periphs_device::hssp_rx_callback), this)); + save_item(NAME(m_icp_regs.hssp.tx_fifo)); + save_item(NAME(m_icp_regs.hssp.tx_fifo_read_idx)); + save_item(NAME(m_icp_regs.hssp.tx_fifo_write_idx)); + save_item(NAME(m_icp_regs.hssp.tx_fifo_count)); + m_icp_regs.hssp.tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sa1110_periphs_device::hssp_tx_callback), this)); + save_item(NAME(m_uart_regs.utcr)); save_item(NAME(m_uart_regs.utsr0)); save_item(NAME(m_uart_regs.utsr1)); @@ -1783,6 +2320,18 @@ void sa1110_periphs_device::device_start() save_item(NAME(m_intc_regs.icfp)); save_item(NAME(m_intc_regs.icpr)); + save_item(NAME(m_ppc_regs.ppdr)); + save_item(NAME(m_ppc_regs.ppsr)); + save_item(NAME(m_ppc_regs.ppar)); + save_item(NAME(m_ppc_regs.psdr)); + save_item(NAME(m_ppc_regs.ppfr)); + + save_item(STRUCT_MEMBER(m_dma_regs, ddar)); + save_item(STRUCT_MEMBER(m_dma_regs, dsr)); + save_item(STRUCT_MEMBER(m_dma_regs, dbs)); + save_item(STRUCT_MEMBER(m_dma_regs, dbt)); + save_item(NAME(m_dma_active_mask)); + m_gpio_out.resolve_all_safe(); m_ssp_out.resolve_safe(); m_uart3_tx_out.resolve_safe(); @@ -1790,6 +2339,38 @@ void sa1110_periphs_device::device_start() void sa1110_periphs_device::device_reset() { + // init ICP + memset(m_icp_regs.uart.utcr, 0, sizeof(uint32_t) * 4); + m_icp_regs.uart.utsr0 = 0; + m_icp_regs.uart.utsr1 = 0; + memset(m_icp_regs.uart.rx_fifo, 0, sizeof(uint16_t) * 12); + m_icp_regs.uart.rx_fifo_read_idx = 0; + m_icp_regs.uart.rx_fifo_write_idx = 0; + m_icp_regs.uart.rx_fifo_count = 0; + m_icp_regs.uart_rx_timer->adjust(attotime::never); + memset(m_icp_regs.uart.tx_fifo, 0, 8); + m_icp_regs.uart.tx_fifo_read_idx = 0; + m_icp_regs.uart.tx_fifo_write_idx = 0; + m_icp_regs.uart.tx_fifo_count = 0; + m_icp_regs.uart_tx_timer->adjust(attotime::never); + m_icp_regs.uart.rx_break_interlock = false; + + m_icp_regs.utcr4 = 0; + m_icp_regs.hssp.hscr0 = 0; + m_icp_regs.hssp.hscr1 = 0; + m_icp_regs.hssp.hssr0 = 0; + m_icp_regs.hssp.hssr1 = 0; + memset(m_icp_regs.hssp.rx_fifo, 0, sizeof(uint16_t) * 8); + m_icp_regs.hssp.rx_fifo_read_idx = 0; + m_icp_regs.hssp.rx_fifo_write_idx = 0; + m_icp_regs.hssp.rx_fifo_count = 0; + m_icp_regs.hssp.rx_timer->adjust(attotime::never); + memset(m_icp_regs.hssp.tx_fifo, 0, sizeof(uint16_t) * 8); + m_icp_regs.hssp.tx_fifo_read_idx = 0; + m_icp_regs.hssp.tx_fifo_write_idx = 0; + m_icp_regs.hssp.tx_fifo_count = 0; + m_icp_regs.hssp.tx_timer->adjust(attotime::never); + // init UART3 memset(m_uart_regs.utcr, 0, sizeof(uint32_t) * 4); m_uart_regs.utsr0 = 0; @@ -1868,10 +2449,28 @@ void sa1110_periphs_device::device_reset() memset(&m_power_regs, 0, sizeof(m_power_regs)); m_power_regs.posr = 1; // flag oscillator OK + // init PPC regs + m_ppc_regs.ppdr = 0; + m_ppc_regs.ppsr = 0; + m_ppc_regs.ppar = 0; + m_ppc_regs.psdr = 0x003fffff; + m_ppc_regs.ppfr = 0x0007f001; + + // init DMA regs + for (int channel = 0; channel < 6; channel++) + { + m_dma_regs[channel].ddar = 0; + m_dma_regs[channel].dsr = 0; + memset(m_dma_regs[channel].dbs, 0, sizeof(uint32_t) * 2); + memset(m_dma_regs[channel].dbt, 0, sizeof(uint32_t) * 2); + } // bulk-init other registers m_rcsr = 0x00000001; // indicate hardware reset memset(&m_gpio_regs, 0, sizeof(m_gpio_regs)); memset(&m_intc_regs, 0, sizeof(m_intc_regs)); + + uart_check_rx_fifo_service(); + uart_check_tx_fifo_service(); } void sa1110_periphs_device::device_add_mconfig(machine_config &config) diff --git a/src/devices/machine/sa1110.h b/src/devices/machine/sa1110.h index 3069e7006ab..64900bf163b 100644 --- a/src/devices/machine/sa1110.h +++ b/src/devices/machine/sa1110.h @@ -46,6 +46,8 @@ public: auto uart3_tx_out() { return m_uart3_tx_out.bind(); } + uint32_t icp_r(offs_t offset, uint32_t mem_mask = ~0); + void icp_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); uint32_t uart3_r(offs_t offset, uint32_t mem_mask = ~0); void uart3_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); uint32_t mcp_r(offs_t offset, uint32_t mem_mask = ~0); @@ -64,6 +66,10 @@ public: void gpio_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); uint32_t intc_r(offs_t offset, uint32_t mem_mask = ~0); void intc_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + uint32_t ppc_r(offs_t offset, uint32_t mem_mask = ~0); + void ppc_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + uint32_t dma_r(offs_t offset, uint32_t mem_mask = ~0); + void dma_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); protected: virtual void device_add_mconfig(machine_config &config) override; @@ -71,6 +77,23 @@ protected: virtual void device_reset() override; static constexpr uint32_t INTERNAL_OSC = 3686400; + + TIMER_CALLBACK_MEMBER(icp_rx_callback); + TIMER_CALLBACK_MEMBER(icp_tx_callback); + TIMER_CALLBACK_MEMBER(hssp_rx_callback); + TIMER_CALLBACK_MEMBER(hssp_tx_callback); + void icp_uart_set_receiver_enabled(bool enabled); + void icp_uart_set_transmitter_enabled(bool enabled); + void icp_uart_set_receive_irq_enabled(bool enabled); + void icp_uart_set_transmit_irq_enabled(bool enabled); + uint8_t icp_uart_read_receive_fifo(); + void icp_uart_write_transmit_fifo(uint8_t data); + uint16_t icp_hssp_read_receive_fifo(); + void icp_hssp_write_transmit_fifo(uint8_t data); + void icp_uart_set_receiver_idle(); + void icp_uart_begin_of_break(); + void icp_uart_end_of_break(); + DECLARE_WRITE_LINE_MEMBER(uart3_irq_callback); void uart_recalculate_divisor(); void uart_update_eif_status(); @@ -125,9 +148,20 @@ protected: void set_irq_line(uint32_t line, int state); void update_interrupts(); + void dma_set_control_bits(int channel, uint32_t bits); + void dma_clear_control_bits(int channel, uint32_t bits); + // register offsets enum { + ICP_BASE_ADDR = 0x80030000, + REG_UTCR4 = (0x00000010 >> 2), + REG_HSCR0 = (0x00000060 >> 2), + REG_HSCR1 = (0x00000064 >> 2), + REG_HSDR = (0x0000006c >> 2), + REG_HSSR0 = (0x00000074 >> 2), + REG_HSSR1 = (0x00000078 >> 2), + UART_BASE_ADDR = 0x80050000, REG_UTCR0 = (0x00000000 >> 2), REG_UTCR1 = (0x00000004 >> 2), @@ -196,7 +230,24 @@ protected: REG_ICLR = (0x00000008 >> 2), REG_ICCR = (0x0000000c >> 2), REG_ICFP = (0x00000010 >> 2), - REG_ICPR = (0x00000020 >> 2) + REG_ICPR = (0x00000020 >> 2), + + PPC_BASE_ADDR = 0x90060000, + REG_PPDR = (0x00000000 >> 2), + REG_PPSR = (0x00000004 >> 2), + REG_PPAR = (0x00000008 >> 2), + REG_PSDR = (0x0000000c >> 2), + REG_PPFR = (0x00000010 >> 2), + + DMA_BASE_ADDR = 0xb0000000, + REG_DDAR = (0x00000000 >> 2), + REG_DSSR = (0x00000004 >> 2), + REG_DCSR = (0x00000008 >> 2), + REG_DSR = (0x0000000c >> 2), + REG_DBSA = (0x00000010 >> 2), + REG_DBTA = (0x00000014 >> 2), + REG_DBSB = (0x00000018 >> 2), + REG_DBTB = (0x0000001c >> 2) }; // register contents @@ -213,6 +264,9 @@ protected: UTCR3_TIE_BIT = 4, UTCR3_LBM_BIT = 5, + UTCR4_HSE_BIT = 0, + UTCR4_LPM_BIT = 1, + UTSR0_TFS_BIT = 0, UTSR0_RFS_BIT = 1, UTSR0_RID_BIT = 2, @@ -227,6 +281,37 @@ protected: UTSR1_FRE_BIT = 4, UTSR1_ROR_BIT = 5, + HSCR0_ITR_BIT = 0, + HSCR0_LBM_BIT = 1, + HSCR0_TUS_BIT = 2, + HSCR0_TXE_BIT = 3, + HSCR0_RXE_BIT = 4, + HSCR0_RIE_BIT = 5, + HSCR0_TIE_BIT = 6, + HSCR0_AME_BIT = 7, + + HSCR2_TXP_BIT = 18, + HSCR2_RXP_BIT = 19, + + HSDR_EOF_BIT = 8, + HSDR_CRE_BIT = 9, + HSDR_ROR_BIT = 10, + + HSSR0_EIF_BIT = 0, + HSSR0_TUR_BIT = 1, + HSSR0_RAB_BIT = 2, + HSSR0_TFS_BIT = 3, + HSSR0_RFS_BIT = 4, + HSSR0_FRE_BIT = 5, + + HSSR1_RSY_BIT = 0, + HSSR1_TBY_BIT = 1, + HSSR1_RNE_BIT = 2, + HSSR1_TNF_BIT = 3, + HSSR1_EOF_BIT = 4, + HSSR1_CRE_BIT = 5, + HSSR1_ROR_BIT = 6, + MCCR0_ASD_BIT = 0, MCCR0_ASD_MASK = 0x0000007f, MCCR0_TSD_BIT = 8, @@ -294,7 +379,27 @@ protected: RTSR_ALE_BIT = 2, RTSR_ALE_MASK = (1 << RTSR_ALE_BIT), RTSR_HZE_BIT = 3, - RTSR_HZE_MASK = (1 << RTSR_HZE_BIT) + RTSR_HZE_MASK = (1 << RTSR_HZE_BIT), + + DDAR_RW_BIT = 0, + DDAR_E_BIT = 1, + DDAR_BS_BIT = 2, + DDAR_DW_BIT = 3, + DDAR_DA0_BIT = 4, + DDAR_DA0_MASK = 0x000000f0, + DDAR_DA8_BIT = 8, + DDAR_DA8_MASK = 0xffffff00, + + DSR_RUN_BIT = 0, + DSR_IE_BIT = 1, + DSR_ERROR_BIT = 2, + DSR_DONEA_BIT = 3, + DSR_STRTA_BIT = 4, + DSR_DONEB_BIT = 5, + DSR_STRTB_BIT = 6, + DSR_BIU_BIT = 7, + + DBT_MASK = 0x00001fff }; // interrupt bits @@ -376,6 +481,36 @@ protected: bool rx_break_interlock; }; + struct hssp_regs + { + uint32_t hscr0; + uint32_t hscr1; + uint32_t hssr0; + uint32_t hssr1; + + uint16_t rx_fifo[8]; + int rx_fifo_read_idx; + int rx_fifo_write_idx; + int rx_fifo_count; + emu_timer *rx_timer; + + uint16_t tx_fifo[8]; + int tx_fifo_read_idx; + int tx_fifo_write_idx; + int tx_fifo_count; + emu_timer *tx_timer; + }; + + struct icp_regs + { + uart_regs uart; + uint32_t utcr4; + emu_timer *uart_rx_timer; + emu_timer *uart_tx_timer; + + hssp_regs hssp; + }; + struct mcp_regs { uint32_t mccr0; @@ -486,7 +621,27 @@ protected: uint32_t icpr; }; + struct ppc_regs + { + uint32_t ppdr; + uint32_t ppsr_out; + uint32_t ppsr_in; + uint32_t ppsr; + uint32_t ppar; + uint32_t psdr; + uint32_t ppfr; + }; + + struct dma_regs + { + uint32_t ddar; + uint32_t dsr; + uint32_t dbs[2]; + uint32_t dbt[2]; + }; + uart_regs m_uart_regs; + icp_regs m_icp_regs; mcp_regs m_mcp_regs; ssp_regs m_ssp_regs; ostimer_regs m_ostmr_regs; @@ -495,8 +650,11 @@ protected: uint32_t m_rcsr; gpio_regs m_gpio_regs; intc_regs m_intc_regs; + ppc_regs m_ppc_regs; + dma_regs m_dma_regs[6]; + uint8_t m_dma_active_mask; - required_device m_maincpu; + required_device m_maincpu; required_device m_uart3_irqs; required_device m_mcp_irqs; optional_device m_codec; 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; - if (BIT(data, SADTCS_TDBDA_BIT)) - m_audio_regs.sadtcs &= ~(1 << SADTCS_TDBDA_BIT); - if (BIT(data, SADTCS_TDBDB_BIT)) - m_audio_regs.sadtcs &= ~(1 << SADTCS_TDBDB_BIT); + 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(m_audio_regs.sadtcs, SADTCS_TDEN_BIT)) + if (BIT(data, SADTCS_TDBDA_BIT) || BIT(data, SADTCS_TDSTA_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 - } + LOGMASKED(LOG_AUDIO_DMA, "%s: sadtcs_w: Clearing done A bit, lowering AUDTXA IRQ\n"); + m_audio_regs.sadtcs &= ~(1 << SADTCS_TDBDA_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(changed, SADTCS_TDEN_BIT)) + { + 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); - if (BIT(data, SADRCS_RDBDB_BIT)) - m_audio_regs.sadrcs &= ~(1 << SADRCS_RDBDB_BIT); - - if (BIT(m_audio_regs.sadrcs, 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 - } + 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(changed, SADRCS_RDEN_BIT)) + { + 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +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 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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) diff --git a/src/devices/machine/sa1111.h b/src/devices/machine/sa1111.h index 78ca930cb98..1524900be20 100644 --- a/src/devices/machine/sa1111.h +++ b/src/devices/machine/sa1111.h @@ -11,25 +11,38 @@ #pragma once -#include "machine/input_merger.h" +#include "cpu/arm7/arm7.h" +#include "cpu/arm7/arm7core.h" class sa1111_device : public device_t { public: - sa1111_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + template + sa1111_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag) + : sa1111_device(mconfig, tag, owner, clock) + { + m_maincpu.set_tag(std::forward(cpu_tag)); + } - template void pa_in(int state) { gpio_in(0 + Line, state); } - template void pb_in(int state) { gpio_in(8 + Line, state); } - template void pc_in(int state) { gpio_in(16 + Line, state); } - template auto pa_out() { return m_gpio_out[0 + Line].bind(); } - template auto pb_out() { return m_gpio_out[8 + Line].bind(); } - template auto pc_out() { return m_gpio_out[16 + Line].bind(); } + sa1111_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template void set_audio_codec_tag(T &&tag) { m_audio_codec.set_tag(std::forward(tag)); } + + auto irq_out() { return m_irq_out.bind(); } + + template void pa_in(int state) { gpio_in(0 + Line, state); } + template void pb_in(int state) { gpio_in(8 + Line, state); } + template void pc_in(int state) { gpio_in(16 + Line, state); } + template auto pa_out() { return m_gpio_out[0 + Line].bind(); } + template auto pb_out() { return m_gpio_out[8 + Line].bind(); } + template auto pc_out() { return m_gpio_out[16 + Line].bind(); } void ssp_in(uint16_t data) { ssp_rx_fifo_push(data); } auto ssp_out() { return m_ssp_out.bind(); } auto l3_addr_out() { return m_l3_addr_out.bind(); } auto l3_data_out() { return m_l3_data_out.bind(); } + auto i2s_out() { return m_i2s_out.bind(); } DECLARE_WRITE_LINE_MEMBER(l3wd_in); @@ -40,11 +53,31 @@ protected: virtual void device_reset() override; virtual void device_add_mconfig(machine_config &config) override; + void set_irq_line(uint32_t line, int state); + void update_interrupts(); + TIMER_CALLBACK_MEMBER(ssp_rx_callback); TIMER_CALLBACK_MEMBER(ssp_tx_callback); + TIMER_CALLBACK_MEMBER(audio_rx_dma_callback); TIMER_CALLBACK_MEMBER(audio_rx_callback); + TIMER_CALLBACK_MEMBER(audio_tx_dma_callback); TIMER_CALLBACK_MEMBER(audio_tx_callback); + void audio_update_mode(); + void audio_clear_interrupts(); + void audio_set_enabled(bool enabled); + void audio_controller_reset(); + void audio_set_tx_dma_enabled(bool enabled); + void audio_set_rx_dma_enabled(bool enabled); + void audio_start_tx_dma(const uint32_t buf); + void audio_start_rx_dma(const uint32_t buf); + void audio_update_tx_fifo_levels(); + void audio_update_rx_fifo_levels(); + void audio_update_busy_flag(); + void audio_tx_fifo_push(uint32_t data); + uint32_t audio_tx_fifo_pop(); + void audio_rx_fifo_push(uint32_t data); + uint32_t audio_rx_fifo_pop(); uint32_t unknown_r(offs_t offset, uint32_t mem_mask); void unknown_w(offs_t offset, uint32_t data, uint32_t mem_mask); @@ -161,30 +194,30 @@ protected: void mouse_kbdprecnt_w(offs_t offset, uint32_t data, uint32_t mem_mask); void mouse_kbditr_w(offs_t offset, uint32_t data, uint32_t mem_mask); - template uint32_t ddr_r(offs_t offset, uint32_t mem_mask); - template uint32_t drr_r(offs_t offset, uint32_t mem_mask); - template uint32_t sdr_r(offs_t offset, uint32_t mem_mask); - template uint32_t ssr_r(offs_t offset, uint32_t mem_mask); - template void ddr_w(offs_t offset, uint32_t data, uint32_t mem_mask); - template void dwr_w(offs_t offset, uint32_t data, uint32_t mem_mask); - template void sdr_w(offs_t offset, uint32_t data, uint32_t mem_mask); - template void ssr_w(offs_t offset, uint32_t data, uint32_t mem_mask); + template uint32_t ddr_r(offs_t offset, uint32_t mem_mask); + template uint32_t drr_r(offs_t offset, uint32_t mem_mask); + template uint32_t sdr_r(offs_t offset, uint32_t mem_mask); + template uint32_t ssr_r(offs_t offset, uint32_t mem_mask); + template void ddr_w(offs_t offset, uint32_t data, uint32_t mem_mask); + template void dwr_w(offs_t offset, uint32_t data, uint32_t mem_mask); + template void sdr_w(offs_t offset, uint32_t data, uint32_t mem_mask); + template void ssr_w(offs_t offset, uint32_t data, uint32_t mem_mask); - template uint32_t inttest_r(offs_t offset, uint32_t mem_mask); - template uint32_t inten_r(offs_t offset, uint32_t mem_mask); - template uint32_t intpol_r(offs_t offset, uint32_t mem_mask); + template uint32_t inttest_r(offs_t offset, uint32_t mem_mask); + template uint32_t inten_r(offs_t offset, uint32_t mem_mask); + template uint32_t intpol_r(offs_t offset, uint32_t mem_mask); uint32_t inttstsel_r(offs_t offset, uint32_t mem_mask); - template uint32_t intstat_r(offs_t offset, uint32_t mem_mask); - template uint32_t wake_en_r(offs_t offset, uint32_t mem_mask); - template uint32_t wake_pol_r(offs_t offset, uint32_t mem_mask); - template void inttest_w(offs_t offset, uint32_t data, uint32_t mem_mask); - template void inten_w(offs_t offset, uint32_t data, uint32_t mem_mask); - template void intpol_w(offs_t offset, uint32_t data, uint32_t mem_mask); + template uint32_t intstat_r(offs_t offset, uint32_t mem_mask); + template uint32_t wake_en_r(offs_t offset, uint32_t mem_mask); + template uint32_t wake_pol_r(offs_t offset, uint32_t mem_mask); + template void inttest_w(offs_t offset, uint32_t data, uint32_t mem_mask); + template void inten_w(offs_t offset, uint32_t data, uint32_t mem_mask); + template void intpol_w(offs_t offset, uint32_t data, uint32_t mem_mask); void inttstsel_w(offs_t offset, uint32_t data, uint32_t mem_mask); - template void intclr_w(offs_t offset, uint32_t data, uint32_t mem_mask); - template void intset_w(offs_t offset, uint32_t data, uint32_t mem_mask); - template void wake_en_w(offs_t offset, uint32_t data, uint32_t mem_mask); - template void wake_pol_w(offs_t offset, uint32_t data, uint32_t mem_mask); + template void intclr_w(offs_t offset, uint32_t data, uint32_t mem_mask); + template void intset_w(offs_t offset, uint32_t data, uint32_t mem_mask); + template void wake_en_w(offs_t offset, uint32_t data, uint32_t mem_mask); + template void wake_pol_w(offs_t offset, uint32_t data, uint32_t mem_mask); uint32_t pccr_r(offs_t offset, uint32_t mem_mask); uint32_t pcssr_r(offs_t offset, uint32_t mem_mask); @@ -201,13 +234,7 @@ protected: void gpio_in(const uint32_t line, const int state); void gpio_update_direction(const uint32_t block, const uint32_t old_dir); - void gpio_update_outputs(const uint32_t block, const uint32_t old_latch); - - // interrupt lines - enum : uint32_t - { - INT_AUDDTS = 40 - }; + void gpio_update_outputs(const uint32_t block, const uint32_t changed); // register contents enum : uint32_t @@ -220,7 +247,7 @@ protected: SKCR_SCANTST_BIT = 5, SKCR_CLKTST_BIT = 6, SKCR_RDY_BIT = 7, - SKCR_SLAC_BIT = 8, + SKCR_SACMDSL_BIT = 8, SKCR_OPPC_BIT = 9, SKCR_PII_BIT = 10, SKCR_UIOTEN_BIT = 11, @@ -319,31 +346,23 @@ protected: SASCR_RDD_BIT = 17, SASCR_STO_BIT = 18, - SASR0_TNF_BIT = 0, - SASR0_RNE_BIT = 1, - SASR0_BSY_BIT = 2, - SASR0_TFS_BIT = 3, - SASR0_RFS_BIT = 4, - SASR0_TUR_BIT = 5, - SASR0_ROR_BIT = 6, - SASR0_TFL_BIT = 7, - SASR0_TFL_MASK = 0x00000f00, - SASR0_RFL_BIT = 12, - SASR0_RFL_MASK = 0x0000f000, + SASR_TNF_BIT = 0, + SASR_RNE_BIT = 1, + SASR_BSY_BIT = 2, + SASR_TFS_BIT = 3, + SASR_RFS_BIT = 4, + SASR_TUR_BIT = 5, + SASR_ROR_BIT = 6, + SASR_TFL_BIT = 8, + SASR_TFL_MASK = 0x00000f00, + SASR_RFL_BIT = 12, + SASR_RFL_MASK = 0x0000f000, + SASR_SEND_BIT = 16, + SASR_RECV_BIT = 17, + SASR0_L3WD_BIT = 16, SASR0_L3RD_BIT = 17, - SASR1_TNF_BIT = 0, - SASR1_RNE_BIT = 1, - SASR1_BSY_BIT = 2, - SASR1_TFS_BIT = 3, - SASR1_RFS_BIT = 4, - SASR1_TUR_BIT = 5, - SASR1_ROR_BIT = 6, - SASR1_TFL_BIT = 8, - SASR1_TFL_MASK = 0x00000f00, - SASR1_RFL_BIT = 12, - SASR1_RFL_MASK = 0x0000f000, SASR1_CADT_BIT = 16, SASR1_SADR_BIT = 17, SASR1_RSTO_BIT = 18, @@ -357,12 +376,14 @@ protected: SADTCS_TDSTA_BIT = 4, SADTCS_TDBDB_BIT = 5, SADTCS_TDSTB_BIT = 6, + SADTCS_TBIU_BIT = 7, SADRCS_RDEN_BIT = 0, SADRCS_RDBDA_BIT = 3, SADRCS_RDSTA_BIT = 4, SADRCS_RDBDB_BIT = 5, SADRCS_RDSTB_BIT = 6, + SADRCS_RBIU_BIT = 7, SAITR_TFS_BIT = 0, SAITR_RFS_BIT = 1, @@ -456,6 +477,61 @@ protected: PCSSR_S1SLP_BIT = 1 }; + // interrupt lines + enum : uint32_t + { + INT_GPA0 = 0, + INT_GPA1 = 1, + INT_GPA2 = 2, + INT_GPA3 = 3, + INT_GPB0 = 4, + INT_GPB1 = 5, + INT_GPB2 = 6, + INT_GPB3 = 7, + INT_GPB4 = 8, + INT_GPB5 = 9, + INT_GPC0 = 10, + INT_GPC1 = 11, + INT_GPC2 = 12, + INT_GPC3 = 13, + INT_GPC4 = 14, + INT_GPC5 = 15, + INT_GPC6 = 16, + INT_GPC7 = 17, + INT_MSTX = 18, + INT_MSRX = 19, + INT_MSERR = 20, + INT_TPTX = 21, + INT_TPRX = 22, + INT_TPERR = 23, + INT_SSPTX = 24, + INT_SSPRX = 25, + INT_SSPROR = 26, + INT_AUDTXA = 32, + INT_AUDRXA = 33, + INT_AUDTXB = 34, + INT_AUDRXB = 35, + INT_AUDTFS = 36, + INT_AUDRFS = 37, + INT_AUDTUR = 38, + INT_AUDROR = 39, + INT_AUDDTS = 40, + INT_AUDRDD = 41, + INT_AUDSTO = 42, + INT_USBPWR = 43, + INT_USBHCIM = 44, + INT_USBHCIBUF = 45, + INT_USBHCIWAKE = 46, + INT_USBHCIMFC = 47, + INT_USBRESUME = 48, + INT_S0RDY = 49, + INT_S1RDY = 50, + INT_S0CD = 51, + INT_S1CD = 52, + INT_S0BVD = 53, + INT_S1BVD = 54 + }; + struct sbi_regs { uint32_t skcr; @@ -499,15 +575,15 @@ protected: uint32_t acsar; uint32_t acsdr; uint32_t sadtcs; - uint32_t sadtsa; - uint32_t sadtca; - uint32_t sadtsb; - uint32_t sadtcb; + uint32_t sadts[2]; + uint32_t sadtc[2]; + uint32_t sadta; + uint32_t sadtcc; uint32_t sadrcs; - uint32_t sadrsa; - uint32_t sadrca; - uint32_t sadrsb; - uint32_t sadrcb; + uint32_t sadrs[2]; + uint32_t sadrc[2]; + uint32_t sadra; + uint32_t sadrcc; uint32_t saitr; uint32_t rx_fifo[16]; @@ -515,12 +591,14 @@ protected: int rx_fifo_write_idx; int rx_fifo_count; emu_timer *rx_timer; + emu_timer *rx_dma_timer; uint32_t tx_fifo[16]; int tx_fifo_read_idx; int tx_fifo_write_idx; int tx_fifo_count; emu_timer *tx_timer; + emu_timer *tx_dma_timer; }; struct ssp_regs @@ -573,6 +651,8 @@ protected: uint32_t intstat[2]; uint32_t wake_en[2]; uint32_t wake_pol[2]; + + uint32_t intraw[2]; }; struct card_regs @@ -593,10 +673,15 @@ protected: intc_regs m_intc_regs; card_regs m_card_regs; + required_device m_maincpu; + optional_device m_audio_codec; + + devcb_write_line m_irq_out; devcb_write_line::array<24> m_gpio_out; devcb_write16 m_ssp_out; devcb_write8 m_l3_addr_out; devcb_write8 m_l3_data_out; + devcb_write32 m_i2s_out; }; DECLARE_DEVICE_TYPE(SA1111, sa1111_device) diff --git a/src/devices/sound/uda1344.cpp b/src/devices/sound/uda1344.cpp index 047f4c03d95..8cc08d936b7 100644 --- a/src/devices/sound/uda1344.cpp +++ b/src/devices/sound/uda1344.cpp @@ -12,9 +12,11 @@ #define LOG_ADDR (1 << 1) #define LOG_STATUS_REG (1 << 2) #define LOG_DATA_REG (1 << 3) -#define LOG_ALL (LOG_ADDR | LOG_STATUS_REG | LOG_DATA_REG) +#define LOG_INPUT (1 << 4) +#define LOG_OVERRUNS (1 << 5) +#define LOG_ALL (LOG_ADDR | LOG_STATUS_REG | LOG_DATA_REG | LOG_INPUT | LOG_OVERRUNS) -#define VERBOSE (LOG_ALL) +#define VERBOSE (0) #include "logmacro.h" @@ -26,52 +28,138 @@ uda1344_device::uda1344_device(const machine_config &mconfig, const char *tag, d : device_t(mconfig, UDA1344, tag, owner, clock) , device_sound_interface(mconfig, *this) , m_stream(nullptr) + , m_volume(1.0) + , m_frequency(BASE_FREQUENCY) , m_data_transfer_mode(0) , m_status_reg(0) + , m_clock_divider(512) , m_volume_reg(0) , m_equalizer_reg(0) , m_filter_reg(0) , m_power_reg(0) + , m_dac_enable(false) + , m_adc_enable(false) , m_l3_ack_out(*this) { } void uda1344_device::device_start() { - m_stream = stream_alloc(0, 2, 44100); + m_stream = stream_alloc(0, 2, BASE_FREQUENCY); + + save_item(NAME(m_buffer[0])); + save_item(NAME(m_buffer[1])); + save_item(NAME(m_bufin)); + save_item(NAME(m_bufout)); + save_item(NAME(m_volume)); + save_item(NAME(m_frequency)); save_item(NAME(m_data_transfer_mode)); save_item(NAME(m_status_reg)); + save_item(NAME(m_clock_divider)); save_item(NAME(m_volume_reg)); save_item(NAME(m_equalizer_reg)); save_item(NAME(m_filter_reg)); save_item(NAME(m_power_reg)); + save_item(NAME(m_dac_enable)); + save_item(NAME(m_adc_enable)); m_l3_ack_out.resolve_safe(); + + m_buffer[0].resize(BUFFER_SIZE); + m_buffer[1].resize(BUFFER_SIZE); } void uda1344_device::device_reset() { m_data_transfer_mode = 0; m_status_reg = 0; + m_clock_divider = 512; m_volume_reg = 0; m_equalizer_reg = 0; m_filter_reg = 0; m_power_reg = 0; + + m_dac_enable = false; + m_adc_enable = false; + + m_volume = 1.0; + m_frequency = BASE_FREQUENCY; + + memset(m_bufin, 0, sizeof(uint32_t) * 2); + memset(m_bufout, 0, sizeof(uint32_t) * 2); } void uda1344_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) { - auto &buffer = outputs[0]; - - /* fill in the samples */ - for (int sampindex = 0; sampindex < buffer.samples(); sampindex++) + for (int channel = 0; channel < 2 && channel < outputs.size(); channel++) { - // TODO: Generate audio - buffer.put(sampindex, 0); + auto &output = outputs[channel]; + uint32_t curout = m_bufout[channel]; + uint32_t curin = m_bufin[channel]; + + // feed as much as we can + int sampindex; + for (sampindex = 0; curout != curin && sampindex < output.samples(); sampindex++) + { + output.put(sampindex, stream_buffer::sample_t(m_buffer[channel][curout]) * m_volume); + curout = (curout + 1) % BUFFER_SIZE; + } + + // fill the rest with silence + output.fill(0, sampindex); + + // save the new output pointer + m_bufout[channel] = curout; } } +void uda1344_device::ingest_samples(int16_t left, int16_t right) +{ + const int16_t samples[2] = { left, right }; + + const stream_buffer::sample_t sample_scale = 1.0 / 32768.0; + const stream_buffer::sample_t enable_scale = m_dac_enable ? 1.0 : 0.0; + + m_stream->update(); + + for (int channel = 0; channel < 2; channel++) + { + int maxin = (m_bufout[channel] + BUFFER_SIZE - 1) % BUFFER_SIZE; + if (m_bufin[channel] != maxin) + { + m_buffer[channel][m_bufin[channel]] = stream_buffer::sample_t(samples[channel]) * sample_scale * enable_scale; + m_bufin[channel] = (m_bufin[channel] + 1) % BUFFER_SIZE; + } + else + { + LOGMASKED(LOG_OVERRUNS, "ingest_samples: buffer overrun (short 1 frame on channel %d)\n", channel); + } + } +} + +void uda1344_device::device_clock_changed() +{ + if (clock() == 0) + return; + + m_stream->update(); + m_stream->set_sample_rate(clock() / m_clock_divider); +} + +void uda1344_device::set_clock_divider(const uint32_t divider) +{ + m_clock_divider = divider; + device_clock_changed(); +} + +void uda1344_device::i2s_input_w(uint32_t data) +{ + const int16_t left = (int16_t)(data >> 16); + const int16_t right = (int16_t)data; + ingest_samples(left, right); +} + void uda1344_device::l3_addr_w(offs_t offset, uint8_t data) { // Check for L3 address match, ignore if not addressed to us @@ -115,6 +203,19 @@ void uda1344_device::l3_data_w(offs_t offset, uint8_t data) s_format_names[(reg_bits & STATUS_IF_MASK) >> STATUS_IF_BIT], BIT(reg_bits, STATUS_DC_BIT) ? "on" : "off"); m_status_reg = reg_bits; + + switch ((reg_bits & STATUS_SC_MASK) >> STATUS_SC_BIT) + { + case 1: + set_clock_divider(384); + break; + case 2: + set_clock_divider(256); + break; + default: + set_clock_divider(512); + break; + } } else { @@ -123,13 +224,24 @@ void uda1344_device::l3_data_w(offs_t offset, uint8_t data) { case VOLUME_REG: { + m_stream->update(); + const uint8_t reg_bits = data & VOLUME_REG_MASK; if (reg_bits < 2) + { LOGMASKED(LOG_DATA_REG, "%s: Volume register data: %02x, no attenuation\n", machine().describe_context(), reg_bits); + m_volume = 1.0; + } else if (reg_bits >= 62) + { LOGMASKED(LOG_DATA_REG, "%s: Volume register data: %02x, full attenuation\n", machine().describe_context(), reg_bits); + m_volume = 0.0; + } else + { LOGMASKED(LOG_DATA_REG, "%s: Volume register data: %02x, -%ddB attenuation\n", machine().describe_context(), reg_bits, reg_bits - 1); + m_volume = 1.0 - ((reg_bits - 1) / 62.0); + } m_volume_reg = reg_bits; break; @@ -163,6 +275,10 @@ void uda1344_device::l3_data_w(offs_t offset, uint8_t data) BIT(reg_bits, POWER_ADC_BIT) ? "on" : "off", BIT(reg_bits, POWER_DAC_BIT) ? "on" : "off"); m_power_reg = reg_bits; + + m_stream->update(); + m_dac_enable = BIT(reg_bits, POWER_DAC_BIT); + m_adc_enable = BIT(reg_bits, POWER_ADC_BIT); break; } } diff --git a/src/devices/sound/uda1344.h b/src/devices/sound/uda1344.h index 430be48c1fc..6d9041442c7 100644 --- a/src/devices/sound/uda1344.h +++ b/src/devices/sound/uda1344.h @@ -21,14 +21,24 @@ public: auto l3_ack_out() { return m_l3_ack_out.bind(); } + void i2s_input_w(uint32_t data); + protected: // device-level overrides virtual void device_start() override; virtual void device_reset() override; + virtual void device_clock_changed() override; // sound stream update overrides virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; + void ingest_samples(int16_t left, int16_t right); + + void set_clock_divider(const uint32_t divider); + + static constexpr double BASE_FREQUENCY = 44100; + static constexpr size_t BUFFER_SIZE = 65536; + enum : uint8_t { CHIP_ADDR_MASK = 0xfc, @@ -63,20 +73,29 @@ protected: STATUS_REG_MASK = 0x3f, STATUS_SC_MASK = 0x30, STATUS_SC_BIT = 4, - STATUS_IF_MASK = 0xe0, + STATUS_IF_MASK = 0x0e, STATUS_IF_BIT = 1, STATUS_DC_BIT = 0 }; sound_stream *m_stream; + std::vector m_buffer[2]; + uint32_t m_bufin[2]; + uint32_t m_bufout[2]; + stream_buffer::sample_t m_volume; + double m_frequency; uint8_t m_data_transfer_mode; uint8_t m_status_reg; + uint32_t m_clock_divider; uint8_t m_volume_reg; uint8_t m_equalizer_reg; uint8_t m_filter_reg; uint8_t m_power_reg; + bool m_dac_enable; + bool m_adc_enable; + devcb_write_line m_l3_ack_out; }; diff --git a/src/devices/video/sed1356.cpp b/src/devices/video/sed1356.cpp index bc5b83aaf0f..dba2233b3cc 100644 --- a/src/devices/video/sed1356.cpp +++ b/src/devices/video/sed1356.cpp @@ -23,13 +23,16 @@ #define LOG_CRT_WR (1 << 6) #define LOG_BITBLT_RD (1 << 7) #define LOG_BITBLT_WR (1 << 8) -#define LOG_LUT_RD (1 << 9) -#define LOG_LUT_WR (1 << 10) -#define LOG_MPLUG_RD (1 << 11) -#define LOG_MPLUG_WR (1 << 12) -#define LOG_ALL (LOG_MISC_RD | LOG_MISC_WR | LOG_LCD_RD | LOG_LCD_WR | LOG_CRT_RD | LOG_CRT_WR | LOG_BITBLT_RD | LOG_BITBLT_WR | LOG_LUT_RD | LOG_LUT_WR | LOG_MPLUG_RD | LOG_MPLUG_WR) +#define LOG_BITBLT_OP (1 << 9) +#define LOG_LUT_RD (1 << 10) +#define LOG_LUT_WR (1 << 11) +#define LOG_MPLUG_RD (1 << 12) +#define LOG_MPLUG_WR (1 << 13) +#define LOG_LCD_RD_HF (1 << 14) +#define LOG_ALL (LOG_MISC_RD | LOG_MISC_WR | LOG_LCD_RD | LOG_LCD_WR | LOG_CRT_RD | LOG_CRT_WR | LOG_BITBLT_RD | LOG_BITBLT_WR | LOG_BITBLT_OP | LOG_LUT_RD \ + | LOG_LUT_WR | LOG_MPLUG_RD | LOG_MPLUG_WR) -#define VERBOSE (0) // (LOG_ALL) +#define VERBOSE (0) #include "logmacro.h" DEFINE_DEVICE_TYPE(SED1356, sed1356_device, "sed1356", "Epson SED1356") @@ -398,8 +401,10 @@ uint8_t sed1356_device::lcd_display_height_r(offs_t offset) uint8_t sed1356_device::lcd_vblank_period_r(offs_t offset) { - LOGMASKED(LOG_LCD_RD, "%s: lcd_vblank_period_r: %02x\n", machine().describe_context(), m_lcd_vblank_period); - return m_lcd_vblank_period; + const uint8_t vblank = screen().vblank() ? (1 << LCDVBL_STATUS_BIT) : 0x00; + const uint8_t data = m_lcd_vblank_period | vblank; + LOGMASKED(LOG_LCD_RD, "%s: lcd_vblank_period_r: %02x\n", machine().describe_context(), data); + return data; } uint8_t sed1356_device::tft_fpframe_start_pos_r(offs_t offset) @@ -1016,6 +1021,83 @@ void sed1356_device::crt_cursor_fifo_thresh_w(offs_t offset, uint8_t data) } +template +void sed1356_device::bitblt_solid_fill() +{ + uint16_t *dst = (uint16_t*)&m_vram[m_bitblt_dst_addr >> 2]; + if (m_bitblt_dst_addr & 2) + dst++; + + for (uint32_t y = 0; y <= m_bitblt_height; y++) + { + for (uint32_t x = 0; x <= m_bitblt_width; x++) + { + if (Linear) + *dst++ = m_bitblt_fgcolor; + else + dst[x] = m_bitblt_fgcolor; + } + + if (!Linear) + dst += m_bitblt_mem_offset; + } +} + +void sed1356_device::bitblt_execute_command() +{ + switch (m_bitblt_op) + { + case 0: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Write BitBLT with ROP\n"); + return; + case 1: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Read BitBLT\n"); + return; + case 2: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Move BitBLT in + direction with ROP\n"); + return; + case 3: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Move BitBLT in - direction with ROP\n"); + return; + case 4: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Transparent Write BitBLT\n"); + return; + case 5: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Transparent Move BitBLT in + direction\n"); + return; + case 6: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Pattern Fill with ROP\n"); + return; + case 7: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Pattern Fill with transparency\n"); + return; + case 8: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Color Expansion\n"); + return; + case 9: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Color Expansion with transparency\n"); + return; + case 10: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Move BitBLT with Color Expansion\n"); + return; + case 11: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Command not yet implemented: Move BitBLT with Color Expansion and transparency\n"); + return; + case 12: + { + LOGMASKED(LOG_BITBLT_OP, "bitblt: Solid Fill\n"); + if (BIT(m_bitblt_ctrl[0], BBCTRL0_DSTLIN_BIT)) + bitblt_solid_fill(); + else + bitblt_solid_fill(); + return; + } + default: + LOGMASKED(LOG_BITBLT_OP, "bitblt: Unsupported command type: %02x\n", m_bitblt_op); + return; + } +} + uint8_t sed1356_device::bitblt_ctrl0_r(offs_t offset) { LOGMASKED(LOG_BITBLT_RD, "%s: bitblt_ctrl0_r: %02x\n", machine().describe_context(), m_bitblt_ctrl[0]); @@ -1098,6 +1180,10 @@ void sed1356_device::bitblt_ctrl0_w(offs_t offset, uint8_t data) LOGMASKED(LOG_BITBLT_WR, "%s: bitblt_ctrl0_w = %02x\n", machine().describe_context(), data); m_bitblt_ctrl[0] &= ~BBCTRL0_WR_MASK; m_bitblt_ctrl[0] |= data & BBCTRL0_WR_MASK; + if (BIT(data, BBCTRL0_ACTIVE_BIT)) + { + bitblt_execute_command(); + } } void sed1356_device::bitblt_ctrl1_w(offs_t offset, uint8_t data) diff --git a/src/devices/video/sed1356.h b/src/devices/video/sed1356.h index dc5f00ec1af..ca32f8dfdb8 100644 --- a/src/devices/video/sed1356.h +++ b/src/devices/video/sed1356.h @@ -170,6 +170,8 @@ protected: void crt_cursor_color1_red_w(offs_t offset, uint8_t data); void crt_cursor_fifo_thresh_w(offs_t offset, uint8_t data); + template void bitblt_solid_fill(); + void bitblt_execute_command(); uint8_t bitblt_ctrl0_r(offs_t offset); uint8_t bitblt_ctrl1_r(offs_t offset); uint8_t bitblt_rop_code_r(offs_t offset); diff --git a/src/mame/drivers/jornada.cpp b/src/mame/drivers/jornada.cpp index f1f184913d5..25d2c2de387 100644 --- a/src/mame/drivers/jornada.cpp +++ b/src/mame/drivers/jornada.cpp @@ -4,29 +4,33 @@ HP Jornada PDA skeleton driver - Notes: - - GPIO1: IRQ from SA-1111 + To boot: + - Start MAME with the debugger enabled + - Use the following breakpoint command: bp 13E2C,R3==3 && R1==10 + - Close the debugger and allow the machine to run + - When the breakpoint is hit, use the following command: R3=0 + - Close the debugger, booting will proceed ***************************************************************************/ #include "emu.h" #include "cpu/arm7/arm7.h" #include "cpu/arm7/arm7core.h" +#include "machine/m950x0.h" #include "machine/sa1110.h" #include "machine/sa1111.h" #include "sound/uda1344.h" #include "video/sed1356.h" #include "screen.h" #include "emupal.h" +#include "speaker.h" #define LOG_MCU (1 << 1) #define LOG_ALL (LOG_MCU) -#define VERBOSE (LOG_ALL) +#define VERBOSE (0) #include "logmacro.h" -#define SA1110_CLOCK 206000000 - namespace { @@ -39,26 +43,58 @@ public: , m_ram(*this, "ram") , m_sa_periphs(*this, "onboard") , m_companion(*this, "companion") - , m_eeprom_data(*this, "eeprom") , m_epson(*this, "epson") , m_codec(*this, "codec") - , m_kbd_port(*this, "KBD0") + , m_nvram(*this, "nvram") + , m_kbd_ports(*this, "KBD%u", 0U) + , m_pen_x(*this, "PENX") + , m_pen_y(*this, "PENY") + , m_pen_button(*this, "PENZ") { } void jornada720(machine_config &config); DECLARE_INPUT_CHANGED_MEMBER(key_changed); + DECLARE_INPUT_CHANGED_MEMBER(pen_changed); + + enum : uint8_t + { + MCU_TXDUMMY = 0x11, + MCU_TXDUMMY2 = 0x88 + }; + enum { - KEY_ON_OFF, - KEY_S, - KEY_K, - KEY_1, - KEY_2, - KEY_3, - KEY_4, - KEY_9 + KEY_ON_OFF = 0x7f, + KEY_S = 0x32, + KEY_K = 0x38, + KEY_1 = 0x11, + KEY_2 = 0x12, + KEY_3 = 0x13, + KEY_4 = 0x14, + KEY_9 = 0x19, + KEY_TAB = 0x51, + KEY_ENTER = 0x4c, + KEY_A = 0x31, + KEY_N = 0x46, + KEY_L = 0x39, + KEY_M = 0x47, + KEY_P = 0x2a, + KEY_C = 0x43, + KEY_B = 0x45, + KEY_ALT = 0x65, + KEY_SPACE = 0x74, + KEY_BACKSPACE = 0x2c, + KEY_LSHIFT = 0x53, + KEY_RSHIFT = 0x5c + }; + + enum + { + PEN_X, + PEN_Y, + PEN_BUTTON }; protected: @@ -67,17 +103,23 @@ protected: virtual void machine_reset() override; virtual void device_reset_after_children() override; + static constexpr uint32_t SA1110_CLOCK = 206000000; + void main_map(address_map &map); + void mcu_assemble_touch_data(); void mcu_byte_received(uint16_t data); - void eeprom_cmd_received(uint16_t data); + void eeprom_data_received(uint16_t data); + void eeprom_select(int state); enum mcu_state : int { MCU_IDLE, MCU_KBD_SEND_COUNT, - MCU_KBD_SEND_CODES + MCU_KBD_SEND_CODES, + + MCU_TOUCH_SEND_DATA }; // devices @@ -85,22 +127,25 @@ protected: required_shared_ptr m_ram; required_device m_sa_periphs; required_device m_companion; - required_region_ptr m_eeprom_data; required_device m_epson; required_device m_codec; + required_device m_nvram; - required_ioport m_kbd_port; + required_ioport_array<3> m_kbd_ports; + required_ioport m_pen_x; + required_ioport m_pen_y; + required_ioport m_pen_button; // MCU-related members int m_mcu_state; uint8_t m_mcu_key_send_idx; uint8_t m_mcu_key_codes[2][8]; uint8_t m_mcu_key_count[2]; - - // EEPROM-related members - uint8_t m_eeprom_cmd; - uint8_t m_eeprom_count; - uint8_t m_eeprom_read_idx; + uint8_t m_mcu_key_idx[2]; + uint8_t m_mcu_touch_send_idx; + uint8_t m_mcu_touch_data[2][8]; + uint8_t m_mcu_touch_count[2]; + uint8_t m_mcu_touch_idx[2]; }; void jornada_state::main_map(address_map &map) @@ -110,6 +155,7 @@ void jornada_state::main_map(address_map &map) map(0x40000000, 0x40001fff).m(m_companion, FUNC(sa1111_device::map)); map(0x48000000, 0x481fffff).m(m_epson, FUNC(sed1356_device::map)); map(0x48200000, 0x4827ffff).m(m_epson, FUNC(sed1356_device::vram_map)); + map(0x80030000, 0x8003007b).rw(m_sa_periphs, FUNC(sa1110_periphs_device::icp_r), FUNC(sa1110_periphs_device::icp_w)); map(0x80050000, 0x80050023).rw(m_sa_periphs, FUNC(sa1110_periphs_device::uart3_r), FUNC(sa1110_periphs_device::uart3_w)); map(0x80060000, 0x8006001b).rw(m_sa_periphs, FUNC(sa1110_periphs_device::mcp_r), FUNC(sa1110_periphs_device::mcp_w)); map(0x80070000, 0x80070077).rw(m_sa_periphs, FUNC(sa1110_periphs_device::ssp_r), FUNC(sa1110_periphs_device::ssp_w)); @@ -119,6 +165,8 @@ void jornada_state::main_map(address_map &map) map(0x90030000, 0x90030007).rw(m_sa_periphs, FUNC(sa1110_periphs_device::reset_r), FUNC(sa1110_periphs_device::reset_w)); map(0x90040000, 0x90040023).rw(m_sa_periphs, FUNC(sa1110_periphs_device::gpio_r), FUNC(sa1110_periphs_device::gpio_w)); map(0x90050000, 0x90050023).rw(m_sa_periphs, FUNC(sa1110_periphs_device::intc_r), FUNC(sa1110_periphs_device::intc_w)); + map(0x90060000, 0x90060013).rw(m_sa_periphs, FUNC(sa1110_periphs_device::ppc_r), FUNC(sa1110_periphs_device::ppc_w)); + map(0xb0000000, 0xb00000bf).rw(m_sa_periphs, FUNC(sa1110_periphs_device::dma_r), FUNC(sa1110_periphs_device::dma_w)); map(0xc0000000, 0xc1ffffff).ram().share("ram"); map(0xe0000000, 0xe0003fff).noprw(); // Cache-Flush Region 0 map(0xe0100000, 0xe01003ff).noprw(); // Cache-Flush Region 1 @@ -126,6 +174,23 @@ void jornada_state::main_map(address_map &map) void jornada_state::device_reset_after_children() { + m_sa_periphs->gpio_in<9>(1); +} + +void jornada_state::mcu_assemble_touch_data() +{ + const uint16_t pen_x = m_pen_x->read(); + const uint16_t pen_y = m_pen_y->read(); + const uint8_t touch_recv_idx = 1 - m_mcu_touch_send_idx; + m_mcu_touch_data[touch_recv_idx][0] = (uint8_t)pen_x; + m_mcu_touch_data[touch_recv_idx][1] = (uint8_t)pen_x; + m_mcu_touch_data[touch_recv_idx][2] = (uint8_t)pen_x; + m_mcu_touch_data[touch_recv_idx][3] = (uint8_t)pen_y; + m_mcu_touch_data[touch_recv_idx][4] = (uint8_t)pen_y; + m_mcu_touch_data[touch_recv_idx][5] = (uint8_t)pen_y; + m_mcu_touch_data[touch_recv_idx][6] = (uint8_t)((pen_x >> 8) * 0x15); + m_mcu_touch_data[touch_recv_idx][7] = (uint8_t)((pen_y >> 8) * 0x15); + m_mcu_touch_count[touch_recv_idx] = 8; } void jornada_state::mcu_byte_received(uint16_t data) @@ -133,7 +198,7 @@ void jornada_state::mcu_byte_received(uint16_t data) const uint8_t raw_value = (uint8_t)(data >> 8); const uint8_t value = bitswap<8>(raw_value, 0, 1, 2, 3, 4, 5, 6, 7); - uint8_t response = 0x11; + uint8_t response = MCU_TXDUMMY; switch (m_mcu_state) { case MCU_IDLE: @@ -144,6 +209,11 @@ void jornada_state::mcu_byte_received(uint16_t data) m_mcu_state = MCU_KBD_SEND_COUNT; m_mcu_key_send_idx = 1 - m_mcu_key_send_idx; break; + case 0xa0: + LOGMASKED(LOG_MCU, "mcu_byte_received in MCU_IDLE: GetTouchSamples, entering TOUCH_SEND_DATA state\n"); + m_mcu_state = MCU_TOUCH_SEND_DATA; + m_mcu_touch_send_idx = 1 - m_mcu_touch_send_idx; + break; default: LOGMASKED(LOG_MCU, "mcu_byte_received in MCU_IDLE: Unknown (%02x), ignoring and sending TxDummy response\n", value); break; @@ -151,7 +221,7 @@ void jornada_state::mcu_byte_received(uint16_t data) break; case MCU_KBD_SEND_COUNT: - if (value == 0x11) + if (value == MCU_TXDUMMY || value == MCU_TXDUMMY2) { LOGMASKED(LOG_MCU, "mcu_byte_received in MCU_KBD_SEND_COUNT: TxDummy, entering KBD_SEND_CODES state\n"); response = m_mcu_key_count[m_mcu_key_send_idx]; @@ -159,16 +229,42 @@ void jornada_state::mcu_byte_received(uint16_t data) } else { - LOGMASKED(LOG_MCU, "mcu_byte_received in MCU_KBD_SEND_COUNT: Unknown (%02x), sending ErrorCode response and returning to IDLE state\n"); + LOGMASKED(LOG_MCU, "mcu_byte_received in MCU_KBD_SEND_COUNT: Unknown (%02x), sending ErrorCode response and returning to IDLE state\n", value); + response = 0; + } + break; + + case MCU_TOUCH_SEND_DATA: + if (value == MCU_TXDUMMY || value == MCU_TXDUMMY2) + { + m_mcu_touch_count[m_mcu_touch_send_idx]--; + response = m_mcu_touch_data[m_mcu_touch_send_idx][m_mcu_touch_idx[m_mcu_touch_send_idx]]; + m_mcu_touch_idx[m_mcu_touch_send_idx]++; + if (m_mcu_touch_count[m_mcu_touch_send_idx]) + { + LOGMASKED(LOG_MCU, "mcu_byte_received in MCU_TOUCH_SEND_DATA: TxDummy, sending touch data %02x with %d remaining\n", response, m_mcu_touch_count[m_mcu_touch_send_idx]); + } + else + { + LOGMASKED(LOG_MCU, "mcu_byte_received in MCU_TOUCH_SEND_DATA: TxDummy, sending touch data %02x and returning to IDLE state\n", response); + m_mcu_state = MCU_IDLE; + m_mcu_touch_idx[m_mcu_touch_send_idx] = 0; + //machine().debug_break(); + } + } + else + { + LOGMASKED(LOG_MCU, "mcu_byte_received in MCU_TOUCH_SEND_DATA: Unknown (%02x), sending ErrorCode response and returning to IDLE state\n", value); response = 0; } break; case MCU_KBD_SEND_CODES: - if (value == 0x11) + if (value == MCU_TXDUMMY || value == MCU_TXDUMMY2) { m_mcu_key_count[m_mcu_key_send_idx]--; - response = m_mcu_key_codes[m_mcu_key_send_idx][m_mcu_key_count[m_mcu_key_send_idx]]; + response = m_mcu_key_codes[m_mcu_key_send_idx][m_mcu_key_idx[m_mcu_key_send_idx]]; + m_mcu_key_idx[m_mcu_key_send_idx]++; if (m_mcu_key_count[m_mcu_key_send_idx]) { LOGMASKED(LOG_MCU, "mcu_byte_received in MCU_KBD_SEND_CODES: TxDummy, sending scan code %02x with %d remaining\n", response, m_mcu_key_count[m_mcu_key_send_idx]); @@ -177,6 +273,7 @@ void jornada_state::mcu_byte_received(uint16_t data) { LOGMASKED(LOG_MCU, "mcu_byte_received in MCU_KBD_SEND_CODES: TxDummy, sending scan code %02x and returning to IDLE state\n", response); m_mcu_state = MCU_IDLE; + m_mcu_key_idx[m_mcu_key_send_idx] = 0; } } else @@ -190,59 +287,20 @@ void jornada_state::mcu_byte_received(uint16_t data) m_sa_periphs->ssp_in((uint16_t)response); } -void jornada_state::eeprom_cmd_received(uint16_t data) +void jornada_state::eeprom_select(int state) { - bool reset_state = true; - uint8_t response = 0; - - if (m_eeprom_cmd == 0) - { - m_eeprom_cmd = (uint8_t)data; - if (m_eeprom_cmd == 3) - reset_state = false; - } - else if (m_eeprom_count == 0) - { - if (m_eeprom_cmd == 3) - { - m_eeprom_count = (uint8_t)data; - m_eeprom_read_idx = 0; - reset_state = false; - } - } - else if (m_eeprom_read_idx < m_eeprom_count) - { - response = m_eeprom_data[m_eeprom_read_idx]; - m_eeprom_read_idx++; - if (m_eeprom_read_idx < m_eeprom_count) - reset_state = false; - } + m_nvram->select_w(!state); +} +void jornada_state::eeprom_data_received(uint16_t data) +{ + const uint8_t response = m_nvram->access((uint8_t)data); m_companion->ssp_in((uint16_t)response); - - if (reset_state) - { - m_eeprom_cmd = 0; - m_eeprom_count = 0; - m_eeprom_read_idx = 0; - } } INPUT_CHANGED_MEMBER(jornada_state::key_changed) { - uint8_t scan_code = 0; - switch (param) - { - case KEY_ON_OFF: scan_code = 0x7f; break; - case KEY_S: scan_code = 0x32; break; - case KEY_K: scan_code = 0x38; break; - case KEY_1: scan_code = 0x11; break; - case KEY_2: scan_code = 0x12; break; - case KEY_3: scan_code = 0x13; break; - case KEY_4: scan_code = 0x14; break; - case KEY_9: scan_code = 0x19; break; - default: return; - } + uint8_t scan_code = (uint8_t)param; m_sa_periphs->gpio_in<0>(1); m_sa_periphs->gpio_in<0>(0); @@ -255,16 +313,72 @@ INPUT_CHANGED_MEMBER(jornada_state::key_changed) } } +INPUT_CHANGED_MEMBER(jornada_state::pen_changed) +{ + switch (param) + { + case PEN_X: + case PEN_Y: + if (m_pen_button->read() && m_mcu_state == MCU_IDLE) + { + mcu_assemble_touch_data(); + m_sa_periphs->gpio_in<9>(1); + m_sa_periphs->gpio_in<9>(0); + } + break; + case PEN_BUTTON: + if (newval) + { + m_sa_periphs->gpio_in<9>(0); + mcu_assemble_touch_data(); + } + else + { + m_sa_periphs->gpio_in<9>(1); + } + break; + } +} + static INPUT_PORTS_START( jornada720 ) PORT_START("KBD0") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("On/Off") PORT_CODE(KEYCODE_HOME) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_ON_OFF) - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_S) - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_K) - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_1) - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_2) - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("3") PORT_CODE(KEYCODE_1) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_3) - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("4") PORT_CODE(KEYCODE_2) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_4) - PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("9") PORT_CODE(KEYCODE_2) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_9) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("On/Off") PORT_CODE(KEYCODE_HOME) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_ON_OFF) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_S) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_K) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_1) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_2) + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_1) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_3) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4") PORT_CODE(KEYCODE_2) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_4) + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_2) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_9) + + PORT_START("KBD1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_TAB) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_ENTER) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_A) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_N) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_L) + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_M) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_P) + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_C) + + PORT_START("KBD2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_B) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Alt") PORT_CODE(KEYCODE_LALT) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_ALT) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_SPACE) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Backspace") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_BACKSPACE) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Left Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_LSHIFT) + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Right Shift") PORT_CODE(KEYCODE_RSHIFT) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, key_changed, jornada_state::KEY_RSHIFT) + PORT_BIT(0xc0, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("PENX") + PORT_BIT(0x3ff, 590, IPT_LIGHTGUN_X) PORT_NAME("Pen X") PORT_MINMAX(270, 910) PORT_SENSITIVITY(50) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, pen_changed, jornada_state::PEN_X) + + PORT_START("PENY") + PORT_BIT(0x3ff, 500, IPT_LIGHTGUN_Y) PORT_NAME("Pen Y") PORT_MINMAX(180, 820) PORT_SENSITIVITY(50) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, pen_changed, jornada_state::PEN_Y) + + PORT_START("PENZ") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Pen Touch") PORT_CODE(MOUSECODE_BUTTON1) PORT_CHANGED_MEMBER(DEVICE_SELF, jornada_state, pen_changed, jornada_state::PEN_BUTTON) + PORT_BIT(0xfe, IP_ACTIVE_HIGH, IPT_UNUSED) INPUT_PORTS_END void jornada_state::machine_start() @@ -273,23 +387,28 @@ void jornada_state::machine_start() save_item(NAME(m_mcu_key_send_idx)); save_item(NAME(m_mcu_key_codes)); save_item(NAME(m_mcu_key_count)); - - save_item(NAME(m_eeprom_cmd)); - save_item(NAME(m_eeprom_count)); - save_item(NAME(m_eeprom_read_idx)); + save_item(NAME(m_mcu_key_idx)); + save_item(NAME(m_mcu_touch_send_idx)); + save_item(NAME(m_mcu_touch_data)); + save_item(NAME(m_mcu_touch_count)); + save_item(NAME(m_mcu_touch_idx)); } void jornada_state::machine_reset() { m_mcu_state = MCU_IDLE; + m_mcu_key_send_idx = 0; memset(m_mcu_key_codes[0], 0, 8); memset(m_mcu_key_codes[1], 0, 8); memset(m_mcu_key_count, 0, 2); + memset(m_mcu_key_idx, 0, 2); - m_eeprom_cmd = 0; - m_eeprom_count = 0; - m_eeprom_read_idx = 0; + m_mcu_touch_send_idx = 0; + memset(m_mcu_touch_data[0], 0, 8); + memset(m_mcu_touch_data[1], 0, 8); + memset(m_mcu_touch_count, 0, 2); + memset(m_mcu_touch_idx, 0, 2); } void jornada_state::jornada720(machine_config &config) @@ -300,13 +419,24 @@ void jornada_state::jornada720(machine_config &config) SA1110_PERIPHERALS(config, m_sa_periphs, SA1110_CLOCK, m_maincpu); m_sa_periphs->ssp_out().set(FUNC(jornada_state::mcu_byte_received)); - SA1111(config, m_companion); - m_companion->ssp_out().set(FUNC(jornada_state::eeprom_cmd_received)); + SA1111(config, m_companion, 3.6864_MHz_XTAL, m_maincpu); + m_companion->set_audio_codec_tag(m_codec); + m_companion->pb_out<0>().set(FUNC(jornada_state::eeprom_select)); + m_companion->ssp_out().set(FUNC(jornada_state::eeprom_data_received)); m_companion->l3_addr_out().set(m_codec, FUNC(uda1344_device::l3_addr_w)); m_companion->l3_data_out().set(m_codec, FUNC(uda1344_device::l3_data_w)); + m_companion->i2s_out().set(m_codec, FUNC(uda1344_device::i2s_input_w)); + m_companion->irq_out().set(m_sa_periphs, FUNC(sa1110_periphs_device::gpio_in<1>)); + + M95020(config, m_nvram); UDA1344(config, m_codec); m_codec->l3_ack_out().set(m_companion, FUNC(sa1111_device::l3wd_in)); + m_codec->add_route(0, "lspeaker", 0.5); + m_codec->add_route(1, "rspeaker", 0.5); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); SED1356(config, m_epson); m_epson->set_screen("screen"); @@ -328,8 +458,8 @@ ROM_START( jorn720 ) ROM_REGION32_LE( 0x2000000, "firmware", ROMREGION_ERASE00 ) ROM_LOAD( "jornada720.bin", 0x0000000, 0x2000000, CRC(5fcd433a) SHA1(f05f7b377b582a7355bf119d74435f0ee6104cca) ) - ROM_REGION( 0x80, "eeprom", ROMREGION_ERASE00 ) - ROM_LOAD( "jorn720_eeprom.bin", 0x00, 0x80, CRC(54ffaaff) SHA1(5b8296782b6dc1c60b80169c071fb157d0681567) BAD_DUMP ) + ROM_REGION( 0x100, "nvram", ROMREGION_ERASE00 ) + ROM_LOAD( "jorn720_eeprom.bin", 0x000, 0x100, CRC(9bc1d53a) SHA1(793d6ff355e2e9b3e75574ff80edfa5af2aaeee6) BAD_DUMP ) ROM_END } // anonymous namespace