diff --git a/src/devices/machine/spg2xx.cpp b/src/devices/machine/spg2xx.cpp index 3ca6e8b5ada..95814ab145b 100644 --- a/src/devices/machine/spg2xx.cpp +++ b/src/devices/machine/spg2xx.cpp @@ -41,12 +41,14 @@ DEFINE_DEVICE_TYPE(SPG28X, spg28x_device, "spg28x", "SPG280-series System-on-a-C #define LOG_PPU_READS (1U << 22) #define LOG_PPU_WRITES (1U << 23) #define LOG_UNKNOWN_PPU (1U << 24) +#define LOG_FIQ (1U << 25) +#define LOG_SIO (1U << 26) #define LOG_IO (LOG_IO_READS | LOG_IO_WRITES | LOG_IRQS | LOG_GPIO | LOG_UART | LOG_I2C | LOG_DMA | LOG_TIMERS | LOG_UNKNOWN_IO) #define LOG_CHANNELS (LOG_CHANNEL_READS | LOG_CHANNEL_WRITES) #define LOG_SPU (LOG_SPU_READS | LOG_SPU_WRITES | LOG_UNKNOWN_SPU | LOG_CHANNEL_READS | LOG_CHANNEL_WRITES \ | LOG_ENVELOPES | LOG_SAMPLES | LOG_RAMPDOWN | LOG_BEAT) #define LOG_PPU (LOG_PPU_READS | LOG_PPU_WRITES | LOG_UNKNOWN_PPU) -#define LOG_ALL (LOG_IO | LOG_SPU | LOG_PPU | LOG_VLINES | LOG_SEGMENT) +#define LOG_ALL (LOG_IO | LOG_SPU | LOG_PPU | LOG_VLINES | LOG_SEGMENT | LOG_FIQ) #define VERBOSE (0) #include "logmacro.h" @@ -891,7 +893,8 @@ void spg2xx_device::uart_rx(uint8_t data) m_uart_rx_fifo[m_uart_rx_fifo_end] = data; m_uart_rx_fifo_end = (m_uart_rx_fifo_end + 1) % ARRAY_LENGTH(m_uart_rx_fifo); m_uart_rx_fifo_count++; - m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); + if (m_uart_rx_timer->remaining() == attotime::never) + m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); } } @@ -947,6 +950,8 @@ READ16_MEMBER(spg2xx_device::io_r) case 0x27: // ADC Data m_io_regs[0x27] = 0; + IO_IRQ_STATUS &= ~0x4000; + check_irqs(0x4000); LOGMASKED(LOG_IO_READS, "%s: io_r: ADC Data = %04x\n", machine().describe_context(), val); break; @@ -964,7 +969,7 @@ READ16_MEMBER(spg2xx_device::io_r) break; case 0x2e: // FIQ Source Select - LOGMASKED(LOG_IRQS, "io_r: FIQ Source Select = %04x\n", val); + LOGMASKED(LOG_FIQ, "io_r: FIQ Source Select = %04x\n", val); break; case 0x2f: // Data Segment @@ -979,20 +984,30 @@ READ16_MEMBER(spg2xx_device::io_r) case 0x36: // UART RX Data if (m_uart_rx_available) { + m_io_regs[0x31] &= ~0x0081; + logerror("UART Rx data is available, clearing bits\n"); if (m_uart_rx_fifo_count) { + logerror("Remaining count %d, value %02x\n", m_uart_rx_fifo_count, m_uart_rx_fifo[m_uart_rx_fifo_start]); m_io_regs[0x36] = m_uart_rx_fifo[m_uart_rx_fifo_start]; + val = m_io_regs[0x36]; m_uart_rx_fifo_start = (m_uart_rx_fifo_start + 1) % ARRAY_LENGTH(m_uart_rx_fifo); m_uart_rx_fifo_count--; + if (m_uart_rx_fifo_count == 0) { - m_io_regs[0x31] &= ~0x0081; m_uart_rx_available = false; } + else + { + logerror("Remaining count %d, setting up timer\n", m_uart_rx_fifo_count); + //uart_receive_tick(); + if (m_uart_rx_timer->remaining() == attotime::never) + m_uart_rx_timer->adjust(attotime::from_ticks(BIT(m_io_regs[0x30], 5) ? 11 : 10, m_uart_baud_rate)); + } } else { - m_io_regs[0x31] &= ~0x0081; m_uart_rx_available = false; } } @@ -1091,6 +1106,20 @@ void spg2xx_device::update_portb_special_modes() } } +WRITE16_MEMBER(spg28x_device::io_w) +{ + if (offset == 0x33) + { + m_io_regs[offset] = data; + m_uart_baud_rate = 27000000 / (0x10000 - m_io_regs[0x33]); + LOGMASKED(LOG_UART, "io_w: UART Baud Rate scaler = %04x (%d baud)\n", data, m_uart_baud_rate); + } + else + { + spg2xx_device::io_w(space, offset, data, mem_mask); + } +} + WRITE16_MEMBER(spg2xx_device::io_w) { static const char *const gpioregs[] = { "GPIO Data Port", "GPIO Buffer Port", "GPIO Direction Port", "GPIO Attribute Port", "GPIO IRQ/Latch Port" }; @@ -1274,16 +1303,17 @@ WRITE16_MEMBER(spg2xx_device::io_w) case 0x25: // ADC Control { LOGMASKED(LOG_IO_WRITES, "%s: io_w: ADC Control = %04x\n", machine().describe_context(), data); - const uint16_t changed = m_io_regs[offset] ^ data; - m_io_regs[offset] = data; - if (BIT(changed, 12) && BIT(data, 12) && !BIT(m_io_regs[offset], 1)) + m_io_regs[offset] = data & ~0x1000; + if (BIT(data, 12) && !BIT(m_io_regs[offset], 1)) { m_io_regs[0x27] = 0x8000 | (m_adc_in() & 0x7fff); const uint16_t old = IO_IRQ_STATUS; - IO_IRQ_STATUS |= 0x2000; + IO_IRQ_STATUS |= 0x4000; const uint16_t changed = IO_IRQ_STATUS ^ old; if (changed) + { check_irqs(changed); + } } break; } @@ -1324,7 +1354,7 @@ WRITE16_MEMBER(spg2xx_device::io_w) { "PPU", "SPU Channel", "Timer A", "Timer B", "UART/SPI", "External", "Reserved", "None" }; - LOGMASKED(LOG_IRQS, "io_w: FIQ Source Select (not yet implemented) = %04x, %s\n", data, s_fiq_select[data & 7]); + LOGMASKED(LOG_FIQ, "io_w: FIQ Source Select (not yet implemented) = %04x, %s\n", data, s_fiq_select[data & 7]); m_io_regs[offset] = data; break; } @@ -1424,6 +1454,33 @@ WRITE16_MEMBER(spg2xx_device::io_w) m_io_regs[offset] |= data & 0x0007; break; + case 0x50: // SIO Setup + { + static const char* const s_addr_mode[4] = { "16-bit", "None", "8-bit", "24-bit" }; + static const char* const s_baud_rate[4] = { "/16", "/4", "/8", "/32" }; + LOGMASKED(LOG_SIO, "io_w: SIO Setup (not implemented) = %04x (DS301Ready:%d, Start:%d, Auto:%d, IRQEn:%d, Width:%d, Related:%d\n", data + , BIT(data, 11), BIT(data, 10), BIT(data, 9), BIT(data, 8), BIT(data, 7) ? 16 : 8, BIT(data, 6)); + LOGMASKED(LOG_SIO, " (Mode:%s, RWProtocol:%d, Rate:sysclk%s, AddrMode:%s)\n" + , BIT(data, 5), BIT(data, 4), s_baud_rate[(data >> 2) & 3], s_addr_mode[data & 3]); + break; + } + + case 0x52: // SIO Start Address (low) + LOGMASKED(LOG_SIO, "io_w: SIO Stat Address (low) (not implemented) = %04x\n", data); + break; + + case 0x53: // SIO Start Address (hi) + LOGMASKED(LOG_SIO, "io_w: SIO Stat Address (hi) (not implemented) = %04x\n", data); + break; + + case 0x54: // SIO Data + LOGMASKED(LOG_SIO, "io_w: SIO Data (not implemented) = %04x\n", data); + break; + + case 0x55: // SIO Automatic Transmit Count + LOGMASKED(LOG_SIO, "io_w: SIO Auto Transmit Count (not implemented) = %04x\n", data); + break; + case 0x58: // I2C Command LOGMASKED(LOG_I2C, "io_w: I2C Command = %04x\n", data); m_io_regs[offset] = data; @@ -1607,9 +1664,6 @@ void spg2xx_device::uart_receive_tick() { LOGMASKED(LOG_UART, "uart_receive_tick: Setting RBF and RxRDY\n"); m_io_regs[0x31] |= 0x81; - m_io_regs[0x36] = m_uart_rx_fifo[m_uart_rx_fifo_start]; - m_uart_rx_fifo_start = (m_uart_rx_fifo_start + 1) % ARRAY_LENGTH(m_uart_rx_fifo); - m_uart_rx_fifo_count--; m_uart_rx_available = true; if (BIT(m_io_regs[0x30], 0)) { @@ -1732,8 +1786,6 @@ void spg2xx_device::do_gpio(uint32_t offset) uint16_t what = (buffer & (push | pull)); what ^= (dir & ~attr); what &= ~special; - //if (index == 0) - //printf("buf:%04x, dir:%04x, pull:%04x, push:%04x\n", buffer, dir, pull, push); switch (index) { diff --git a/src/devices/machine/spg2xx.h b/src/devices/machine/spg2xx.h index 1220b4bfb3b..937fe1d4ead 100644 --- a/src/devices/machine/spg2xx.h +++ b/src/devices/machine/spg2xx.h @@ -387,8 +387,8 @@ protected: DECLARE_WRITE16_MEMBER(video_w); DECLARE_READ16_MEMBER(audio_r); DECLARE_WRITE16_MEMBER(audio_w); - DECLARE_READ16_MEMBER(io_r); - DECLARE_WRITE16_MEMBER(io_w); + virtual DECLARE_READ16_MEMBER(io_r); + virtual DECLARE_WRITE16_MEMBER(io_w); void check_irqs(const uint16_t changed); inline void check_video_irq(); @@ -552,6 +552,8 @@ public: } spg28x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual DECLARE_WRITE16_MEMBER(io_w) override; }; DECLARE_DEVICE_TYPE(SPG24X, spg24x_device) diff --git a/src/mame/drivers/clickstart.cpp b/src/mame/drivers/clickstart.cpp index 9b0edd2fe42..70eb2b2d1c7 100644 --- a/src/mame/drivers/clickstart.cpp +++ b/src/mame/drivers/clickstart.cpp @@ -6,8 +6,6 @@ Status: - Calls to unmapped space - Some games have Checksums listed in the header area that appear to be like the byte checksums on the Radica games in vii.cpp, however the calculation doesn't add up correctly. There is also a checksum in @@ -44,12 +42,29 @@ public: , m_spg(*this, "spg") , m_cart(*this, "cartslot") , m_system_region(*this, "maincpu") + , m_io_mouse_x(*this, "MOUSEX") + , m_io_mouse_y(*this, "MOUSEY") , m_cart_region(nullptr) + , m_mouse_x(0) + , m_mouse_y(0) + , m_mouse_dx(0) + , m_mouse_dy(0) + , m_uart_tx_fifo_start(0) + , m_uart_tx_fifo_end(0) + , m_uart_tx_fifo_count(0) + , m_uart_tx_timer(nullptr) + , m_unk_portc_toggle(0) { } void clickstart(machine_config &config); + DECLARE_INPUT_CHANGED_MEMBER(mouse_update); + private: + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + static const device_timer_id TIMER_UART_TX = 0; + virtual void machine_start() override; virtual void machine_reset() override; @@ -68,17 +83,35 @@ private: DECLARE_WRITE8_MEMBER(chip_sel_w); + void handle_uart_tx(); + void uart_tx_fifo_push(uint8_t value); + + void update_mouse_buffer(); + required_device m_maincpu; required_device m_screen; required_device m_spg; required_device m_cart; required_memory_region m_system_region; + required_ioport m_io_mouse_x; + required_ioport m_io_mouse_y; memory_region *m_cart_region; + uint16_t m_mouse_x; + uint16_t m_mouse_y; + int16_t m_mouse_dx; + int16_t m_mouse_dy; + uint8_t m_mouse_buffer[16]; + + uint8_t m_uart_tx_fifo[32]; // arbitrary size + uint8_t m_uart_tx_fifo_start; + uint8_t m_uart_tx_fifo_end; + uint8_t m_uart_tx_fifo_count; + emu_timer *m_uart_tx_timer; + uint16_t m_unk_portc_toggle; }; - void clickstart_state::machine_start() { // if there's a cart, override the standard mapping @@ -88,11 +121,37 @@ void clickstart_state::machine_start() m_cart_region = memregion(region_tag.assign(m_cart->tag()).append(GENERIC_ROM_REGION_TAG).c_str()); } + save_item(NAME(m_mouse_x)); + save_item(NAME(m_mouse_y)); + save_item(NAME(m_mouse_dx)); + save_item(NAME(m_mouse_dy)); + save_item(NAME(m_mouse_buffer)); + + save_item(NAME(m_uart_tx_fifo)); + save_item(NAME(m_uart_tx_fifo_start)); + save_item(NAME(m_uart_tx_fifo_end)); + save_item(NAME(m_uart_tx_fifo_count)); + save_item(NAME(m_unk_portc_toggle)); + + m_uart_tx_timer = timer_alloc(TIMER_UART_TX); + m_uart_tx_timer->adjust(attotime::never); } void clickstart_state::machine_reset() { + m_mouse_x = 0xffff; + m_mouse_y = 0xffff; + m_mouse_dx = 0; + m_mouse_dy = 0; + memset(m_mouse_buffer, 0, ARRAY_LENGTH(m_mouse_buffer)); + + memset(m_uart_tx_fifo, 0, ARRAY_LENGTH(m_uart_tx_fifo)); + m_uart_tx_fifo_start = 0; + m_uart_tx_fifo_end = 0; + m_uart_tx_fifo_count = 0; + m_uart_tx_timer->adjust(attotime::from_hz(3200/10), 0, attotime::from_hz(3200/10)); + m_unk_portc_toggle = 0; } @@ -106,6 +165,95 @@ DEVICE_IMAGE_LOAD_MEMBER(clickstart_state, cart) return image_init_result::PASS; } +void clickstart_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_UART_TX) + { + handle_uart_tx(); + } +} + +void clickstart_state::handle_uart_tx() +{ + if (m_uart_tx_fifo_count == 0) + return; + + m_spg->uart_rx(m_uart_tx_fifo[m_uart_tx_fifo_start]); + m_uart_tx_fifo_start = (m_uart_tx_fifo_start + 1) % ARRAY_LENGTH(m_uart_tx_fifo); + m_uart_tx_fifo_count--; +} + +void clickstart_state::uart_tx_fifo_push(uint8_t value) +{ + if (m_uart_tx_fifo_count >= ARRAY_LENGTH(m_uart_tx_fifo)) + { + logerror("Warning: Trying to push too much data onto the mouse Tx FIFO, data will be lost.\n"); + } + + m_uart_tx_fifo[m_uart_tx_fifo_end] = value; + m_uart_tx_fifo_end = (m_uart_tx_fifo_end + 1) % ARRAY_LENGTH(m_uart_tx_fifo); + m_uart_tx_fifo_count++; +} + +INPUT_CHANGED_MEMBER(clickstart_state::mouse_update) +{ + uint16_t x = m_io_mouse_x->read(); + uint16_t y = m_io_mouse_y->read(); + uint16_t old_mouse_x = m_mouse_x; + uint16_t old_mouse_y = m_mouse_y; + + if (m_mouse_x == 0xffff) + { + old_mouse_x = x; + old_mouse_y = y; + } + + m_mouse_x = x; + m_mouse_y = y; + + m_mouse_dx += (m_mouse_x - old_mouse_x); + m_mouse_dy += (m_mouse_y - old_mouse_y); + + if (m_mouse_dx < -63) + m_mouse_dx = -63; + else if (m_mouse_dx > 62) + m_mouse_dx = 62; + + if (m_mouse_dy < -63) + m_mouse_dy = -63; + else if (m_mouse_dy > 62) + m_mouse_dy = 62; + + update_mouse_buffer(); + + m_mouse_dx = 0; + m_mouse_dy = 0; +} + +void clickstart_state::update_mouse_buffer() +{ + if (m_mouse_dx == 0 && m_mouse_dy == 0) + return; + + m_mouse_buffer[0] = 0x03; + m_mouse_buffer[1] = (m_mouse_x + 1) & 0x3f; + m_mouse_buffer[2] = (m_mouse_y + 1) & 0x3f; + m_mouse_buffer[3] = (m_mouse_dx + 1) & 0x3f; + m_mouse_buffer[4] = (m_mouse_dy + 1) & 0x3f; + + //printf("Queueing: "); + uint16_t sum = 0; + for (int i = 0; i < 5; i++) + { + uart_tx_fifo_push(m_mouse_buffer[i] ^ 0xff); + sum += m_mouse_buffer[i]; + //printf("%02x ", m_mouse_buffer[i] ^ 0xff); + } + sum = (sum & 0xff) ^ 0xff; + uart_tx_fifo_push((uint8_t)sum); + //printf("%02x\n", (uint8_t)sum); +} + READ16_MEMBER(clickstart_state::rom_r) { if (offset < 0x400000 / 2) @@ -123,7 +271,7 @@ READ16_MEMBER(clickstart_state::rom_r) WRITE16_MEMBER(clickstart_state::porta_w) { - logerror("%s: porta_w: %04x & %04x\n", machine().describe_context(), data, mem_mask); + //logerror("%s: porta_w: %04x & %04x\n", machine().describe_context(), data, mem_mask); } WRITE16_MEMBER(clickstart_state::portb_w) @@ -138,8 +286,8 @@ WRITE16_MEMBER(clickstart_state::portc_w) READ16_MEMBER(clickstart_state::porta_r) { - uint16_t data = 0x5000; - logerror("%s: porta_r: %04x & %04x\n", machine().describe_context(), data, mem_mask); + uint16_t data = 0x4000; + //logerror("%s: porta_r: %04x & %04x\n", machine().describe_context(), data, mem_mask); return data; } @@ -169,6 +317,11 @@ void clickstart_state::mem_map(address_map &map) } static INPUT_PORTS_START( clickstart ) + PORT_START("MOUSEX") + PORT_BIT(0x3e, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(10) PORT_CHANGED_MEMBER(DEVICE_SELF, clickstart_state, mouse_update, 0) + + PORT_START("MOUSEY") + PORT_BIT(0x3e, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(10) PORT_CHANGED_MEMBER(DEVICE_SELF, clickstart_state, mouse_update, 0) INPUT_PORTS_END // There is a SEEPROM on the motherboard (type?) @@ -188,7 +341,7 @@ void clickstart_state::clickstart(machine_config &config) SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); - SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen); + SPG28X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen); m_spg->porta_out().set(FUNC(clickstart_state::porta_w)); m_spg->portb_out().set(FUNC(clickstart_state::portb_w)); m_spg->portc_out().set(FUNC(clickstart_state::portc_w));