summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/scc68070.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/scc68070.cpp')
-rw-r--r--src/devices/machine/scc68070.cpp945
1 files changed, 759 insertions, 186 deletions
diff --git a/src/devices/machine/scc68070.cpp b/src/devices/machine/scc68070.cpp
index 38511711e75..57238532f41 100644
--- a/src/devices/machine/scc68070.cpp
+++ b/src/devices/machine/scc68070.cpp
@@ -13,33 +13,194 @@
STATUS:
-- Skeleton. Just enough for the CD-i to run.
+- Skeleton. Just enough for the CD-i and Magicard to run.
TODO:
- Proper handling of the 68070's internal devices (UART, DMA, Timers, etc.)
+- I2C could do with re-visiting.
*******************************************************************************/
#include "emu.h"
-#include "machine/scc68070.h"
-
-#define LOG_I2C (1 << 0)
-#define LOG_UART (1 << 1)
-#define LOG_TIMERS (1 << 2)
-#define LOG_TIMERS_HF (1 << 3)
-#define LOG_DMA (1 << 4)
-#define LOG_MMU (1 << 5)
-#define LOG_IRQS (1 << 6)
-#define LOG_UNKNOWN (1 << 7)
+#include "scc68070.h"
+
+#define LOG_I2C (1U << 1)
+#define LOG_UART (1U << 2)
+#define LOG_TIMERS (1U << 3)
+#define LOG_TIMERS_HF (1U << 4)
+#define LOG_DMA (1U << 5)
+#define LOG_MMU (1U << 6)
+#define LOG_IRQS (1U << 7)
+#define LOG_UNKNOWN (1U << 8)
+#define LOG_MORE_UART (1U << 9)
#define LOG_ALL (LOG_I2C | LOG_UART | LOG_TIMERS | LOG_DMA | LOG_MMU | LOG_IRQS | LOG_UNKNOWN)
-#define VERBOSE (LOG_UART)
+#define VERBOSE (0)
#include "logmacro.h"
#define ENABLE_UART_PRINTING (0)
+//**************************************************************************
+// Register defines
+//**************************************************************************
+enum isr_bits
+{
+ ISR_MST = 0x80, // Master
+ ISR_TRX = 0x40, // Transmitter
+ ISR_BB = 0x20, // Busy
+ ISR_PIN = 0x10, // No Pending Interrupt
+ ISR_AL = 0x08, // Arbitration Lost
+ ISR_AAS = 0x04, // Addressed As Slave
+ ISR_AD0 = 0x02, // Address Zero
+ ISR_LRB = 0x01, // Last Received Bit
+ ISR_SSR_MASK = (ISR_MST | ISR_TRX | ISR_BB),// Mask for detecting start/stop/restart
+ ISR_START = (ISR_MST | ISR_TRX | ISR_BB),// Start bit request
+ ISR_STOP = (ISR_MST | ISR_TRX) // Stop bit request
+};
+
+enum umr_bits
+{
+ UMR_OM = 0xc0,
+ UMR_OM_NORMAL = 0x00,
+ UMR_OM_ECHO = 0x40,
+ UMR_OM_LOOPBACK = 0x80,
+ UMR_OM_RLOOP = 0xc0,
+ UMR_TXC = 0x10,
+ UMR_PC = 0x08,
+ UMR_P = 0x04,
+ UMR_SB = 0x02,
+ UMR_CL = 0x01
+};
+
+enum usr_bits
+{
+ USR_RB = 0x80,
+ USR_FE = 0x40,
+ USR_PE = 0x20,
+ USR_OE = 0x10,
+ USR_TXEMT = 0x08,
+ USR_TXRDY = 0x04,
+ USR_RXRDY = 0x01
+};
+
+enum tsr_bits
+{
+ TSR_OV0 = 0x80,
+ TSR_MA1 = 0x40,
+ TSR_CAP1 = 0x20,
+ TSR_OV1 = 0x10,
+ TSR_MA2 = 0x08,
+ TSR_CAP2 = 0x04,
+ TSR_OV2 = 0x02
+};
+
+enum tcr_bits
+{
+ TCR_E1 = 0xc0,
+ TCR_E1_NONE = 0x00,
+ TCR_E1_RISING = 0x40,
+ TCR_E1_FALLING = 0x80,
+ TCR_E1_BOTH = 0xc0,
+ TCR_M1 = 0x30,
+ TCR_M1_NONE = 0x00,
+ TCR_M1_MATCH = 0x10,
+ TCR_M1_CAPTURE = 0x20,
+ TCR_M1_COUNT = 0x30,
+ TCR_E2 = 0x0c,
+ TCR_E2_NONE = 0x00,
+ TCR_E2_RISING = 0x04,
+ TCR_E2_FALLING = 0x08,
+ TCR_E2_BOTH = 0x0c,
+ TCR_M2 = 0x03,
+ TCR_M2_NONE = 0x00,
+ TCR_M2_MATCH = 0x01,
+ TCR_M2_CAPTURE = 0x02,
+ TCR_M2_COUNT = 0x03
+};
+
+enum csr_bits
+{
+ CSR_COC = 0x80,
+ CSR_NDT = 0x20,
+ CSR_ERR = 0x10,
+ CSR_CA = 0x08
+};
+
+enum cer_bits
+{
+ CER_EC = 0x1f,
+ CER_NONE = 0x00,
+ CER_TIMING = 0x02,
+ CER_BUSERR_MEM = 0x09,
+ CER_BUSERR_DEV = 0x0a,
+ CER_SOFT_ABORT = 0x11
+};
+
+enum dcr1_bits
+{
+ DCR1_ERM = 0x80,
+ DCR1_DT = 0x30
+};
+
+enum dcr2_bits
+{
+ DCR2_ERM = 0x80,
+ DCR2_DT = 0x30,
+ DCR2_DS = 0x08
+};
+
+
+enum scr2_bits
+{
+ SCR2_MAC = 0x0c,
+ SCR2_MAC_NONE = 0x00,
+ SCR2_MAC_INC = 0x04,
+ SCR2_DAC = 0x03,
+ SCR2_DAC_NONE = 0x00,
+ SCR2_DAC_INC = 0x01
+};
+
+enum ccr_bits
+{
+ CCR_SO = 0x80,
+ CCR_SA = 0x10,
+ CCR_INE = 0x08,
+ CCR_IPL = 0x07
+};
+
+enum icr_bits
+{
+ ICR_SEL = 0x40,
+ ICR_ESO = 0x08,
+ ICR_ACK = 0x04
+};
+
+enum i2c_states
+{
+ I2C_IDLE = 0,
+ I2C_TX_IN_PROGRESS,
+ I2C_RX_IN_PROGRESS,
+ I2C_RX_COMPLETE,
+ I2C_GET_ACK,
+ I2C_SEND_ACK,
+ I2C_SEND_ACK_AND_RX,
+ I2C_SEND_ACK_AND_STOP,
+ I2C_SEND_STOP,
+ I2C_CHANGED_TO_RX,
+ I2C_SEND_RESTART
+};
+
+enum i2c_clock_states
+{
+ I2C_SCL_IDLE = 0,
+ I2C_SCL_SET_0,
+ I2C_SCL_SET_1,
+ I2C_SCL_WAIT_1,
+};
+
+
// device type definition
DEFINE_DEVICE_TYPE(SCC68070, scc68070_device, "scc68070", "Philips SCC68070")
@@ -79,11 +240,15 @@ void scc68070_device::cpu_space_map(address_map &map)
scc68070_device::scc68070_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: scc68070_base_device(mconfig, tag, owner, clock, SCC68070, address_map_constructor(FUNC(scc68070_device::internal_map), this))
- , m_iack2_callback(*this)
- , m_iack4_callback(*this)
- , m_iack5_callback(*this)
- , m_iack7_callback(*this)
+ , m_iack2_callback(*this, autovector(2))
+ , m_iack4_callback(*this, autovector(4))
+ , m_iack5_callback(*this, autovector(5))
+ , m_iack7_callback(*this, autovector(7))
, m_uart_tx_callback(*this)
+ , m_uart_rtsn_callback(*this)
+ , m_i2c_scl_callback(*this)
+ , m_i2c_sdaw_callback(*this)
+ , m_i2c_sdar_callback(*this, 0)
, m_ipl(0)
, m_in2_line(CLEAR_LINE)
, m_in4_line(CLEAR_LINE)
@@ -96,23 +261,6 @@ scc68070_device::scc68070_device(const machine_config &mconfig, const char *tag,
}
//-------------------------------------------------
-// device_resolve_objects - resolve objects that
-// may be needed for other devices to set
-// initial conditions at start time
-//-------------------------------------------------
-
-void scc68070_device::device_resolve_objects()
-{
- scc68070_base_device::device_resolve_objects();
-
- m_iack2_callback.resolve_safe(autovector(2));
- m_iack4_callback.resolve_safe(autovector(4));
- m_iack5_callback.resolve_safe(autovector(5));
- m_iack7_callback.resolve_safe(autovector(7));
- m_uart_tx_callback.resolve_safe();
-}
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -143,13 +291,28 @@ void scc68070_device::device_start()
save_item(NAME(m_i2c.status_register));
save_item(NAME(m_i2c.control_register));
save_item(NAME(m_i2c.clock_control_register));
+ save_item(NAME(m_i2c.scl_out_state));
+ save_item(NAME(m_i2c.scl_in_state));
+ save_item(NAME(m_i2c.sda_out_state));
+ save_item(NAME(m_i2c.sda_in_state));
+ save_item(NAME(m_i2c.state));
+ save_item(NAME(m_i2c.counter));
+ save_item(NAME(m_i2c.clock_change_state));
+ save_item(NAME(m_i2c.clocks));
+ save_item(NAME(m_i2c.first_byte));
+ save_item(NAME(m_i2c.ack_or_nak_sent));
save_item(NAME(m_uart.mode_register));
save_item(NAME(m_uart.status_register));
save_item(NAME(m_uart.clock_select));
save_item(NAME(m_uart.command_register));
- save_item(NAME(m_uart.transmit_holding_register));
save_item(NAME(m_uart.receive_holding_register));
+ save_item(NAME(m_uart.receive_pointer));
+ save_item(NAME(m_uart.receive_buffer));
+ save_item(NAME(m_uart.transmit_holding_register));
+ save_item(NAME(m_uart.transmit_pointer));
+ save_item(NAME(m_uart.transmit_buffer));
+ save_item(NAME(m_uart.transmit_ctsn));
save_item(NAME(m_timers.timer_status_register));
save_item(NAME(m_timers.timer_control_register));
@@ -158,68 +321,34 @@ void scc68070_device::device_start()
save_item(NAME(m_timers.timer1));
save_item(NAME(m_timers.timer2));
- save_item(NAME(m_dma.channel[0].channel_status));
- save_item(NAME(m_dma.channel[0].channel_error));
- save_item(NAME(m_dma.channel[0].device_control));
- save_item(NAME(m_dma.channel[0].operation_control));
- save_item(NAME(m_dma.channel[0].sequence_control));
- save_item(NAME(m_dma.channel[0].channel_control));
- save_item(NAME(m_dma.channel[0].transfer_counter));
- save_item(NAME(m_dma.channel[0].memory_address_counter));
- save_item(NAME(m_dma.channel[0].device_address_counter));
- save_item(NAME(m_dma.channel[1].channel_status));
- save_item(NAME(m_dma.channel[1].channel_error));
- save_item(NAME(m_dma.channel[1].device_control));
- save_item(NAME(m_dma.channel[1].operation_control));
- save_item(NAME(m_dma.channel[1].sequence_control));
- save_item(NAME(m_dma.channel[1].channel_control));
- save_item(NAME(m_dma.channel[1].transfer_counter));
- save_item(NAME(m_dma.channel[1].memory_address_counter));
- save_item(NAME(m_dma.channel[1].device_address_counter));
+ save_item(STRUCT_MEMBER(m_dma.channel, channel_status));
+ save_item(STRUCT_MEMBER(m_dma.channel, channel_error));
+ save_item(STRUCT_MEMBER(m_dma.channel, device_control));
+ save_item(STRUCT_MEMBER(m_dma.channel, operation_control));
+ save_item(STRUCT_MEMBER(m_dma.channel, sequence_control));
+ save_item(STRUCT_MEMBER(m_dma.channel, channel_control));
+ save_item(STRUCT_MEMBER(m_dma.channel, transfer_counter));
+ save_item(STRUCT_MEMBER(m_dma.channel, memory_address_counter));
+ save_item(STRUCT_MEMBER(m_dma.channel, device_address_counter));
save_item(NAME(m_mmu.status));
save_item(NAME(m_mmu.control));
- save_item(NAME(m_mmu.desc[0].attr));
- save_item(NAME(m_mmu.desc[0].length));
- save_item(NAME(m_mmu.desc[0].segment));
- save_item(NAME(m_mmu.desc[0].base));
- save_item(NAME(m_mmu.desc[1].attr));
- save_item(NAME(m_mmu.desc[1].length));
- save_item(NAME(m_mmu.desc[1].segment));
- save_item(NAME(m_mmu.desc[1].base));
- save_item(NAME(m_mmu.desc[2].attr));
- save_item(NAME(m_mmu.desc[2].length));
- save_item(NAME(m_mmu.desc[2].segment));
- save_item(NAME(m_mmu.desc[2].base));
- save_item(NAME(m_mmu.desc[3].attr));
- save_item(NAME(m_mmu.desc[3].length));
- save_item(NAME(m_mmu.desc[3].segment));
- save_item(NAME(m_mmu.desc[3].base));
- save_item(NAME(m_mmu.desc[4].attr));
- save_item(NAME(m_mmu.desc[4].length));
- save_item(NAME(m_mmu.desc[4].segment));
- save_item(NAME(m_mmu.desc[4].base));
- save_item(NAME(m_mmu.desc[5].attr));
- save_item(NAME(m_mmu.desc[5].length));
- save_item(NAME(m_mmu.desc[5].segment));
- save_item(NAME(m_mmu.desc[5].base));
- save_item(NAME(m_mmu.desc[6].attr));
- save_item(NAME(m_mmu.desc[6].length));
- save_item(NAME(m_mmu.desc[6].segment));
- save_item(NAME(m_mmu.desc[6].base));
- save_item(NAME(m_mmu.desc[7].attr));
- save_item(NAME(m_mmu.desc[7].length));
- save_item(NAME(m_mmu.desc[7].segment));
- save_item(NAME(m_mmu.desc[7].base));
-
- m_timers.timer0_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scc68070_device::timer0_callback), this));
+ save_item(STRUCT_MEMBER(m_mmu.desc, attr));
+ save_item(STRUCT_MEMBER(m_mmu.desc, length));
+ save_item(STRUCT_MEMBER(m_mmu.desc, segment));
+ save_item(STRUCT_MEMBER(m_mmu.desc, base));
+
+ m_timers.timer0_timer = timer_alloc(FUNC(scc68070_device::timer0_callback), this);
m_timers.timer0_timer->adjust(attotime::never);
- m_uart.rx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scc68070_device::rx_callback), this));
+ m_uart.rx_timer = timer_alloc(FUNC(scc68070_device::rx_callback), this);
m_uart.rx_timer->adjust(attotime::never);
- m_uart.tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scc68070_device::tx_callback), this));
+ m_uart.tx_timer = timer_alloc(FUNC(scc68070_device::tx_callback), this);
m_uart.tx_timer->adjust(attotime::never);
+
+ m_i2c.timer = timer_alloc(FUNC(scc68070_device::i2c_callback), this);
+ m_i2c.timer->adjust(attotime::never);
}
//-------------------------------------------------
@@ -241,9 +370,15 @@ void scc68070_device::device_reset()
m_i2c.data_register = 0;
m_i2c.address_register = 0;
- m_i2c.status_register = 0;
+ m_i2c.status_register = ISR_PIN;
m_i2c.control_register = 0;
m_i2c.clock_control_register = 0;
+ m_i2c.scl_out_state = true;
+ m_i2c.scl_in_state = true;
+ m_i2c.sda_out_state = true;
+ m_i2c.state = I2C_IDLE;
+ m_i2c.clock_change_state = I2C_SCL_IDLE;
+ m_i2c.clocks = 0;
m_uart.mode_register = 0;
m_uart.status_register = USR_TXRDY;
@@ -253,6 +388,7 @@ void scc68070_device::device_reset()
m_uart.receive_holding_register = 0;
m_uart.receive_pointer = -1;
m_uart.transmit_pointer = -1;
+ m_uart.transmit_ctsn = true;
m_timers.timer_status_register = 0;
m_timers.timer_control_register = 0;
@@ -285,34 +421,61 @@ void scc68070_device::device_reset()
}
update_ipl();
+
+ m_uart.rx_timer->adjust(attotime::never);
+ m_uart.tx_timer->adjust(attotime::never);
+ set_timer_callback(0);
}
-void scc68070_device::m68k_reset_peripherals()
+
+void scc68070_device::device_config_complete()
{
- m_lir = 0;
+ scc68070_base_device::device_config_complete();
- m_picr1 = 0;
- m_picr2 = 0;
- m_timer_int = false;
- m_i2c_int = false;
- m_uart_rx_int = false;
- m_uart_tx_int = false;
+ reset_cb().append(*this, FUNC(scc68070_device::reset_peripherals));
+}
- m_i2c.status_register = 0;
- m_i2c.control_register = 0;
- m_i2c.clock_control_register = 0;
- m_uart.command_register = 0;
- m_uart.receive_pointer = -1;
- m_uart.transmit_pointer = -1;
- m_uart.mode_register = 0;
- m_uart.status_register = USR_TXRDY;
- m_uart.clock_select = 0;
+void scc68070_device::reset_peripherals(int state)
+{
+ if (state)
+ {
+ m_lir = 0;
+
+ m_picr1 = 0;
+ m_picr2 = 0;
+ m_timer_int = false;
+ m_i2c_int = false;
+ m_uart_rx_int = false;
+ m_uart_tx_int = false;
+
+ m_i2c.status_register = ISR_PIN;
+ m_i2c.control_register = 0;
+ m_i2c.clock_control_register = 0;
+ m_i2c.scl_out_state = true;
+ m_i2c.scl_in_state = true;
+ m_i2c.sda_out_state = true;
+ m_i2c.state = I2C_IDLE;
+ m_i2c.clock_change_state = I2C_SCL_IDLE;
+ m_i2c.clocks = 0;
+ m_uart.command_register = 0;
+ m_uart.receive_pointer = -1;
+ m_uart.transmit_pointer = -1;
+
+ m_uart.mode_register = 0;
+ m_uart.status_register = USR_TXRDY;
+ m_uart.clock_select = 0;
+
+ m_timers.timer_status_register = 0;
+ m_timers.timer_control_register = 0;
- m_timers.timer_status_register = 0;
- m_timers.timer_control_register = 0;
+ m_uart.rx_timer->adjust(attotime::never);
+ m_uart.tx_timer->adjust(attotime::never);
+ m_timers.timer0_timer->adjust(attotime::never);
+ m_i2c.timer->adjust(attotime::never);
- update_ipl();
+ update_ipl();
+ }
}
void scc68070_device::update_ipl()
@@ -342,31 +505,31 @@ void scc68070_device::update_ipl()
}
}
-WRITE_LINE_MEMBER(scc68070_device::in2_w)
+void scc68070_device::in2_w(int state)
{
m_in2_line = state;
update_ipl();
}
-WRITE_LINE_MEMBER(scc68070_device::in4_w)
+void scc68070_device::in4_w(int state)
{
m_in4_line = state;
update_ipl();
}
-WRITE_LINE_MEMBER(scc68070_device::in5_w)
+void scc68070_device::in5_w(int state)
{
m_in5_line = state;
update_ipl();
}
-WRITE_LINE_MEMBER(scc68070_device::nmi_w)
+void scc68070_device::nmi_w(int state)
{
m_nmi_line = state;
update_ipl();
}
-WRITE_LINE_MEMBER(scc68070_device::int1_w)
+void scc68070_device::int1_w(int state)
{
if (m_int1_line != state)
{
@@ -380,7 +543,7 @@ WRITE_LINE_MEMBER(scc68070_device::int1_w)
}
}
-WRITE_LINE_MEMBER(scc68070_device::int2_w)
+void scc68070_device::int2_w(int state)
{
if (m_int2_line != state)
{
@@ -390,7 +553,7 @@ WRITE_LINE_MEMBER(scc68070_device::int2_w)
update_ipl();
}
- m_int1_line = state;
+ m_int2_line = state;
}
}
@@ -475,7 +638,7 @@ void scc68070_device::set_timer_callback(int channel)
}
}
-TIMER_CALLBACK_MEMBER( scc68070_device::timer0_callback )
+TIMER_CALLBACK_MEMBER(scc68070_device::timer0_callback)
{
m_timers.timer0 = m_timers.reload_register;
m_timers.timer_status_register |= TSR_OV0;
@@ -488,60 +651,25 @@ TIMER_CALLBACK_MEMBER( scc68070_device::timer0_callback )
set_timer_callback(0);
}
-void scc68070_device::uart_rx_check()
-{
- if ((m_uart.command_register & 3) == 1)
- {
- uint32_t div = 0x10000 >> ((m_uart.clock_select >> 4) & 7);
- m_uart.rx_timer->adjust(attotime::from_hz((49152000 / div) / 8));
- }
- else
- {
- m_uart.status_register &= ~USR_RXRDY;
- m_uart.rx_timer->adjust(attotime::never);
- }
-}
-
-void scc68070_device::uart_tx_check()
+void scc68070_device::uart_ctsn(int state)
{
- if (((m_uart.command_register >> 2) & 3) == 1)
- {
- if (m_uart.transmit_pointer >= 0)
- {
- m_uart.status_register &= ~USR_TXRDY;
- }
- else
- {
- m_uart.status_register |= USR_TXRDY;
- }
-
- if (m_uart.tx_timer->remaining() == attotime::never)
- {
- uint32_t div = 0x10000 >> (m_uart.clock_select & 7);
- m_uart.tx_timer->adjust(attotime::from_hz((49152000 / div) / 8));
- }
- }
- else
- {
- m_uart.tx_timer->adjust(attotime::never);
- }
+ m_uart.transmit_ctsn = state ? true : false;
}
void scc68070_device::uart_rx(uint8_t data)
{
m_uart.receive_pointer++;
m_uart.receive_buffer[m_uart.receive_pointer] = data;
- uart_rx_check();
}
void scc68070_device::uart_tx(uint8_t data)
{
m_uart.transmit_pointer++;
m_uart.transmit_buffer[m_uart.transmit_pointer] = data;
- uart_tx_check();
+ m_uart.status_register &= ~USR_TXEMT;
}
-TIMER_CALLBACK_MEMBER( scc68070_device::rx_callback )
+TIMER_CALLBACK_MEMBER(scc68070_device::rx_callback)
{
if ((m_uart.command_register & 3) == 1)
{
@@ -564,8 +692,6 @@ TIMER_CALLBACK_MEMBER( scc68070_device::rx_callback )
update_ipl();
m_uart.status_register |= USR_RXRDY;
- uint32_t div = 0x10000 >> ((m_uart.clock_select >> 4) & 7);
- m_uart.rx_timer->adjust(attotime::from_hz((49152000 / div) / 8));
}
else
{
@@ -576,55 +702,80 @@ TIMER_CALLBACK_MEMBER( scc68070_device::rx_callback )
{
m_uart.status_register &= ~USR_RXRDY;
}
-
- uart_rx_check();
}
-TIMER_CALLBACK_MEMBER( scc68070_device::tx_callback )
+TIMER_CALLBACK_MEMBER(scc68070_device::tx_callback)
{
if (((m_uart.command_register >> 2) & 3) == 1)
{
+ m_uart.status_register |= USR_TXRDY;
+
m_uart_tx_int = true;
update_ipl();
if (m_uart.transmit_pointer > -1)
{
+ if (m_uart.transmit_ctsn && BIT(m_uart.mode_register, 4))
+ {
+ return;
+ }
+
m_uart.transmit_holding_register = m_uart.transmit_buffer[0];
m_uart_tx_callback(m_uart.transmit_holding_register);
- LOGMASKED(LOG_UART, "tx_callback: Transmitting %02x\n", machine().describe_context(), m_uart.transmit_holding_register);
+ LOGMASKED(LOG_MORE_UART, "tx_callback: Transmitting %02x\n", m_uart.transmit_holding_register);
for(int index = 0; index < m_uart.transmit_pointer; index++)
{
m_uart.transmit_buffer[index] = m_uart.transmit_buffer[index+1];
}
m_uart.transmit_pointer--;
-
- uint32_t div = 0x10000 >> (m_uart.clock_select & 7);
- m_uart.tx_timer->adjust(attotime::from_hz((49152000 / div) / 8));
}
- else
+
+ if (m_uart.transmit_pointer < 0)
{
- m_uart.tx_timer->adjust(attotime::never);
+ m_uart.status_register |= USR_TXEMT;
}
}
- else
- {
- m_uart.tx_timer->adjust(attotime::never);
- }
-
- uart_tx_check();
}
uint8_t scc68070_device::lir_r()
{
// LIR priority level: 80001001
- return m_lir;
+ return m_lir & 0x77;
}
void scc68070_device::lir_w(uint8_t data)
{
LOGMASKED(LOG_IRQS, "%s: LIR Write: %02x\n", machine().describe_context(), data);
- m_lir = data;
+
+ switch (data & 0x88)
+ {
+ case 0x08:
+ if (m_lir & 0x08)
+ {
+ m_lir &= 0xf7;
+ update_ipl();
+ }
+ break;
+
+ case 0x80:
+ if (data & 0x80)
+ {
+ m_lir &= 0x7f;
+ update_ipl();
+ }
+ break;
+
+ case 0x88:
+ if (data & 0x88)
+ {
+ m_lir &= 0x77;
+ update_ipl();
+ }
+ break;
+ }
+
+ m_lir = (m_lir & 0x88) | (data & 0x77);
}
uint8_t scc68070_device::picr1_r()
@@ -714,6 +865,35 @@ uint8_t scc68070_device::idr_r()
// I2C data register: 80002001
if (!machine().side_effects_disabled())
LOGMASKED(LOG_I2C, "%s: I2C Data Register Read: %02x\n", machine().describe_context(), m_i2c.data_register);
+
+ m_i2c.counter = 0;
+ m_i2c.status_register |= ISR_PIN;
+ m_i2c_int = false;
+ update_ipl();
+
+ if (m_i2c.state != I2C_RX_COMPLETE)
+ {
+ }
+ else
+ {
+ m_i2c.sda_out_state = (m_i2c.control_register & ICR_ACK) ? false : true;
+ m_i2c_sdaw_callback(m_i2c.sda_out_state);
+
+ if (m_i2c.control_register & ICR_ACK)
+ {
+ m_i2c.state = I2C_SEND_ACK_AND_RX;
+ m_i2c.clocks = 9;
+ }
+ else
+ {
+ m_i2c.state = I2C_SEND_ACK;
+ m_i2c.clocks = 1;
+ }
+ m_i2c.ack_or_nak_sent = true;
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ set_i2c_timer();
+
+ }
return m_i2c.data_register;
}
@@ -721,6 +901,18 @@ void scc68070_device::idr_w(uint8_t data)
{
LOGMASKED(LOG_I2C, "%s: I2C Data Register Write: %02x\n", machine().describe_context(), data);
m_i2c.data_register = data;
+ if (m_i2c.status_register & ISR_MST && m_i2c.status_register & ISR_TRX && m_i2c.status_register & ISR_BB)
+ {
+ m_i2c.status_register |= ISR_PIN;
+ m_i2c_int = false;
+ update_ipl();
+ m_i2c.counter = 0;
+ m_i2c.state = I2C_TX_IN_PROGRESS;
+ m_i2c.clocks = 9;
+ i2c_process_falling_scl();
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ set_i2c_timer();
+ }
}
uint8_t scc68070_device::iar_r()
@@ -742,13 +934,154 @@ uint8_t scc68070_device::isr_r()
// I2C status register: 80002005
if (!machine().side_effects_disabled())
LOGMASKED(LOG_I2C, "%s: I2C Status Register Read: %02x\n", machine().describe_context(), m_i2c.status_register);
- return m_i2c.status_register & 0xef; // hack for magicard
+ return m_i2c.status_register;
}
void scc68070_device::isr_w(uint8_t data)
{
LOGMASKED(LOG_I2C, "%s: I2C Status Register Write: %02x\n", machine().describe_context(), data);
- m_i2c.status_register = data;
+ if (data & ISR_MST)
+ {
+ if ((data & ISR_SSR_MASK) == ISR_START)
+ {
+ if ((m_i2c.status_register & ISR_SSR_MASK) == ISR_STOP || (m_i2c.status_register & ISR_SSR_MASK) == 0)
+ {
+ if (m_i2c_sdar_callback() && m_i2c.state == I2C_IDLE)
+ {
+ m_i2c.status_register = data;
+ if (data & ISR_PIN)
+ {
+ m_i2c_int = false;
+ update_ipl();
+ }
+ m_i2c.sda_out_state = false;
+ m_i2c_sdaw_callback(false);
+ m_i2c.clock_change_state = I2C_SCL_SET_0;
+ m_i2c.clocks = 10;
+ m_i2c.state = I2C_TX_IN_PROGRESS;
+ m_i2c.first_byte = true;
+ m_i2c.ack_or_nak_sent = false;
+ set_i2c_timer();
+ m_i2c.counter = 0;
+ }
+ else
+ {
+ m_i2c.status_register |= ISR_AL;
+ m_i2c.status_register &= ~ISR_PIN;
+ m_i2c_int = true;
+ update_ipl();
+ }
+ }
+ else if ((m_i2c.status_register & ISR_SSR_MASK) == ISR_MST)
+ {
+ m_i2c.status_register = data;
+ if (data & ISR_PIN)
+ {
+ m_i2c_int = false;
+ update_ipl();
+ }
+ m_i2c.sda_out_state = true;
+ m_i2c_sdaw_callback(true);
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ m_i2c.clocks = 10;
+ m_i2c.state = I2C_SEND_RESTART;
+ m_i2c.first_byte = true;
+ m_i2c.ack_or_nak_sent = false;
+ set_i2c_timer();
+ m_i2c.counter = 0;
+ }
+ }
+ else if ((data & ISR_SSR_MASK) == ISR_STOP && m_i2c.status_register & ISR_BB)
+ {
+ // we should send STOP here, however, unkte06 in magicard appears to expect
+ // NAK followed by STOP when in read mode.
+
+ if (data & ISR_PIN)
+ {
+ m_i2c_int = false;
+ update_ipl();
+ }
+
+ if (m_i2c.ack_or_nak_sent || (m_i2c.status_register & ISR_TRX))
+ {
+ m_i2c.state = I2C_SEND_STOP;
+ m_i2c.sda_out_state = false;
+ m_i2c_sdaw_callback(false);
+ }
+ else
+ {
+ m_i2c.ack_or_nak_sent = true;
+ m_i2c.sda_out_state = (m_i2c.control_register&ICR_ACK) ? false : true;
+ m_i2c_sdaw_callback(m_i2c.sda_out_state);
+ m_i2c.state = I2C_SEND_ACK_AND_STOP;
+ m_i2c.clocks = 2;
+ }
+ m_i2c.status_register = data | ISR_BB;
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ set_i2c_timer();
+ }
+ else if ((data & ISR_SSR_MASK) == ISR_MST)
+ {
+ m_i2c.status_register = data;
+ if (data & ISR_PIN)
+ {
+ m_i2c_int = false;
+ update_ipl();
+ }
+ }
+ else
+ {
+ if (data & ISR_PIN && !(m_i2c.status_register & ISR_PIN))
+ {
+ if (m_i2c.state == I2C_CHANGED_TO_RX)
+ {
+ m_i2c.state = I2C_RX_IN_PROGRESS;
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ m_i2c.status_register = data;
+ m_i2c_int = false;
+ update_ipl();
+ m_i2c.counter = 0;
+ m_i2c.clocks = 8;
+ set_i2c_timer();
+ }
+ else
+ {
+ m_i2c.ack_or_nak_sent = true;
+ m_i2c.sda_out_state = (m_i2c.control_register&ICR_ACK) ? false : true;
+ m_i2c_sdaw_callback(m_i2c.sda_out_state);
+ m_i2c.status_register = data;
+ m_i2c_int = false;
+ update_ipl();
+ m_i2c.state = I2C_SEND_ACK;
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ m_i2c.clocks = 1;
+ set_i2c_timer();
+ }
+ }
+ else
+ {
+ m_i2c.status_register = data;
+ if (data & ISR_PIN)
+ {
+ m_i2c_int = false;
+ update_ipl();
+ }
+ }
+ }
+ }
+ else
+ {
+ m_i2c.status_register = data;
+ m_i2c_int = false;
+ update_ipl();
+ m_i2c.timer->adjust(attotime::never);
+ m_i2c_scl_callback(1);
+ m_i2c_sdaw_callback(1);
+ m_i2c.scl_out_state = true;
+ m_i2c.scl_in_state = true;
+ m_i2c.sda_out_state = true;
+ m_i2c.state = I2C_IDLE;
+ }
}
uint8_t scc68070_device::icr_r()
@@ -763,6 +1096,17 @@ void scc68070_device::icr_w(uint8_t data)
{
LOGMASKED(LOG_I2C, "%s: I2C Control Register Write: %02x\n", machine().describe_context(), data);
m_i2c.control_register = data;
+
+ if (!(data & ICR_ESO))
+ {
+ m_i2c.timer->adjust(attotime::never);
+ m_i2c_scl_callback(1);
+ m_i2c_sdaw_callback(1);
+ m_i2c.scl_out_state = true;
+ m_i2c.scl_in_state = true;
+ m_i2c.sda_out_state = true;
+ m_i2c.state = I2C_IDLE;
+ }
}
uint8_t scc68070_device::iccr_r()
@@ -779,17 +1123,211 @@ void scc68070_device::iccr_w(uint8_t data)
m_i2c.clock_control_register = data & 0x1f;
}
+
+void scc68070_device::i2c_process_falling_scl()
+{
+ switch (m_i2c.state)
+ {
+ case I2C_TX_IN_PROGRESS:
+ if (m_i2c.counter<8)
+ {
+ m_i2c.sda_out_state = BIT(m_i2c.data_register, 7 - m_i2c.counter);
+ m_i2c_sdaw_callback(m_i2c.sda_out_state);
+ m_i2c.counter++;
+ }
+ else
+ {
+ m_i2c.sda_out_state = true;
+ m_i2c_sdaw_callback(true);
+ m_i2c.state = I2C_GET_ACK;
+ }
+ break;
+
+ case I2C_GET_ACK:
+ m_i2c.status_register &= ~ISR_PIN;
+ m_i2c_int = true;
+ update_ipl();
+ m_i2c.state = I2C_IDLE;
+ if (m_i2c.first_byte)
+ {
+ m_i2c.first_byte = false;
+ if (BIT(m_i2c.data_register, 0))
+ {
+ m_i2c.status_register &= ~ISR_TRX;
+ if (!(m_i2c.status_register & ISR_LRB))
+ {
+ m_i2c.state = I2C_CHANGED_TO_RX;
+ }
+ }
+ }
+ break;
+
+ case I2C_RX_IN_PROGRESS:
+ if (m_i2c.counter >= 8)
+ {
+ m_i2c.status_register &= ~ISR_PIN;
+ m_i2c_int = true;
+ update_ipl();
+ m_i2c.state = I2C_RX_COMPLETE;
+ }
+ break;
+
+ case I2C_SEND_ACK_AND_RX:
+ m_i2c.sda_out_state = true;
+ m_i2c_sdaw_callback(true);
+ m_i2c.state = I2C_RX_IN_PROGRESS;
+ m_i2c.counter = 0;
+ break;
+
+ case I2C_SEND_ACK_AND_STOP:
+ m_i2c.sda_out_state = false;
+ m_i2c_sdaw_callback(false);
+ m_i2c.state = I2C_SEND_STOP;
+ break;
+
+ case I2C_SEND_ACK:
+ m_i2c.state = I2C_IDLE;
+ m_i2c.status_register &= ~ISR_PIN;
+ m_i2c_int = true;
+ update_ipl();
+ break;
+ }
+}
+
+void scc68070_device::i2c_process_rising_scl()
+{
+ switch (m_i2c.state)
+ {
+ case I2C_GET_ACK:
+ if (m_i2c_sdar_callback())
+ {
+ m_i2c.status_register |= ISR_LRB;
+ }
+ else
+ {
+ m_i2c.status_register &= ~ISR_LRB;
+ }
+ break;
+
+ case I2C_SEND_STOP:
+ case I2C_SEND_RESTART:
+ m_i2c.timer->adjust(attotime::from_nsec(5000));
+ break;
+
+ case I2C_RX_IN_PROGRESS:
+ if (m_i2c.counter < 8)
+ {
+ m_i2c.data_register <<= 1;
+ m_i2c.data_register |= m_i2c_sdar_callback();
+ m_i2c.counter++;
+ }
+ break;
+ }
+}
+
+void scc68070_device::write_scl(int state)
+{
+ if (m_i2c.status_register & ISR_MST)
+ {
+ if (m_i2c.scl_in_state != state && state)
+ {
+ i2c_process_rising_scl();
+ i2c_next_state();
+ }
+ }
+ m_i2c.scl_in_state = state;
+}
+
+TIMER_CALLBACK_MEMBER(scc68070_device::i2c_callback)
+{
+ i2c_next_state();
+}
+
+void scc68070_device::i2c_next_state()
+{
+ switch (m_i2c.clock_change_state)
+ {
+ case I2C_SCL_SET_0:
+ if (m_i2c.state == I2C_SEND_STOP)
+ {
+ if (!m_i2c.sda_out_state)
+ {
+ m_i2c.sda_out_state = true;
+ m_i2c_sdaw_callback(true);
+ set_i2c_timer();
+ }
+ else
+ {
+ m_i2c.state = I2C_IDLE;
+ m_i2c.status_register &= ~(ISR_PIN | ISR_BB);
+ m_i2c_int = true;
+ update_ipl();
+ m_i2c.clock_change_state = I2C_SCL_IDLE;
+ }
+ }
+ else if (m_i2c.state == I2C_SEND_RESTART)
+ {
+ m_i2c.sda_out_state = false;
+ m_i2c_sdaw_callback(false);
+ set_i2c_timer();
+ m_i2c.clock_change_state = I2C_SCL_SET_0;
+ m_i2c.state = I2C_TX_IN_PROGRESS;
+ }
+ else
+ {
+ m_i2c.scl_out_state = false;
+ m_i2c_scl_callback(false);
+ if (m_i2c.clocks)
+ {
+ m_i2c.clocks--;
+ }
+ if (m_i2c.clocks == 0)
+ {
+ m_i2c.clock_change_state = I2C_SCL_IDLE;
+ }
+ else
+ {
+ set_i2c_timer();
+ m_i2c.clock_change_state = I2C_SCL_SET_1;
+ }
+ i2c_process_falling_scl();
+ }
+ break;
+
+ case I2C_SCL_SET_1:
+ m_i2c.clock_change_state = I2C_SCL_WAIT_1;
+ m_i2c.scl_out_state = true;
+ m_i2c_scl_callback(true);
+ break;
+
+ case I2C_SCL_WAIT_1:
+ set_i2c_timer();
+ m_i2c.clock_change_state = I2C_SCL_SET_0;
+ break;
+ }
+}
+
+void scc68070_device::set_i2c_timer()
+{
+ // divider offset 0 entry is illegal
+ static constexpr int divider[]={ 1, 78, 90, 102, 126, 150, 174, 198,
+ 246, 294, 342, 390, 486, 582, 678, 774,
+ 996, 1158, 1350, 1542, 1926, 2310, 2694, 3078,
+ 3846, 4614, 5382, 6150, 7686, 9222, 10758, 12294 };
+ m_i2c.timer->adjust(cycles_to_attotime(divider[m_i2c.clock_control_register]));
+}
+
uint8_t scc68070_device::umr_r()
{
// UART mode register: 80002011
if (!machine().side_effects_disabled())
- LOGMASKED(LOG_UART, "%s: UART Mode Register Read: %02x\n", machine().describe_context(), m_uart.mode_register);
+ LOGMASKED(LOG_MORE_UART, "%s: UART Mode Register Read: %02x\n", machine().describe_context(), m_uart.mode_register);
return m_uart.mode_register | 0x20;
}
void scc68070_device::umr_w(uint8_t data)
{
- LOGMASKED(LOG_UART, "%s: UART Mode Register Write: %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_MORE_UART, "%s: UART Mode Register Write: %02x\n", machine().describe_context(), data);
m_uart.mode_register = data;
}
@@ -799,7 +1337,7 @@ uint8_t scc68070_device::usr_r()
if (!machine().side_effects_disabled())
{
m_uart.status_register |= (1 << 1);
- LOGMASKED(LOG_UART, "%s: UART Status Register Read: %02x\n", machine().describe_context(), m_uart.status_register);
+ LOGMASKED(LOG_MORE_UART, "%s: UART Status Register Read: %02x\n", machine().describe_context(), m_uart.status_register);
}
return m_uart.status_register | 0x08; // hack for magicard
}
@@ -816,6 +1354,13 @@ void scc68070_device::ucsr_w(uint8_t data)
{
LOGMASKED(LOG_UART, "%s: UART Clock Select Write: %02x\n", machine().describe_context(), data);
m_uart.clock_select = data;
+
+ static const uint32_t s_baud_divisors[8] = { 65536, 32768, 16384, 4096, 2048, 1024, 512, 256 };
+
+ attotime rx_rate = attotime::from_ticks(s_baud_divisors[(data >> 4) & 7] * 10, 49152000);
+ attotime tx_rate = attotime::from_ticks(s_baud_divisors[data & 7] * 10, 49152000);
+ m_uart.rx_timer->adjust(rx_rate, 0, rx_rate);
+ m_uart.tx_timer->adjust(tx_rate, 0, tx_rate);
}
uint8_t scc68070_device::ucr_r()
@@ -828,10 +1373,36 @@ uint8_t scc68070_device::ucr_r()
void scc68070_device::ucr_w(uint8_t data)
{
- LOGMASKED(LOG_UART, "%s: UART Command Register Write: %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_MORE_UART, "%s: UART Command Register Write: %02x\n", machine().describe_context(), data);
m_uart.command_register = data;
- uart_rx_check();
- uart_tx_check();
+ const uint8_t misc_command = (data & 0x70) >> 4;
+ switch (misc_command)
+ {
+ case 0x2: // Reset receiver
+ LOGMASKED(LOG_MORE_UART, "%s: Reset receiver\n", machine().describe_context());
+ m_uart.receive_pointer = -1;
+ m_uart.command_register &= 0xf0;
+ m_uart.receive_holding_register = 0x00;
+ break;
+ case 0x3: // Reset transmitter
+ LOGMASKED(LOG_MORE_UART, "%s: Reset transmitter\n", machine().describe_context());
+ m_uart.transmit_pointer = -1;
+ m_uart.status_register |= USR_TXEMT;
+ m_uart.command_register &= 0xf0;
+ m_uart.transmit_holding_register = 0x00;
+ break;
+ case 0x4: // Reset error status
+ LOGMASKED(LOG_MORE_UART, "%s: Reset error status\n", machine().describe_context());
+ m_uart.status_register &= 0x87; // Clear error bits in USR
+ m_uart.command_register &= 0xf0;
+ break;
+ case 0x6: // Start break
+ LOGMASKED(LOG_MORE_UART, "%s: Start break (not yet implemented)\n", machine().describe_context());
+ break;
+ case 0x7: // Stop break
+ LOGMASKED(LOG_MORE_UART, "%s: Stop break (not yet implemented)\n", machine().describe_context());
+ break;
+ }
}
uint8_t scc68070_device::uth_r()
@@ -844,7 +1415,7 @@ uint8_t scc68070_device::uth_r()
void scc68070_device::uth_w(uint8_t data)
{
- LOGMASKED(LOG_UART, "%s: UART Transmit Holding Register Write: %02x ('%c')\n", machine().describe_context(), data, (data >= 0x20 && data < 0x7f) ? data : ' ');
+ LOGMASKED(LOG_MORE_UART, "%s: UART Transmit Holding Register Write: %02x ('%c')\n", machine().describe_context(), data, (data >= 0x20 && data < 0x7f) ? data : ' ');
uart_tx(data);
m_uart.transmit_holding_register = data;
}
@@ -897,7 +1468,8 @@ uint16_t scc68070_device::timer_r(offs_t offset, uint16_t mem_mask)
case 0x4/2:
if (!machine().side_effects_disabled())
LOGMASKED(LOG_TIMERS, "%s: Timer 0 Read: %04x & %04x\n", machine().describe_context(), m_timers.timer0, mem_mask);
- return m_timers.timer0;
+ return 0x10000 - (attotime_to_cycles(m_timers.timer0_timer->remaining()) / 96);
+
case 0x6/2:
if (!machine().side_effects_disabled())
LOGMASKED(LOG_TIMERS, "%s: Timer 1 Read: %04x & %04x\n", machine().describe_context(), m_timers.timer1, mem_mask);
@@ -935,6 +1507,7 @@ void scc68070_device::timer_w(offs_t offset, uint16_t data, uint16_t mem_mask)
case 0x2/2:
LOGMASKED(LOG_TIMERS, "%s: Timer Reload Register Write: %04x & %04x\n", machine().describe_context(), data, mem_mask);
COMBINE_DATA(&m_timers.reload_register);
+ set_timer_callback(0);
break;
case 0x4/2:
LOGMASKED(LOG_TIMERS, "%s: Timer 0 Write: %04x & %04x\n", machine().describe_context(), data, mem_mask);
@@ -1254,7 +1827,7 @@ void scc68070_device::mmu_w(offs_t offset, uint16_t data, uint16_t mem_mask)
}
#if ENABLE_UART_PRINTING
-READ16_MEMBER( scc68070_device::uart_loopback_enable )
+uint16_t scc68070_device::uart_loopback_enable()
{
return 0x1234;
}