-clickstart: Favor specific values over rand(), nw

-devices/cpu/unsp: Added a function to get current chip-select state, nw

-devicesp/machine/spg2xx: Various changes: [Ryan Holtz]
 * Added 4kHz/2kHz/1kHz/1Hz timers.
 * Added ADC read callback.
 * Fixed a bug with floating GPIO inputs.

Clickstart games now generally get to the title screen or main menu, other than Bob The Builder, which is missing some graphics. nw
This commit is contained in:
mooglyguy 2019-01-05 22:13:58 +01:00
parent f0931b1994
commit b1bedd018d
5 changed files with 226 additions and 20 deletions

View File

@ -967,3 +967,8 @@ void unsp_device::execute_set_input(int irqline, int state)
break;
}
}
uint8_t unsp_device::get_csb()
{
return 1 << ((UNSP_LPC >> 20) & 3);
}

View File

@ -68,6 +68,8 @@ public:
void set_timer_interval(int timer, uint32_t interval);
uint8_t get_csb();
protected:
// device-level overrides
virtual void device_start() override;

View File

@ -48,7 +48,7 @@ DEFINE_DEVICE_TYPE(SPG28X, spg28x_device, "spg28x", "SPG280-series System-on-a-C
#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 VERBOSE (LOG_UART | LOG_UNKNOWN_IO)
#define VERBOSE (LOG_IO_READS | LOG_IO_WRITES | LOG_UART | LOG_UNKNOWN_IO | LOG_I2C)
#include "logmacro.h"
#define SPG_DEBUG_VIDEO (0)
@ -68,6 +68,7 @@ spg2xx_device::spg2xx_device(const machine_config &mconfig, device_type type, co
, m_porta_in(*this)
, m_portb_in(*this)
, m_portc_in(*this)
, m_adc_in(*this)
, m_eeprom_w(*this)
, m_eeprom_r(*this)
, m_uart_tx(*this)
@ -109,6 +110,7 @@ void spg2xx_device::device_start()
m_porta_in.resolve_safe(0);
m_portb_in.resolve_safe(0);
m_portc_in.resolve_safe(0);
m_adc_in.resolve_safe(0x0fff);
m_eeprom_w.resolve_safe();
m_eeprom_r.resolve_safe(0);
m_uart_tx.resolve_safe();
@ -131,9 +133,60 @@ void spg2xx_device::device_start()
m_uart_rx_timer = timer_alloc(TIMER_UART_RX);
m_uart_rx_timer->adjust(attotime::never);
m_4khz_timer = timer_alloc(TIMER_4KHZ);
m_4khz_timer->adjust(attotime::never);
m_stream = stream_alloc(0, 2, 44100);
m_channel_debug = -1;
save_item(NAME(m_hide_page0));
save_item(NAME(m_hide_page1));
save_item(NAME(m_hide_sprites));
save_item(NAME(m_debug_sprites));
save_item(NAME(m_debug_blit));
save_item(NAME(m_sprite_index_to_debug));
save_item(NAME(m_debug_samples));
save_item(NAME(m_debug_rates));
save_item(NAME(m_audio_regs));
save_item(NAME(m_sample_shift));
save_item(NAME(m_sample_count));
save_item(NAME(m_sample_addr));
save_item(NAME(m_channel_rate));
save_item(NAME(m_channel_rate_accum));
save_item(NAME(m_rampdown_frame));
save_item(NAME(m_envclk_frame));
save_item(NAME(m_envelope_addr));
save_item(NAME(m_channel_debug));
save_item(NAME(m_audio_curr_beat_base_count));
save_item(NAME(m_io_regs));
save_item(NAME(m_uart_rx_fifo));
save_item(NAME(m_uart_rx_fifo_start));
save_item(NAME(m_uart_rx_fifo_end));
save_item(NAME(m_uart_rx_fifo_count));
save_item(NAME(m_uart_rx_available));
save_item(NAME(m_uart_rx_irq));
save_item(NAME(m_uart_tx_irq));
save_item(NAME(m_extint));
save_item(NAME(m_video_regs));
save_item(NAME(m_sprite_limit));
save_item(NAME(m_pal_flag));
save_item(NAME(m_2khz_divider));
save_item(NAME(m_1khz_divider));
save_item(NAME(m_4hz_divider));
save_item(NAME(m_uart_baud_rate));
for (int i = 0; i < 16; i++)
{
save_item(NAME(m_adpcm[i].m_signal), i);
save_item(NAME(m_adpcm[i].m_step), i);
}
}
void spg2xx_device::device_reset()
@ -181,6 +234,12 @@ void spg2xx_device::device_reset()
m_audio_regs[AUDIO_CHANNEL_ENV_MODE] = 0x3f;
m_audio_beat->adjust(attotime::from_ticks(4, 281250), 0, attotime::from_ticks(4, 281250));
m_4khz_timer->adjust(attotime::from_hz(4096), 0, attotime::from_hz(4096));
m_2khz_divider = 0;
m_1khz_divider = 0;
m_4hz_divider = 0;
}
@ -880,7 +939,7 @@ READ16_MEMBER(spg2xx_device::io_r)
case 0x27: // ADC Data
m_io_regs[0x27] = 0;
LOGMASKED(LOG_IO_READS, "io_r: ADC Data = %04x\n", val);
LOGMASKED(LOG_IO_READS, "%s: io_r: ADC Data = %04x\n", machine().describe_context(), val);
break;
case 0x29: // Wakeup Source
@ -1206,17 +1265,17 @@ WRITE16_MEMBER(spg2xx_device::io_w)
case 0x25: // ADC Control
{
LOGMASKED(LOG_IO_WRITES, "io_w: ADC Control = %04x\n", data);
//const uint16_t changed = m_io_regs[offset] ^ data;
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))
if (BIT(changed, 12) && BIT(data, 12) && !BIT(m_io_regs[offset], 1))
{
//m_io_regs[0x27] = 0x80ff;
//const uint16_t old = IO_IRQ_STATUS;
//IO_IRQ_STATUS |= 0x2000;
//const uint16_t changed = IO_IRQ_STATUS ^ old;
//if (changed)
//check_irqs(changed);
m_io_regs[0x27] = 0x8000 | (m_adc_in() & 0x7fff);
const uint16_t old = IO_IRQ_STATUS;
IO_IRQ_STATUS |= 0x2000;
const uint16_t changed = IO_IRQ_STATUS ^ old;
if (changed)
check_irqs(changed);
}
break;
}
@ -1469,9 +1528,51 @@ void spg2xx_device::device_timer(emu_timer &timer, device_timer_id id, int param
case TIMER_UART_RX:
uart_receive_tick();
break;
case TIMER_4KHZ:
system_timer_tick();
break;
}
}
void spg2xx_device::system_timer_tick()
{
uint16_t check_mask = 0x0040;
IO_IRQ_STATUS |= 0x0040;
if (machine().input().code_pressed_once(KEYCODE_H))
{
IO_IRQ_STATUS |= 0x4000;
check_irqs(0x4000);
}
m_2khz_divider++;
if (m_2khz_divider == 2)
{
m_2khz_divider = 0;
IO_IRQ_STATUS |= 0x0020;
check_mask |= 0x0020;
m_1khz_divider++;
if (m_1khz_divider == 2)
{
m_1khz_divider = 0;
IO_IRQ_STATUS |= 0x0010;
check_mask |= 0x0010;
m_4hz_divider++;
if (m_4hz_divider == 256)
{
m_4hz_divider = 0;
IO_IRQ_STATUS |= 0x0008;
check_mask |= 0x0008;
}
}
}
check_irqs(check_mask);
}
void spg2xx_device::uart_transmit_tick()
{
LOGMASKED(LOG_UART, "uart_transmit_tick: Transmitting %02x, setting TxReady, clearing TxBusy\n", (uint8_t)m_io_regs[0x35]);
@ -1583,6 +1684,31 @@ void spg2xx_device::check_irqs(const uint16_t changed)
}
}
uint16_t spg2xx_device::do_special_gpio(uint32_t index, uint16_t mask)
{
uint16_t data = 0;
switch (index)
{
case 0: // Port A
if (mask & 0xe000)
{
const uint8_t csel = m_cpu->get_csb() & 0x0e;
data = (csel << 12) & mask;
}
break;
case 1: // Port B
// To do
break;
case 2: // Port C
// To do
break;
default:
// Can't happen
break;
}
return data;
}
void spg2xx_device::do_gpio(uint32_t offset)
{
uint32_t index = (offset - 1) / 5;
@ -1592,10 +1718,12 @@ void spg2xx_device::do_gpio(uint32_t offset)
uint16_t special = m_io_regs[5 * index + 5];
uint16_t push = dir;
uint16_t pull = (~dir) & (~attr);
uint16_t pull = ~dir;
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)
{
@ -1613,6 +1741,7 @@ void spg2xx_device::do_gpio(uint32_t offset)
break;
}
what |= do_special_gpio(index, special);
m_io_regs[5 * index + 1] = what;
}

View File

@ -60,6 +60,8 @@ public:
auto portb_in() { return m_portb_in.bind(); }
auto portc_in() { return m_portc_in.bind(); }
auto adc_in() { return m_adc_in.bind(); }
auto eeprom_w() { return m_eeprom_w.bind(); }
auto eeprom_r() { return m_eeprom_r.bind(); }
@ -75,7 +77,7 @@ public:
DECLARE_WRITE_LINE_MEMBER(vblank);
protected:
spg2xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const size_t sprite_limit)
spg2xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const uint32_t sprite_limit)
: spg2xx_device(mconfig, type, tag, owner, clock)
{
m_sprite_limit = sprite_limit;
@ -399,6 +401,7 @@ protected:
static const device_timer_id TIMER_BEAT = 3;
static const device_timer_id TIMER_UART_TX = 4;
static const device_timer_id TIMER_UART_RX = 5;
static const device_timer_id TIMER_4KHZ = 6;
virtual void device_start() override;
virtual void device_reset() override;
@ -407,10 +410,13 @@ protected:
void update_porta_special_modes();
void update_portb_special_modes();
void do_gpio(uint32_t offset);
uint16_t do_special_gpio(uint32_t index, uint16_t mask);
void uart_transmit_tick();
void uart_receive_tick();
void system_timer_tick();
void do_i2c();
void do_cpu_dma(uint32_t len);
@ -474,7 +480,7 @@ protected:
bool m_extint[2];
uint16_t m_video_regs[0x100];
size_t m_sprite_limit;
uint32_t m_sprite_limit;
uint16_t m_pal_flag;
devcb_write16 m_porta_out;
@ -484,6 +490,8 @@ protected:
devcb_read16 m_portb_in;
devcb_read16 m_portc_in;
devcb_read16 m_adc_in;
devcb_write8 m_eeprom_w;
devcb_read8 m_eeprom_r;
@ -496,6 +504,11 @@ protected:
emu_timer *m_screenpos_timer;
emu_timer *m_audio_beat;
emu_timer *m_4khz_timer;
uint32_t m_2khz_divider;
uint32_t m_1khz_divider;
uint32_t m_4hz_divider;
uint32_t m_uart_baud_rate;
emu_timer *m_uart_tx_timer;
emu_timer *m_uart_rx_timer;

View File

@ -3,7 +3,7 @@
/******************************************************************************
Leapfrog Clickstart Emulation
Status:
Calls to unmapped space
@ -13,7 +13,7 @@
calculation doesn't add up correctly. There is also a checksum in
a footer area at the end of every ROM that does add up correctly in
all cases.
The ROM carts are marked for 4MByte ROMs at least so the sizes
should be correct.
@ -59,10 +59,14 @@ private:
DECLARE_READ16_MEMBER(rom_r);
DECLARE_READ16_MEMBER(portc_r)
{
return machine().rand();
};
DECLARE_WRITE16_MEMBER(porta_w);
DECLARE_WRITE16_MEMBER(portb_w);
DECLARE_WRITE16_MEMBER(portc_w);
DECLARE_READ16_MEMBER(porta_r);
DECLARE_READ16_MEMBER(portb_r);
DECLARE_READ16_MEMBER(portc_r);
DECLARE_WRITE8_MEMBER(chip_sel_w);
required_device<cpu_device> m_maincpu;
required_device<screen_device> m_screen;
@ -70,6 +74,8 @@ private:
required_device<generic_slot_device> m_cart;
required_memory_region m_system_region;
memory_region *m_cart_region;
uint16_t m_unk_portc_toggle;
};
@ -81,10 +87,13 @@ void clickstart_state::machine_start()
std::string region_tag;
m_cart_region = memregion(region_tag.assign(m_cart->tag()).append(GENERIC_ROM_REGION_TAG).c_str());
}
save_item(NAME(m_unk_portc_toggle));
}
void clickstart_state::machine_reset()
{
m_unk_portc_toggle = 0;
}
DEVICE_IMAGE_LOAD_MEMBER(clickstart_state, cart)
@ -112,6 +121,47 @@ 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);
}
WRITE16_MEMBER(clickstart_state::portb_w)
{
logerror("%s: portb_w: %04x & %04x\n", machine().describe_context(), data, mem_mask);
}
WRITE16_MEMBER(clickstart_state::portc_w)
{
//logerror("%s: portc_w: %04x & %04x\n", machine().describe_context(), data, mem_mask);
}
READ16_MEMBER(clickstart_state::porta_r)
{
uint16_t data = 0x5000;
logerror("%s: porta_r: %04x & %04x\n", machine().describe_context(), data, mem_mask);
return data;
}
READ16_MEMBER(clickstart_state::portb_r)
{
logerror("%s: portb_r: %04x\n", machine().describe_context(), mem_mask);
return 0;
}
READ16_MEMBER(clickstart_state::portc_r)
{
uint16_t data = m_unk_portc_toggle;
m_unk_portc_toggle ^= 0x0400;
//logerror("%s: portc_r: %04x & %04x\n", machine().describe_context(), data, mem_mask);
return data;
}
WRITE8_MEMBER(clickstart_state::chip_sel_w)
{
// Seems unused, currently
}
void clickstart_state::mem_map(address_map &map)
{
map(0x000000, 0x3fffff).r(FUNC(clickstart_state::rom_r));
@ -139,7 +189,14 @@ void clickstart_state::clickstart(machine_config &config)
SPEAKER(config, "rspeaker").front_right();
SPG24X(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));
m_spg->porta_in().set(FUNC(clickstart_state::porta_r));
m_spg->portb_in().set(FUNC(clickstart_state::portb_r));
m_spg->portc_in().set(FUNC(clickstart_state::portc_r));
m_spg->adc_in().set_constant(0x0fff);
m_spg->chip_select().set(FUNC(clickstart_state::chip_sel_w));
m_spg->add_route(ALL_OUTPUTS, "lspeaker", 0.5);
m_spg->add_route(ALL_OUTPUTS, "rspeaker", 0.5);