diff options
Diffstat (limited to 'src/devices/machine/scc68070.cpp')
-rw-r--r-- | src/devices/machine/scc68070.cpp | 945 |
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; } |