-spg2xx: Various changes: [Ryan Holtz]

* Adjusted UART receive behavior to flag an available byte only at the specified baud rate.
 * Added separate UART baud rate calculation for SPG24x vs. SPG28x.
 * Adjusted ADC behavior to flag an IRQ when the relevant data bit is set, not when register bit is newly set.
 * Added separate logging for FIQ registers.
 * Added logging for SIO registers.

-clickstart: Added preliminary mouse hookup. Only accepts a mouse update once, ignores further updates. Needs further investigation. (nw)
This commit is contained in:
mooglyguy 2019-01-08 22:19:39 +01:00
parent ac01e295c0
commit 2e1ad76d92
3 changed files with 231 additions and 24 deletions

View File

@ -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)
{

View File

@ -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)

View File

@ -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<cpu_device> m_maincpu;
required_device<screen_device> m_screen;
required_device<spg2xx_device> m_spg;
required_device<generic_slot_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));