-quizard: Replaced protection HLE with proper MCU hookup. Removed MUP flags. Re-promoted Quizard 1 and Quizard 2. [Ryan Holtz]

-scc68070: Improved UART Tx/Rx behavior, though it still functions in parallel rather than serial. [Ryan Holtz]
This commit is contained in:
Ryan Holtz 2020-05-24 22:02:04 +02:00
parent 3ed842c01c
commit 04ed39a051
5 changed files with 196 additions and 393 deletions

View File

@ -32,9 +32,10 @@ TODO:
#define LOG_MMU (1 << 5)
#define LOG_IRQS (1 << 6)
#define LOG_UNKNOWN (1 << 7)
#define LOG_MORE_UART (1 << 8)
#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"
@ -84,6 +85,7 @@ scc68070_device::scc68070_device(const machine_config &mconfig, const char *tag,
, m_iack5_callback(*this)
, m_iack7_callback(*this)
, m_uart_tx_callback(*this)
, m_uart_rtsn_callback(*this)
, m_ipl(0)
, m_in2_line(CLEAR_LINE)
, m_in4_line(CLEAR_LINE)
@ -110,6 +112,7 @@ void scc68070_device::device_resolve_objects()
m_iack5_callback.resolve_safe(autovector(5));
m_iack7_callback.resolve_safe(autovector(7));
m_uart_tx_callback.resolve_safe();
m_uart_rtsn_callback.resolve_safe();
}
//-------------------------------------------------
@ -148,8 +151,13 @@ void scc68070_device::device_start()
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));
@ -175,13 +183,13 @@ void scc68070_device::device_start()
save_item(STRUCT_MEMBER(m_mmu.desc, segment));
save_item(STRUCT_MEMBER(m_mmu.desc, base));
m_timers.timer0_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scc68070_device::timer0_callback), this));
m_timers.timer0_timer = timer_alloc(TIMER_TMR0);
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(TIMER_UART_RX);
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(TIMER_UART_TX);
m_uart.tx_timer->adjust(attotime::never);
}
@ -216,6 +224,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;
@ -248,6 +257,24 @@ void scc68070_device::device_reset()
}
update_ipl();
m_uart.rx_timer->adjust(attotime::never);
m_uart.tx_timer->adjust(attotime::never);
m_timers.timer0_timer->adjust(attotime::never);
}
//-------------------------------------------------
// device_timer - device-specific timer callback
//-------------------------------------------------
void scc68070_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
if (id == TIMER_TMR0)
timer0_callback();
else if (id == TIMER_UART_RX)
rx_callback();
else if (id == TIMER_UART_TX)
tx_callback();
}
void scc68070_device::m68k_reset_peripherals()
@ -275,6 +302,10 @@ void scc68070_device::m68k_reset_peripherals()
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);
update_ipl();
}
@ -438,7 +469,7 @@ void scc68070_device::set_timer_callback(int channel)
}
}
TIMER_CALLBACK_MEMBER( scc68070_device::timer0_callback )
void scc68070_device::timer0_callback()
{
m_timers.timer0 = m_timers.reload_register;
m_timers.timer_status_register |= TSR_OV0;
@ -451,60 +482,25 @@ TIMER_CALLBACK_MEMBER( scc68070_device::timer0_callback )
set_timer_callback(0);
}
void scc68070_device::uart_rx_check()
void scc68070_device::uart_ctsn(int state)
{
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()
{
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 )
void scc68070_device::rx_callback()
{
if ((m_uart.command_register & 3) == 1)
{
@ -527,8 +523,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
{
@ -539,43 +533,40 @@ TIMER_CALLBACK_MEMBER( scc68070_device::rx_callback )
{
m_uart.status_register &= ~USR_RXRDY;
}
uart_rx_check();
}
TIMER_CALLBACK_MEMBER( scc68070_device::tx_callback )
void 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()
@ -746,13 +737,13 @@ 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;
}
@ -762,7 +753,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
}
@ -779,6 +770,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()
@ -791,10 +789,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()
@ -807,7 +831,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;
}

View File

@ -140,6 +140,7 @@ public:
auto iack5_callback() { return m_iack5_callback.bind(); }
auto iack7_callback() { return m_iack7_callback.bind(); }
auto uart_tx_callback() { return m_uart_tx_callback.bind(); }
auto uart_rtsn_callback() { return m_uart_rtsn_callback.bind(); }
DECLARE_WRITE_LINE_MEMBER(in2_w);
DECLARE_WRITE_LINE_MEMBER(in4_w);
@ -150,10 +151,11 @@ public:
// external callbacks
void uart_rx(uint8_t data);
void uart_ctsn(int state);
TIMER_CALLBACK_MEMBER( timer0_callback );
TIMER_CALLBACK_MEMBER( rx_callback );
TIMER_CALLBACK_MEMBER( tx_callback );
void timer0_callback();
void rx_callback();
void tx_callback();
// register structures
struct i2c_regs_t
@ -192,6 +194,7 @@ public:
int16_t transmit_pointer;
uint8_t transmit_buffer[32768];
emu_timer* tx_timer;
bool transmit_ctsn;
};
struct timer_regs_t
@ -261,6 +264,7 @@ protected:
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_execute_interface overrides
virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 2 - 1) / 2; }
@ -273,6 +277,10 @@ private:
void internal_map(address_map &map);
void cpu_space_map(address_map &map);
static constexpr device_timer_id TIMER_TMR0 = 0;
static constexpr device_timer_id TIMER_UART_RX = 1;
static constexpr device_timer_id TIMER_UART_TX = 2;
void update_ipl();
uint8_t iack_r(offs_t offset);
@ -323,6 +331,7 @@ private:
void uart_rx_check();
void uart_tx_check();
void uart_tx(uint8_t data);
void uart_do_tx();
void set_timer_callback(int channel);
// callbacks
@ -331,6 +340,7 @@ private:
devcb_read8 m_iack5_callback;
devcb_read8 m_iack7_callback;
devcb_write8 m_uart_tx_callback;
devcb_write_line m_uart_rtsn_callback;
// internal state
uint8_t m_ipl;

View File

@ -31,14 +31,8 @@ STATUS:
* PC85010 DSP
Quizard:
- Quizard does not work due to MCU not being fully hooked up.
- The Quizard MCU makes use of both serial ports, the second of which is
connected to the SCC68070's UART, and the first of which, which is connected
to the RDI and TDO pins of the SLAVE MCU's UART. Thus the Quizard MCU cannot
be hooked up fully until there is proper LLE of the SLAVE MCU, or input
reading is decoupled from the high-level simulation so that arbitrary serial
devices can be hooked up.
- Quizard 3 and 4 fail when going in-game, presumably due to CD-i emulation
faults.
TODO:
@ -69,7 +63,13 @@ TODO:
// TODO: NTSC system clock is 30.2098 MHz; additional 4.9152 MHz XTAL provided for UART
#define CLOCK_A 30_MHz_XTAL
#define VERBOSE (1)
#define LOG_DVC (1 << 1)
#define LOG_QUIZARD_READS (1 << 2)
#define LOG_QUIZARD_WRITES (1 << 3)
#define LOG_QUIZARD_OTHER (1 << 4)
#define LOG_UART (1 << 5)
#define VERBOSE (0)
#include "logmacro.h"
#define ENABLE_UART_PRINTING (0)
@ -144,52 +144,6 @@ void cdi_state::cdi910_mem(address_map &map)
* Input ports *
*************************/
INPUT_CHANGED_MEMBER(quizard_state::mcu_input)
{
bool send = false;
switch (param)
{
case 0x39:
//if (m_input1.read_safe(0) & 0x01) send = true;
break;
case 0x37:
//if (m_input1.read_safe(0) & 0x02) send = true;
break;
case 0x31:
//if (m_input1.read_safe(0) & 0x04) send = true;
break;
case 0x32:
//if (m_input1.read_safe(0) & 0x08) send = true;
break;
case 0x33:
//if (m_input1.read_safe(0) & 0x10) send = true;
break;
case 0x30:
//if (m_input2.read_safe(0) & 0x01) send = true;
break;
case 0x38:
//if (m_input2.read_safe(0) & 0x02) send = true;
break;
case 0x34:
//if (m_input2.read_safe(0) & 0x04) send = true;
break;
case 0x35:
//if (m_input2.read_safe(0) & 0x08) send = true;
break;
case 0x36:
//if (m_input2.read_safe(0) & 0x10) send = true;
break;
}
if (send)
{
uint8_t data = uint8_t(param & 0x000000ff);
mcu_hle_tx(data);
}
}
static INPUT_PORTS_START( cdi )
PORT_START("DEBUG")
PORT_CONFNAME( 0x01, 0x00, "Plane A Disable")
@ -269,8 +223,7 @@ static INPUT_PORTS_START( quizard )
PORT_BIT( 0xc8, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("P1")
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x1f, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START1 )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SERVICE1 )
@ -283,10 +236,6 @@ static INPUT_PORTS_START( quizard )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("Player 2 B")
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("Player 2 C")
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("P3")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_NAME("Fake RTS from Console")
PORT_BIT( 0xfe, IP_ACTIVE_HIGH, IPT_UNUSED )
INPUT_PORTS_END
@ -303,236 +252,103 @@ void cdi_state::machine_reset()
void quizard_state::machine_start()
{
save_item(NAME(m_seeds));
save_item(NAME(m_state));
save_item(NAME(m_mcu_value));
save_item(NAME(m_mcu_ack));
save_item(NAME(m_mcu_rx_from_cpu));
save_item(NAME(m_mcu_initial_byte));
}
void quizard_state::machine_reset()
{
cdi_state::machine_reset();
memset(m_seeds, 0, 10 * sizeof(uint16_t));
memset(m_state, 0, 8 * sizeof(uint8_t));
m_mcu_rx_from_cpu = 0x00;
m_mcu_initial_byte = true;
}
/***************************
* Quizard Protection HLE *
***************************/
/**********************
* Quizard Protection *
**********************/
void quizard_state::set_mcu_ack(uint8_t ack)
void quizard_state::mcu_rtsn_from_cpu(int state)
{
m_mcu_ack = ack;
LOGMASKED(LOG_UART, "MCU receiving RTSN from CPU: %d\n", state);
}
void quizard_state::set_mcu_value(uint16_t value)
void quizard_state::mcu_rx_from_cpu(uint8_t data)
{
m_mcu_value = value;
}
void quizard_state::mcu_hle_tx(uint8_t data)
{
m_maincpu->uart_rx(0x5a);
m_maincpu->uart_rx(data);
}
void quizard_state::mcu_set_seeds(uint8_t *rx)
{
m_seeds[0] = (rx[1] << 8) | rx[0];
m_seeds[1] = (rx[3] << 8) | rx[2];
m_seeds[2] = (rx[5] << 8) | rx[4];
m_seeds[3] = (rx[7] << 8) | rx[6];
m_seeds[4] = (rx[9] << 8) | rx[8];
m_seeds[5] = (rx[11] << 8) | rx[10];
m_seeds[6] = (rx[13] << 8) | rx[12];
m_seeds[7] = (rx[15] << 8) | rx[14];
m_seeds[8] = (rx[17] << 8) | rx[16];
m_seeds[9] = (rx[19] << 8) | rx[18];
}
void quizard_state::mcu_calculate_state()
{
//const uint16_t desired_bitfield = mcu_value;
const uint16_t field0 = 0x00ff;
const uint16_t field1 = m_mcu_value ^ 0x00ff;
uint16_t total0 = 0;
uint16_t total1 = 0;
for(int index = 0; index < 10; index++)
LOGMASKED(LOG_UART, "MCU receiving %02x from CPU\n", data);
if (m_mcu_initial_byte)
{
if (field0 & (1 << index))
{
total0 += m_seeds[index];
}
if (field1 & (1 << index))
{
total1 += m_seeds[index];
}
m_mcu_initial_byte = false;
return;
}
uint16_t hi0 = (total0 >> 8) + 0x40;
m_state[2] = hi0 / 2;
m_state[3] = hi0 - m_state[2];
m_mcu_rx_from_cpu = data;
uint16_t lo0 = (total0 & 0x00ff) + 0x40;
m_state[0] = lo0 / 2;
m_state[1] = lo0 - m_state[0];
uint16_t hi1 = (total1 >> 8) + 0x40;
m_state[6] = hi1 / 2;
m_state[7] = hi1 - m_state[6];
uint16_t lo1 = (total1 & 0x00ff) + 0x40;
m_state[4] = lo1 / 2;
m_state[5] = lo1 - m_state[4];
}
void quizard_state::mcu_hle_rx(uint8_t data)
{
static int state = 0;
static uint8_t rx[0x100];
static uint8_t rx_ptr = 0xff;
switch (state)
{
case 0: // Waiting for a leadoff byte
if (data == m_mcu_ack) // Sequence end
{
//scc68070_uart_rx(machine, scc68070, 0x5a);
//scc68070_uart_rx(machine, scc68070, 0x42);
}
else
{
switch (data)
{
case 0x44: // DATABASEPATH = **_DATABASE/
rx[0] = 0x44;
rx_ptr = 1;
state = 3;
break;
case 0x2e: // Unknown; ignored
break;
case 0x56: // Seed start
rx_ptr = 0;
state = 1;
break;
default:
//printf("Unknown leadoff byte: %02x\n", data);
break;
}
}
break;
case 1: // Receiving the seed
rx[rx_ptr] = data;
rx_ptr++;
if (rx_ptr == 20)
{
//printf("Calculating seeds\n");
mcu_set_seeds(rx);
mcu_calculate_state();
state = 2;
}
break;
case 2: // Receiving the seed acknowledge
case 4:
if (data == m_mcu_ack)
{
if (state == 2)
{
state = 4;
}
else
{
state = 0;
}
//printf("Sending seed ack\n");
m_maincpu->uart_rx(0x5a);
m_maincpu->uart_rx(m_state[0]);
m_maincpu->uart_rx(m_state[1]);
m_maincpu->uart_rx(m_state[2]);
m_maincpu->uart_rx(m_state[3]);
m_maincpu->uart_rx(m_state[4]);
m_maincpu->uart_rx(m_state[5]);
m_maincpu->uart_rx(m_state[6]);
m_maincpu->uart_rx(m_state[7]);
}
break;
case 3: // Receiving the database path
rx[rx_ptr] = data;
rx_ptr++;
if (data == 0x0a)
{
/*rx[rx_ptr] = 0;
//printf("Database path: %s\n", rx);
scc68070_uart_rx(machine, scc68070, 0x5a);
scc68070_uart_rx(machine, scc68070, g_state[0]);
scc68070_uart_rx(machine, scc68070, g_state[1]);
scc68070_uart_rx(machine, scc68070, g_state[2]);
scc68070_uart_rx(machine, scc68070, g_state[3]);
scc68070_uart_rx(machine, scc68070, g_state[4]);
scc68070_uart_rx(machine, scc68070, g_state[5]);
scc68070_uart_rx(machine, scc68070, g_state[6]);
scc68070_uart_rx(machine, scc68070, g_state[7]);*/
state = 0;
}
break;
}
m_mcu->set_input_line(MCS51_RX_LINE, ASSERT_LINE);
m_mcu->set_input_line(MCS51_RX_LINE, CLEAR_LINE);
}
uint8_t quizard_state::mcu_p0_r()
{
const uint8_t data = m_inputs[0]->read();
LOG("%s: MCU Port 0 Read (%02x)\n", machine().describe_context(), data);
LOGMASKED(LOG_QUIZARD_READS, "%s: MCU Port 0 Read (%02x)\n", machine().describe_context(), data);
return data;
}
uint8_t quizard_state::mcu_p1_r()
{
const uint8_t data = m_inputs[1]->read();
LOG("%s: MCU Port 1 Read (%02x)\n", machine().describe_context(), data);
uint8_t data = m_inputs[1]->read();
if (BIT(~m_inputs[0]->read(), 4))
data &= ~(1 << 4);
LOGMASKED(LOG_QUIZARD_READS, "%s: MCU Port 1 Read (%02x)\n", machine().describe_context(), data);
return data;
}
uint8_t quizard_state::mcu_p2_r()
{
const uint8_t data = m_inputs[2]->read();
LOG("%s: MCU Port 2 Read (%02x)\n", machine().describe_context(), data);
LOGMASKED(LOG_QUIZARD_READS, "%s: MCU Port 2 Read (%02x)\n", machine().describe_context(), data);
return data;
}
uint8_t quizard_state::mcu_p3_r()
{
const uint8_t data = 0x04 | (m_inputs[3]->read() ? 0x80 : 0x00);
LOG("%s: MCU Port 3 Read (%02x)\n", machine().describe_context(), data);
return data;
LOGMASKED(LOG_QUIZARD_READS, "%s: MCU Port 3 Read (%02x)\n", machine().describe_context(), 0x04);
return 0x04;
}
void quizard_state::mcu_p0_w(uint8_t data)
{
LOGMASKED(LOG_QUIZARD_WRITES, "%s: MCU Port 0 Write (%02x)\n", machine().describe_context(), data);
}
void quizard_state::mcu_p1_w(uint8_t data)
{
LOGMASKED(LOG_QUIZARD_WRITES, "%s: MCU Port 1 Write (%02x)\n", machine().describe_context(), data);
}
void quizard_state::mcu_p2_w(uint8_t data)
{
LOG("%s: MCU Port 2 Write (%02x)\n", machine().describe_context(), data);
m_mcu->set_input_line(MCS51_INT1_LINE, BIT(data, 7) ? ASSERT_LINE : CLEAR_LINE);
LOGMASKED(LOG_QUIZARD_WRITES, "%s: MCU Port 2 Write (%02x)\n", machine().describe_context(), data);
}
void quizard_state::mcu_p3_w(uint8_t data)
{
LOG("%s: MCU Port 3 Write (%02x)\n", machine().describe_context(), data);
LOGMASKED(LOG_QUIZARD_WRITES, "%s: MCU Port 3 Write (%02x)\n", machine().describe_context(), data);
m_maincpu->uart_ctsn(BIT(data, 6));
}
void quizard_state::mcu_tx(uint8_t data)
{
LOG("%s: MCU transmitting %02x\n", machine().describe_context(), data);
LOGMASKED(LOG_QUIZARD_OTHER, "%s: MCU transmitting %02x\n", machine().describe_context(), data);
m_maincpu->uart_rx(data);
}
uint8_t quizard_state::mcu_rx()
{
uint8_t data = 0;
LOG("%s: MCU receiving %02x\n", machine().describe_context(), data);
uint8_t data = m_mcu_rx_from_cpu;
LOGMASKED(LOG_QUIZARD_OTHER, "%s: MCU receiving %02x\n", machine().describe_context(), data);
return data;
}
@ -542,13 +358,13 @@ uint8_t quizard_state::mcu_rx()
READ16_MEMBER( cdi_state::dvc_r )
{
logerror("%s: dvc_r: %08x = 0000 & %04x\n", machine().describe_context(), 0xe80000 + (offset << 1), mem_mask);
LOGMASKED(LOG_DVC, "%s: dvc_r: %08x = 0000 & %04x\n", machine().describe_context(), 0xe80000 + (offset << 1), mem_mask);
return 0;
}
WRITE16_MEMBER( cdi_state::dvc_w )
{
logerror("%s: dvc_w: %08x = %04x & %04x\n", machine().describe_context(), 0xe80000 + (offset << 1), data, mem_mask);
LOGMASKED(LOG_DVC, "%s: dvc_w: %08x = %04x & %04x\n", machine().describe_context(), 0xe80000 + (offset << 1), data, mem_mask);
}
/*************************
@ -794,13 +610,16 @@ void quizard_state::quizard(machine_config &config)
{
cdimono1_base(config);
m_maincpu->set_addrmap(AS_PROGRAM, &quizard_state::cdimono1_mem);
m_maincpu->uart_tx_callback().set(FUNC(quizard_state::mcu_hle_rx));
m_maincpu->uart_rtsn_callback().set(FUNC(quizard_state::mcu_rtsn_from_cpu));
m_maincpu->uart_tx_callback().set(FUNC(quizard_state::mcu_rx_from_cpu));
I8751(config, m_mcu, 8000000);
m_mcu->port_in_cb<0>().set(FUNC(quizard_state::mcu_p0_r));
m_mcu->port_in_cb<1>().set(FUNC(quizard_state::mcu_p1_r));
m_mcu->port_in_cb<2>().set(FUNC(quizard_state::mcu_p2_r));
m_mcu->port_in_cb<3>().set(FUNC(quizard_state::mcu_p3_r));
m_mcu->port_out_cb<0>().set(FUNC(quizard_state::mcu_p0_w));
m_mcu->port_out_cb<1>().set(FUNC(quizard_state::mcu_p1_w));
m_mcu->port_out_cb<2>().set(FUNC(quizard_state::mcu_p2_w));
m_mcu->port_out_cb<3>().set(FUNC(quizard_state::mcu_p3_w));
m_mcu->serial_tx_cb().set(FUNC(quizard_state::mcu_tx));
@ -882,15 +701,15 @@ ROM_END
/* Quizard notes
The MCU controls the protection sequence, which in turn controls the game display language.
Each Quizard game (1,2,3,4) requires it's own MCU, you can upgrade between revisions by changing
Each Quizard game (1,2,3,4) requires its own MCU, you can upgrade between revisions by changing
just the CD, but not between games as a new MCU is required.
MCU Notes:
i8751 MCU dumps confirmed good on original hardware
German language MCUs for Quizard 1 through 4 are dumped
Czechoslovakian language MCU for Quizard 4 is dumped
Known to exist a Quizard 1 Italian language MCU IT 11 L2 (not dumped)
Known to exist is an alternate Quizard 2 German language MCU DE 122 D3 (not dumped)
Czech language MCU for Quizard 4 is dumped
Italian language MCU for Quizard 1 is known to exist (IT 11 L2, not dumped)
Alt. German language MCU for Quizard 2 is known to exist (DE 122 D3, not dumped)
*/
@ -1071,24 +890,24 @@ CONS( 1991, cdimono2, 0, 0, cdimono2, cdimono2, cdi_state, empty_init,
CONS( 1991, cdi910, 0, 0, cdi910, cdimono2, cdi_state, empty_init, "Philips", "CD-i 910-17P Mini-MMC (PAL)", MACHINE_NOT_WORKING )
CONS( 1991, cdi490a, 0, 0, cdimono1, cdi, cdi_state, empty_init, "Philips", "CD-i 490", MACHINE_NOT_WORKING )
// The Quizard games are RETAIL CD-i units, with additional JAMMA adapters & dongles for protection, hence being 'clones' of the system.
// The Quizard games are retail CD-i units in a cabinet, with an additional JAMMA adapter and dongle for protection, hence being clones of the system.
/* YEAR NAME PARENT MACHINE INPUT DEVICE INIT MONITOR COMPANY FULLNAME */
GAME( 1995, cdibios, 0, cdimono1, quizard, cdi_state, empty_init, ROT0, "Philips", "CD-i (Mono-I) (PAL) BIOS", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IS_BIOS_ROOT )
GAME( 1995, cdibios, 0, cdimono1, quizard, cdi_state, empty_init, ROT0, "Philips", "CD-i (Mono-I) (PAL) BIOS", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IS_BIOS_ROOT )
GAME( 1995, quizard, cdibios, quizard, quizard, quizard1_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.8, German, i8751 DE 11 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1995, quizard_17, quizard, quizard, quizard, quizard1_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.7, German, i8751 DE 11 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1995, quizard_12, quizard, quizard, quizard, quizard1_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.2, German, i8751 DE 11 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1995, quizard_10, quizard, quizard, quizard, quizard1_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.0, German, i8751 DE 11 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1995, quizard, cdibios, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.8, German, i8751 DE 11 D3)", MACHINE_IMPERFECT_SOUND )
GAME( 1995, quizard_17, quizard, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.7, German, i8751 DE 11 D3)", MACHINE_IMPERFECT_SOUND )
GAME( 1995, quizard_12, quizard, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.2, German, i8751 DE 11 D3)", MACHINE_IMPERFECT_SOUND )
GAME( 1995, quizard_10, quizard, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.0, German, i8751 DE 11 D3)", MACHINE_IMPERFECT_SOUND )
GAME( 1995, quizard2, cdibios, quizard, quizard, quizard2_state, empty_init, ROT0, "TAB Austria", "Quizard 2 (v2.3, German, i8751 DN 122 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1995, quizard2_22, quizard2, quizard, quizard, quizard2_state, empty_init, ROT0, "TAB Austria", "Quizard 2 (v2.2, German, i8751 DN 122 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1995, quizard2, cdibios, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 2 (v2.3, German, i8751 DN 122 D3)", MACHINE_IMPERFECT_SOUND )
GAME( 1995, quizard2_22, quizard2, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 2 (v2.2, German, i8751 DN 122 D3)", MACHINE_IMPERFECT_SOUND )
// Quizard 3 and 4 will hang after inserting a coin (incomplete protection sims?)
GAME( 1995, quizard3, cdibios, quizard, quizard, quizard3_state, empty_init, ROT0, "TAB Austria", "Quizard 3 (v3.4, German, i8751 DE 132 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1995, quizard3a, quizard3, quizard, quizard, quizard3_state, empty_init, ROT0, "TAB Austria", "Quizard 3 (v3.4, German, i8751 DE 132 A1)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1996, quizard3_32, quizard3, quizard, quizard, quizard3_state, empty_init, ROT0, "TAB Austria", "Quizard 3 (v3.2, German, i8751 DE 132 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
// Quizard 3 and 4 will hang after starting a game (CDIC issues?)
GAME( 1995, quizard3, cdibios, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 3 (v3.4, German, i8751 DE 132 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
GAME( 1995, quizard3a, quizard3, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 3 (v3.4, German, i8751 DE 132 A1)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
GAME( 1996, quizard3_32, quizard3, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 3 (v3.2, German, i8751 DE 132 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
GAME( 1998, quizard4, cdibios, quizard, quizard, quizard4_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.2, German, i8751 DE 142 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1998, quizard4cz, quizard4, quizard, quizard, quizard4_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.2, Czech, i8751 TS142 CZ1)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1998, quizard4_41, quizard4, quizard, quizard, quizard4_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.1, German, i8751 DE 142 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1997, quizard4_40, quizard4, quizard, quizard, quizard4_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.0, German, i8751 DE 142 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION )
GAME( 1998, quizard4, cdibios, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.2, German, i8751 DE 142 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
GAME( 1998, quizard4cz, quizard4, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.2, Czech, i8751 TS142 CZ1)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
GAME( 1998, quizard4_41, quizard4, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.1, German, i8751 DE 142 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
GAME( 1997, quizard4_40, quizard4, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.0, German, i8751 DE 142 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )

View File

@ -89,12 +89,6 @@ public:
void quizard(machine_config &config);
DECLARE_INPUT_CHANGED_MEMBER(mcu_input);
protected:
void set_mcu_value(uint16_t value);
void set_mcu_ack(uint8_t ack);
private:
virtual void machine_start() override;
virtual void machine_reset() override;
@ -103,71 +97,26 @@ private:
uint8_t mcu_p1_r();
uint8_t mcu_p2_r();
uint8_t mcu_p3_r();
void mcu_p0_w(uint8_t data);
void mcu_p1_w(uint8_t data);
void mcu_p2_w(uint8_t data);
void mcu_p3_w(uint8_t data);
void mcu_tx(uint8_t data);
uint8_t mcu_rx();
void mcu_hle_tx(uint8_t data);
void mcu_calculate_state();
void mcu_set_seeds(uint8_t *rx);
void mcu_hle_rx(uint8_t data);
void mcu_rx_from_cpu(uint8_t data);
void mcu_rtsn_from_cpu(int state);
required_device<i8751_device> m_mcu;
required_ioport_array<4> m_inputs;
required_ioport_array<3> m_inputs;
uint16_t m_seeds[10];
uint8_t m_state[8];
uint16_t m_mcu_value;
uint8_t m_mcu_ack;
uint8_t m_mcu_rx_from_cpu;
bool m_mcu_initial_byte;
};
class quizard1_state : public quizard_state
{
public:
quizard1_state(const machine_config &mconfig, device_type type, const char *tag)
: quizard_state(mconfig, type, tag)
{
set_mcu_value(0x021f);
set_mcu_ack(0x5a);
}
};
class quizard2_state : public quizard_state
{
public:
quizard2_state(const machine_config &mconfig, device_type type, const char *tag)
: quizard_state(mconfig, type, tag)
{
// 0x2b1: Italian
// 0x001: French
// 0x188: German
set_mcu_value(0x0188);
set_mcu_ack(0x59);
}
};
class quizard3_state : public quizard_state
{
public:
quizard3_state(const machine_config &mconfig, device_type type, const char *tag)
: quizard_state(mconfig, type, tag)
{
set_mcu_value(0x00ae);
set_mcu_ack(0x58);
}
};
class quizard4_state : public quizard_state
{
public:
quizard4_state(const machine_config &mconfig, device_type type, const char *tag)
: quizard_state(mconfig, type, tag)
{
set_mcu_value(0x011f);
set_mcu_ack(0x57);
}
};
// Quizard 2 language values:
// 0x2b1: Italian
// 0x001: French
// 0x188: German
#endif // MAME_INCLUDES_CDI_H

View File

@ -23,6 +23,7 @@ TODO:
#define LOG_READS (1 << 2)
#define LOG_WRITES (1 << 3)
#define LOG_UNKNOWNS (1 << 4)
#define LOG_ALL (LOG_IRQS | LOG_COMMANDS | LOG_READS | LOG_WRITES | LOG_UNKNOWNS)
#define VERBOSE (0)
#include "logmacro.h"