mirror of
https://github.com/holub/mame
synced 2025-07-03 09:06:08 +03:00
namco/namcos12.cpp: Emulated games with CDXA board. (#11558)
* machine/t10mmc.cpp: Added support for T10SBC_CMD_SEEK_10 command. * cpu/sh: Added SH7014 SoC. * machine/icd2061a.cpp: Emulated IC Designs 2061A programmable clock generator. * sound/lc78836m.cpp: Emulated Sanyo LC78836M audio DAC. * namco/namcos12_cdxa.cpp: Emulated Namco System 12 CDXA board. Systems promoted to working ----------------------------- Truck Kyosokyoku (Japan, TKK2/VER.A) [Windy Fairy] New working systems ----------------------------- Um Jammer Lammy NOW! (Japan, UL1/VER.A) [Phil Bennett, Eric Yockey, Windy Fairy]
This commit is contained in:
parent
85ce279c63
commit
f60fd23e3e
@ -871,6 +871,20 @@ if CPUS["SH"] then
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh4regs.h",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh4tmu.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh4tmu.h",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_bsc.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_bsc.h",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_dmac.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_dmac.h",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_intc.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_intc.h",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_mtu.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_mtu.h",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_port.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_port.h",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_sci.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014_sci.h",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7014.h",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7021.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7021.h",
|
||||
MAME_DIR .. "src/devices/cpu/sh/sh7032.cpp",
|
||||
|
@ -1754,18 +1754,6 @@ if (MACHINES["I80130"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/icm7170.h,MACHINES["ICM7170"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (MACHINES["ICM7170"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/icm7170.cpp",
|
||||
MAME_DIR .. "src/devices/machine/icm7170.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/ibm21s850.h,MACHINES["IBM21S850"] = true
|
||||
@ -1778,6 +1766,30 @@ if (MACHINES["IBM21S850"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/icd2061a.h,MACHINES["ICD2061A"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (MACHINES["ICD2061A"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/icd2061a.cpp",
|
||||
MAME_DIR .. "src/devices/machine/icd2061a.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/icm7170.h,MACHINES["ICM7170"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (MACHINES["ICM7170"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/icm7170.cpp",
|
||||
MAME_DIR .. "src/devices/machine/icm7170.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/idectrl.h,MACHINES["IDECTRL"] = true
|
||||
|
@ -1441,6 +1441,18 @@ if (SOUNDS["LC7535"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
-- Sanyo LC78836M
|
||||
--@src/devices/sound/lc78836m.h,SOUNDS["LC78836M"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (SOUNDS["LC78836M"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/sound/lc78836m.cpp",
|
||||
MAME_DIR .. "src/devices/sound/lc78836m.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
-- Sanyo LC82310
|
||||
--@src/devices/sound/lc82310.h,SOUNDS["LC82310"] = true
|
||||
|
@ -169,6 +169,7 @@ void atapi_cdrom_device::ExecCommand()
|
||||
case T10MMC_CMD_PLAY_AUDIO_12:
|
||||
case T10MMC_CMD_READ_CD:
|
||||
case T10SBC_CMD_READ_12:
|
||||
case T10SBC_CMD_SEEK_10:
|
||||
if(!m_image->exists())
|
||||
{
|
||||
m_phase = SCSI_PHASE_STATUS;
|
||||
@ -197,4 +198,10 @@ void atapi_cdrom_device::ExecCommand()
|
||||
break;
|
||||
}
|
||||
t10mmc::ExecCommand();
|
||||
|
||||
// truckk requires seek complete flag to be set after calling the SEEK command
|
||||
// so set the seek complete status flag after a successful request to emulate
|
||||
// having asked the device itself to seek
|
||||
if (command[0] == T10SBC_CMD_SEEK_10 && m_status_code == SCSI_STATUS_CODE_GOOD)
|
||||
m_status |= IDE_STATUS_DSC;
|
||||
}
|
||||
|
201
src/devices/cpu/sh/sh7014.cpp
Normal file
201
src/devices/cpu/sh/sh7014.cpp
Normal file
@ -0,0 +1,201 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH-2 SH7014
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#include "sh7014.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(SH2_SH7014, sh2_sh7014_device, "sh2_sh7014", "Hitachi SH-2 (SH7014)")
|
||||
|
||||
sh2_sh7014_device::sh2_sh7014_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sh2_device(mconfig, SH2_SH7014, tag, owner, clock, CPU_TYPE_SH2, address_map_constructor(FUNC(sh2_sh7014_device::sh7014_map), this), 32, 0xffffffff)
|
||||
, m_sci(*this, "sci%u", 0u)
|
||||
, m_bsc(*this, "bsc")
|
||||
, m_dmac(*this, "dmac")
|
||||
, m_intc(*this, "intc")
|
||||
, m_mtu(*this, "mtu")
|
||||
, m_port(*this, "io_port")
|
||||
, m_sci_tx_cb(*this)
|
||||
{
|
||||
}
|
||||
|
||||
void sh2_sh7014_device::device_start()
|
||||
{
|
||||
sh2_device::device_start();
|
||||
|
||||
save_item(NAME(m_ccr));
|
||||
}
|
||||
|
||||
void sh2_sh7014_device::device_reset()
|
||||
{
|
||||
sh2_device::device_reset();
|
||||
|
||||
// CAC
|
||||
m_ccr = 0;
|
||||
}
|
||||
|
||||
void sh2_sh7014_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
SH7014_SCI(config, m_sci[0], DERIVED_CLOCK(1, 1), m_intc,
|
||||
0, // id
|
||||
sh7014_intc_device::INT_VECTOR_SCI_ERI0,
|
||||
sh7014_intc_device::INT_VECTOR_SCI_RXI0,
|
||||
sh7014_intc_device::INT_VECTOR_SCI_TXI0,
|
||||
sh7014_intc_device::INT_VECTOR_SCI_TEI0
|
||||
);
|
||||
|
||||
SH7014_SCI(config, m_sci[1], DERIVED_CLOCK(1, 1), m_intc,
|
||||
1, // id
|
||||
sh7014_intc_device::INT_VECTOR_SCI_ERI1,
|
||||
sh7014_intc_device::INT_VECTOR_SCI_RXI1,
|
||||
sh7014_intc_device::INT_VECTOR_SCI_TXI1,
|
||||
sh7014_intc_device::INT_VECTOR_SCI_TEI1
|
||||
);
|
||||
|
||||
SH7014_BSC(config, m_bsc);
|
||||
|
||||
SH7014_DMAC(config, m_dmac, DERIVED_CLOCK(1, 1), *this, m_intc);
|
||||
m_dmac->set_notify_dma_source_callback(FUNC(sh2_sh7014_device::notify_dma_source));
|
||||
|
||||
SH7014_INTC(config, m_intc);
|
||||
m_intc->set_irq_callback(FUNC(sh2_sh7014_device::set_irq));
|
||||
|
||||
SH7014_MTU(config, m_mtu, DERIVED_CLOCK(1, 1), m_intc);
|
||||
|
||||
SH7014_PORT(config, m_port);
|
||||
}
|
||||
|
||||
void sh2_sh7014_device::sh7014_map(address_map &map)
|
||||
{
|
||||
// SCI - Serial Communication Interface
|
||||
map(0xffff81a0, 0xffff81af).m(m_sci[0], FUNC(sh7014_sci_device::map));
|
||||
map(0xffff81b0, 0xffff81bf).m(m_sci[1], FUNC(sh7014_sci_device::map));
|
||||
|
||||
// MTU - Multifunction Timer Pulse Unit
|
||||
map(0xffff8240, 0xffff82af).m(m_mtu, FUNC(sh7014_mtu_device::map));
|
||||
|
||||
// INTC - Interrupt Controller
|
||||
map(0xffff8348, 0xffff835b).m(m_intc, FUNC(sh7014_intc_device::map));
|
||||
|
||||
// I/O - I/O Ports (DR registers)
|
||||
// PFC - Pin Function Controller (IOR, CR registers)
|
||||
// TODO: SH7016/SH7017 support additionally C and D ports in addition to the A, B, E, F that the SH7014 supports
|
||||
map(0xffff8382, 0xffff8383).rw(m_port, FUNC(sh7014_port_device::padrl_r), FUNC(sh7014_port_device::padrl_w));
|
||||
map(0xffff8386, 0xffff8387).rw(m_port, FUNC(sh7014_port_device::paiorl_r), FUNC(sh7014_port_device::paiorl_w));
|
||||
map(0xffff838c, 0xffff838d).rw(m_port, FUNC(sh7014_port_device::pacrl1_r), FUNC(sh7014_port_device::pacrl1_w));
|
||||
map(0xffff838e, 0xffff838f).rw(m_port, FUNC(sh7014_port_device::pacrl2_r), FUNC(sh7014_port_device::pacrl2_w));
|
||||
|
||||
map(0xffff8390, 0xffff8391).rw(m_port, FUNC(sh7014_port_device::pbdr_r), FUNC(sh7014_port_device::pbdr_w));
|
||||
map(0xffff8394, 0xffff8395).rw(m_port, FUNC(sh7014_port_device::pbior_r), FUNC(sh7014_port_device::pbior_w));
|
||||
map(0xffff8398, 0xffff8399).rw(m_port, FUNC(sh7014_port_device::pbcr1_r), FUNC(sh7014_port_device::pbcr1_w));
|
||||
map(0xffff839a, 0xffff839b).rw(m_port, FUNC(sh7014_port_device::pbcr2_r), FUNC(sh7014_port_device::pbcr2_w));
|
||||
|
||||
map(0xffff83b0, 0xffff83b1).rw(m_port, FUNC(sh7014_port_device::pedr_r), FUNC(sh7014_port_device::pedr_w));
|
||||
map(0xffff83b4, 0xffff83b5).rw(m_port, FUNC(sh7014_port_device::peior_r), FUNC(sh7014_port_device::peior_w));
|
||||
map(0xffff83b8, 0xffff83b9).rw(m_port, FUNC(sh7014_port_device::pecr1_r), FUNC(sh7014_port_device::pecr1_w));
|
||||
map(0xffff83ba, 0xffff83bb).rw(m_port, FUNC(sh7014_port_device::pecr2_r), FUNC(sh7014_port_device::pecr2_w));
|
||||
|
||||
map(0xffff83b3, 0xffff83b3).r(m_port, FUNC(sh7014_port_device::pfdr_r));
|
||||
|
||||
// TODO: CMT - Compare Match Timer
|
||||
// 0xffff83d0 - 0xffff83df
|
||||
|
||||
// TODO: A/D - A/D Converter (High Speed, for SH7014)
|
||||
// 0xffff83e0 - 0xffff83ff
|
||||
|
||||
// TODO: A/D - A/D Converter (Mid Speed, for SH7016/SH7017)
|
||||
// 0xffff8420 - 0xffff8429
|
||||
|
||||
// TODO: WDT - Watchdog Timer
|
||||
// 0xffff8610 - 0xffff8613
|
||||
|
||||
// TODO: Power-down state
|
||||
// 0xffff8614
|
||||
|
||||
// BSC - Bus State Controller
|
||||
map(0xffff8620, 0xffff8633).m(m_bsc, FUNC(sh7014_bsc_device::map));
|
||||
|
||||
// DMAC - Direct Memory Access Controller
|
||||
map(0xffff86b0, 0xffff86df).m(m_dmac, FUNC(sh7014_dmac_device::map));
|
||||
|
||||
// CAC - Cache Memory
|
||||
map(0xffff8740, 0xffff8741).rw(FUNC(sh2_sh7014_device::ccr_r), FUNC(sh2_sh7014_device::ccr_w));
|
||||
|
||||
// Cache space
|
||||
map(0xfffff000, 0xffffffff).ram();
|
||||
}
|
||||
|
||||
void sh2_sh7014_device::sh2_exception_internal(const char *message, int irqline, int vector)
|
||||
{
|
||||
// IRQ was taken so clear it in the interrupt controller and pass it down
|
||||
m_intc->set_interrupt(vector, CLEAR_LINE);
|
||||
sh2_device::sh2_exception_internal(message, irqline, vector);
|
||||
}
|
||||
|
||||
void sh2_sh7014_device::execute_set_input(int irqline, int state)
|
||||
{
|
||||
/*
|
||||
Flow for SH7014 IRQs:
|
||||
sh2_sh7014_device::execute_set_input (for externally triggered IRQs)
|
||||
-> sh7014_intc_device::set_input
|
||||
-> sh2_sh7014_device::set_irq
|
||||
-> sh2_device::execute_set_input (if not internal peripheral IRQ) OR DMA interception OR set sh2_device's internal IRQ flags
|
||||
*/
|
||||
m_intc->set_input(irqline, state);
|
||||
}
|
||||
|
||||
void sh2_sh7014_device::set_irq(int vector, int level, bool is_internal)
|
||||
{
|
||||
if (!is_internal) {
|
||||
sh2_device::execute_set_input(vector, ASSERT_LINE);
|
||||
return;
|
||||
}
|
||||
|
||||
// SH7014's DMA controller can be configured to trigger based on various
|
||||
// on-board peripheral IRQs, so on-board peripheral IRQs must go through here
|
||||
if (m_dmac->is_dma_activated(vector)) {
|
||||
m_intc->set_interrupt(vector, CLEAR_LINE);
|
||||
return;
|
||||
}
|
||||
|
||||
m_sh2_state->internal_irq_level = level;
|
||||
m_internal_irq_vector = vector;
|
||||
m_test_irq = 1;
|
||||
}
|
||||
|
||||
void sh2_sh7014_device::notify_dma_source(uint32_t source)
|
||||
{
|
||||
if (source == sh7014_dmac_channel_device::RS_SCI_TXI0)
|
||||
m_sci[0]->set_dma_source_tx(true);
|
||||
else if (source == sh7014_dmac_channel_device::RS_SCI_TXI1)
|
||||
m_sci[1]->set_dma_source_tx(true);
|
||||
else if (source == sh7014_dmac_channel_device::RS_SCI_RXI0)
|
||||
m_sci[0]->set_dma_source_rx(true);
|
||||
else if (source == sh7014_dmac_channel_device::RS_SCI_RXI1)
|
||||
m_sci[1]->set_dma_source_rx(true);
|
||||
}
|
||||
|
||||
///////
|
||||
// CAC
|
||||
|
||||
uint16_t sh2_sh7014_device::ccr_r()
|
||||
{
|
||||
// bits 15-5 are undefined
|
||||
return m_ccr & 0x1f;
|
||||
}
|
||||
|
||||
void sh2_sh7014_device::ccr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
// bit 0 - CECS0 CS0 Space Cache Enable
|
||||
// bit 1 - CECS1 CS1 Space Cache Enable
|
||||
// bit 2 - CECS2 CS2 Space Cache Enable
|
||||
// bit 3 - CECS3 CS3 Space Cache Enable
|
||||
// bit 4 - CEDRAM DRAM Space Cache Enable
|
||||
COMBINE_DATA(&m_ccr);
|
||||
}
|
83
src/devices/cpu/sh/sh7014.h
Normal file
83
src/devices/cpu/sh/sh7014.h
Normal file
@ -0,0 +1,83 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH-2 SH7014
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_CPU_SH_SH7014_H
|
||||
#define MAME_CPU_SH_SH7014_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sh2.h"
|
||||
#include "sh7014_bsc.h"
|
||||
#include "sh7014_dmac.h"
|
||||
#include "sh7014_intc.h"
|
||||
#include "sh7014_mtu.h"
|
||||
#include "sh7014_port.h"
|
||||
#include "sh7014_sci.h"
|
||||
|
||||
class sh2_sh7014_device : public sh2_device
|
||||
{
|
||||
public:
|
||||
sh2_sh7014_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
template<int Sci> auto sci_tx_w() {
|
||||
return m_sci[Sci].lookup()->write_sci_tx();
|
||||
}
|
||||
|
||||
template<int Sci> void sci_set_external_clock_period(const attotime &period) {
|
||||
m_sci[Sci].lookup()->set_external_clock_period(period);
|
||||
}
|
||||
|
||||
template<int Sci> void sci_set_send_full_data_transmit_on_sync_hack(bool enabled) {
|
||||
m_sci[Sci].lookup()->set_send_full_data_transmit_on_sync_hack(enabled);
|
||||
}
|
||||
|
||||
auto read_porta() { return m_port.lookup()->port_a_read_callback(); }
|
||||
auto write_porta() { return m_port.lookup()->port_a_write_callback(); }
|
||||
|
||||
auto read_portb() { return m_port.lookup()->port_b_read_callback(); }
|
||||
auto write_portb() { return m_port.lookup()->port_b_write_callback(); }
|
||||
|
||||
auto read_porte() { return m_port.lookup()->port_e_read_callback(); }
|
||||
auto write_porte() { return m_port.lookup()->port_e_write_callback(); }
|
||||
|
||||
auto read_portf() { return m_port.lookup()->port_f_read_callback(); }
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
virtual void execute_set_input(int inputnum, int state) override;
|
||||
|
||||
virtual void sh2_exception_internal(const char *message, int irqline, int vector) override;
|
||||
|
||||
private:
|
||||
void sh7014_map(address_map &map);
|
||||
|
||||
void set_irq(int vector, int level, bool is_internal);
|
||||
|
||||
void notify_dma_source(uint32_t source);
|
||||
|
||||
uint16_t ccr_r();
|
||||
void ccr_w(offs_t offset, uint16_t dat, uint16_t mem_mask = ~0);
|
||||
|
||||
required_device_array<sh7014_sci_device, 2> m_sci;
|
||||
required_device<sh7014_bsc_device> m_bsc;
|
||||
required_device<sh7014_dmac_device> m_dmac;
|
||||
required_device<sh7014_intc_device> m_intc;
|
||||
required_device<sh7014_mtu_device> m_mtu;
|
||||
required_device<sh7014_port_device> m_port;
|
||||
|
||||
devcb_write_line::array<2> m_sci_tx_cb;
|
||||
|
||||
uint16_t m_ccr;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(SH2_SH7014, sh2_sh7014_device)
|
||||
|
||||
#endif // MAME_CPU_SH_SH7014_H
|
148
src/devices/cpu/sh/sh7014_bsc.cpp
Normal file
148
src/devices/cpu/sh/sh7014_bsc.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 Bus State Controller
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "sh7014_bsc.h"
|
||||
|
||||
// #define VERBOSE (LOG_GENERAL)
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(SH7014_BSC, sh7014_bsc_device, "sh7014bsc", "SH7014 Bus State Controller")
|
||||
|
||||
|
||||
sh7014_bsc_device::sh7014_bsc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, SH7014_BSC, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
void sh7014_bsc_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_bcr1));
|
||||
save_item(NAME(m_bcr2));
|
||||
save_item(NAME(m_wcr1));
|
||||
save_item(NAME(m_wcr2));
|
||||
save_item(NAME(m_dcr));
|
||||
save_item(NAME(m_rtcsr));
|
||||
save_item(NAME(m_rtcnt));
|
||||
save_item(NAME(m_rtcor));
|
||||
}
|
||||
|
||||
void sh7014_bsc_device::device_reset()
|
||||
{
|
||||
m_bcr1 = 0;
|
||||
m_bcr2 = 0xffff;
|
||||
m_wcr1 = 0xffff;
|
||||
m_wcr2 = 0x000f;
|
||||
m_dcr = 0;
|
||||
m_rtcsr = 0;
|
||||
m_rtcnt = 0;
|
||||
m_rtcor = 0;
|
||||
}
|
||||
|
||||
void sh7014_bsc_device::map(address_map &map)
|
||||
{
|
||||
map(0x00, 0x01).rw(FUNC(sh7014_bsc_device::bcr1_r), FUNC(sh7014_bsc_device::bcr1_w));
|
||||
map(0x02, 0x03).rw(FUNC(sh7014_bsc_device::bcr2_r), FUNC(sh7014_bsc_device::bcr2_w));
|
||||
map(0x04, 0x05).rw(FUNC(sh7014_bsc_device::wcr1_r), FUNC(sh7014_bsc_device::wcr1_w));;
|
||||
map(0x06, 0x07).rw(FUNC(sh7014_bsc_device::wcr2_r), FUNC(sh7014_bsc_device::wcr2_w));
|
||||
map(0x0a, 0x0b).rw(FUNC(sh7014_bsc_device::dcr_r), FUNC(sh7014_bsc_device::dcr_w));
|
||||
map(0x0c, 0x0d).rw(FUNC(sh7014_bsc_device::rtcsr_r), FUNC(sh7014_bsc_device::rtcsr_w));
|
||||
map(0x0e, 0x0f).rw(FUNC(sh7014_bsc_device::rtcnt_r), FUNC(sh7014_bsc_device::rtcnt_w));
|
||||
map(0x10, 0x11).rw(FUNC(sh7014_bsc_device::rtcor_r), FUNC(sh7014_bsc_device::rtcor_w));
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
uint16_t sh7014_bsc_device::bcr1_r()
|
||||
{
|
||||
// bit 0 [R/W] CS0 Space Size Specification (A0SZ)
|
||||
// bit 1 [R/W] CS1 Space Size Specification (A1SZ)
|
||||
// bit 2 [R/W] CS2 Space Size Specification (A2SZ)
|
||||
// bit 3 [R/W] CS3 Space Size Specification (A3SZ)
|
||||
// bit 8 [R/W] Multiplex I/O Enable (IOE)
|
||||
// bit 13 [R] Always returns 1
|
||||
// Everything else is read-only and will return 0
|
||||
return (m_bcr1 & 0x10f) | (1 << 13);
|
||||
}
|
||||
|
||||
void sh7014_bsc_device::bcr1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_bcr1);
|
||||
}
|
||||
|
||||
uint16_t sh7014_bsc_device::bcr2_r()
|
||||
{
|
||||
return m_bcr2;
|
||||
}
|
||||
|
||||
void sh7014_bsc_device::bcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_bcr2);
|
||||
}
|
||||
|
||||
uint16_t sh7014_bsc_device::wcr1_r()
|
||||
{
|
||||
return m_wcr1;
|
||||
}
|
||||
|
||||
void sh7014_bsc_device::wcr1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_wcr1);
|
||||
}
|
||||
|
||||
uint16_t sh7014_bsc_device::wcr2_r()
|
||||
{
|
||||
return m_wcr2 & 0x3ff;
|
||||
}
|
||||
|
||||
void sh7014_bsc_device::wcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_wcr2);
|
||||
}
|
||||
|
||||
uint16_t sh7014_bsc_device::dcr_r()
|
||||
{
|
||||
return m_dcr & ~0x48;
|
||||
}
|
||||
|
||||
void sh7014_bsc_device::dcr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_dcr);
|
||||
}
|
||||
|
||||
uint16_t sh7014_bsc_device::rtcsr_r()
|
||||
{
|
||||
return m_rtcsr & 0x7f;
|
||||
}
|
||||
|
||||
void sh7014_bsc_device::rtcsr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_rtcsr);
|
||||
}
|
||||
|
||||
uint16_t sh7014_bsc_device::rtcnt_r()
|
||||
{
|
||||
return m_rtcnt & 0xff;
|
||||
}
|
||||
|
||||
void sh7014_bsc_device::rtcnt_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_rtcnt);
|
||||
}
|
||||
|
||||
uint16_t sh7014_bsc_device::rtcor_r()
|
||||
{
|
||||
return m_rtcor & 0xff;
|
||||
}
|
||||
|
||||
void sh7014_bsc_device::rtcor_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_rtcor);
|
||||
}
|
62
src/devices/cpu/sh/sh7014_bsc.h
Normal file
62
src/devices/cpu/sh/sh7014_bsc.h
Normal file
@ -0,0 +1,62 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 Bus State Controller
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_CPU_SH_SH7014_BSC_H
|
||||
#define MAME_CPU_SH_SH7014_BSC_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
class sh7014_bsc_device : public device_t
|
||||
{
|
||||
public:
|
||||
sh7014_bsc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
void map(address_map &map);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
private:
|
||||
uint16_t bcr1_r();
|
||||
void bcr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t bcr2_r();
|
||||
void bcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t wcr1_r();
|
||||
void wcr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t wcr2_r();
|
||||
void wcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t dcr_r();
|
||||
void dcr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t rtcsr_r();
|
||||
void rtcsr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t rtcor_r();
|
||||
void rtcor_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t rtcnt_r();
|
||||
void rtcnt_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t m_bcr1, m_bcr2;
|
||||
uint16_t m_wcr1, m_wcr2;
|
||||
uint16_t m_dcr;
|
||||
uint16_t m_rtcsr;
|
||||
uint16_t m_rtcnt;
|
||||
uint16_t m_rtcor;
|
||||
};
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(SH7014_BSC, sh7014_bsc_device)
|
||||
|
||||
#endif // MAME_CPU_SH_SH7014_BSC_H
|
400
src/devices/cpu/sh/sh7014_dmac.cpp
Normal file
400
src/devices/cpu/sh/sh7014_dmac.cpp
Normal file
@ -0,0 +1,400 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 Direct Memory Access Controller
|
||||
|
||||
TODO list (not comprehensive):
|
||||
- Channel priority
|
||||
- External dual and single address modes
|
||||
- DREQ, DACK, DRAK pins
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "sh7014_dmac.h"
|
||||
|
||||
#define LOG_TX (1U << 1)
|
||||
|
||||
// #define VERBOSE (LOG_GENERAL | LOG_TX)
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(SH7014_DMAC, sh7014_dmac_device, "sh7014dmac", "SH7014 Direct Memory Access Controller")
|
||||
DEFINE_DEVICE_TYPE(SH7014_DMAC_CHANNEL, sh7014_dmac_channel_device, "sh7014dmacchan", "SH7014 Direct Memory Access Controller Channel")
|
||||
|
||||
|
||||
sh7014_dmac_device::sh7014_dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, SH7014_DMAC, tag, owner, clock)
|
||||
, m_cpu(*this, finder_base::DUMMY_TAG)
|
||||
, m_intc(*this, finder_base::DUMMY_TAG)
|
||||
, m_chan(*this, "ch%u", 0u)
|
||||
{
|
||||
}
|
||||
|
||||
void sh7014_dmac_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_dmaor));
|
||||
}
|
||||
|
||||
void sh7014_dmac_device::device_reset()
|
||||
{
|
||||
m_dmaor = 0;
|
||||
}
|
||||
|
||||
void sh7014_dmac_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
SH7014_DMAC_CHANNEL(config, m_chan[0], DERIVED_CLOCK(1, 1), *this, m_cpu, m_intc,
|
||||
0, // channel
|
||||
sh7014_intc_device::INT_VECTOR_DMA_CH0
|
||||
);
|
||||
|
||||
SH7014_DMAC_CHANNEL(config, m_chan[1], DERIVED_CLOCK(1, 1), *this, m_cpu, m_intc,
|
||||
1, // channel
|
||||
sh7014_intc_device::INT_VECTOR_DMA_CH1
|
||||
);
|
||||
}
|
||||
|
||||
void sh7014_dmac_device::map(address_map &map)
|
||||
{
|
||||
map(0x00, 0x01).rw(FUNC(sh7014_dmac_device::dmaor_r), FUNC(sh7014_dmac_device::dmaor_w));
|
||||
map(0x10, 0x1f).m(m_chan[0], FUNC(sh7014_dmac_channel_device::map));
|
||||
map(0x20, 0x2f).m(m_chan[1], FUNC(sh7014_dmac_channel_device::map));
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
uint16_t sh7014_dmac_device::dmaor_r()
|
||||
{
|
||||
return m_dmaor & 7;
|
||||
}
|
||||
|
||||
void sh7014_dmac_device::dmaor_w(uint16_t data)
|
||||
{
|
||||
m_dmaor = (data & ~6) | (m_dmaor & data & 6);
|
||||
m_chan[0]->dma_check();
|
||||
m_chan[1]->dma_check();
|
||||
}
|
||||
|
||||
bool sh7014_dmac_device::is_transfer_allowed()
|
||||
{
|
||||
const bool is_enabled = (m_dmaor & DMAOR_DME) != 0;
|
||||
const bool has_address_error = (m_dmaor & DMAOR_AE) != 0;
|
||||
const bool has_nmi_flag = (m_dmaor & DMAOR_NMIF) != 0;
|
||||
return is_enabled && !has_nmi_flag && !has_address_error;
|
||||
}
|
||||
|
||||
int sh7014_dmac_device::is_dma_activated(int vector)
|
||||
{
|
||||
int activated = 0;
|
||||
|
||||
if (!is_transfer_allowed())
|
||||
return 0;
|
||||
|
||||
if (m_chan[0]->is_dma_activated(vector))
|
||||
activated |= 1;
|
||||
if (m_chan[1]->is_dma_activated(vector))
|
||||
activated |= 2;
|
||||
|
||||
return activated;
|
||||
}
|
||||
|
||||
|
||||
//////////////////
|
||||
|
||||
|
||||
void sh7014_dmac_channel_device::map(address_map &map)
|
||||
{
|
||||
map(0x00, 0x03).rw(FUNC(sh7014_dmac_channel_device::sar_r), FUNC(sh7014_dmac_channel_device::sar_w));
|
||||
map(0x04, 0x07).rw(FUNC(sh7014_dmac_channel_device::dar_r), FUNC(sh7014_dmac_channel_device::dar_w));
|
||||
map(0x08, 0x0b).rw(FUNC(sh7014_dmac_channel_device::dmatcr_r), FUNC(sh7014_dmac_channel_device::dmatcr_w));
|
||||
map(0x0c, 0x0f).rw(FUNC(sh7014_dmac_channel_device::chcr_r), FUNC(sh7014_dmac_channel_device::chcr_w));
|
||||
}
|
||||
|
||||
sh7014_dmac_channel_device::sh7014_dmac_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, SH7014_DMAC_CHANNEL, tag, owner, clock)
|
||||
, m_dmac(*this, finder_base::DUMMY_TAG)
|
||||
, m_cpu(*this, finder_base::DUMMY_TAG)
|
||||
, m_intc(*this, finder_base::DUMMY_TAG)
|
||||
, m_notify_dma_source_cb(*this)
|
||||
{
|
||||
}
|
||||
|
||||
void sh7014_dmac_channel_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_sar));
|
||||
save_item(NAME(m_dar));
|
||||
save_item(NAME(m_dmatcr));
|
||||
save_item(NAME(m_chcr));
|
||||
|
||||
save_item(NAME(m_dma_timer_active));
|
||||
save_item(NAME(m_active_dma_addr_mode_source));
|
||||
save_item(NAME(m_active_dma_addr_mode_dest));
|
||||
save_item(NAME(m_active_dma_unit_size));
|
||||
save_item(NAME(m_active_dma_is_burst));
|
||||
|
||||
save_item(NAME(m_selected_resource));
|
||||
save_item(NAME(m_request_source_type));
|
||||
save_item(NAME(m_expected_irq_vector));
|
||||
|
||||
m_dma_current_active_timer = timer_alloc(FUNC(sh7014_dmac_channel_device::dma_timer_callback), this);
|
||||
}
|
||||
|
||||
void sh7014_dmac_channel_device::device_reset()
|
||||
{
|
||||
m_sar = m_dar = 0;
|
||||
m_dmatcr = 0;
|
||||
m_chcr = 0;
|
||||
|
||||
m_dma_timer_active = false;
|
||||
m_active_dma_addr_mode_source = 0;
|
||||
m_active_dma_addr_mode_dest = 0;
|
||||
m_active_dma_unit_size = 1;
|
||||
m_active_dma_is_burst = false;
|
||||
|
||||
m_selected_resource = RS_EXTERNAL_DUAL_ADDR;
|
||||
m_request_source_type = RS_TYPE_EXTERNAL_DUAL;
|
||||
m_expected_irq_vector = -1;
|
||||
|
||||
m_dma_current_active_timer->adjust(attotime::never);
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
bool sh7014_dmac_channel_device::is_enabled()
|
||||
{
|
||||
return (m_chcr & CHCR_DE) != 0;
|
||||
}
|
||||
|
||||
uint32_t sh7014_dmac_channel_device::sar_r()
|
||||
{
|
||||
return m_sar;
|
||||
}
|
||||
|
||||
void sh7014_dmac_channel_device::sar_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_sar);
|
||||
}
|
||||
|
||||
uint32_t sh7014_dmac_channel_device::dar_r()
|
||||
{
|
||||
return m_dar;
|
||||
}
|
||||
|
||||
void sh7014_dmac_channel_device::dar_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_dar);
|
||||
}
|
||||
|
||||
uint32_t sh7014_dmac_channel_device::dmatcr_r()
|
||||
{
|
||||
return m_dmatcr & 0xffff;
|
||||
}
|
||||
|
||||
void sh7014_dmac_channel_device::dmatcr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_dmatcr);
|
||||
m_dmatcr &= 0xffff;
|
||||
}
|
||||
|
||||
uint32_t sh7014_dmac_channel_device::chcr_r()
|
||||
{
|
||||
return m_chcr & 0xbff7f;
|
||||
}
|
||||
|
||||
void sh7014_dmac_channel_device::chcr_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_chcr);
|
||||
|
||||
m_selected_resource = BIT(m_chcr, 8, 4);
|
||||
m_expected_irq_vector = -1;
|
||||
|
||||
switch (m_selected_resource) {
|
||||
case RS_MTU_TGI0A:
|
||||
m_request_source_type = RS_TYPE_INTERNAL;
|
||||
m_expected_irq_vector = sh7014_intc_device::INT_VECTOR_MTU_TGI0A;
|
||||
break;
|
||||
case RS_MTU_TGI1A:
|
||||
m_request_source_type = RS_TYPE_INTERNAL;
|
||||
m_expected_irq_vector = sh7014_intc_device::INT_VECTOR_MTU_TGI1A;
|
||||
break;
|
||||
case RS_MTU_TGI2A:
|
||||
m_request_source_type = RS_TYPE_INTERNAL;
|
||||
m_expected_irq_vector = sh7014_intc_device::INT_VECTOR_MTU_TGI2A;
|
||||
break;
|
||||
case RS_AD:
|
||||
m_request_source_type = RS_TYPE_INTERNAL;
|
||||
m_expected_irq_vector = sh7014_intc_device::INT_VECTOR_AD;
|
||||
break;
|
||||
case RS_SCI_TXI0:
|
||||
m_request_source_type = RS_TYPE_INTERNAL;
|
||||
m_expected_irq_vector = sh7014_intc_device::INT_VECTOR_SCI_TXI0;
|
||||
break;
|
||||
case RS_SCI_RXI0:
|
||||
m_request_source_type = RS_TYPE_INTERNAL;
|
||||
m_expected_irq_vector = sh7014_intc_device::INT_VECTOR_SCI_RXI0;
|
||||
break;
|
||||
case RS_SCI_TXI1:
|
||||
m_request_source_type = RS_TYPE_INTERNAL;
|
||||
m_expected_irq_vector = sh7014_intc_device::INT_VECTOR_SCI_TXI1;
|
||||
break;
|
||||
case RS_SCI_RXI1:
|
||||
m_request_source_type = RS_TYPE_INTERNAL;
|
||||
m_expected_irq_vector = sh7014_intc_device::INT_VECTOR_SCI_RXI1;
|
||||
break;
|
||||
|
||||
case RS_AUTO_REQUEST:
|
||||
m_request_source_type = RS_TYPE_AUTO;
|
||||
break;
|
||||
|
||||
case RS_EXTERNAL_DUAL_ADDR:
|
||||
m_request_source_type = RS_TYPE_EXTERNAL_DUAL;
|
||||
break;
|
||||
|
||||
case RS_EXTERNAL_SINGLE_ADDR_TO_DEV:
|
||||
case RS_EXTERNAL_SINGLE_DEV_TO_ADDR:
|
||||
m_request_source_type = RS_TYPE_EXTERNAL_SINGLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
m_request_source_type = RS_TYPE_PROHIBITED;
|
||||
break;
|
||||
}
|
||||
|
||||
dma_check();
|
||||
}
|
||||
|
||||
bool sh7014_dmac_channel_device::is_dma_activated(int vector)
|
||||
{
|
||||
if (m_request_source_type != RS_TYPE_INTERNAL || m_expected_irq_vector == -1 || vector != m_expected_irq_vector)
|
||||
return false;
|
||||
|
||||
if (!m_dma_timer_active)
|
||||
dma_check();
|
||||
|
||||
if (!m_dma_timer_active)
|
||||
return false;
|
||||
|
||||
m_dma_current_active_timer->adjust(attotime::from_ticks(2, clock()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( sh7014_dmac_channel_device::dma_timer_callback )
|
||||
{
|
||||
if (!m_dma_timer_active)
|
||||
return;
|
||||
|
||||
if (!m_dmac->is_transfer_allowed()) {
|
||||
LOG("SH7014: DMA %d transfer aborted\n", m_channel_id);
|
||||
m_dma_timer_active = false;
|
||||
return;
|
||||
}
|
||||
|
||||
LOGMASKED(LOG_TX, "DMAC ch %d remaining %08x size %d | source %08x dest %08x\n", m_channel_id, m_dmatcr, m_active_dma_unit_size, m_sar, m_dar);
|
||||
|
||||
if (m_active_dma_addr_mode_source == DMA_ADDR_MODE_DEC)
|
||||
m_sar -= m_active_dma_unit_size;
|
||||
|
||||
if (m_active_dma_addr_mode_dest == DMA_ADDR_MODE_DEC)
|
||||
m_dar -= m_active_dma_unit_size;
|
||||
|
||||
if (m_request_source_type == RS_TYPE_INTERNAL)
|
||||
m_notify_dma_source_cb(m_selected_resource);
|
||||
|
||||
switch (m_active_dma_unit_size) {
|
||||
case 1:
|
||||
m_cpu->m_program->write_byte(
|
||||
m_dar,
|
||||
m_cpu->m_program->read_byte(m_sar)
|
||||
);
|
||||
break;
|
||||
case 2:
|
||||
m_cpu->m_program->write_word(
|
||||
m_dar,
|
||||
m_cpu->m_program->read_word(m_sar)
|
||||
);
|
||||
break;
|
||||
case 4:
|
||||
m_cpu->m_program->write_dword(
|
||||
m_dar,
|
||||
m_cpu->m_program->read_dword(m_sar)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_active_dma_addr_mode_source == DMA_ADDR_MODE_INC)
|
||||
m_sar += m_active_dma_unit_size;
|
||||
|
||||
if (m_active_dma_addr_mode_dest == DMA_ADDR_MODE_INC)
|
||||
m_dar += m_active_dma_unit_size;
|
||||
|
||||
m_dmatcr--;
|
||||
|
||||
if (m_dmatcr <= 0) {
|
||||
LOGMASKED(LOG_TX, "SH7014: DMA %d complete\n", m_channel_id);
|
||||
|
||||
m_dmatcr = 0;
|
||||
m_chcr |= CHCR_TE; // transfer end
|
||||
m_dma_timer_active = false;
|
||||
|
||||
if (m_active_dma_is_burst)
|
||||
m_cpu->resume(SUSPEND_REASON_HALT);
|
||||
|
||||
const auto interrupt_enable = (m_chcr & CHCR_IE) != 0;
|
||||
if (interrupt_enable)
|
||||
m_intc->set_interrupt(m_vector, ASSERT_LINE);
|
||||
} else {
|
||||
// schedule next DMA callback
|
||||
// Internal source transfers in burst mode end on last transfer, otherwise should end after the first transfer when burst mode is off
|
||||
// TODO: DREQ and DACK are needed for external sources instead of being handled like an auto requests
|
||||
if (m_request_source_type != RS_TYPE_INTERNAL || (m_request_source_type == RS_TYPE_INTERNAL && m_active_dma_is_burst))
|
||||
m_dma_current_active_timer->adjust(attotime::from_ticks(2, clock()));
|
||||
}
|
||||
}
|
||||
|
||||
void sh7014_dmac_channel_device::dma_check()
|
||||
{
|
||||
if (!m_dmac->is_transfer_allowed()) {
|
||||
if (m_dma_timer_active) {
|
||||
LOG("SH7014: DMA %d cancelled in-flight\n", m_channel_id);
|
||||
m_dma_current_active_timer->adjust(attotime::never);
|
||||
m_dma_timer_active = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_dma_timer_active)
|
||||
return;
|
||||
|
||||
m_active_dma_addr_mode_dest = BIT(m_chcr, 14, 2); // DM
|
||||
m_active_dma_addr_mode_source = BIT(m_chcr, 12, 2); // SM
|
||||
m_active_dma_unit_size = 1 << BIT(m_chcr, 3, 2); // TS
|
||||
m_active_dma_is_burst = (m_chcr & CHCR_TM) != 0;
|
||||
|
||||
if (m_active_dma_addr_mode_dest == DMA_ADDR_MODE_PROHIBITED || m_active_dma_addr_mode_source == DMA_ADDR_MODE_PROHIBITED || m_active_dma_unit_size > 4) {
|
||||
LOG("SH7014: DMA %d: bad increment values (%d, %d, %d, %04x)\n", m_channel_id, m_active_dma_addr_mode_dest, m_active_dma_addr_mode_source, m_active_dma_unit_size, m_chcr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_dmatcr == 0)
|
||||
m_dmatcr = 0x10000;
|
||||
|
||||
m_dma_timer_active = true;
|
||||
|
||||
LOG("SH7014: DMA %d start %x, %x, %x, %04x, %d, %d, %d, %d\n", m_channel_id, m_sar, m_dar, m_dmatcr, m_chcr, m_active_dma_addr_mode_source, m_active_dma_addr_mode_dest, m_active_dma_unit_size, m_active_dma_is_burst);
|
||||
|
||||
if (m_active_dma_unit_size > 1) {
|
||||
const int mask = m_active_dma_unit_size - 1;
|
||||
m_sar &= ~mask;
|
||||
m_dar &= ~mask;
|
||||
}
|
||||
|
||||
if (m_active_dma_is_burst)
|
||||
m_cpu->suspend(SUSPEND_REASON_HALT, 1);
|
||||
|
||||
if (m_request_source_type != RS_TYPE_INTERNAL || (m_request_source_type == RS_TYPE_INTERNAL && m_active_dma_is_burst))
|
||||
m_dma_current_active_timer->adjust(attotime::from_ticks(2, clock()));
|
||||
}
|
173
src/devices/cpu/sh/sh7014_dmac.h
Normal file
173
src/devices/cpu/sh/sh7014_dmac.h
Normal file
@ -0,0 +1,173 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 Direct Memory Access Controller
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_CPU_SH_SH7014_DMAC_H
|
||||
#define MAME_CPU_SH_SH7014_DMAC_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sh2.h"
|
||||
#include "sh7014_intc.h"
|
||||
|
||||
DECLARE_DEVICE_TYPE(SH7014_DMAC, sh7014_dmac_device)
|
||||
DECLARE_DEVICE_TYPE(SH7014_DMAC_CHANNEL, sh7014_dmac_channel_device)
|
||||
|
||||
class sh7014_dmac_device;
|
||||
|
||||
class sh7014_dmac_channel_device : public device_t
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
RS_EXTERNAL_DUAL_ADDR = 0, // External request, dual address mode
|
||||
RS_EXTERNAL_SINGLE_ADDR_TO_DEV = 2, // External request, single address mode. External address space -> external device
|
||||
RS_EXTERNAL_SINGLE_DEV_TO_ADDR = 3, // External request, single address mode. External device -> external address space
|
||||
RS_AUTO_REQUEST = 4,
|
||||
RS_MTU_TGI0A = 6,
|
||||
RS_MTU_TGI1A = 7,
|
||||
RS_MTU_TGI2A = 8,
|
||||
RS_AD = 11,
|
||||
RS_SCI_TXI0 = 12,
|
||||
RS_SCI_RXI0 = 13,
|
||||
RS_SCI_TXI1 = 14,
|
||||
RS_SCI_RXI1 = 15,
|
||||
};
|
||||
|
||||
sh7014_dmac_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
template<typename T, typename U, typename V> sh7014_dmac_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&dmac, U &&cpu, V &&intc, int chan_id, int vector)
|
||||
: sh7014_dmac_channel_device(mconfig, tag, owner, clock)
|
||||
{
|
||||
m_dmac.set_tag(std::forward<T>(dmac));
|
||||
m_cpu.set_tag(std::forward<U>(cpu));
|
||||
m_intc.set_tag(std::forward<V>(intc));
|
||||
m_channel_id = chan_id;
|
||||
m_vector = vector;
|
||||
}
|
||||
|
||||
auto notify_dma_source_callback() { return m_notify_dma_source_cb.bind(); }
|
||||
|
||||
void map(address_map &map);
|
||||
|
||||
void dma_check();
|
||||
|
||||
bool is_dma_activated(int vector);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
private:
|
||||
enum {
|
||||
RS_TYPE_EXTERNAL_DUAL = 0,
|
||||
RS_TYPE_EXTERNAL_SINGLE,
|
||||
RS_TYPE_AUTO,
|
||||
RS_TYPE_INTERNAL,
|
||||
RS_TYPE_PROHIBITED,
|
||||
};
|
||||
|
||||
enum {
|
||||
DMA_ADDR_MODE_FIXED = 0,
|
||||
DMA_ADDR_MODE_INC,
|
||||
DMA_ADDR_MODE_DEC,
|
||||
DMA_ADDR_MODE_PROHIBITED,
|
||||
};
|
||||
|
||||
enum {
|
||||
CHCR_DE = 1 << 0,
|
||||
CHCR_TE = 1 << 1,
|
||||
CHCR_IE = 1 << 2,
|
||||
CHCR_TM = 1 << 5,
|
||||
};
|
||||
|
||||
bool is_enabled();
|
||||
|
||||
uint32_t sar_r();
|
||||
void sar_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
|
||||
uint32_t dar_r();
|
||||
void dar_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
|
||||
uint32_t dmatcr_r();
|
||||
void dmatcr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
|
||||
uint32_t chcr_r();
|
||||
void chcr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
|
||||
TIMER_CALLBACK_MEMBER( dma_timer_callback );
|
||||
|
||||
required_device<sh7014_dmac_device> m_dmac;
|
||||
required_device<sh2_device> m_cpu;
|
||||
required_device<sh7014_intc_device> m_intc;
|
||||
|
||||
emu_timer *m_dma_current_active_timer;
|
||||
|
||||
devcb_write32 m_notify_dma_source_cb;
|
||||
|
||||
uint32_t m_channel_id;
|
||||
uint32_t m_vector;
|
||||
|
||||
uint32_t m_chcr;
|
||||
uint32_t m_sar;
|
||||
uint32_t m_dar;
|
||||
int32_t m_dmatcr;
|
||||
|
||||
bool m_dma_timer_active;
|
||||
uint32_t m_active_dma_addr_mode_source;
|
||||
uint32_t m_active_dma_addr_mode_dest;
|
||||
uint32_t m_active_dma_unit_size;
|
||||
bool m_active_dma_is_burst;
|
||||
|
||||
int32_t m_request_source_type, m_selected_resource;
|
||||
int32_t m_expected_irq_vector;
|
||||
};
|
||||
|
||||
class sh7014_dmac_device : public device_t
|
||||
{
|
||||
public:
|
||||
sh7014_dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
template<typename T, typename U> sh7014_dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu, U &&intc)
|
||||
: sh7014_dmac_device(mconfig, tag, owner, clock)
|
||||
{
|
||||
m_cpu.set_tag(std::forward<T>(cpu));
|
||||
m_intc.set_tag(std::forward<U>(intc));
|
||||
}
|
||||
|
||||
template <typename... T> void set_notify_dma_source_callback(T &&... args) {
|
||||
m_chan[0].lookup()->notify_dma_source_callback().set(std::forward<T>(args)...);
|
||||
m_chan[1].lookup()->notify_dma_source_callback().set(std::forward<T>(args)...);
|
||||
}
|
||||
|
||||
void map(address_map &map);
|
||||
|
||||
int is_dma_activated(int vector);
|
||||
bool is_transfer_allowed();
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
private:
|
||||
enum {
|
||||
DMAOR_DME = 1 << 0,
|
||||
DMAOR_NMIF = 1 << 1,
|
||||
DMAOR_AE = 1 << 2,
|
||||
};
|
||||
|
||||
void dmaor_w(uint16_t data);
|
||||
uint16_t dmaor_r();
|
||||
|
||||
required_device<sh2_device> m_cpu;
|
||||
required_device<sh7014_intc_device> m_intc;
|
||||
required_device_array<sh7014_dmac_channel_device, 2> m_chan;
|
||||
|
||||
uint16_t m_dmaor;
|
||||
};
|
||||
|
||||
#endif // MAME_CPU_SH_SH7014_DMAC_H
|
313
src/devices/cpu/sh/sh7014_intc.cpp
Normal file
313
src/devices/cpu/sh/sh7014_intc.cpp
Normal file
@ -0,0 +1,313 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 Interrupt Controller
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "sh7014_intc.h"
|
||||
|
||||
// #define VERBOSE (LOG_GENERAL)
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(SH7014_INTC, sh7014_intc_device, "sh7014intc", "SH7014 Interrupt Controller")
|
||||
|
||||
|
||||
sh7014_intc_device::sh7014_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, SH7014_INTC, tag, owner, clock)
|
||||
, m_set_irq_cb(*this)
|
||||
{
|
||||
}
|
||||
|
||||
void sh7014_intc_device::device_start()
|
||||
{
|
||||
m_set_irq_cb.resolve();
|
||||
|
||||
save_item(NAME(m_ipra));
|
||||
save_item(NAME(m_iprb));
|
||||
save_item(NAME(m_iprc));
|
||||
save_item(NAME(m_iprd));
|
||||
save_item(NAME(m_ipre));
|
||||
save_item(NAME(m_iprf));
|
||||
save_item(NAME(m_iprg));
|
||||
save_item(NAME(m_iprh));
|
||||
save_item(NAME(m_icr));
|
||||
save_item(NAME(m_isr));
|
||||
save_item(NAME(m_irq_type));
|
||||
save_item(NAME(m_nmi_input));
|
||||
save_item(NAME(m_pending_irqs));
|
||||
save_item(NAME(m_irq_levels));
|
||||
}
|
||||
|
||||
void sh7014_intc_device::device_reset()
|
||||
{
|
||||
m_ipra = 0;
|
||||
m_iprb = 0;
|
||||
m_iprc = 0;
|
||||
m_iprd = 0;
|
||||
m_ipre = 0;
|
||||
m_iprf = 0;
|
||||
m_iprg = 0;
|
||||
m_iprh = 0;
|
||||
m_icr = m_isr = 0;
|
||||
m_nmi_input = false;
|
||||
|
||||
std::fill(std::begin(m_irq_type), std::end(m_irq_type), IRQ_LEVEL);
|
||||
std::fill(std::begin(m_irq_levels), std::end(m_irq_levels), 0);
|
||||
std::fill(std::begin(m_pending_irqs), std::end(m_pending_irqs), 0);
|
||||
|
||||
m_irq_levels[INT_VECTOR_NMI] = 16; // fixed value
|
||||
}
|
||||
|
||||
void sh7014_intc_device::map(address_map &map)
|
||||
{
|
||||
map(0x00, 0x01).rw(FUNC(sh7014_intc_device::ipra_r), FUNC(sh7014_intc_device::ipra_w));
|
||||
map(0x02, 0x03).rw(FUNC(sh7014_intc_device::iprb_r), FUNC(sh7014_intc_device::iprb_w));
|
||||
map(0x04, 0x05).rw(FUNC(sh7014_intc_device::iprc_r), FUNC(sh7014_intc_device::iprc_w));
|
||||
map(0x06, 0x07).rw(FUNC(sh7014_intc_device::iprd_r), FUNC(sh7014_intc_device::iprd_w));
|
||||
map(0x08, 0x09).rw(FUNC(sh7014_intc_device::ipre_r), FUNC(sh7014_intc_device::ipre_w));
|
||||
map(0x0a, 0x0b).rw(FUNC(sh7014_intc_device::iprf_r), FUNC(sh7014_intc_device::iprf_w));
|
||||
map(0x0c, 0x0d).rw(FUNC(sh7014_intc_device::iprg_r), FUNC(sh7014_intc_device::iprg_w));
|
||||
map(0x0e, 0x0f).rw(FUNC(sh7014_intc_device::iprh_r), FUNC(sh7014_intc_device::iprh_w));
|
||||
map(0x10, 0x11).rw(FUNC(sh7014_intc_device::icr_r), FUNC(sh7014_intc_device::icr_w));
|
||||
map(0x12, 0x13).rw(FUNC(sh7014_intc_device::isr_r), FUNC(sh7014_intc_device::isr_w));
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
uint16_t sh7014_intc_device::ipra_r()
|
||||
{
|
||||
return m_ipra;
|
||||
}
|
||||
|
||||
void sh7014_intc_device::ipra_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_ipra);
|
||||
|
||||
m_irq_levels[INT_VECTOR_IRQ0] = BIT(m_ipra, 12, 4);
|
||||
m_irq_levels[INT_VECTOR_IRQ1] = BIT(m_ipra, 8, 4);
|
||||
m_irq_levels[INT_VECTOR_IRQ2] = BIT(m_ipra, 4, 4);
|
||||
m_irq_levels[INT_VECTOR_IRQ3] = BIT(m_ipra, 0, 4);
|
||||
|
||||
update_irq_state();
|
||||
}
|
||||
|
||||
uint16_t sh7014_intc_device::iprb_r()
|
||||
{
|
||||
return m_iprb & 0xff00;
|
||||
}
|
||||
|
||||
void sh7014_intc_device::iprb_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_iprb);
|
||||
|
||||
m_irq_levels[INT_VECTOR_IRQ6] = BIT(m_iprb, 4, 4);
|
||||
m_irq_levels[INT_VECTOR_IRQ7] = BIT(m_iprb, 0, 4);
|
||||
|
||||
update_irq_state();
|
||||
}
|
||||
|
||||
uint16_t sh7014_intc_device::iprc_r()
|
||||
{
|
||||
return m_iprc;
|
||||
}
|
||||
|
||||
void sh7014_intc_device::iprc_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_iprc);
|
||||
|
||||
m_irq_levels[INT_VECTOR_DMA_CH0] = BIT(m_iprc, 12, 4);
|
||||
m_irq_levels[INT_VECTOR_DMA_CH1] = BIT(m_iprc, 8, 4);
|
||||
|
||||
update_irq_state();
|
||||
}
|
||||
|
||||
uint16_t sh7014_intc_device::iprd_r()
|
||||
{
|
||||
return m_iprd;
|
||||
}
|
||||
|
||||
void sh7014_intc_device::iprd_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_iprd);
|
||||
|
||||
m_irq_levels[INT_VECTOR_MTU_TGI0A] = m_irq_levels[INT_VECTOR_MTU_TGI0B] = m_irq_levels[INT_VECTOR_MTU_TGI0C] = m_irq_levels[INT_VECTOR_MTU_TGI0D] = BIT(m_iprd, 12, 4);
|
||||
m_irq_levels[INT_VECTOR_MTU_TGI0V] = BIT(m_iprd, 8, 4);
|
||||
m_irq_levels[INT_VECTOR_MTU_TGI1A] = m_irq_levels[INT_VECTOR_MTU_TGI1B] = BIT(m_iprd, 4, 4);
|
||||
m_irq_levels[INT_VECTOR_MTU_TGI1V] = m_irq_levels[INT_VECTOR_MTU_TGI1U] = BIT(m_iprd, 0, 4);
|
||||
|
||||
update_irq_state();
|
||||
}
|
||||
|
||||
uint16_t sh7014_intc_device::ipre_r()
|
||||
{
|
||||
return m_ipre & 0xff00;
|
||||
}
|
||||
|
||||
void sh7014_intc_device::ipre_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_ipre);
|
||||
|
||||
m_irq_levels[INT_VECTOR_MTU_TGI2A] = m_irq_levels[INT_VECTOR_MTU_TGI2B] = BIT(m_ipre, 12, 4);
|
||||
m_irq_levels[INT_VECTOR_MTU_TGI2V] = m_irq_levels[INT_VECTOR_MTU_TGI2U] = BIT(m_ipre, 8, 4);
|
||||
|
||||
update_irq_state();
|
||||
}
|
||||
|
||||
uint16_t sh7014_intc_device::iprf_r()
|
||||
{
|
||||
return m_iprf & 0xff;
|
||||
}
|
||||
|
||||
void sh7014_intc_device::iprf_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_iprf);
|
||||
|
||||
m_irq_levels[INT_VECTOR_SCI_ERI0] = m_irq_levels[INT_VECTOR_SCI_RXI0] = m_irq_levels[INT_VECTOR_SCI_TXI0] = m_irq_levels[INT_VECTOR_SCI_TEI0] = BIT(m_iprf, 4, 4);
|
||||
m_irq_levels[INT_VECTOR_SCI_ERI1] = m_irq_levels[INT_VECTOR_SCI_RXI1] = m_irq_levels[INT_VECTOR_SCI_TXI1] = m_irq_levels[INT_VECTOR_SCI_TEI1] = BIT(m_iprf, 0, 4);
|
||||
|
||||
update_irq_state();
|
||||
}
|
||||
|
||||
uint16_t sh7014_intc_device::iprg_r()
|
||||
{
|
||||
return m_iprg & 0xf0ff;
|
||||
}
|
||||
|
||||
void sh7014_intc_device::iprg_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_iprg);
|
||||
|
||||
m_irq_levels[INT_VECTOR_AD] = BIT(m_iprg, 12, 4);
|
||||
m_irq_levels[INT_VECTOR_CMT_CH0] = BIT(m_iprg, 4, 4);
|
||||
m_irq_levels[INT_VECTOR_CMT_CH1] = BIT(m_iprg, 0, 4);
|
||||
|
||||
update_irq_state();
|
||||
}
|
||||
|
||||
uint16_t sh7014_intc_device::iprh_r()
|
||||
{
|
||||
return m_iprh & 0xf000;
|
||||
}
|
||||
|
||||
void sh7014_intc_device::iprh_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_iprh);
|
||||
|
||||
m_irq_levels[INT_VECTOR_WDT] = m_irq_levels[INT_VECTOR_BSC] = BIT(m_iprh, 12, 4);
|
||||
|
||||
update_irq_state();
|
||||
}
|
||||
|
||||
uint16_t sh7014_intc_device::icr_r()
|
||||
{
|
||||
uint16_t r = m_icr & 0x01f3;
|
||||
|
||||
if (m_nmi_input == ((m_icr & ICR_NMIE) ? ASSERT_LINE : CLEAR_LINE))
|
||||
r |= ICR_NMIL;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void sh7014_intc_device::icr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_icr);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
m_irq_type[i] = BIT(m_icr, 7 - i);
|
||||
}
|
||||
|
||||
uint16_t sh7014_intc_device::isr_r()
|
||||
{
|
||||
return m_isr & 0xf3;
|
||||
}
|
||||
|
||||
void sh7014_intc_device::isr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
// ICR will be set to 1 for edge detection, and it's only possible to
|
||||
// clear flags in ISR for IRQs set to edge detection
|
||||
auto old = m_isr;
|
||||
|
||||
COMBINE_DATA(&m_isr);
|
||||
|
||||
m_isr = (old & ~m_icr) | (old & m_isr & m_icr);
|
||||
|
||||
update_irq_state();
|
||||
}
|
||||
|
||||
void sh7014_intc_device::set_interrupt(int vector, int state)
|
||||
{
|
||||
if (vector != -1) {
|
||||
if (state == ASSERT_LINE)
|
||||
m_pending_irqs[vector >> 5] |= 1 << (vector & 31);
|
||||
else if (state == CLEAR_LINE)
|
||||
m_pending_irqs[vector >> 5] &= ~(1 << (vector & 31));
|
||||
|
||||
if (vector == INT_VECTOR_NMI) {
|
||||
m_nmi_input = state == ASSERT_LINE;
|
||||
} else if ((vector >= INT_VECTOR_IRQ0 && vector <= INT_VECTOR_IRQ3) || vector == INT_VECTOR_IRQ6 || vector == INT_VECTOR_IRQ7) {
|
||||
const int irq = vector - INT_VECTOR_IRQ0;
|
||||
|
||||
if (state == ASSERT_LINE) {
|
||||
if (m_irq_type[irq] == IRQ_LEVEL)
|
||||
m_isr |= 1 << (7 - irq);
|
||||
} else if (state == CLEAR_LINE) {
|
||||
if (m_irq_type[irq] == IRQ_LEVEL)
|
||||
m_isr &= ~(1 << (7 - irq));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_irq_state();
|
||||
}
|
||||
|
||||
void sh7014_intc_device::update_irq_state()
|
||||
{
|
||||
int cur_vector = 0;
|
||||
int cur_level = -1;
|
||||
|
||||
// isr has the bits in reverse order
|
||||
m_pending_irqs[INT_VECTOR_IRQ0 >> 5] &= ~0xff;
|
||||
m_pending_irqs[INT_VECTOR_IRQ0 >> 5] |= BIT(m_isr, 7)
|
||||
| (BIT(m_isr, 6) << 1)
|
||||
| (BIT(m_isr, 5) << 2)
|
||||
| (BIT(m_isr, 4) << 3)
|
||||
| (BIT(m_isr, 1) << 6)
|
||||
| (BIT(m_isr, 0) << 7);
|
||||
|
||||
for (int i = 0; i < MAX_VECTORS / 32; i++) {
|
||||
if (!m_pending_irqs[i])
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < 32; j++) {
|
||||
if (BIT(m_pending_irqs[i], j)) {
|
||||
const int vector = i * 32 + j;
|
||||
const int level = m_irq_levels[vector];
|
||||
|
||||
if (level > cur_level) {
|
||||
cur_vector = vector;
|
||||
cur_level = level;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cur_vector == INT_VECTOR_NMI)
|
||||
m_set_irq_cb(INPUT_LINE_NMI, cur_level, false);
|
||||
else if ((cur_vector >= INT_VECTOR_IRQ0 && cur_vector <= INT_VECTOR_IRQ3) || cur_vector == INT_VECTOR_IRQ6 || cur_vector == INT_VECTOR_IRQ7)
|
||||
m_set_irq_cb(cur_vector - INT_VECTOR_IRQ0, cur_level, false);
|
||||
else if (cur_vector > INT_VECTOR_IRQ7)
|
||||
m_set_irq_cb(cur_vector, cur_level, true);
|
||||
}
|
||||
|
||||
void sh7014_intc_device::set_input(int inputnum, int state)
|
||||
{
|
||||
if (inputnum == INPUT_LINE_NMI)
|
||||
set_interrupt(INT_VECTOR_NMI, state);
|
||||
else if ((inputnum >= INPUT_LINE_IRQ0 && inputnum <= INPUT_LINE_IRQ3) || inputnum == INPUT_LINE_IRQ6 || inputnum == INPUT_LINE_IRQ7)
|
||||
set_interrupt(INT_VECTOR_IRQ0 + (inputnum - INPUT_LINE_IRQ0), state);
|
||||
}
|
147
src/devices/cpu/sh/sh7014_intc.h
Normal file
147
src/devices/cpu/sh/sh7014_intc.h
Normal file
@ -0,0 +1,147 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 Interrupt Controller
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_CPU_SH_SH7014_INTC_H
|
||||
#define MAME_CPU_SH_SH7014_INTC_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
class sh7014_intc_device : public device_t
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
INT_VECTOR_NMI = 11,
|
||||
|
||||
INT_VECTOR_IRQ0 = 64,
|
||||
INT_VECTOR_IRQ1 = 65,
|
||||
INT_VECTOR_IRQ2 = 66,
|
||||
INT_VECTOR_IRQ3 = 67,
|
||||
// 68 and 69 are reserved
|
||||
INT_VECTOR_IRQ6 = 70,
|
||||
INT_VECTOR_IRQ7 = 71,
|
||||
|
||||
INT_VECTOR_DMA_CH0 = 72,
|
||||
INT_VECTOR_DMA_CH1 = 76,
|
||||
|
||||
INT_VECTOR_MTU_TGI0A = 88,
|
||||
INT_VECTOR_MTU_TGI0B = 89,
|
||||
INT_VECTOR_MTU_TGI0C = 90,
|
||||
INT_VECTOR_MTU_TGI0D = 91,
|
||||
INT_VECTOR_MTU_TGI0V = 92,
|
||||
|
||||
INT_VECTOR_MTU_TGI1A = 96,
|
||||
INT_VECTOR_MTU_TGI1B = 97,
|
||||
INT_VECTOR_MTU_TGI1V = 100,
|
||||
INT_VECTOR_MTU_TGI1U = 101,
|
||||
|
||||
INT_VECTOR_MTU_TGI2A = 104,
|
||||
INT_VECTOR_MTU_TGI2B = 105,
|
||||
INT_VECTOR_MTU_TGI2V = 108,
|
||||
INT_VECTOR_MTU_TGI2U = 109,
|
||||
|
||||
INT_VECTOR_SCI_ERI0 = 128,
|
||||
INT_VECTOR_SCI_RXI0 = 129,
|
||||
INT_VECTOR_SCI_TXI0 = 130,
|
||||
INT_VECTOR_SCI_TEI0 = 131,
|
||||
|
||||
INT_VECTOR_SCI_ERI1 = 132,
|
||||
INT_VECTOR_SCI_RXI1 = 133,
|
||||
INT_VECTOR_SCI_TXI1 = 134,
|
||||
INT_VECTOR_SCI_TEI1 = 135,
|
||||
|
||||
INT_VECTOR_AD = 136,
|
||||
|
||||
INT_VECTOR_CMT_CH0 = 144,
|
||||
INT_VECTOR_CMT_CH1 = 148,
|
||||
|
||||
INT_VECTOR_WDT = 152,
|
||||
|
||||
INT_VECTOR_BSC = 153,
|
||||
};
|
||||
|
||||
typedef device_delegate<void (int vector, int level, bool is_internal)> set_irq_delegate;
|
||||
|
||||
sh7014_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
template <typename... T> void set_irq_callback(T &&... args) { m_set_irq_cb.set(std::forward<T>(args)...); }
|
||||
|
||||
void map(address_map &map);
|
||||
|
||||
void set_input(int inputnum, int state);
|
||||
|
||||
void set_interrupt(int vector, int state);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
private:
|
||||
enum {
|
||||
IRQ_LEVEL,
|
||||
IRQ_EDGE,
|
||||
};
|
||||
|
||||
enum {
|
||||
MAX_VECTORS = 256,
|
||||
};
|
||||
|
||||
enum {
|
||||
ICR_NMIE = 1 << 8,
|
||||
ICR_NMIL = 1 << 15,
|
||||
};
|
||||
|
||||
uint16_t ipra_r();
|
||||
void ipra_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t iprb_r();
|
||||
void iprb_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t iprc_r();
|
||||
void iprc_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t iprd_r();
|
||||
void iprd_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t ipre_r();
|
||||
void ipre_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t iprf_r();
|
||||
void iprf_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t iprg_r();
|
||||
void iprg_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t iprh_r();
|
||||
void iprh_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t icr_r();
|
||||
void icr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t isr_r();
|
||||
void isr_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
void update_irq_state();
|
||||
|
||||
set_irq_delegate m_set_irq_cb;
|
||||
|
||||
uint16_t m_ipra, m_iprb, m_iprc, m_iprd, m_ipre, m_iprf, m_iprg, m_iprh;
|
||||
uint16_t m_icr, m_isr;
|
||||
|
||||
int8_t m_irq_levels[MAX_VECTORS];
|
||||
|
||||
uint32_t m_irq_type[8];
|
||||
bool m_nmi_input;
|
||||
|
||||
uint32_t m_pending_irqs[MAX_VECTORS/32];
|
||||
};
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(SH7014_INTC, sh7014_intc_device)
|
||||
|
||||
#endif // MAME_CPU_SH_SH7014_INTC_H
|
571
src/devices/cpu/sh/sh7014_mtu.cpp
Normal file
571
src/devices/cpu/sh/sh7014_mtu.cpp
Normal file
@ -0,0 +1,571 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 Multifunction Timer Pulse Unit
|
||||
|
||||
TODO list (not comprehensive):
|
||||
- Synchronized operation
|
||||
- Cascade connection operation
|
||||
- External clocks
|
||||
- Timer modes (PWM mode, phase counting mode (+ decrementing counter mode), etc)
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#include "sh7014_mtu.h"
|
||||
|
||||
// #define VERBOSE (LOG_GENERAL)
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(SH7014_MTU, sh7014_mtu_device, "sh7014mtu", "SH7014 Multifunction Timer Pulse Unit")
|
||||
DEFINE_DEVICE_TYPE(SH7014_MTU_CHANNEL, sh7014_mtu_channel_device, "sh7014mtuchan", "SH7014 Multifunction Timer Pulse Unit Channel")
|
||||
|
||||
sh7014_mtu_device::sh7014_mtu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, SH7014_MTU, tag, owner, clock)
|
||||
, m_intc(*this, finder_base::DUMMY_TAG)
|
||||
, m_chan(*this, "ch%u", 0u)
|
||||
{
|
||||
}
|
||||
|
||||
void sh7014_mtu_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_tsyr));
|
||||
}
|
||||
|
||||
void sh7014_mtu_device::device_reset()
|
||||
{
|
||||
m_tsyr = 0;
|
||||
}
|
||||
|
||||
void sh7014_mtu_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
SH7014_MTU_CHANNEL(config, m_chan[0], DERIVED_CLOCK(1, 1), m_intc,
|
||||
0, // channel
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI0A,
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI0B,
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI0C,
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI0D,
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI0V,
|
||||
-1
|
||||
);
|
||||
|
||||
SH7014_MTU_CHANNEL(config, m_chan[1], DERIVED_CLOCK(1, 1), m_intc,
|
||||
1, // channel
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI1A,
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI1B,
|
||||
-1,
|
||||
-1,
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI1V,
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI1U
|
||||
);
|
||||
|
||||
SH7014_MTU_CHANNEL(config, m_chan[2], DERIVED_CLOCK(1, 1), m_intc,
|
||||
2, // channel
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI2A,
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI2B,
|
||||
-1,
|
||||
-1,
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI2V,
|
||||
sh7014_intc_device::INT_VECTOR_MTU_TGI2U
|
||||
);
|
||||
}
|
||||
|
||||
void sh7014_mtu_device::map(address_map &map)
|
||||
{
|
||||
map(0x00, 0x00).rw(FUNC(sh7014_mtu_device::tstr_r), FUNC(sh7014_mtu_device::tstr_w));
|
||||
map(0x01, 0x01).rw(FUNC(sh7014_mtu_device::tsyr_r), FUNC(sh7014_mtu_device::tsyr_w));
|
||||
|
||||
map(0x20, 0x3f).m(m_chan[0], FUNC(sh7014_mtu_channel_device::map_chan0));
|
||||
map(0x40, 0x5f).m(m_chan[1], FUNC(sh7014_mtu_channel_device::map_chan1_2));
|
||||
map(0x60, 0x7f).m(m_chan[2], FUNC(sh7014_mtu_channel_device::map_chan1_2));
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
uint8_t sh7014_mtu_device::tstr_r()
|
||||
{
|
||||
return m_chan[0]->is_enabled()
|
||||
| (m_chan[1]->is_enabled() << 1)
|
||||
| (m_chan[2]->is_enabled() << 2);
|
||||
}
|
||||
|
||||
void sh7014_mtu_device::tstr_w(uint8_t data)
|
||||
{
|
||||
LOG("%s: tstr_w %02x\n", machine().describe_context().c_str(), data);
|
||||
|
||||
m_chan[0]->set_enable((data & TSTR_CST0) != 0);
|
||||
m_chan[1]->set_enable((data & TSTR_CST1) != 0);
|
||||
m_chan[2]->set_enable((data & TSTR_CST2) != 0);
|
||||
}
|
||||
|
||||
uint8_t sh7014_mtu_device::tsyr_r()
|
||||
{
|
||||
return m_tsyr & (TSYR_SYNC0 | TSYR_SYNC1 | TSYR_SYNC2);
|
||||
}
|
||||
|
||||
void sh7014_mtu_device::tsyr_w(uint8_t data)
|
||||
{
|
||||
LOG("%s: tsyr_w %02x\n", machine().describe_context().c_str(), data);
|
||||
|
||||
m_tsyr = data;
|
||||
}
|
||||
|
||||
|
||||
//////////////////
|
||||
|
||||
sh7014_mtu_channel_device::sh7014_mtu_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, SH7014_MTU_CHANNEL, tag, owner, clock)
|
||||
, m_intc(*this, finder_base::DUMMY_TAG)
|
||||
, m_timer(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_tcr));
|
||||
save_item(NAME(m_tmdr));
|
||||
save_item(NAME(m_tiorh));
|
||||
save_item(NAME(m_tiorl));
|
||||
save_item(NAME(m_tier));
|
||||
save_item(NAME(m_tsr));
|
||||
save_item(NAME(m_tcnt));
|
||||
save_item(NAME(m_tgr));
|
||||
|
||||
save_item(NAME(m_last_clock_update));
|
||||
save_item(NAME(m_clock_type));
|
||||
save_item(NAME(m_clock_divider));
|
||||
save_item(NAME(m_channel_active));
|
||||
save_item(NAME(m_phase));
|
||||
save_item(NAME(m_counter_cycle));
|
||||
save_item(NAME(m_tgr_clearing));
|
||||
|
||||
m_timer = timer_alloc(FUNC(sh7014_mtu_channel_device::timer_callback), this);
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::device_reset()
|
||||
{
|
||||
m_tcr = 0;
|
||||
m_tmdr = 0;
|
||||
m_tier = 0;
|
||||
m_tsr = TSR_TCFD;
|
||||
m_tiorh = m_tiorl = 0;
|
||||
std::fill(std::begin(m_tgr), std::end(m_tgr), 0);
|
||||
|
||||
m_tcnt = 0;
|
||||
m_last_clock_update = 0;
|
||||
m_clock_type = INPUT_INTERNAL;
|
||||
m_clock_divider = DIV_1;
|
||||
m_channel_active = false;
|
||||
m_phase = 0;
|
||||
m_counter_cycle = 0x10000;
|
||||
m_tgr_clearing = TGR_CLEAR_NONE;
|
||||
|
||||
m_timer->adjust(attotime::never);
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::map_chan0(address_map &map)
|
||||
{
|
||||
map(0x00, 0x00).rw(FUNC(sh7014_mtu_channel_device::tcr_r), FUNC(sh7014_mtu_channel_device::tcr_w));
|
||||
map(0x01, 0x01).rw(FUNC(sh7014_mtu_channel_device::tmdr_r), FUNC(sh7014_mtu_channel_device::tmdr_w));
|
||||
map(0x02, 0x02).rw(FUNC(sh7014_mtu_channel_device::tiorh_r), FUNC(sh7014_mtu_channel_device::tiorh_w));
|
||||
map(0x03, 0x03).rw(FUNC(sh7014_mtu_channel_device::tiorl_r), FUNC(sh7014_mtu_channel_device::tiorl_w));
|
||||
map(0x04, 0x04).rw(FUNC(sh7014_mtu_channel_device::tier_r), FUNC(sh7014_mtu_channel_device::tier_w));
|
||||
map(0x05, 0x05).rw(FUNC(sh7014_mtu_channel_device::tsr_r), FUNC(sh7014_mtu_channel_device::tsr_w));
|
||||
map(0x06, 0x07).rw(FUNC(sh7014_mtu_channel_device::tcnt_r), FUNC(sh7014_mtu_channel_device::tcnt_w));
|
||||
map(0x08, 0x09).rw(FUNC(sh7014_mtu_channel_device::tgra_r), FUNC(sh7014_mtu_channel_device::tgra_w));
|
||||
map(0x0a, 0x0b).rw(FUNC(sh7014_mtu_channel_device::tgrb_r), FUNC(sh7014_mtu_channel_device::tgrb_w));
|
||||
map(0x0c, 0x0d).rw(FUNC(sh7014_mtu_channel_device::tgrc_r), FUNC(sh7014_mtu_channel_device::tgrc_w));
|
||||
map(0x0e, 0x0f).rw(FUNC(sh7014_mtu_channel_device::tgrd_r), FUNC(sh7014_mtu_channel_device::tgrd_w));
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::map_chan1_2(address_map &map)
|
||||
{
|
||||
map(0x00, 0x00).rw(FUNC(sh7014_mtu_channel_device::tcr_r), FUNC(sh7014_mtu_channel_device::tcr_w));
|
||||
map(0x01, 0x01).rw(FUNC(sh7014_mtu_channel_device::tmdr_r), FUNC(sh7014_mtu_channel_device::tmdr_w));
|
||||
map(0x02, 0x02).rw(FUNC(sh7014_mtu_channel_device::tiorh_r), FUNC(sh7014_mtu_channel_device::tiorh_w));
|
||||
map(0x04, 0x04).rw(FUNC(sh7014_mtu_channel_device::tier_r), FUNC(sh7014_mtu_channel_device::tier_w));
|
||||
map(0x05, 0x05).rw(FUNC(sh7014_mtu_channel_device::tsr_r), FUNC(sh7014_mtu_channel_device::tsr_w));
|
||||
map(0x06, 0x07).rw(FUNC(sh7014_mtu_channel_device::tcnt_r), FUNC(sh7014_mtu_channel_device::tcnt_w));
|
||||
map(0x08, 0x09).rw(FUNC(sh7014_mtu_channel_device::tgra_r), FUNC(sh7014_mtu_channel_device::tgra_w));
|
||||
map(0x0a, 0x0b).rw(FUNC(sh7014_mtu_channel_device::tgrb_r), FUNC(sh7014_mtu_channel_device::tgrb_w));
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
TIMER_CALLBACK_MEMBER( sh7014_mtu_channel_device::timer_callback )
|
||||
{
|
||||
update_counter();
|
||||
schedule_next_event();
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::set_enable(bool enabled)
|
||||
{
|
||||
update_counter();
|
||||
|
||||
m_channel_active = enabled;
|
||||
|
||||
schedule_next_event();
|
||||
}
|
||||
|
||||
uint8_t sh7014_mtu_channel_device::tcr_r()
|
||||
{
|
||||
uint8_t r = m_tcr;
|
||||
|
||||
if (m_channel_id > 0)
|
||||
r &= 0x7f;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::tcr_w(uint8_t data)
|
||||
{
|
||||
LOG("%s: tcr_w<%d> %02x\n", machine().describe_context().c_str(), m_channel_id, data);
|
||||
|
||||
update_counter();
|
||||
|
||||
m_tcr = data;
|
||||
|
||||
constexpr uint32_t divider_type[3][8] = {
|
||||
{INPUT_INTERNAL, INPUT_INTERNAL, INPUT_INTERNAL, INPUT_INTERNAL, INPUT_A, INPUT_B, INPUT_C, INPUT_D},
|
||||
{INPUT_INTERNAL, INPUT_INTERNAL, INPUT_INTERNAL, INPUT_INTERNAL, INPUT_A, INPUT_B, INPUT_INTERNAL, INPUT_TCNT2},
|
||||
{INPUT_INTERNAL, INPUT_INTERNAL, INPUT_INTERNAL, INPUT_INTERNAL, INPUT_A, INPUT_B, INPUT_C, INPUT_INTERNAL},
|
||||
};
|
||||
|
||||
const int prescaler = BIT(m_tcr, 0, 3);
|
||||
|
||||
m_clock_type = divider_type[m_channel_id][prescaler];
|
||||
|
||||
if (m_clock_type == INPUT_INTERNAL) {
|
||||
constexpr int32_t dividers[3][8] = {
|
||||
{DIV_1, DIV_4, DIV_16, DIV_64, -1, -1, -1, -1},
|
||||
{DIV_1, DIV_4, DIV_16, DIV_64, -1, -1, DIV_256, -1},
|
||||
{DIV_1, DIV_4, DIV_16, DIV_64, -1, -1, -1, DIV_1024},
|
||||
};
|
||||
|
||||
m_clock_divider = dividers[m_channel_id][prescaler];
|
||||
} else {
|
||||
m_clock_divider = DIV_1;
|
||||
}
|
||||
|
||||
const int clock_edge = BIT(m_tcr, 3, 2);
|
||||
if (m_clock_divider < DIV_4) {
|
||||
m_phase = 0;
|
||||
} else {
|
||||
switch (clock_edge) {
|
||||
case 0:
|
||||
m_phase = 0;
|
||||
break;
|
||||
case 1:
|
||||
m_phase = 1 << (m_clock_divider - 1);
|
||||
break;
|
||||
case 2:
|
||||
// If count on both rising and falling edges, input clock frequency becomes 1/2
|
||||
m_phase = 0;
|
||||
m_clock_divider--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int counting_clear = BIT(m_tcr, 5, m_channel_id == 0 ? 3 : 2);
|
||||
if (counting_clear == 3 || (m_channel_id == 0 && counting_clear == 7))
|
||||
m_tgr_clearing = TGR_CLEAR_SYNC;
|
||||
else if (counting_clear >= 1 && counting_clear <= 2)
|
||||
m_tgr_clearing = counting_clear - 1; // TGRA, TGRB
|
||||
else if (m_channel_id == 0 && counting_clear >= 5 && counting_clear <= 6)
|
||||
m_tgr_clearing = counting_clear - 3; // TGRC, TGRD (ch 0 only)
|
||||
else
|
||||
m_tgr_clearing = TGR_CLEAR_NONE; // 0, 4, and anything else
|
||||
|
||||
schedule_next_event();
|
||||
}
|
||||
|
||||
uint8_t sh7014_mtu_channel_device::tmdr_r()
|
||||
{
|
||||
uint8_t r = m_tmdr;
|
||||
|
||||
if (m_channel_id > 0)
|
||||
r &= 0x0f;
|
||||
|
||||
return r | 0xc0;
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::tmdr_w(uint8_t data)
|
||||
{
|
||||
LOG("%s: tmdr_w<%d> %02x\n", machine().describe_context().c_str(), m_channel_id, data);
|
||||
|
||||
m_tmdr = data;
|
||||
}
|
||||
|
||||
uint8_t sh7014_mtu_channel_device::tiorh_r()
|
||||
{
|
||||
return m_tiorh;
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::tiorh_w(uint8_t data)
|
||||
{
|
||||
LOG("%s: tiorh_w<%d> %02x\n", machine().describe_context().c_str(), m_channel_id, data);
|
||||
|
||||
const bool trga_is_output_compare_register = BIT(data, 3) == 0;
|
||||
const bool trga_was_output_compare_register = BIT(m_tiorh, 3) == 0;
|
||||
if (trga_is_output_compare_register) {
|
||||
const auto tgra_mode = BIT(data, 2);
|
||||
const auto old_tgra_mode = BIT(m_tiorh, 2);
|
||||
|
||||
if ((tgra_mode != old_tgra_mode) || (trga_is_output_compare_register != trga_was_output_compare_register)) {
|
||||
const auto initial_output = tgra_mode ? TSR_TGFA : 0;
|
||||
m_tsr = (m_tsr & ~TSR_TGFA) | initial_output;
|
||||
}
|
||||
}
|
||||
|
||||
const bool trgb_is_output_compare_register = BIT(data, 7) == 0;
|
||||
const bool trgb_was_output_compare_register = BIT(m_tiorh, 7) == 0;
|
||||
if (trgb_is_output_compare_register) {
|
||||
const auto tgrb_mode = BIT(data, 6);
|
||||
const auto old_tgrb_mode = BIT(m_tiorh, 6);
|
||||
|
||||
if ((tgrb_mode != old_tgrb_mode) || (trgb_is_output_compare_register != trgb_was_output_compare_register)) {
|
||||
const auto initial_output = tgrb_mode ? TSR_TGFB : 0;
|
||||
m_tsr = (m_tsr & ~TSR_TGFB) | initial_output;
|
||||
}
|
||||
}
|
||||
|
||||
m_tiorh = data;
|
||||
}
|
||||
|
||||
uint8_t sh7014_mtu_channel_device::tiorl_r()
|
||||
{
|
||||
if (m_channel_id > 0)
|
||||
return 0;
|
||||
|
||||
return m_tiorl;
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::tiorl_w(uint8_t data)
|
||||
{
|
||||
LOG("%s: tiorl_w<%d> %02x\n", machine().describe_context().c_str(), m_channel_id, data);
|
||||
|
||||
if (m_channel_id > 0)
|
||||
return;
|
||||
|
||||
const bool trgc_is_output_compare_register = BIT(data, 3) == 0;
|
||||
const bool trgc_was_output_compare_register = BIT(m_tiorl, 3) == 0;
|
||||
if (trgc_is_output_compare_register) {
|
||||
const auto tgrc_mode = BIT(data, 2);
|
||||
const auto old_tgrc_mode = BIT(m_tiorl, 2);
|
||||
|
||||
if ((tgrc_mode != old_tgrc_mode) || (trgc_is_output_compare_register != trgc_was_output_compare_register)) {
|
||||
const auto initial_output = tgrc_mode ? TSR_TGFC : 0;
|
||||
m_tsr = (m_tsr & ~TSR_TGFC) | initial_output;
|
||||
}
|
||||
}
|
||||
|
||||
const bool trgd_is_output_compare_register = BIT(data, 7) == 0;
|
||||
const bool trgd_was_output_compare_register = BIT(m_tiorl, 7) == 0;
|
||||
if (trgd_is_output_compare_register) {
|
||||
const auto tgrd_mode = BIT(data, 6);
|
||||
const auto old_tgrd_mode = BIT(m_tiorl, 6);
|
||||
|
||||
if ((tgrd_mode != old_tgrd_mode) || (trgd_is_output_compare_register != trgd_was_output_compare_register)) {
|
||||
const auto initial_output = tgrd_mode ? TSR_TGFD : 0;
|
||||
m_tsr = (m_tsr & ~TSR_TGFD) | initial_output;
|
||||
}
|
||||
}
|
||||
|
||||
m_tiorl = data;
|
||||
}
|
||||
|
||||
uint8_t sh7014_mtu_channel_device::tier_r()
|
||||
{
|
||||
return m_tier | 0x40;
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::tier_w(uint8_t data)
|
||||
{
|
||||
LOG("%s: tier_w<%d> %02x\n", machine().describe_context().c_str(), m_channel_id, data);
|
||||
|
||||
m_tier = data;
|
||||
}
|
||||
|
||||
uint8_t sh7014_mtu_channel_device::tsr_r()
|
||||
{
|
||||
uint8_t r;
|
||||
|
||||
if (m_channel_id == 0)
|
||||
r = (m_tsr & (TSR_TGFA | TSR_TGFB | TSR_TGFC | TSR_TGFD | TSR_TCFV)) | TSR_TCFD;
|
||||
else
|
||||
r = m_tsr & (TSR_TGFA | TSR_TGFB | TSR_TCFV | TSR_TCFU | TSR_TCFD);
|
||||
|
||||
return r | (1 << 6);
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::tsr_w(uint8_t data)
|
||||
{
|
||||
LOG("%s: tsr_w<%d> %02x\n", machine().describe_context().c_str(), m_channel_id, data);
|
||||
|
||||
if (m_channel_id == 0) {
|
||||
const uint8_t mask = TSR_TGFA | TSR_TGFB | TSR_TGFC | TSR_TGFD | TSR_TCFV;
|
||||
m_tsr = (data & ~mask) | (m_tsr & data & mask);
|
||||
} else {
|
||||
const uint8_t mask = TSR_TGFA | TSR_TGFB | TSR_TCFV | TSR_TCFU;
|
||||
m_tsr = (data & ~mask) | (m_tsr & data & mask) | (m_tsr & TSR_TCFD);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t sh7014_mtu_channel_device::tcnt_r()
|
||||
{
|
||||
update_counter();
|
||||
return m_tcnt;
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::tcnt_w(uint16_t data)
|
||||
{
|
||||
LOG("%s: tcnt_w<%d> %04x -> %04x\n", machine().describe_context().c_str(), m_channel_id, m_tcnt, data);
|
||||
|
||||
m_tcnt = data;
|
||||
}
|
||||
|
||||
uint16_t sh7014_mtu_channel_device::tgra_r()
|
||||
{
|
||||
return m_tgr[0];
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::tgra_w(uint16_t data)
|
||||
{
|
||||
LOG("%s: tgra_w<%d> %04x -> %04x\n", machine().describe_context().c_str(), m_channel_id, m_tgr[0], data);
|
||||
|
||||
m_tgr[0] = data;
|
||||
}
|
||||
|
||||
uint16_t sh7014_mtu_channel_device::tgrb_r()
|
||||
{
|
||||
return m_tgr[1];
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::tgrb_w(uint16_t data)
|
||||
{
|
||||
LOG("%s: tgrb_w<%d> %04x -> %04x\n", machine().describe_context().c_str(), m_channel_id, m_tgr[1], data);
|
||||
|
||||
m_tgr[1] = data;
|
||||
}
|
||||
|
||||
uint16_t sh7014_mtu_channel_device::tgrc_r()
|
||||
{
|
||||
return m_tgr[2];
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::tgrc_w(uint16_t data)
|
||||
{
|
||||
LOG("%s: tgrc_w<%d> %04x -> %04x\n", machine().describe_context().c_str(), m_channel_id, m_tgr[2], data);
|
||||
|
||||
m_tgr[2] = data;
|
||||
}
|
||||
|
||||
uint16_t sh7014_mtu_channel_device::tgrd_r()
|
||||
{
|
||||
return m_tgr[3];
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::tgrd_w(uint16_t data)
|
||||
{
|
||||
LOG("%s: tgrd_w<%d> %04x -> %04x\n", machine().describe_context().c_str(), m_channel_id, m_tgr[3], data);
|
||||
|
||||
m_tgr[3] = data;
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::update_counter()
|
||||
{
|
||||
if (m_clock_type != INPUT_INTERNAL)
|
||||
return;
|
||||
|
||||
uint64_t cur_time = machine().time().as_ticks(clock());
|
||||
|
||||
if (!m_channel_active) {
|
||||
m_last_clock_update = cur_time;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_last_clock_update == cur_time)
|
||||
return;
|
||||
|
||||
uint64_t base_time = (m_last_clock_update + m_phase) >> m_clock_divider;
|
||||
uint64_t new_time = (cur_time + m_phase) >> m_clock_divider;
|
||||
int tt = m_tcnt + (new_time - base_time);
|
||||
m_tcnt = tt % m_counter_cycle;
|
||||
|
||||
for (int i = 0; i < m_tgr_count; i++) {
|
||||
if (!BIT(m_tsr, i) && BIT(m_tier, i) && tt >= m_tgr[i]) {
|
||||
m_tsr |= 1 << i;
|
||||
m_intc->set_interrupt(m_vectors[i], ASSERT_LINE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(m_tsr & TSR_TCFV) && tt >= 0x10000) {
|
||||
// Overflowed
|
||||
m_tsr |= TSR_TCFV;
|
||||
|
||||
if (m_tier & TIER_TCIEV)
|
||||
m_intc->set_interrupt(m_vectors[VECTOR_TCIV], ASSERT_LINE);
|
||||
} else if (m_channel_id == 0 && !(m_tsr & TSR_TCFU) && tt < 0) {
|
||||
// Underflowed, only usable on channel 0
|
||||
m_tsr |= TSR_TCFU;
|
||||
|
||||
if (m_tier & TIER_TCIEU)
|
||||
m_intc->set_interrupt(m_vectors[VECTOR_TCIU], ASSERT_LINE);
|
||||
}
|
||||
|
||||
m_last_clock_update = cur_time;
|
||||
}
|
||||
|
||||
void sh7014_mtu_channel_device::schedule_next_event()
|
||||
{
|
||||
m_timer->adjust(attotime::never);
|
||||
|
||||
if (!m_channel_active || m_clock_type != INPUT_INTERNAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t event_delay = 0xffffffff;
|
||||
if (m_tgr_clearing >= 0 && m_tgr[m_tgr_clearing]) {
|
||||
m_counter_cycle = m_tgr[m_tgr_clearing];
|
||||
} else {
|
||||
m_counter_cycle = 0x10000;
|
||||
|
||||
if (m_tier & TIER_TCIEV) {
|
||||
// Try to schedule next event for when the overflow should happen if overflow interrupt is enabled
|
||||
event_delay = m_counter_cycle - m_tcnt;
|
||||
|
||||
if (event_delay == 0)
|
||||
event_delay = m_counter_cycle;
|
||||
}
|
||||
}
|
||||
|
||||
// If one of the comparison register interrupts is enabled then set the next event time to be when the next interrupt should happen
|
||||
for (int i = 0; i < m_tgr_count; i++) {
|
||||
if (BIT(m_tier, i)) {
|
||||
uint32_t new_delay = 0xffffffff;
|
||||
|
||||
if (m_tgr[i] > m_tcnt) {
|
||||
if (m_tcnt >= m_counter_cycle || m_tgr[i] <= m_counter_cycle)
|
||||
new_delay = m_tgr[i] - m_tcnt;
|
||||
} else if (m_tgr[i] <= m_counter_cycle) {
|
||||
if (m_tcnt < m_counter_cycle)
|
||||
new_delay = (m_counter_cycle - m_tcnt) + m_tgr[i];
|
||||
else
|
||||
new_delay = (0x10000 - m_tcnt) + m_tgr[i];
|
||||
}
|
||||
|
||||
if (event_delay > new_delay)
|
||||
event_delay = new_delay;
|
||||
}
|
||||
}
|
||||
|
||||
if (event_delay != 0xffffffff) {
|
||||
const uint32_t next_event = (((((1ULL << m_clock_divider) - m_phase) >> m_clock_divider) + event_delay - 1) << m_clock_divider) + m_phase;
|
||||
m_timer->adjust(attotime::from_ticks(next_event, clock()));
|
||||
|
||||
}
|
||||
}
|
211
src/devices/cpu/sh/sh7014_mtu.h
Normal file
211
src/devices/cpu/sh/sh7014_mtu.h
Normal file
@ -0,0 +1,211 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 Multifunction Timer Pulse Unit
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_CPU_SH_SH7014_MTU_H
|
||||
#define MAME_CPU_SH_SH7014_MTU_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sh7014_intc.h"
|
||||
|
||||
DECLARE_DEVICE_TYPE(SH7014_MTU, sh7014_mtu_device)
|
||||
DECLARE_DEVICE_TYPE(SH7014_MTU_CHANNEL, sh7014_mtu_channel_device)
|
||||
|
||||
|
||||
class sh7014_mtu_device : public device_t
|
||||
{
|
||||
public:
|
||||
sh7014_mtu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
template<typename T> sh7014_mtu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&intc)
|
||||
: sh7014_mtu_device(mconfig, tag, owner, clock)
|
||||
{
|
||||
m_intc.set_tag(std::forward<T>(intc));
|
||||
}
|
||||
|
||||
void map(address_map &map);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
private:
|
||||
enum {
|
||||
TSTR_CST0 = 1 << 0,
|
||||
TSTR_CST1 = 1 << 1,
|
||||
TSTR_CST2 = 1 << 2,
|
||||
|
||||
TSYR_SYNC0 = 1 << 0,
|
||||
TSYR_SYNC1 = 1 << 1,
|
||||
TSYR_SYNC2 = 1 << 2,
|
||||
};
|
||||
|
||||
uint8_t tstr_r();
|
||||
void tstr_w(uint8_t data);
|
||||
|
||||
uint8_t tsyr_r();
|
||||
void tsyr_w(uint8_t data);
|
||||
|
||||
required_device<sh7014_intc_device> m_intc;
|
||||
required_device_array<sh7014_mtu_channel_device, 3> m_chan;
|
||||
|
||||
uint8_t m_tsyr;
|
||||
};
|
||||
|
||||
|
||||
class sh7014_mtu_channel_device : public device_t
|
||||
{
|
||||
public:
|
||||
sh7014_mtu_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
template<typename T> sh7014_mtu_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&intc, int chan_id, int32_t vector_tgia, int32_t vector_tgib, int32_t vector_tgic, int32_t vector_tgid, int32_t vector_tgiv, int32_t vector_tgiu)
|
||||
: sh7014_mtu_channel_device(mconfig, tag, owner, clock)
|
||||
{
|
||||
m_intc.set_tag(std::forward<T>(intc));
|
||||
m_channel_id = chan_id;
|
||||
m_vectors[VECTOR_TGIA] = vector_tgia;
|
||||
m_vectors[VECTOR_TGIB] = vector_tgib;
|
||||
m_vectors[VECTOR_TGIC] = vector_tgic;
|
||||
m_vectors[VECTOR_TGID] = vector_tgid;
|
||||
m_vectors[VECTOR_TCIV] = vector_tgiv;
|
||||
m_vectors[VECTOR_TCIU] = vector_tgiu;
|
||||
m_tgr_count = chan_id == 0 ? 4 : 2;
|
||||
}
|
||||
|
||||
void map_chan0(address_map &map);
|
||||
void map_chan1_2(address_map &map);
|
||||
|
||||
void set_enable(bool enabled);
|
||||
bool is_enabled() { return m_channel_active; }
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
private:
|
||||
enum {
|
||||
INPUT_INTERNAL = 0,
|
||||
INPUT_A,
|
||||
INPUT_B,
|
||||
INPUT_C,
|
||||
INPUT_D,
|
||||
INPUT_TCNT2
|
||||
};
|
||||
|
||||
enum {
|
||||
DIV_1 = 0,
|
||||
DIV_2,
|
||||
DIV_4,
|
||||
DIV_8,
|
||||
DIV_16,
|
||||
DIV_32,
|
||||
DIV_64,
|
||||
DIV_128,
|
||||
DIV_256,
|
||||
DIV_512,
|
||||
DIV_1024
|
||||
};
|
||||
|
||||
enum {
|
||||
TGR_CLEAR_NONE = -1,
|
||||
TGR_CLEAR_SYNC = -2
|
||||
};
|
||||
|
||||
enum {
|
||||
VECTOR_TGIA = 0,
|
||||
VECTOR_TGIB = 1,
|
||||
VECTOR_TGIC = 2,
|
||||
VECTOR_TGID = 3,
|
||||
VECTOR_TCIV = 4,
|
||||
VECTOR_TCIU = 5
|
||||
};
|
||||
|
||||
enum {
|
||||
|
||||
TSR_TGFA = 1 << 0,
|
||||
TSR_TGFB = 1 << 1,
|
||||
TSR_TGFC = 1 << 2, // ch 0 only
|
||||
TSR_TGFD = 1 << 3, // ch 0 only
|
||||
TSR_TCFV = 1 << 4,
|
||||
TSR_TCFU = 1 << 5, // ch 1/2 only
|
||||
TSR_TCFD = 1 << 7, // ch 1/2 only
|
||||
|
||||
TIER_TGIEA = 1 << 0,
|
||||
TIER_TGIEB = 1 << 1,
|
||||
TIER_TGIEC = 1 << 2, // ch 0 only
|
||||
TIER_TGIED = 1 << 3, // ch 0 only
|
||||
TIER_TCIEV = 1 << 4,
|
||||
TIER_TCIEU = 1 << 5, // ch 1/2 only
|
||||
TIER_TTGE = 1 << 7,
|
||||
};
|
||||
|
||||
uint8_t tcr_r();
|
||||
void tcr_w(uint8_t data);
|
||||
|
||||
uint8_t tmdr_r();
|
||||
void tmdr_w(uint8_t data);
|
||||
|
||||
uint8_t tiorh_r();
|
||||
void tiorh_w(uint8_t data);
|
||||
|
||||
uint8_t tiorl_r();
|
||||
void tiorl_w(uint8_t data);
|
||||
|
||||
uint8_t tier_r();
|
||||
void tier_w(uint8_t data);
|
||||
|
||||
uint8_t tsr_r();
|
||||
void tsr_w(uint8_t data);
|
||||
|
||||
uint16_t tcnt_r();
|
||||
void tcnt_w(uint16_t data);
|
||||
|
||||
uint16_t tgra_r();
|
||||
void tgra_w(uint16_t data);
|
||||
|
||||
uint16_t tgrb_r();
|
||||
void tgrb_w(uint16_t data);
|
||||
|
||||
uint16_t tgrc_r();
|
||||
void tgrc_w(uint16_t data);
|
||||
|
||||
uint16_t tgrd_r();
|
||||
void tgrd_w(uint16_t data);
|
||||
|
||||
void update_counter();
|
||||
void schedule_next_event();
|
||||
|
||||
TIMER_CALLBACK_MEMBER( timer_callback );
|
||||
|
||||
required_device<sh7014_intc_device> m_intc;
|
||||
|
||||
emu_timer *m_timer;
|
||||
|
||||
uint32_t m_channel_id;
|
||||
int32_t m_vectors[6];
|
||||
uint32_t m_tgr_count;
|
||||
|
||||
uint8_t m_tcr;
|
||||
uint8_t m_tmdr;
|
||||
uint8_t m_tiorh, m_tiorl;
|
||||
uint8_t m_tier;
|
||||
uint8_t m_tsr;
|
||||
uint16_t m_tgr[4];
|
||||
uint16_t m_tcnt;
|
||||
|
||||
uint64_t m_last_clock_update;
|
||||
uint32_t m_clock_type, m_clock_divider;
|
||||
uint32_t m_phase;
|
||||
uint32_t m_counter_cycle;
|
||||
int32_t m_tgr_clearing;
|
||||
|
||||
bool m_channel_active;
|
||||
};
|
||||
|
||||
#endif // MAME_CPU_SH_SH7014_MTU_H
|
243
src/devices/cpu/sh/sh7014_port.cpp
Normal file
243
src/devices/cpu/sh/sh7014_port.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 I/O Port
|
||||
|
||||
TODO list (not comprehensive):
|
||||
- Special functions specified by control registers are not implemented
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "sh7014_port.h"
|
||||
|
||||
#define LOG_READ (1U << 1)
|
||||
#define LOG_WRITE (1U << 2)
|
||||
|
||||
// #define VERBOSE (LOG_GENERAL | LOG_READ | LOG_WRITE)
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(SH7014_PORT, sh7014_port_device, "sh7014port", "SH7014 I/O Port")
|
||||
|
||||
|
||||
sh7014_port_device::sh7014_port_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, SH7014_PORT, tag, owner, clock)
|
||||
, m_port_a_read_cb(*this, 0)
|
||||
, m_port_a_write_cb(*this)
|
||||
, m_port_b_read_cb(*this, 0)
|
||||
, m_port_b_write_cb(*this)
|
||||
, m_port_e_read_cb(*this, 0)
|
||||
, m_port_e_write_cb(*this)
|
||||
, m_port_f_read_cb(*this, 0)
|
||||
{
|
||||
}
|
||||
|
||||
void sh7014_port_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_padr));
|
||||
save_item(NAME(m_paior));
|
||||
save_item(NAME(m_pacr1));
|
||||
save_item(NAME(m_pacr2));
|
||||
|
||||
save_item(NAME(m_pbdr));
|
||||
save_item(NAME(m_pbior));
|
||||
save_item(NAME(m_pbcr1));
|
||||
save_item(NAME(m_pbcr2));
|
||||
|
||||
save_item(NAME(m_pedr));
|
||||
save_item(NAME(m_peior));
|
||||
save_item(NAME(m_pecr1));
|
||||
save_item(NAME(m_pecr2));
|
||||
|
||||
save_item(NAME(m_pfdr));
|
||||
}
|
||||
|
||||
void sh7014_port_device::device_reset()
|
||||
{
|
||||
m_padr = 0;
|
||||
m_paior = 0;
|
||||
m_pacr1 = m_pacr2 = 0;
|
||||
|
||||
m_pbdr = 0;
|
||||
m_pbior = 0;
|
||||
m_pbcr1 = m_pbcr2 = 0;
|
||||
|
||||
m_pedr = 0;
|
||||
m_peior = 0;
|
||||
m_pecr1 = m_pecr2 = 0;
|
||||
|
||||
m_pfdr = 0;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
uint16_t sh7014_port_device::padrl_r()
|
||||
{
|
||||
uint16_t pins = m_port_a_read_cb();
|
||||
uint16_t r = ((m_padr & m_paior) | (pins & ~m_paior)) & 0x83ff;
|
||||
LOGMASKED(LOG_READ, "padrl_r %04x (pins: %04x %04x)\n", r, m_paior, pins);
|
||||
return r;
|
||||
}
|
||||
|
||||
void sh7014_port_device::padrl_w(uint16_t data)
|
||||
{
|
||||
m_padr = data & 0x83ff;
|
||||
LOGMASKED(LOG_WRITE, "padrl_w %04x\n", m_padr);
|
||||
|
||||
if (m_paior)
|
||||
m_port_a_write_cb(m_padr & m_paior);
|
||||
}
|
||||
|
||||
uint16_t sh7014_port_device::paiorl_r()
|
||||
{
|
||||
LOGMASKED(LOG_READ, "paiorl_r %04x\n", m_paior);
|
||||
return m_paior;
|
||||
}
|
||||
|
||||
void sh7014_port_device::paiorl_w(uint16_t data)
|
||||
{
|
||||
m_paior = data & 0x83ff;
|
||||
LOGMASKED(LOG_WRITE, "paiorl_w %04x\n", m_paior);
|
||||
}
|
||||
|
||||
uint16_t sh7014_port_device::pacrl1_r()
|
||||
{
|
||||
LOGMASKED(LOG_READ, "m_pacr1 %04x\n", m_pacr1);
|
||||
return m_pacr1;
|
||||
}
|
||||
|
||||
void sh7014_port_device::pacrl1_w(uint16_t data)
|
||||
{
|
||||
m_pacr1 = data & 0x400f;
|
||||
LOGMASKED(LOG_WRITE, "pacrl1_w %04x\n", m_pacr1);
|
||||
}
|
||||
|
||||
uint16_t sh7014_port_device::pacrl2_r()
|
||||
{
|
||||
LOGMASKED(LOG_READ, "pacrl2_r %04x\n", m_pacr2);
|
||||
return m_pacr2;
|
||||
}
|
||||
|
||||
void sh7014_port_device::pacrl2_w(uint16_t data)
|
||||
{
|
||||
m_pacr2 = data & 0xfd75;
|
||||
LOGMASKED(LOG_WRITE, "pacrl2_w %04x\n", m_pacr2);
|
||||
}
|
||||
|
||||
uint16_t sh7014_port_device::pbdr_r()
|
||||
{
|
||||
uint16_t pins = m_port_b_read_cb();
|
||||
uint16_t r = ((m_pbdr & m_pbior) | (pins & ~m_pbior)) & 0x3ff;
|
||||
LOGMASKED(LOG_READ, "pbdr_r %04x (pins: %04x %04x)\n", r, m_pbior, pins);
|
||||
return r;
|
||||
}
|
||||
|
||||
void sh7014_port_device::pbdr_w(uint16_t data)
|
||||
{
|
||||
m_pbdr = data;
|
||||
LOGMASKED(LOG_WRITE, "pbdr_w %04x\n", m_pbdr);
|
||||
|
||||
if (m_pbior)
|
||||
m_port_b_write_cb(m_pbdr & m_pbior);
|
||||
}
|
||||
|
||||
uint16_t sh7014_port_device::pbior_r()
|
||||
{
|
||||
LOGMASKED(LOG_READ, "pbior_r %04x\n", m_pbior);
|
||||
return m_pbior;
|
||||
}
|
||||
|
||||
void sh7014_port_device::pbior_w(uint16_t data)
|
||||
{
|
||||
// For SH7014 specifically, bits 0 and 1 are read only
|
||||
m_pbior = data & 0x3fc;
|
||||
LOGMASKED(LOG_WRITE, "pbior_w %04x\n", m_pbior);
|
||||
}
|
||||
|
||||
uint16_t sh7014_port_device::pbcr1_r()
|
||||
{
|
||||
LOGMASKED(LOG_READ, "pbcr1_r %04x\n", m_pbcr1);
|
||||
return m_pbcr1;
|
||||
}
|
||||
|
||||
void sh7014_port_device::pbcr1_w(uint16_t data)
|
||||
{
|
||||
m_pbcr1 = data & 0xf;
|
||||
LOGMASKED(LOG_WRITE, "pbcr1_w %04x\n", m_pbcr1);
|
||||
}
|
||||
|
||||
uint16_t sh7014_port_device::pbcr2_r()
|
||||
{
|
||||
LOGMASKED(LOG_READ, "pbcr2_r %04x\n", m_pbcr2);
|
||||
return m_pbcr2;
|
||||
}
|
||||
|
||||
void sh7014_port_device::pbcr2_w(uint16_t data)
|
||||
{
|
||||
m_pbcr2 = data & 0xfff5;
|
||||
LOGMASKED(LOG_WRITE, "pbcr2_w %04x\n", m_pbcr2);
|
||||
}
|
||||
|
||||
uint16_t sh7014_port_device::pedr_r()
|
||||
{
|
||||
uint16_t pins = m_port_e_read_cb();
|
||||
uint16_t r = ((m_pedr & m_peior) | (pins & ~m_peior));
|
||||
LOGMASKED(LOG_READ, "pedr_r %04x (pins: %04x %04x)\n", r, m_peior, pins);
|
||||
return r;
|
||||
}
|
||||
|
||||
void sh7014_port_device::pedr_w(uint16_t data)
|
||||
{
|
||||
m_pedr = data;
|
||||
LOGMASKED(LOG_WRITE, "pedr_w %04x\n", m_pedr);
|
||||
|
||||
if (m_peior)
|
||||
m_port_e_write_cb(m_pedr & m_peior);
|
||||
}
|
||||
|
||||
uint16_t sh7014_port_device::peior_r()
|
||||
{
|
||||
LOGMASKED(LOG_READ, "peior_r %04x\n", m_peior);
|
||||
return m_peior;
|
||||
}
|
||||
|
||||
void sh7014_port_device::peior_w(uint16_t data)
|
||||
{
|
||||
m_peior = data;
|
||||
LOGMASKED(LOG_WRITE, "peior_w %04x\n", m_peior);
|
||||
}
|
||||
|
||||
uint16_t sh7014_port_device::pecr1_r()
|
||||
{
|
||||
LOGMASKED(LOG_READ, "pecr1_r %04x\n", m_pecr1);
|
||||
return m_pecr1;
|
||||
}
|
||||
|
||||
void sh7014_port_device::pecr1_w(uint16_t data)
|
||||
{
|
||||
m_pecr1 = data & 0xf000;
|
||||
LOGMASKED(LOG_WRITE, "pecr1_w %04x\n", m_pecr1);
|
||||
}
|
||||
|
||||
uint16_t sh7014_port_device::pecr2_r()
|
||||
{
|
||||
LOGMASKED(LOG_READ, "pecr2_r %04x\n", m_pecr2);
|
||||
return m_pecr2;
|
||||
}
|
||||
|
||||
void sh7014_port_device::pecr2_w(uint16_t data)
|
||||
{
|
||||
m_pecr2 = data & 0x55ff;
|
||||
LOGMASKED(LOG_WRITE, "pecr2_w %04x\n", m_pecr2);
|
||||
}
|
||||
|
||||
|
||||
uint8_t sh7014_port_device::pfdr_r()
|
||||
{
|
||||
auto r = m_port_f_read_cb();
|
||||
LOGMASKED(LOG_READ, "pfdr_r %02x\n", r);
|
||||
return r;
|
||||
}
|
98
src/devices/cpu/sh/sh7014_port.h
Normal file
98
src/devices/cpu/sh/sh7014_port.h
Normal file
@ -0,0 +1,98 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 Bus State Controller
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_CPU_SH_SH7014_PORT_H
|
||||
#define MAME_CPU_SH_SH7014_PORT_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
class sh7014_port_device : public device_t
|
||||
{
|
||||
public:
|
||||
sh7014_port_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
auto port_a_read_callback() { return m_port_a_read_cb.bind(); }
|
||||
auto port_a_write_callback() { return m_port_a_write_cb.bind(); }
|
||||
|
||||
auto port_b_read_callback() { return m_port_b_read_cb.bind(); }
|
||||
auto port_b_write_callback() { return m_port_b_write_cb.bind(); }
|
||||
|
||||
auto port_e_read_callback() { return m_port_e_read_cb.bind(); }
|
||||
auto port_e_write_callback() { return m_port_e_write_cb.bind(); }
|
||||
|
||||
auto port_f_read_callback() { return m_port_f_read_cb.bind(); }
|
||||
|
||||
// port A
|
||||
uint16_t padrl_r();
|
||||
void padrl_w(uint16_t data);
|
||||
|
||||
uint16_t paiorl_r();
|
||||
void paiorl_w(uint16_t data);
|
||||
|
||||
uint16_t pacrl1_r();
|
||||
void pacrl1_w(uint16_t data);
|
||||
|
||||
uint16_t pacrl2_r();
|
||||
void pacrl2_w(uint16_t data);
|
||||
|
||||
// port b
|
||||
uint16_t pbdr_r();
|
||||
void pbdr_w(uint16_t data);
|
||||
|
||||
uint16_t pbior_r();
|
||||
void pbior_w(uint16_t data);
|
||||
|
||||
uint16_t pbcr1_r();
|
||||
void pbcr1_w(uint16_t data);
|
||||
|
||||
uint16_t pbcr2_r();
|
||||
void pbcr2_w(uint16_t data);
|
||||
|
||||
// port e
|
||||
uint16_t pedr_r();
|
||||
void pedr_w(uint16_t data);
|
||||
|
||||
uint16_t peior_r();
|
||||
void peior_w(uint16_t data);
|
||||
|
||||
uint16_t pecr1_r();
|
||||
void pecr1_w(uint16_t data);
|
||||
|
||||
uint16_t pecr2_r();
|
||||
void pecr2_w(uint16_t data);
|
||||
|
||||
// port f
|
||||
uint8_t pfdr_r();
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
private:
|
||||
devcb_read16 m_port_a_read_cb;
|
||||
devcb_write16 m_port_a_write_cb;
|
||||
|
||||
devcb_read16 m_port_b_read_cb;
|
||||
devcb_write16 m_port_b_write_cb;
|
||||
|
||||
devcb_read16 m_port_e_read_cb;
|
||||
devcb_write16 m_port_e_write_cb;
|
||||
|
||||
devcb_read16 m_port_f_read_cb;
|
||||
|
||||
uint16_t m_padr, m_paior, m_pacr1, m_pacr2;
|
||||
uint16_t m_pbdr, m_pbior, m_pbcr1, m_pbcr2;
|
||||
uint16_t m_pedr, m_peior, m_pecr1, m_pecr2;
|
||||
uint8_t m_pfdr;
|
||||
};
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(SH7014_PORT, sh7014_port_device)
|
||||
|
||||
#endif // MAME_CPU_SH_SH7014_PORT_H
|
380
src/devices/cpu/sh/sh7014_sci.cpp
Normal file
380
src/devices/cpu/sh/sh7014_sci.cpp
Normal file
@ -0,0 +1,380 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 SCI Controller
|
||||
|
||||
TODO list (not comprehensive):
|
||||
- RX is untested
|
||||
- Multiprocessor bit is not handled at all
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "sh7014_sci.h"
|
||||
|
||||
#define LOG_REGISTERS (1U << 1)
|
||||
#define LOG_TXRX (1U << 2)
|
||||
#define LOG_CLOCK (1U << 3)
|
||||
|
||||
// #define VERBOSE (LOG_GENERAL | LOG_REGISTERS | LOG_TXRX | LOG_CLOCK)
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(SH7014_SCI, sh7014_sci_device, "sh7014sci", "SH7014 SCI Controller")
|
||||
|
||||
sh7014_sci_device::sh7014_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, SH7014_SCI, tag, owner, clock)
|
||||
, device_serial_interface(mconfig, *this)
|
||||
, m_intc(*this, finder_base::DUMMY_TAG)
|
||||
, m_sci_tx_cb(*this)
|
||||
, m_hack_set_full_data_transmit_on_sync(false)
|
||||
{
|
||||
m_external_clock_period = attotime::never;
|
||||
}
|
||||
|
||||
void sh7014_sci_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_smr));
|
||||
save_item(NAME(m_brr));
|
||||
save_item(NAME(m_scr));
|
||||
save_item(NAME(m_tdr));
|
||||
save_item(NAME(m_ssr));
|
||||
save_item(NAME(m_rdr));
|
||||
save_item(NAME(m_is_dma_source_tx));
|
||||
save_item(NAME(m_is_dma_source_rx));
|
||||
save_item(NAME(m_clock_speed));
|
||||
save_item(NAME(m_external_clock_period));
|
||||
}
|
||||
|
||||
void sh7014_sci_device::device_reset()
|
||||
{
|
||||
m_smr = 0;
|
||||
m_brr = 0xff;
|
||||
m_scr = 0;
|
||||
m_tdr = 0xff;
|
||||
m_ssr = SSR_TDRE | SSR_TEND;
|
||||
m_rdr = 0;
|
||||
m_is_dma_source_tx = m_is_dma_source_rx = false;
|
||||
m_clock_speed = attotime::never;
|
||||
|
||||
update_data_format();
|
||||
update_clock();
|
||||
}
|
||||
|
||||
void sh7014_sci_device::map(address_map &map)
|
||||
{
|
||||
map(0x00, 0x00).rw(FUNC(sh7014_sci_device::smr_r), FUNC(sh7014_sci_device::smr_w));
|
||||
map(0x01, 0x01).rw(FUNC(sh7014_sci_device::brr_r), FUNC(sh7014_sci_device::brr_w));
|
||||
map(0x02, 0x02).rw(FUNC(sh7014_sci_device::scr_r), FUNC(sh7014_sci_device::scr_w));
|
||||
map(0x03, 0x03).rw(FUNC(sh7014_sci_device::tdr_r), FUNC(sh7014_sci_device::tdr_w));
|
||||
map(0x04, 0x04).rw(FUNC(sh7014_sci_device::ssr_r), FUNC(sh7014_sci_device::ssr_w));
|
||||
map(0x05, 0x05).r(FUNC(sh7014_sci_device::rdr_r));
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
void sh7014_sci_device::set_send_full_data_transmit_on_sync_hack(bool enabled)
|
||||
{
|
||||
// Synchronous clock mode forces a fixed 8-bit transmissions with no start, stop, parity, or multiprocessor bits.
|
||||
// This flag makes it so that all 8 bits in the transmit register will be transferred at the start of a transmission
|
||||
// instead of transmitting 1 bit at a time when in synchronous clock mode, allowing the transmit clock to be set to
|
||||
// 1/8th of its normal speed.
|
||||
m_hack_set_full_data_transmit_on_sync = enabled;
|
||||
}
|
||||
|
||||
void sh7014_sci_device::set_external_clock_period(const attotime &period)
|
||||
{
|
||||
m_external_clock_period = period;
|
||||
|
||||
// Update clock again if it's being used
|
||||
if (m_scr & SCR_CKE1)
|
||||
update_clock();
|
||||
}
|
||||
|
||||
uint8_t sh7014_sci_device::smr_r()
|
||||
{
|
||||
return m_smr;
|
||||
}
|
||||
|
||||
void sh7014_sci_device::smr_w(uint8_t data)
|
||||
{
|
||||
LOGMASKED(LOG_REGISTERS, "smr_w %02x %s %c%c%c%s /%d\n", data,
|
||||
data & SMR_CA ? "sync" : "async",
|
||||
data & SMR_CHR ? '7' : '8',
|
||||
data & SMR_PE ? data & SMR_OE ? 'o' : 'e' : 'n',
|
||||
data & SMR_STOP ? '2' : '1',
|
||||
data & SMR_MP ? " mp" : "",
|
||||
1 << (2 * (data & SMR_CKS)));
|
||||
|
||||
bool do_clock_update = (data & (SMR_CKS | SMR_CA)) != (m_smr & (SMR_CKS | SMR_CA));
|
||||
bool do_format_update = false;
|
||||
|
||||
if (!(data & SMR_CA))
|
||||
do_format_update = (data & ~SMR_CKS) != (m_smr & ~SMR_CKS);
|
||||
else
|
||||
do_format_update = (data & SMR_CA) != (m_smr & SMR_CA);
|
||||
|
||||
m_smr = data;
|
||||
|
||||
if (do_format_update)
|
||||
update_data_format();
|
||||
|
||||
if (do_clock_update)
|
||||
update_clock();
|
||||
}
|
||||
|
||||
uint8_t sh7014_sci_device::scr_r()
|
||||
{
|
||||
return m_scr;
|
||||
}
|
||||
|
||||
void sh7014_sci_device::scr_w(uint8_t data)
|
||||
{
|
||||
const auto old = m_scr;
|
||||
|
||||
LOGMASKED(LOG_REGISTERS, "scr_w %02x%s%s%s%s%s%s clk=%d\n", data,
|
||||
(data & SCR_TIE) ? " txi" : "",
|
||||
(data & SCR_RIE) ? " rxi" : "",
|
||||
(data & SCR_TE) ? " tx" : "",
|
||||
(data & SCR_RE) ? " rx" : "",
|
||||
(data & SCR_MPIE) ? " mpi" : "",
|
||||
(data & SCR_TEIE) ? " tei" : "",
|
||||
data & SCR_CKE);
|
||||
|
||||
if ((m_scr & SCR_TE) && !(data & SCR_TE))
|
||||
m_ssr |= SSR_TEND | SSR_TDRE;
|
||||
|
||||
if ((m_scr & SCR_TIE) && !(data & SCR_TIE))
|
||||
m_intc->set_interrupt(m_txi_int, CLEAR_LINE);
|
||||
|
||||
if ((m_scr & SCR_TEIE) && !(data & SCR_TEIE))
|
||||
m_intc->set_interrupt(m_tei_int, CLEAR_LINE);
|
||||
|
||||
if ((m_scr & SCR_RIE) && !(data & SCR_RIE)) {
|
||||
m_intc->set_interrupt(m_rxi_int, CLEAR_LINE);
|
||||
m_intc->set_interrupt(m_eri_int, CLEAR_LINE);
|
||||
}
|
||||
|
||||
m_scr = data;
|
||||
|
||||
if ((data & SCR_CKE) != (old & SCR_CKE))
|
||||
update_clock();
|
||||
}
|
||||
|
||||
uint8_t sh7014_sci_device::ssr_r()
|
||||
{
|
||||
LOGMASKED(LOG_REGISTERS, "ssr_r %02x\n", m_ssr);
|
||||
return m_ssr;
|
||||
}
|
||||
|
||||
void sh7014_sci_device::ssr_w(uint8_t data)
|
||||
{
|
||||
const auto old = m_ssr;
|
||||
bool do_tx_update = false;
|
||||
|
||||
m_ssr = (data & (m_ssr & (SSR_TDRE | SSR_RDRF | SSR_ORER | SSR_FER | SSR_PER)))
|
||||
| (m_ssr & (SSR_TEND | SSR_MPB))
|
||||
| (data & SSR_MPBT);
|
||||
|
||||
if (!(m_scr & SCR_TE)) {
|
||||
m_ssr |= SSR_TEND | SSR_TDRE;
|
||||
} else if ((old & SSR_TDRE) || !(m_scr & SSR_TDRE)) {
|
||||
do_tx_update = true;
|
||||
m_ssr &= ~(SSR_TEND | SSR_TDRE);
|
||||
}
|
||||
|
||||
if ((old & (SSR_ORER | SSR_FER | SSR_PER)) && !(data & (SSR_ORER | SSR_FER | SSR_PER)))
|
||||
m_intc->set_interrupt(m_eri_int, CLEAR_LINE);
|
||||
|
||||
LOGMASKED(LOG_REGISTERS, "ssr_w %02x | %02x -> %02x\n", data, old, m_ssr);
|
||||
|
||||
if (do_tx_update)
|
||||
update_tx_state();
|
||||
}
|
||||
|
||||
uint8_t sh7014_sci_device::brr_r()
|
||||
{
|
||||
return m_brr;
|
||||
}
|
||||
|
||||
void sh7014_sci_device::brr_w(uint8_t data)
|
||||
{
|
||||
LOGMASKED(LOG_REGISTERS, "brr_w %02x\n", data);
|
||||
m_brr = data;
|
||||
update_clock();
|
||||
}
|
||||
|
||||
uint8_t sh7014_sci_device::tdr_r()
|
||||
{
|
||||
LOGMASKED(LOG_TXRX, "tdr_r %02x\n", m_tdr);
|
||||
return m_tdr;
|
||||
}
|
||||
|
||||
void sh7014_sci_device::tdr_w(uint8_t data)
|
||||
{
|
||||
LOGMASKED(LOG_TXRX, "tdr_w%s %02x %d %d\n", m_is_dma_source_tx ? " (dma)" : "", data, is_transmit_register_empty(), (m_scr & SCR_TE) != 0);
|
||||
|
||||
m_tdr = data;
|
||||
|
||||
if (!(m_scr & SCR_TE))
|
||||
return;
|
||||
|
||||
if (m_is_dma_source_tx) {
|
||||
// Normally this would happen with a write to SCR but DMAs can only write to TDR,
|
||||
// so these flags are handled here as a special case for DMA writes only
|
||||
m_ssr &= ~(SSR_TEND | SSR_TDRE);
|
||||
m_is_dma_source_tx = false;
|
||||
|
||||
update_tx_state();
|
||||
}
|
||||
}
|
||||
|
||||
void sh7014_sci_device::tra_callback()
|
||||
{
|
||||
if (!is_transmit_register_empty())
|
||||
m_sci_tx_cb(transmit_register_get_data_bit());
|
||||
|
||||
if ((m_smr & SMR_CA) && m_hack_set_full_data_transmit_on_sync) {
|
||||
while (!is_transmit_register_empty())
|
||||
m_sci_tx_cb(transmit_register_get_data_bit());
|
||||
}
|
||||
}
|
||||
|
||||
void sh7014_sci_device::tra_complete()
|
||||
{
|
||||
if (!(m_ssr & SSR_TDRE)) {
|
||||
update_tx_state();
|
||||
return;
|
||||
}
|
||||
|
||||
LOGMASKED(LOG_TXRX, "transmit ended\n");
|
||||
|
||||
m_ssr |= SSR_TEND;
|
||||
if (m_scr & SCR_TEIE)
|
||||
m_intc->set_interrupt(m_tei_int, ASSERT_LINE);
|
||||
}
|
||||
|
||||
void sh7014_sci_device::update_tx_state()
|
||||
{
|
||||
if (!(m_scr & SCR_TE) || (m_ssr & SSR_TDRE) || !is_transmit_register_empty())
|
||||
return;
|
||||
|
||||
LOGMASKED(LOG_TXRX, "transmitting %02x\n", m_tdr);
|
||||
|
||||
transmit_register_setup(m_tdr);
|
||||
|
||||
m_ssr = (m_ssr & ~SSR_TEND) | SSR_TDRE;
|
||||
|
||||
if (m_scr & SCR_TIE)
|
||||
m_intc->set_interrupt(m_txi_int, ASSERT_LINE);
|
||||
}
|
||||
|
||||
uint8_t sh7014_sci_device::rdr_r()
|
||||
{
|
||||
auto r = m_rdr;
|
||||
|
||||
LOGMASKED(LOG_TXRX, "rdr_r%s %02x\n", m_is_dma_source_rx ? " (dma)" : "", m_rdr);
|
||||
|
||||
// DMA reads cause RDRF to be cleared
|
||||
if (m_is_dma_source_rx)
|
||||
m_ssr &= ~SSR_RDRF;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void sh7014_sci_device::rcv_complete()
|
||||
{
|
||||
receive_register_extract();
|
||||
|
||||
if (!(m_scr & SCR_RE))
|
||||
return;
|
||||
|
||||
if (is_receive_framing_error())
|
||||
m_ssr |= SSR_FER;
|
||||
if (is_receive_parity_error())
|
||||
m_ssr |= SSR_PER;
|
||||
|
||||
if (!(m_ssr & SSR_RDRF)) {
|
||||
m_rdr = get_received_char();
|
||||
m_ssr |= SSR_RDRF;
|
||||
|
||||
if (m_scr & SCR_RIE)
|
||||
m_intc->set_interrupt(m_rxi_int, ASSERT_LINE);
|
||||
|
||||
if ((m_ssr & SSR_FER) | (m_ssr & SSR_PER) || (m_ssr & SSR_ORER))
|
||||
m_intc->set_interrupt(m_eri_int, ASSERT_LINE);
|
||||
} else {
|
||||
m_ssr |= SSR_ORER;
|
||||
}
|
||||
}
|
||||
|
||||
void sh7014_sci_device::update_data_format()
|
||||
{
|
||||
if (m_smr & SMR_CA) {
|
||||
// Synchronous clock is a fixed 8-bit data length transmission
|
||||
set_data_frame(0, 8, PARITY_NONE, STOP_BITS_0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Async
|
||||
set_data_frame(
|
||||
1,
|
||||
(m_smr & SMR_CHR) ? 8 : 7,
|
||||
(m_smr & SMR_MP) ? PARITY_NONE : ((m_smr & SMR_PE) ? PARITY_ODD : PARITY_EVEN), // Multiprocessor mode does not use parity
|
||||
(m_smr & SMR_STOP) ? STOP_BITS_1 : STOP_BITS_2
|
||||
);
|
||||
}
|
||||
|
||||
void sh7014_sci_device::update_clock()
|
||||
{
|
||||
auto clock_mode = INTERNAL_SYNC_OUT;
|
||||
if (m_smr & SMR_CA) {
|
||||
if (m_scr & SCR_CKE1)
|
||||
clock_mode = EXTERNAL_SYNC;
|
||||
else
|
||||
clock_mode = INTERNAL_SYNC_OUT;
|
||||
} else {
|
||||
if (m_scr & SCR_CKE1)
|
||||
clock_mode = EXTERNAL_ASYNC;
|
||||
else if (m_scr & SCR_CKE0)
|
||||
clock_mode = INTERNAL_ASYNC_OUT;
|
||||
else
|
||||
clock_mode = INTERNAL_ASYNC;
|
||||
}
|
||||
|
||||
if (clock_mode == EXTERNAL_ASYNC && !m_external_clock_period.is_never())
|
||||
clock_mode = EXTERNAL_RATE_ASYNC;
|
||||
else if (clock_mode == EXTERNAL_SYNC && !m_external_clock_period.is_never())
|
||||
clock_mode = EXTERNAL_RATE_SYNC;
|
||||
|
||||
auto clock_speed = attotime::zero;
|
||||
switch (clock_mode) {
|
||||
case INTERNAL_ASYNC:
|
||||
case INTERNAL_ASYNC_OUT:
|
||||
case INTERNAL_SYNC_OUT:
|
||||
{
|
||||
int divider = (1 << (2 * (m_smr & SMR_CKS))) * (m_brr + 1);
|
||||
clock_speed = attotime::from_ticks(divider, clock());
|
||||
}
|
||||
break;
|
||||
|
||||
case EXTERNAL_ASYNC:
|
||||
case EXTERNAL_RATE_ASYNC:
|
||||
case EXTERNAL_SYNC:
|
||||
case EXTERNAL_RATE_SYNC:
|
||||
clock_speed = m_external_clock_period;
|
||||
break;
|
||||
}
|
||||
|
||||
if (clock_speed != m_clock_speed && !clock_speed.is_never()) {
|
||||
LOGMASKED(LOG_CLOCK, "Changing SCI ch %d rate set to %lf (%d %04x %04x)\n", m_channel_id, clock_speed.as_hz(), clock_mode, m_brr, m_smr);
|
||||
|
||||
if (m_hack_set_full_data_transmit_on_sync && (m_smr & SMR_CA))
|
||||
set_rate(clock_speed * 8);
|
||||
else
|
||||
set_rate(clock_speed);
|
||||
|
||||
m_clock_speed = clock_speed;
|
||||
}
|
||||
}
|
135
src/devices/cpu/sh/sh7014_sci.h
Normal file
135
src/devices/cpu/sh/sh7014_sci.h
Normal file
@ -0,0 +1,135 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
SH7014 SCI Controller
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_CPU_SH_SH7014_SCI_H
|
||||
#define MAME_CPU_SH_SH7014_SCI_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sh2.h"
|
||||
#include "sh7014_intc.h"
|
||||
#include "diserial.h"
|
||||
|
||||
class sh7014_sci_device : public device_t, public device_serial_interface
|
||||
{
|
||||
public:
|
||||
sh7014_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
template<typename T> sh7014_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&intc, int channel_id, int eri, int rxi, int txi, int tei)
|
||||
: sh7014_sci_device(mconfig, tag, owner, clock)
|
||||
{
|
||||
m_intc.set_tag(std::forward<T>(intc));
|
||||
m_channel_id = channel_id;
|
||||
m_eri_int = eri;
|
||||
m_rxi_int = rxi;
|
||||
m_txi_int = txi;
|
||||
m_tei_int = tei;
|
||||
}
|
||||
|
||||
auto write_sci_tx() { return m_sci_tx_cb.bind(); }
|
||||
|
||||
void set_dma_source_tx(bool val) { m_is_dma_source_tx = val; }
|
||||
void set_dma_source_rx(bool val) { m_is_dma_source_rx = val; }
|
||||
|
||||
void set_external_clock_period(const attotime &_period);
|
||||
void set_send_full_data_transmit_on_sync_hack(bool enabled);
|
||||
|
||||
void map(address_map &map);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
virtual void rcv_complete() override;
|
||||
|
||||
virtual void tra_callback() override;
|
||||
virtual void tra_complete() override;
|
||||
|
||||
private:
|
||||
enum : uint32_t {
|
||||
INTERNAL_ASYNC = 0,
|
||||
INTERNAL_ASYNC_OUT,
|
||||
EXTERNAL_ASYNC,
|
||||
EXTERNAL_RATE_ASYNC,
|
||||
INTERNAL_SYNC_OUT,
|
||||
EXTERNAL_SYNC,
|
||||
EXTERNAL_RATE_SYNC
|
||||
};
|
||||
|
||||
enum {
|
||||
SMR_CA = 1 << 7,
|
||||
SMR_CHR = 1 << 6,
|
||||
SMR_PE = 1 << 5,
|
||||
SMR_OE = 1 << 4,
|
||||
SMR_STOP = 1 << 3,
|
||||
SMR_MP = 1 << 2,
|
||||
SMR_CKS = (1 << 1) | (1 << 0),
|
||||
|
||||
SCR_TIE = 1 << 7,
|
||||
SCR_RIE = 1 << 6,
|
||||
SCR_TE = 1 << 5,
|
||||
SCR_RE = 1 << 4,
|
||||
SCR_MPIE = 1 << 3,
|
||||
SCR_TEIE = 1 << 2,
|
||||
SCR_CKE = (1 << 1) | (1 << 0),
|
||||
SCR_CKE1 = 1 << 1,
|
||||
SCR_CKE0 = 1 << 0,
|
||||
|
||||
SSR_TDRE = 1 << 7,
|
||||
SSR_RDRF = 1 << 6,
|
||||
SSR_ORER = 1 << 5,
|
||||
SSR_FER = 1 << 4,
|
||||
SSR_PER = 1 << 3,
|
||||
SSR_TEND = 1 << 2,
|
||||
SSR_MPB = 1 << 1,
|
||||
SSR_MPBT = 1 << 0
|
||||
};
|
||||
|
||||
uint8_t smr_r();
|
||||
void smr_w(uint8_t data);
|
||||
|
||||
uint8_t brr_r();
|
||||
void brr_w(uint8_t data);
|
||||
|
||||
uint8_t scr_r();
|
||||
void scr_w(uint8_t data);
|
||||
|
||||
uint8_t tdr_r();
|
||||
void tdr_w(uint8_t data);
|
||||
|
||||
uint8_t ssr_r();
|
||||
void ssr_w(uint8_t data);
|
||||
|
||||
uint8_t rdr_r();
|
||||
|
||||
void update_tx_state();
|
||||
void update_clock();
|
||||
void update_data_format();
|
||||
|
||||
required_device<sh7014_intc_device> m_intc;
|
||||
|
||||
devcb_write_line m_sci_tx_cb;
|
||||
|
||||
int m_channel_id, m_eri_int, m_rxi_int, m_txi_int, m_tei_int;
|
||||
bool m_hack_set_full_data_transmit_on_sync;
|
||||
|
||||
uint8_t m_smr;
|
||||
uint8_t m_brr;
|
||||
uint8_t m_scr;
|
||||
uint8_t m_tdr;
|
||||
uint8_t m_ssr;
|
||||
uint8_t m_rdr;
|
||||
|
||||
attotime m_external_clock_period, m_clock_speed;
|
||||
bool m_is_dma_source_tx, m_is_dma_source_rx;
|
||||
};
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(SH7014_SCI, sh7014_sci_device)
|
||||
|
||||
#endif // MAME_CPU_SH_SH7014_SCI_H
|
312
src/devices/machine/icd2061a.cpp
Normal file
312
src/devices/machine/icd2061a.cpp
Normal file
@ -0,0 +1,312 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
IC Designs 2061A Dual Programmable Graphics Clock Generator
|
||||
____ ____
|
||||
SEL0/CLK -> 1 | \_/ | 16 <- /PWRDWN
|
||||
SEL1/DATA -> 2 | | 15 <- INTCLK
|
||||
AVDD -> 3 | | 14 <- INIT1
|
||||
/OUTDIS -> 4 | ICD2061A | 13 <- VDD
|
||||
GND -> 5 | | 12 <- INIT0
|
||||
XTALIN -> 6 | | 11 <- FEATCLK
|
||||
XTALOUT <- 7 | | 10 -> /ERROUT
|
||||
MCLKOUT <- 8 |___________| 9 -> VCLKOUT
|
||||
|
||||
|
||||
TODO:
|
||||
- Not handled: MCLKOUT_HIGH_Z, VCLKOUT_HIGH_Z, VCLKOUT_FORCED_HIGH
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "icd2061a.h"
|
||||
|
||||
#define LOG_PINS (1 << 1)
|
||||
#define LOG_STATE (1 << 2)
|
||||
|
||||
// #define VERBOSE (LOG_GENERAL | LOG_PINS | LOG_STATE)
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(ICD2061A, icd2061a_device, "icd2061a", "IC Designs 2061A Dual Programmable Graphics Clock Generator")
|
||||
|
||||
|
||||
icd2061a_device::icd2061a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, ICD2061A, tag, owner, clock)
|
||||
, m_vclkout_changed_cb(*this)
|
||||
, m_mclkout_changed_cb(*this)
|
||||
, m_errout_cb(*this)
|
||||
, m_init0(0), m_init1(0)
|
||||
, m_outdis(1), m_pwrdwn(1)
|
||||
, m_intclk(0)
|
||||
{
|
||||
}
|
||||
|
||||
void icd2061a_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_state));
|
||||
save_item(NAME(m_unlock_step));
|
||||
save_item(NAME(m_cur_bit));
|
||||
save_item(NAME(m_data));
|
||||
save_item(NAME(m_data_prev));
|
||||
save_item(NAME(m_clk));
|
||||
save_item(NAME(m_cmd));
|
||||
|
||||
save_item(NAME(m_init0));
|
||||
save_item(NAME(m_init1));
|
||||
save_item(NAME(m_sel0));
|
||||
save_item(NAME(m_sel1));
|
||||
save_item(NAME(m_outdis));
|
||||
save_item(NAME(m_pwrdwn));
|
||||
save_item(NAME(m_intclk));
|
||||
save_item(NAME(m_vclkout_select));
|
||||
save_item(NAME(m_mclkout_select));
|
||||
|
||||
save_item(NAME(m_reg_clocks));
|
||||
save_item(NAME(m_prescale));
|
||||
save_item(NAME(m_powerdown_mode));
|
||||
save_item(NAME(m_muxref_vclkout_source));
|
||||
save_item(NAME(m_timeout_interval));
|
||||
save_item(NAME(m_muxref_adjust));
|
||||
|
||||
save_item(NAME(m_featclock));
|
||||
save_item(NAME(m_vclkout_clock));
|
||||
save_item(NAME(m_mclkout_clock));
|
||||
|
||||
m_watchdog_timer = timer_alloc(FUNC(icd2061a_device::watchdog_callback), this);
|
||||
m_watchdog_timer->adjust(attotime::never);
|
||||
|
||||
m_update_timer = timer_alloc(FUNC(icd2061a_device::update_clock_callback), this);
|
||||
m_update_timer->adjust(attotime::never);
|
||||
|
||||
m_state = CLOCKGEN_UNLOCK;
|
||||
m_unlock_step = 0;
|
||||
m_cur_bit = 0;
|
||||
m_data = m_data_prev = 1;
|
||||
m_clk = 1;
|
||||
m_cmd = 0;
|
||||
|
||||
std::fill(std::begin(m_prescale), std::end(m_prescale), 2);
|
||||
m_powerdown_mode = 0;
|
||||
m_muxref_vclkout_source = 0;
|
||||
m_timeout_interval = 5;
|
||||
m_muxref_adjust = 1;
|
||||
m_powerdown_divisor = 8;
|
||||
m_sel0 = m_sel1 = 0;
|
||||
m_vclkout_select = m_mclkout_select = -1;
|
||||
m_vclkout_clock = m_mclkout_clock = 0;
|
||||
|
||||
// Are these values derived from the XTALIN at all?
|
||||
// The manual only gives the frequencies as these values,
|
||||
// not p/q/m values that could be used to derive it from XTALIN
|
||||
if (m_init0 == 0 && m_init1 == 0) {
|
||||
m_reg_clocks[MREG] = 32'500'000;
|
||||
m_reg_clocks[REG0] = 25'175'000;
|
||||
m_reg_clocks[REG1] = m_reg_clocks[REG2] = 28'322'000;
|
||||
} else if (m_init0 == 0 && m_init1 == 1) {
|
||||
m_reg_clocks[MREG] = 40'000'000;
|
||||
m_reg_clocks[REG0] = 25'175'000;
|
||||
m_reg_clocks[REG1] = m_reg_clocks[REG2] = 28'322'000;
|
||||
} else if (m_init0 == 1 && m_init1 == 0) {
|
||||
m_reg_clocks[MREG] = 50'350'000;
|
||||
m_reg_clocks[REG0] = 40'000'000;
|
||||
m_reg_clocks[REG1] = m_reg_clocks[REG2] = 28'322'000;
|
||||
} else if (m_init0 == 1 && m_init1 == 1) {
|
||||
m_reg_clocks[MREG] = 56'644'000;
|
||||
m_reg_clocks[REG0] = 40'000'000;
|
||||
m_reg_clocks[REG1] = m_reg_clocks[REG2] = 50'350'000;
|
||||
}
|
||||
|
||||
m_errout_cb(1); // set no error start
|
||||
update_clock_callback(0);
|
||||
}
|
||||
|
||||
void icd2061a_device::set_featclock(const uint32_t clock)
|
||||
{
|
||||
m_featclock = clock;
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( icd2061a_device::watchdog_callback )
|
||||
{
|
||||
// If the timeout is hit then rearm the locked mode and accept the last values as sel0/sel1
|
||||
LOG("watchdog timed out, setting sel0 = %d, sel1 = %d\n", m_clk, m_data);
|
||||
|
||||
if (m_sel0 != m_clk || m_sel1 != m_data) {
|
||||
m_sel0 = m_clk;
|
||||
m_sel1 = m_data;
|
||||
|
||||
update_clock();
|
||||
}
|
||||
|
||||
m_state = CLOCKGEN_UNLOCK;
|
||||
m_unlock_step = 0;
|
||||
m_unlock_step = 0;
|
||||
m_cur_bit = 0;
|
||||
m_cmd = 0;
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( icd2061a_device::update_clock_callback )
|
||||
{
|
||||
// mclkout
|
||||
if (m_outdis == 0)
|
||||
m_mclkout_select = MCLKOUT_HIGH_Z;
|
||||
else if (m_outdis == 1 && m_pwrdwn == 1)
|
||||
m_mclkout_select = MCLKOUT_MREG;
|
||||
else if (m_outdis == 1 && m_pwrdwn == 0)
|
||||
m_mclkout_select = MCLKOUT_PWRDWN;
|
||||
|
||||
if (m_mclkout_select == MCLKOUT_PWRDWN) {
|
||||
if (m_powerdown_mode == 1 || m_powerdown_divisor == 0)
|
||||
m_reg_clocks[MREG] = 0;
|
||||
else
|
||||
m_reg_clocks[MREG] = clock() / ((17 - m_powerdown_divisor) * 2); // 1 = divisor of 32, 15 = divisor of 4
|
||||
} else if (m_mclkout_select == MCLKOUT_MREG) {
|
||||
const int a = BIT(m_regs[MREG], 21, 2); // register addr
|
||||
const int p = BIT(m_regs[MREG], 10, 7) + 3; // p counter value
|
||||
const int m = BIT(m_regs[MREG], 7, 3); // post-vco divisor
|
||||
const int q = BIT(m_regs[MREG], 0, 7) + 2; // q counter value
|
||||
m_reg_clocks[MREG] = (clock() * m_prescale[a] * (p / double(q))) / (1 << m);
|
||||
}
|
||||
|
||||
if (m_reg_clocks[MREG] != m_mclkout_clock) {
|
||||
m_mclkout_changed_cb(m_reg_clocks[MREG]);
|
||||
m_mclkout_clock = m_reg_clocks[MREG];
|
||||
}
|
||||
|
||||
// vclkout
|
||||
if (m_outdis == 0)
|
||||
m_vclkout_select = VCLKOUT_HIGH_Z;
|
||||
else if (m_outdis == 1 && m_pwrdwn == 0)
|
||||
m_vclkout_select = VCLKOUT_FORCED_HIGH;
|
||||
else if (m_outdis == 1 && m_pwrdwn == 1 && m_sel1 == 0 && m_sel0 == 0)
|
||||
m_vclkout_select = VCLKOUT_REG0;
|
||||
else if (m_outdis == 1 && m_pwrdwn == 1 && m_sel1 == 0 && m_sel0 == 1)
|
||||
m_vclkout_select = VCLKOUT_REG1;
|
||||
else if (m_outdis == 1 && m_pwrdwn == 1 && m_intclk == 0 && m_sel1 == 1 && m_sel0 == 0)
|
||||
m_vclkout_select = VCLKOUT_FEATCLK;
|
||||
else if (m_outdis == 1 && m_pwrdwn == 1 && m_sel1 == 1 && (m_intclk == 1 || m_sel0 == 1))
|
||||
m_vclkout_select = VCLKOUT_REG2;
|
||||
|
||||
if (m_vclkout_select == VCLKOUT_FEATCLK) {
|
||||
m_reg_clocks[m_vclkout_select] = m_featclock;
|
||||
} else if (m_vclkout_select >= VCLKOUT_REG0 && m_vclkout_select <= VCLKOUT_REG2) {
|
||||
const int a = BIT(m_regs[m_vclkout_select], 21, 2); // register addr
|
||||
const int p = BIT(m_regs[m_vclkout_select], 10, 7) + 3; // p counter value
|
||||
const int m = BIT(m_regs[m_vclkout_select], 7, 3); // post-vco divisor
|
||||
const int q = BIT(m_regs[m_vclkout_select], 0, 7) + 2; // q counter value
|
||||
m_reg_clocks[m_vclkout_select] = (clock() * m_prescale[a] * (p / double(q))) / (1 << m);
|
||||
}
|
||||
|
||||
m_vclkout_changed_cb(m_reg_clocks[m_vclkout_select]);
|
||||
m_vclkout_clock = m_reg_clocks[m_vclkout_select];
|
||||
}
|
||||
|
||||
void icd2061a_device::update_clock()
|
||||
{
|
||||
// Set muxed clock during transition period
|
||||
m_vclkout_changed_cb(m_muxref_vclkout_source ? m_mclkout_clock : clock());
|
||||
|
||||
m_watchdog_timer->adjust(attotime::never);
|
||||
m_update_timer->adjust(attotime::from_msec(m_timeout_interval));
|
||||
}
|
||||
|
||||
void icd2061a_device::data_w(int state)
|
||||
{
|
||||
LOGMASKED(LOG_PINS, "data_w %d\n", state);
|
||||
|
||||
m_watchdog_timer->adjust(attotime::from_msec(m_timeout_interval));
|
||||
|
||||
m_data = state;
|
||||
}
|
||||
|
||||
void icd2061a_device::clk_w(int state)
|
||||
{
|
||||
LOGMASKED(LOG_PINS, "clk_w %d\n", state);
|
||||
|
||||
m_watchdog_timer->adjust(attotime::from_msec(m_timeout_interval));
|
||||
|
||||
if (!m_clk && state) {
|
||||
if (m_state == CLOCKGEN_UNLOCK && m_data == 1) {
|
||||
// Any number of 1s can be read until the final transition with data low
|
||||
m_errout_cb(1); // clear any previous errors since we're in a good state now
|
||||
|
||||
m_unlock_step++;
|
||||
LOGMASKED(LOG_STATE, "unlock count = %d\n", m_unlock_step);
|
||||
} else if (m_state == CLOCKGEN_UNLOCK && m_data == 0 && m_unlock_step >= 5) {
|
||||
// Found last part of unlock sequence, move on to start bit
|
||||
m_state = CLOCKGEN_START_BIT;
|
||||
m_unlock_step = 0;
|
||||
LOGMASKED(LOG_STATE, "found unlock end, state = CLOCKGEN_START_BIT\n");
|
||||
} else if (m_state == CLOCKGEN_START_BIT && m_data == 0) {
|
||||
// Found start bit transition, move on to data
|
||||
m_state = CLOCKGEN_DATA;
|
||||
m_cur_bit = 0;
|
||||
m_cmd = 0;
|
||||
LOGMASKED(LOG_STATE, "found start bit, state = CLOCKGEN_DATA\n");
|
||||
} else if (m_state == CLOCKGEN_DATA && m_data_prev != m_data && m_cur_bit < 24) {
|
||||
// Data uses modified Manchester encoding so the data bit read on each edge must be different
|
||||
// Must read exactly 24 bits of data here
|
||||
m_cmd |= m_data << m_cur_bit;
|
||||
LOGMASKED(LOG_STATE, "data %d %06x\n", m_cur_bit, m_cmd);
|
||||
m_cur_bit++;
|
||||
} else if (m_state == CLOCKGEN_DATA && m_data == 1 && m_cur_bit == 24) {
|
||||
// Found end bit transition, accept data and then rearm lock
|
||||
const int idx = BIT(m_cmd, 21, 3);
|
||||
|
||||
if (idx == 4) {
|
||||
const int p = BIT(m_cmd, 17, 4);
|
||||
LOG("PWRDWN register %06x p[%d]\n", m_cmd, p);
|
||||
m_powerdown_divisor = p;
|
||||
} else if (idx == 6) {
|
||||
const int c = BIT(m_cmd, 15, 6);
|
||||
const int ps = BIT(m_cmd, 12, 3);
|
||||
|
||||
m_powerdown_mode = BIT(c, 5);
|
||||
m_muxref_vclkout_source = BIT(c, 4);
|
||||
m_timeout_interval = 5 * (1 << BIT(c, 3));
|
||||
m_muxref_adjust = BIT(c, 1);
|
||||
|
||||
m_prescale[0] = 2 << BIT(ps, 0);
|
||||
m_prescale[1] = 2 << BIT(ps, 1);
|
||||
m_prescale[2] = 2 << BIT(ps, 2);
|
||||
|
||||
LOG("CNTL program %06x c[%d] ps[%d]\n", m_cmd, c, ps);
|
||||
} else if (idx <= 3) {
|
||||
const int a = BIT(m_cmd, 21, 2); // register addr
|
||||
const int i = BIT(m_cmd, 17, 4); // index, used to make sure clock is in expected range
|
||||
const int p = BIT(m_cmd, 10, 7) + 3; // p counter value
|
||||
const int m = BIT(m_cmd, 7, 3); // post-vco divisor
|
||||
const int q = BIT(m_cmd, 0, 7) + 2; // q counter value
|
||||
const double outclock = (clock() * m_prescale[a] * (p / double(q))) / 1000000.0;
|
||||
const double outclock_scaled = outclock / (1 << m);
|
||||
|
||||
m_regs[idx] = m_cmd;
|
||||
|
||||
LOG("VCO program %06x a[%d] i[%d] p[%d] m[%d] q[%d] prescale[%d] clock[%lf] clock_scaled[%lf]\n", m_cmd, a, i, p, m, q, m_prescale[a], outclock, outclock_scaled);
|
||||
} else {
|
||||
LOG("Unknown register selected: %06x %d\n", m_cmd, idx);
|
||||
}
|
||||
|
||||
m_state = CLOCKGEN_UNLOCK;
|
||||
m_unlock_step = 0;
|
||||
|
||||
LOGMASKED(LOG_STATE, "accepted\n");
|
||||
|
||||
update_clock();
|
||||
} else {
|
||||
// Error state, rearm lock
|
||||
m_state = CLOCKGEN_UNLOCK;
|
||||
m_unlock_step = 0;
|
||||
|
||||
m_errout_cb(0); // notify of error
|
||||
|
||||
LOGMASKED(LOG_STATE, "error\n");
|
||||
}
|
||||
} else {
|
||||
m_data_prev = m_data;
|
||||
}
|
||||
|
||||
m_clk = state;
|
||||
}
|
105
src/devices/machine/icd2061a.h
Normal file
105
src/devices/machine/icd2061a.h
Normal file
@ -0,0 +1,105 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
IC Designs 2061ASC-1 Programmable Clock Generator
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_MACHINE_ICD2061A_H
|
||||
#define MAME_MACHINE_ICD2061A_H
|
||||
|
||||
#pragma once
|
||||
|
||||
class icd2061a_device : public device_t
|
||||
{
|
||||
public:
|
||||
icd2061a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
auto vclkout_changed() { return m_vclkout_changed_cb.bind(); }
|
||||
auto mclkout_changed() { return m_mclkout_changed_cb.bind(); }
|
||||
auto errout() { return m_errout_cb.bind(); }
|
||||
|
||||
void init0_w(int state) { m_init0 = state; }
|
||||
void init1_w(int state) { m_init1 = state; }
|
||||
void outdis_w(int state) { m_outdis = state; }
|
||||
void pwrdwn_w(int state) { m_pwrdwn = state; }
|
||||
void intclk_w(int state) { m_intclk = state; }
|
||||
|
||||
void set_featclock(const uint32_t clock);
|
||||
|
||||
void data_w(int state);
|
||||
void clk_w(int state);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
|
||||
private:
|
||||
enum : uint8_t {
|
||||
CLOCKGEN_UNLOCK = 0,
|
||||
CLOCKGEN_START_BIT,
|
||||
CLOCKGEN_DATA,
|
||||
};
|
||||
|
||||
enum : int8_t {
|
||||
VCLKOUT_REG0 = 0,
|
||||
VCLKOUT_REG1,
|
||||
VCLKOUT_REG2,
|
||||
VCLKOUT_HIGH_Z,
|
||||
VCLKOUT_FORCED_HIGH,
|
||||
VCLKOUT_FEATCLK,
|
||||
|
||||
MCLKOUT_MREG = 0,
|
||||
MCLKOUT_HIGH_Z,
|
||||
MCLKOUT_PWRDWN,
|
||||
};
|
||||
|
||||
enum {
|
||||
REG0 = 0,
|
||||
REG1,
|
||||
REG2,
|
||||
MREG,
|
||||
};
|
||||
|
||||
TIMER_CALLBACK_MEMBER( watchdog_callback );
|
||||
TIMER_CALLBACK_MEMBER( update_clock_callback );
|
||||
|
||||
void update_clock();
|
||||
|
||||
emu_timer *m_watchdog_timer;
|
||||
emu_timer *m_update_timer;
|
||||
|
||||
devcb_write32 m_vclkout_changed_cb, m_mclkout_changed_cb;
|
||||
devcb_write_line m_errout_cb;
|
||||
|
||||
uint8_t m_init0, m_init1;
|
||||
uint8_t m_sel0, m_sel1;
|
||||
uint8_t m_outdis;
|
||||
uint8_t m_pwrdwn;
|
||||
uint8_t m_intclk;
|
||||
int8_t m_vclkout_select, m_mclkout_select;
|
||||
|
||||
uint8_t m_state;
|
||||
uint8_t m_unlock_step;
|
||||
uint8_t m_cur_bit;
|
||||
uint8_t m_data, m_data_prev;
|
||||
uint8_t m_clk;
|
||||
uint32_t m_cmd;
|
||||
|
||||
uint32_t m_regs[4];
|
||||
uint32_t m_reg_clocks[4];
|
||||
uint8_t m_prescale[4];
|
||||
uint8_t m_powerdown_mode;
|
||||
uint8_t m_muxref_vclkout_source;
|
||||
uint8_t m_timeout_interval;
|
||||
uint8_t m_muxref_adjust;
|
||||
uint8_t m_powerdown_divisor;
|
||||
|
||||
uint32_t m_featclock;
|
||||
uint32_t m_vclkout_clock, m_mclkout_clock;
|
||||
};
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(ICD2061A, icd2061a_device)
|
||||
|
||||
#endif // MAME_MACHINE_ICD2061A_H
|
@ -760,6 +760,16 @@ void t10mmc::ExecCommand()
|
||||
break;
|
||||
}
|
||||
|
||||
case T10SBC_CMD_SEEK_10:
|
||||
m_lba = get_u32be(&command[2]);
|
||||
|
||||
m_device->logerror("T10SBC: SEEK EXTENDED to LBA %x\n", m_lba);
|
||||
|
||||
m_phase = SCSI_PHASE_STATUS;
|
||||
m_status_code = SCSI_STATUS_CODE_GOOD;
|
||||
m_transfer_length = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
t10spc::ExecCommand();
|
||||
}
|
||||
|
208
src/devices/sound/lc78836m.cpp
Normal file
208
src/devices/sound/lc78836m.cpp
Normal file
@ -0,0 +1,208 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
Sanyo LC78836M Digital Audio 16-bit D/A Converter
|
||||
with On-Chip Digital Filters
|
||||
____ ____
|
||||
REFH 1 | \_/ | 24 AVDD
|
||||
VrefH 2 | | 23 CH1OUT
|
||||
MUTE 3 | | 22 AGND
|
||||
D/N 4 | | 21 CH2OUT
|
||||
BCLK 5 | | 20 REFL
|
||||
DATA 6 | LC78836M | 19 VrefL
|
||||
LRCK 7 | | 18 CKSL2
|
||||
DVDD 8 | | 17 CKSL1
|
||||
CKOUT 9 | | 16 FS2
|
||||
XOUT 10 | | 15 FS1
|
||||
XIN 11 | | 14 EMP
|
||||
DGND 12 |___________| 13 INITB
|
||||
|
||||
|
||||
TOOD:
|
||||
- INITB, DN aren't implemented
|
||||
- Filters aren't implemented
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "lc78836m.h"
|
||||
|
||||
// #define VERBOSE (LOG_GENERAL)
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(LC78836M, lc78836m_device, "lc78836m", "Sanyo LC78836M Digital Audio 16-bit D/A Converter")
|
||||
|
||||
|
||||
lc78836m_device::lc78836m_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, LC78836M, tag, owner, clock)
|
||||
, device_sound_interface(mconfig, *this)
|
||||
, m_stream(nullptr)
|
||||
, m_cksl1(0), m_cksl2(0)
|
||||
, m_fs1(0), m_fs2(0)
|
||||
, m_emp(0)
|
||||
{
|
||||
}
|
||||
|
||||
void lc78836m_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_cksl1));
|
||||
save_item(NAME(m_cksl2));
|
||||
save_item(NAME(m_fs1));
|
||||
save_item(NAME(m_fs2));
|
||||
save_item(NAME(m_emp));
|
||||
|
||||
save_item(NAME(m_mute));
|
||||
save_item(NAME(m_lrck));
|
||||
save_item(NAME(m_data));
|
||||
save_item(NAME(m_bclk));
|
||||
save_item(NAME(m_sample));
|
||||
save_item(NAME(m_sample_bit));
|
||||
save_item(NAME(m_clock_fs));
|
||||
|
||||
save_item(NAME(m_sample_ch1));
|
||||
save_item(NAME(m_sample_ch2));
|
||||
save_item(NAME(m_att));
|
||||
|
||||
m_stream = stream_alloc(2, 2, m_clock);
|
||||
}
|
||||
|
||||
void lc78836m_device::device_reset()
|
||||
{
|
||||
m_mute = 0;
|
||||
m_lrck = 0;
|
||||
m_data = 0;
|
||||
m_bclk = 0;
|
||||
m_sample = 0;
|
||||
m_sample_bit = 0;
|
||||
m_att = 1024;
|
||||
m_sample_ch1 = m_sample_ch2 = 0;
|
||||
|
||||
update_clock();
|
||||
}
|
||||
|
||||
void lc78836m_device::device_clock_changed()
|
||||
{
|
||||
update_clock();
|
||||
}
|
||||
|
||||
void lc78836m_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
|
||||
{
|
||||
outputs[0].fill(0);
|
||||
outputs[0].put(0, m_sample_ch1 * m_att / 1024.0);
|
||||
m_sample_ch1 = 0;
|
||||
|
||||
outputs[1].fill(0);
|
||||
outputs[1].put(0, m_sample_ch2 * m_att / 1024.0);
|
||||
m_sample_ch2 = 0;
|
||||
|
||||
if (m_mute && m_att > 0)
|
||||
m_att--;
|
||||
else if (!m_mute && m_att < 1024)
|
||||
m_att++;
|
||||
|
||||
}
|
||||
|
||||
void lc78836m_device::mute_w(int state)
|
||||
{
|
||||
// Soft mute
|
||||
m_mute = state;
|
||||
}
|
||||
|
||||
void lc78836m_device::lrck_w(int state)
|
||||
{
|
||||
// CH1 when high, CH2 when low
|
||||
m_lrck = state;
|
||||
}
|
||||
|
||||
void lc78836m_device::data_w(int state)
|
||||
{
|
||||
m_data = state;
|
||||
}
|
||||
|
||||
void lc78836m_device::bclk_w(int state)
|
||||
{
|
||||
if (!m_bclk && state) {
|
||||
m_sample |= m_data << m_sample_bit;
|
||||
m_sample_bit++;
|
||||
|
||||
if (m_sample_bit >= 16) {
|
||||
stream_buffer::sample_t sample = m_sample / double(std::numeric_limits<int16_t>::max());
|
||||
|
||||
if (m_lrck)
|
||||
m_sample_ch1 = sample;
|
||||
else
|
||||
m_sample_ch2 = sample;
|
||||
|
||||
m_sample = 0;
|
||||
m_sample_bit = 0;
|
||||
|
||||
m_stream->update();
|
||||
}
|
||||
}
|
||||
|
||||
m_bclk = state;
|
||||
}
|
||||
|
||||
void lc78836m_device::initb_w(int state)
|
||||
{
|
||||
// Initialization signal input
|
||||
// LSI is initialized when set low
|
||||
m_initb = state;
|
||||
}
|
||||
|
||||
void lc78836m_device::cksl1_w(int state)
|
||||
{
|
||||
// System clock selection bit 1
|
||||
if (state != m_cksl1) {
|
||||
m_cksl1 = state;
|
||||
update_clock();
|
||||
}
|
||||
}
|
||||
|
||||
void lc78836m_device::cksl2_w(int state)
|
||||
{
|
||||
// System clock selection bit 2
|
||||
if (state != m_cksl2) {
|
||||
m_cksl2 = state;
|
||||
update_clock();
|
||||
}
|
||||
}
|
||||
|
||||
void lc78836m_device::fs1_w(int state)
|
||||
{
|
||||
// De-emphasis filter mode selection bit 1
|
||||
m_fs1 = state;
|
||||
}
|
||||
|
||||
void lc78836m_device::fs2_w(int state)
|
||||
{
|
||||
// De-emphasis filter mode selection bit 2
|
||||
m_fs2 = state;
|
||||
}
|
||||
|
||||
void lc78836m_device::emp_w(int state)
|
||||
{
|
||||
// De-emphasis filter on/off
|
||||
m_emp = state;
|
||||
}
|
||||
|
||||
void lc78836m_device::update_clock()
|
||||
{
|
||||
if (m_cksl1 == 0 && m_cksl2 == 0)
|
||||
m_clock_fs = 384;
|
||||
else if (m_cksl1 == 0 && m_cksl2 == 1)
|
||||
m_clock_fs = 392;
|
||||
else if (m_cksl1 == 1 && m_cksl2 == 0)
|
||||
m_clock_fs = 448;
|
||||
else if (m_cksl1 == 1 && m_cksl2 == 1)
|
||||
m_clock_fs = 512;
|
||||
|
||||
const uint32_t new_sample_rate = m_clock / m_clock_fs;
|
||||
if (m_stream != nullptr && new_sample_rate != m_stream->sample_rate()) {
|
||||
LOG("sample rate changed to %d\n", new_sample_rate);
|
||||
m_stream->set_sample_rate(new_sample_rate);
|
||||
}
|
||||
}
|
66
src/devices/sound/lc78836m.h
Normal file
66
src/devices/sound/lc78836m.h
Normal file
@ -0,0 +1,66 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
Sanyo LC78836M Digital Audio 16-bit D/A Converter
|
||||
with On-Chip Digital Filters
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_SOUND_LC78836M_H
|
||||
#define MAME_SOUND_LC78836M_H
|
||||
|
||||
#pragma once
|
||||
|
||||
class lc78836m_device : public device_t, public device_sound_interface
|
||||
{
|
||||
public:
|
||||
lc78836m_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
void mute_w(int state);
|
||||
|
||||
void lrck_w(int state);
|
||||
void data_w(int state);
|
||||
void bclk_w(int state);
|
||||
|
||||
void cksl1_w(int state);
|
||||
void cksl2_w(int state);
|
||||
|
||||
void fs1_w(int state);
|
||||
void fs2_w(int state);
|
||||
|
||||
void emp_w(int state);
|
||||
|
||||
void initb_w(int state);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_clock_changed() override;
|
||||
|
||||
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
|
||||
|
||||
private:
|
||||
void update_clock();
|
||||
|
||||
sound_stream *m_stream;
|
||||
|
||||
uint8_t m_mute;
|
||||
uint8_t m_cksl1, m_cksl2;
|
||||
uint16_t m_clock_fs;
|
||||
uint8_t m_fs1, m_fs2;
|
||||
uint8_t m_emp;
|
||||
uint8_t m_initb;
|
||||
|
||||
uint8_t m_bclk, m_lrck, m_data;
|
||||
uint8_t m_sample_bit;
|
||||
int16_t m_sample;
|
||||
|
||||
stream_buffer::sample_t m_sample_ch1, m_sample_ch2;
|
||||
double m_att;
|
||||
};
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(LC78836M, lc78836m_device)
|
||||
|
||||
#endif // MAME_SOUND_LC78836M_H
|
@ -32826,6 +32826,7 @@ tenkomor // 1998.?? Tenkomori Shooting (World, TKM2/VER.A
|
||||
tenkomorja // 1998.12 Tenkomori Shooting (Japan, TKM1/VER.A1)
|
||||
toukon3 // 1997.12 Shin Nihon Pro Wrestling Toukon Retsuden 3 Arcade Edition (Japan, TR1/VER.A)
|
||||
truckk // 2000.06 Truck Kyousoukyoku (Metro) (Japan, TKK2/VER.A)
|
||||
ujlnow // 1999.10? Um Jammer Lammy NOW! (Japan, UL1/VER.A)
|
||||
|
||||
@source:namco/namcos21.cpp
|
||||
winrun // (c) 1988
|
||||
|
@ -18,9 +18,6 @@
|
||||
- kartduel frame rate is choppy, it freezes every half second
|
||||
memo: this is due to the link PCB not being implemented, it keeps trying to communicate over the network causing hitching.
|
||||
Forcing 0x1f781701 (which is within the shared RAM between the PCBs) to 0xff will stop the hitching.
|
||||
- truckk doesn't boot: the H8/3002 never enters InitJVSBoards @ 1DE2. 1DE2 is referenced in a table of commands at 4032,
|
||||
which is called by the routine at 3FEA. It is not clear how execution is intended to get to 3FEA - there are no direct
|
||||
branches to that location, and the bytes 3F EA don't appear at all in the program.
|
||||
- technodr: printer not emulated. To play the game, press F2 to enter the test menu, navigate to GAME OPTIONS and disable
|
||||
the printer by setting "PRINTER" to OFF.
|
||||
- sws2001 crashes at random times in-game, and always after the opening video. You can spam insert coin and start to get in-game.
|
||||
@ -1055,9 +1052,11 @@ Notes:
|
||||
MB87078 : Fujitsu MB87078 6-bit, 4-channel Electronic Volume Controller (SOIC24)
|
||||
J2 : Custom Namco connector for plug-in CPU PCB
|
||||
J3 : 40 pin connector for IDE CDROM data cable
|
||||
J4 : 6 pin connector (possibly to re-program the CPLD)
|
||||
J8 : 4 pin connector (left/right audio output)
|
||||
J9 : 3 pin connector (possibly mono audio output or another audio output)
|
||||
J4 : 6 pin connector (serial)
|
||||
For Um Jammer Lammy Now this goes to J205 on the M148 EMI DRIVE PCB.
|
||||
According to the manual schematics, only GND and TX are connected going to RxD0 on EMI DRIVE PCB side.
|
||||
J8 : 4 pin connector (left/right audio output, RGND/R/LGND/L pinout)
|
||||
J9 : 3 pin connector (left/right audio output, L/GND/R pinout)
|
||||
|
||||
This PCB was found on the following games (so far)....
|
||||
|
||||
@ -1101,15 +1100,21 @@ The lever must be wired to analog port 0 (pin B22 parts side) of the Namco 48-wa
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "cpu/psx/psx.h"
|
||||
|
||||
#include "bus/ata/ataintf.h"
|
||||
#include "cpu/h8/h83002.h"
|
||||
#include "cpu/h8/h83337.h"
|
||||
#include "video/psx.h"
|
||||
#include "cpu/sh/sh7014.h"
|
||||
#include "cpu/psx/psx.h"
|
||||
#include "machine/at28c16.h"
|
||||
#include "machine/ram.h"
|
||||
#include "sound/c352.h"
|
||||
#include "machine/rtc4543.h"
|
||||
#include "sound/c352.h"
|
||||
#include "video/psx.h"
|
||||
|
||||
#include "namco_settings.h"
|
||||
#include "namcos12_cdxa.h"
|
||||
|
||||
#include "screen.h"
|
||||
#include "speaker.h"
|
||||
|
||||
@ -1237,7 +1242,6 @@ public:
|
||||
void technodr(machine_config &config);
|
||||
void golgo13(machine_config &config);
|
||||
void aplarail(machine_config &config);
|
||||
void truckk(machine_config &config);
|
||||
void tektagt(machine_config &config);
|
||||
void ptblank2(machine_config &config);
|
||||
void kartduel(machine_config &config);
|
||||
@ -1247,6 +1251,28 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class namcos12_cdxa_state : public namcos12_boothack_state
|
||||
{
|
||||
public:
|
||||
namcos12_cdxa_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: namcos12_boothack_state(mconfig, type, tag)
|
||||
, m_cdxa_pcb(*this, "cdxa_pcb")
|
||||
{
|
||||
}
|
||||
|
||||
void cdxa_pcb(machine_config &config);
|
||||
|
||||
void truckk(machine_config &config);
|
||||
|
||||
void init_truckk();
|
||||
|
||||
private:
|
||||
void cdxa_psx_map(address_map &map);
|
||||
|
||||
required_device<namcos12_cdxa_device> m_cdxa_pcb;
|
||||
};
|
||||
|
||||
|
||||
inline void ATTR_PRINTF(3,4) namcos12_state::verboselog( int n_level, const char *s_fmt, ... )
|
||||
{
|
||||
if( VERBOSE_LEVEL >= n_level )
|
||||
@ -1360,10 +1386,10 @@ void namcos12_state::namcos12_rom_read( uint32_t *p_n_psxram, uint32_t n_address
|
||||
{
|
||||
n_region = m_bankedroms;
|
||||
n_offset &= 0x7fffffff;
|
||||
}
|
||||
|
||||
if( !m_has_tektagt_dma && m_alt_bank ) // alt bank method stores the upper bits of the bank into m_n_bankoffset
|
||||
n_offset += m_n_bankoffset * 0x200000;
|
||||
if( !m_has_tektagt_dma && m_alt_bank ) // alt bank method stores the upper bits of the bank into m_n_bankoffset
|
||||
n_offset += m_n_bankoffset * 0x200000;
|
||||
}
|
||||
|
||||
m_has_tektagt_dma = 0;
|
||||
|
||||
@ -1851,21 +1877,6 @@ void namcos12_state::jvsmap(address_map &map)
|
||||
map(0xc000, 0xfb7f).ram();
|
||||
}
|
||||
|
||||
void namcos12_boothack_state::truckk(machine_config &config)
|
||||
{
|
||||
coh700(config);
|
||||
// Timer at 115200*16 for the jvs serial clock
|
||||
m_sub->sci_set_external_clock_period(0, attotime::from_hz(JVSCLOCK/8));
|
||||
|
||||
h83334_device &iocpu(H83334(config, "iocpu", JVSCLOCK));
|
||||
iocpu.set_addrmap(AS_PROGRAM, &namcos12_boothack_state::jvsmap);
|
||||
|
||||
iocpu.write_sci_tx<0>().set(m_sub, FUNC(h8_device::sci_rx_w<0>));
|
||||
m_sub->write_sci_tx<0>().set(iocpu, FUNC(h8_device::sci_rx_w<0>));
|
||||
|
||||
config.set_maximum_quantum(attotime::from_hz(2*115200));
|
||||
}
|
||||
|
||||
uint16_t namcos12_state::iob_p4_r()
|
||||
{
|
||||
return m_tssio_port_4;
|
||||
@ -1966,6 +1977,82 @@ void namcos12_boothack_state::aplarail(machine_config &config)
|
||||
config.set_maximum_quantum(attotime::from_hz(2*115200));
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
void namcos12_cdxa_state::cdxa_pcb(machine_config &config)
|
||||
{
|
||||
coh700(config);
|
||||
|
||||
NAMCOS12_CDXA(config, m_cdxa_pcb, XTAL(14'745'600));
|
||||
m_cdxa_pcb->add_route(0, "lspeaker", 0.30); // roughly matched the volume of speaking lines between the CDXA audio vs non-CDXA audio
|
||||
m_cdxa_pcb->add_route(1, "rspeaker", 0.30);
|
||||
m_cdxa_pcb->psx_int10_callback().set("maincpu:irq", FUNC(psxirq_device::intin10));
|
||||
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &namcos12_cdxa_state::cdxa_psx_map);
|
||||
}
|
||||
|
||||
void namcos12_cdxa_state::cdxa_psx_map(address_map &map)
|
||||
{
|
||||
namcos12_map(map);
|
||||
|
||||
map(0x1f7c0000, 0x1f7cffff).rw(m_cdxa_pcb, FUNC(namcos12_cdxa_device::sh2_ram_r), FUNC(namcos12_cdxa_device::sh2_ram_w));
|
||||
|
||||
map(0x1f7d6002, 0x1f7d6003).w(m_cdxa_pcb, FUNC(namcos12_cdxa_device::reset_sh2_w));
|
||||
map(0x1f7d6004, 0x1f7d600b).w(m_cdxa_pcb, FUNC(namcos12_cdxa_device::clockgen_w));
|
||||
map(0x1f7d6010, 0x1f7d6011).w(m_cdxa_pcb, FUNC(namcos12_cdxa_device::ide_sh2_enabled_w));
|
||||
map(0x1f7d6012, 0x1f7d6013).w(m_cdxa_pcb, FUNC(namcos12_cdxa_device::ide_ps1_enabled_w));
|
||||
// 1f7d6018 unknown, only set once to 1 between the "SH2 Reset" and "SH2 Pll Clock Set" steps during boot
|
||||
map(0x1f7d601a, 0x1f7d601b).w(m_cdxa_pcb, FUNC(namcos12_cdxa_device::sram_enabled_w));
|
||||
map(0x1f7d601e, 0x1f7d601f).w(m_cdxa_pcb, FUNC(namcos12_cdxa_device::ps1_int10_finished_w));
|
||||
|
||||
map(0x1f7d800a, 0x1f7d800b).lr16(NAME([] () {
|
||||
// Might be for the M148 PCB instead of CDXA PCB
|
||||
// Code loops until this returns 0x20 before it starts writing to 0x1f7d8000
|
||||
// Writes "55 x y z" to 0x1f7d8000 where x, y, z are related to the current I/O state
|
||||
// Maybe used for lights?
|
||||
return 0x20;
|
||||
}));
|
||||
|
||||
map(0x1f7e0000, 0x1f7e000f).rw(m_cdxa_pcb, FUNC(namcos12_cdxa_device::cdrom_cs0_r), FUNC(namcos12_cdxa_device::cdrom_cs0_w));
|
||||
// map(0x1f7e8000, 0x1f7e800f).rw(m_cdxa_pcb, FUNC(namcos12_cdxa_device::cdrom_cs1_r), FUNC(namcos12_cdxa_device::cdrom_cs1_w));
|
||||
// 1f7d7000 volume enabled/set? gets set to 6 between the "SH2 Volume Set" and "SH2 Trf Program" steps, after setting 4 volumes registers to 0x7e
|
||||
map(0x1f7f8000, 0x1f7f80ff).w(m_cdxa_pcb, FUNC(namcos12_cdxa_device::volume_w));
|
||||
}
|
||||
|
||||
void namcos12_cdxa_state::truckk(machine_config &config)
|
||||
{
|
||||
cdxa_pcb(config);
|
||||
|
||||
m_sub->read_adc<0>().set_ioport("STEER");
|
||||
m_sub->read_adc<1>().set_ioport("BRAKE");
|
||||
m_sub->read_adc<2>().set_ioport("GAS");
|
||||
|
||||
// Timer at 115200*16 for the jvs serial clock
|
||||
m_sub->sci_set_external_clock_period(0, attotime::from_hz(JVSCLOCK/8));
|
||||
|
||||
h83334_device &iocpu(H83334(config, "iocpu", JVSCLOCK));
|
||||
iocpu.set_addrmap(AS_PROGRAM, &namcos12_cdxa_state::jvsmap);
|
||||
|
||||
iocpu.write_sci_tx<0>().set(m_sub, FUNC(h8_device::sci_rx_w<0>));
|
||||
m_sub->write_sci_tx<0>().set(iocpu, FUNC(h8_device::sci_rx_w<0>));
|
||||
|
||||
config.set_maximum_quantum(attotime::from_hz(2*115200));
|
||||
}
|
||||
|
||||
void namcos12_cdxa_state::init_truckk()
|
||||
{
|
||||
init_alt_bank1();
|
||||
|
||||
/*
|
||||
HACK: Change order of code so that the status flags are set before DMA 5 is started
|
||||
Can be checked at 0x8001f6e4
|
||||
*/
|
||||
uint8_t temp[5 * 4];
|
||||
memcpy(temp, memregion( "maincpu:rom" )->base() + 0x376ec, sizeof(temp)); // copy the 5 instructions that initialize statuses before DMA 5 finishes
|
||||
memcpy(memregion( "maincpu:rom" )->base() + 0x376e4 + sizeof(temp), memregion( "maincpu:rom" )->base() + 0x376e4, 2 * 4); // move the 2 DMA start call instructions below where the initialization code will go
|
||||
memcpy(memregion( "maincpu:rom" )->base() + 0x376e4, temp, sizeof(temp)); // write initialization code in new spot
|
||||
}
|
||||
|
||||
static INPUT_PORTS_START( namcos12 )
|
||||
PORT_START("DSW")
|
||||
PORT_DIPNAME( 0x0080, 0x0080, DEF_STR(Service_Mode) ) PORT_DIPLOCATION( "DIP SW2:1" )
|
||||
@ -2186,6 +2273,66 @@ static INPUT_PORTS_START( aplarail )
|
||||
PORT_BIT(0xff, IP_ACTIVE_LOW, IPT_UNKNOWN)
|
||||
INPUT_PORTS_END
|
||||
|
||||
static INPUT_PORTS_START( truckk )
|
||||
PORT_START("DSW")
|
||||
PORT_BIT( 0xffff, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||
|
||||
PORT_START("IN0")
|
||||
PORT_BIT( 0xfc23, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_NAME("Select Up")
|
||||
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_NAME("Select Down")
|
||||
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_START1 )
|
||||
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Horn")
|
||||
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("View Change")
|
||||
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Music Next")
|
||||
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Music Back")
|
||||
|
||||
PORT_START("IN1")
|
||||
PORT_BIT( 0x1fff, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_COIN1 )
|
||||
PORT_SERVICE( 0x4000, IP_ACTIVE_LOW )
|
||||
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_SERVICE1 )
|
||||
|
||||
PORT_START("GAS")
|
||||
PORT_BIT( 0x3ff, 0x0200, IPT_PEDAL ) PORT_SENSITIVITY(100) PORT_KEYDELTA(10) PORT_NAME("Gas Pedal") PORT_REVERSE
|
||||
|
||||
PORT_START("BRAKE")
|
||||
PORT_BIT( 0x3ff, 0x0200, IPT_PEDAL2 ) PORT_SENSITIVITY(100) PORT_KEYDELTA(10) PORT_NAME("Brake Pedal") PORT_REVERSE
|
||||
|
||||
PORT_START("STEER")
|
||||
PORT_BIT( 0x3ff, 0x0200, IPT_PADDLE ) PORT_SENSITIVITY(100) PORT_KEYDELTA(20) PORT_NAME("Steering Wheel")
|
||||
INPUT_PORTS_END
|
||||
|
||||
static INPUT_PORTS_START( ujlnow )
|
||||
PORT_START("DSW")
|
||||
PORT_BIT( 0xffff, IP_ACTIVE_LOW, IPT_UNKNOWN )
|
||||
|
||||
PORT_START("IN0")
|
||||
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(1) PORT_NAME("P1 Chin Switch (C)")
|
||||
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1) PORT_NAME("P1 Joe Switch (J)")
|
||||
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_NAME("Select Down")
|
||||
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_NAME("Select Up")
|
||||
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("P1 Circle / Enter") // The cabinet enter switch is linked to the P1 circle input as per the manual (bottom of pg 33)
|
||||
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("P1 Cross")
|
||||
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("P1 Triangle")
|
||||
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START1 )
|
||||
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(2) PORT_NAME("P2 Chin Switch (C)")
|
||||
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(2) PORT_NAME("P2 Joe Switch (J)")
|
||||
PORT_BIT( 0x0c00, IP_ACTIVE_HIGH, IPT_UNKNOWN ) // Must be high to get rid of I/O errors
|
||||
PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("P2 Circle")
|
||||
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_NAME("P2 Cross")
|
||||
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_NAME("P2 Triangle")
|
||||
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START2 )
|
||||
|
||||
PORT_START("IN1")
|
||||
PORT_BIT( 0x13ff, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||
PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_NAME("P2 Square")
|
||||
PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("P1 Square")
|
||||
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_COIN1 )
|
||||
PORT_SERVICE( 0x4000, IP_ACTIVE_LOW )
|
||||
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_SERVICE1 )
|
||||
INPUT_PORTS_END
|
||||
|
||||
ROM_START( aquarush )
|
||||
ROM_REGION32_LE( 0x00400000, "maincpu:rom", 0 ) /* main prg */
|
||||
ROM_LOAD16_BYTE( "aq1vera.2l", 0x0000000, 0x200000, CRC(91eb9258) SHA1(30e225eb551bfe1bed6b342dd6d597345d64b677) )
|
||||
@ -3338,8 +3485,8 @@ ROM_START( truckk )
|
||||
ROM_REGION( 0x20000, "iocpu", 0) /* Truck K. I/O board */
|
||||
ROM_LOAD( "tkk1prg0.ic7", 0x000000, 0x020000, CRC(11fd9c31) SHA1(068b8364ec0eb1e88f9f85f40b8b322876f6f3e2) )
|
||||
|
||||
DISK_REGION( "cdrom" )
|
||||
DISK_IMAGE( "tkk2-a", 0, SHA1(6b7c3686b22a508c44f67295b188504b757dd482) )
|
||||
DISK_REGION( "cdxa_pcb:ata:0:cdrom" )
|
||||
DISK_IMAGE_READONLY( "tkk2-a", 0, SHA1(6b7c3686b22a508c44f67295b188504b757dd482) )
|
||||
ROM_END
|
||||
|
||||
ROM_START( technodr )
|
||||
@ -3396,6 +3543,31 @@ ROM_START( aplarail )
|
||||
ROM_LOAD( "at28c16", 0x000000, 0x000800, CRC(db1b63c5) SHA1(01fc3386a2d1cb1bed1b7fd9bd2fd59e503832d3) )
|
||||
ROM_END
|
||||
|
||||
ROM_START( ujlnow )
|
||||
ROM_REGION32_LE( 0x00400000, "maincpu:rom", 0 ) /* main prg */
|
||||
ROM_LOAD16_BYTE( "ul1vera.2l", 0x000000, 0x200000, CRC(40251bc3) SHA1(377a156d738b29d8f19d9696a261cc6e3470ee3e) )
|
||||
ROM_LOAD16_BYTE( "ul1vera.2p", 0x000001, 0x200000, CRC(98181955) SHA1(febd73361d0de10282a850611b5f966a99eecdec) )
|
||||
|
||||
ROM_REGION32_LE( 0x2000000, "bankedroms", 0 ) /* main data */
|
||||
ROM_LOAD16_BYTE( "ul1rom0l.ic12", 0x0000000, 0x800000, CRC(7a77cffd) SHA1(6bd18837f475615061be73ee6d1bc09726e96fb5) )
|
||||
ROM_LOAD16_BYTE( "ul1rom0u.ic11", 0x0000001, 0x800000, CRC(1fdb34b3) SHA1(3773b3fb1574a0b4acebfaf510c75fa117394ae4) )
|
||||
ROM_LOAD16_BYTE( "ul1rom1l.ic10", 0x1000000, 0x800000, CRC(2d300d8c) SHA1(eabd0b4525530e5b33a6d85fa4d959e88c6fbd42) )
|
||||
ROM_LOAD16_BYTE( "ul1rom1u.ic9", 0x1000001, 0x800000, CRC(a4762002) SHA1(0faadc04bcc32e4f805069af8e635765a0b77ca9) )
|
||||
|
||||
ROM_REGION( 0x0080000, "sub", 0 ) /* sound prg */
|
||||
ROM_LOAD16_WORD_SWAP( "ul1vera.11s", 0x000000, 0x080000, CRC(2f466df3) SHA1(6468089c6cf3e056a30fa04274056ff2c9a01d5b) )
|
||||
|
||||
ROM_REGION( 0x1000000, "c352", 0 ) /* samples */
|
||||
ROM_LOAD( "ul1wave0.ic2", 0x0000000, 0x800000, CRC(4efbff5d) SHA1(add4caf9aa9443707bcb6cf9ebad0a5a59900ca9) )
|
||||
ROM_LOAD( "ul1wave1.ic1", 0x0800000, 0x800000, CRC(ad512f4c) SHA1(cfbecaad13a2239be0e697f3f9856401f11a1bc5) )
|
||||
|
||||
ROM_REGION( 0x80000, "m148", 0) /* M148 EMI DRIVE PCB */
|
||||
ROM_LOAD( "ul1spro.10c", 0x000000, 0x080000, CRC(1bd0e763) SHA1(07e9ad77bb983fcb4e4e6f66fbe55808b5a27d2e) )
|
||||
|
||||
DISK_REGION( "cdxa_pcb:ata:0:cdrom" )
|
||||
DISK_IMAGE_READONLY( "ul1-a", 0, SHA1(676f2c530f8d422ab9895ea04a43b2e9272fb8f8) )
|
||||
ROM_END
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
@ -3446,13 +3618,14 @@ GAME( 1999, ohbakyuun, ghlpanic, ptblank2, ghlpanic, namcos12_boothack_state, i
|
||||
GAME( 1999, pacapp2, 0, coh700, namcos12, namcos12_boothack_state, init_namcos12, ROT0, "Produce / Namco", "Paca Paca Passion 2 (Japan, PKS1/VER.A)", 0 ) /* KC046 */
|
||||
GAME( 1999, mrdrillr, 0, coh700, namcos124w,namcos12_boothack_state, init_namcos12, ROT0, "Namco", "Mr. Driller (US, DRI3/VER.A2)", 0 ) /* KC048 */
|
||||
GAME( 1999, mrdrillrj, mrdrillr, coh700, namcos124w,namcos12_boothack_state, init_namcos12, ROT0, "Namco", "Mr. Driller (Japan, DRI1/VER.A2)", 0 ) /* KC048 */
|
||||
GAME( 1999, ujlnow, 0, cdxa_pcb, ujlnow, namcos12_cdxa_state, init_alt_bank1,ROT0, "Namco", "Um Jammer Lammy NOW! (Japan, UL1/VER.A)", 0 ) /* KC049 */
|
||||
GAME( 1999, kaiunqz, 0, coh700, namcos12, namcos12_state, init_alt_bank1,ROT0, "Namco", "Kaiun Quiz (Japan, KW1/VER.A)", 0 ) /* KC050 */
|
||||
GAME( 1999, pacappsp, 0, coh700, namcos12, namcos12_boothack_state, init_namcos12, ROT0, "Produce / Namco", "Paca Paca Passion Special (Japan, PSP1/VER.A)", 0 ) /* KC052 */
|
||||
GAME( 1999, aquarush, 0, coh700, namcos12, namcos12_state, init_namcos12, ROT0, "Namco", "Aqua Rush (Japan, AQ1/VER.A1)", 0 ) /* KC053 */
|
||||
GAME( 1999, golgo13, 0, golgo13, golgo13, namcos12_boothack_state, init_alt_bank1,ROT0, "Eighting / Raizing / Namco", "Golgo 13 (Japan, GLG1/VER.A)", 0 ) /* KC054 */
|
||||
GAME( 2000, g13knd, 0, golgo13, golgo13, namcos12_boothack_state, init_alt_bank1,ROT0, "Eighting / Raizing / Namco", "Golgo 13 Kiseki no Dandou (Japan, GLS1/VER.A)", 0 ) /* KC059 */
|
||||
GAME( 2000, sws2000, 0, coh700, namcos12, namcos12_boothack_state, init_namcos12, ROT0, "Namco", "Super World Stadium 2000 (Japan, SS01/VER.A)", MACHINE_NOT_WORKING ) /* KC055 */
|
||||
GAME( 2000, truckk, 0, truckk, namcos12, namcos12_boothack_state, init_alt_bank1,ROT0, "Metro / Namco", "Truck Kyosokyoku (Japan, TKK2/VER.A)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* KC056 */
|
||||
GAME( 2000, truckk, 0, truckk, truckk, namcos12_cdxa_state, init_truckk, ROT0, "Metro / Namco", "Truck Kyosokyoku (Japan, TKK2/VER.A)", MACHINE_IMPERFECT_SOUND ) /* KC056 */
|
||||
GAME( 2000, kartduel, 0, kartduel, kartduel, namcos12_boothack_state, init_namcos12, ROT0, "Gaps / Namco", "Kart Duel (World, KTD2/VER.A)", MACHINE_NOT_WORKING ) /* KC057 */
|
||||
GAME( 2000, kartduelj, kartduel, kartduel, kartduel, namcos12_boothack_state, init_namcos12, ROT0, "Gaps / Namco", "Kart Duel (Japan, KTD1/VER.A)", MACHINE_NOT_WORKING ) /* KC057 */
|
||||
GAME( 2001, sws2001, sws2000, coh716, namcos12, namcos12_boothack_state, init_alt_bank1,ROT0, "Namco", "Super World Stadium 2001 (Japan, SS11/VER.A)", MACHINE_NOT_WORKING ) /* KC061 */
|
||||
|
256
src/mame/namco/namcos12_cdxa.cpp
Normal file
256
src/mame/namco/namcos12_cdxa.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
Namco System 12 CDXA PCB
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "namcos12_cdxa.h"
|
||||
|
||||
#include "bus/ata/atapicdr.h"
|
||||
|
||||
// Any drive as long as the ident name starts with "TOSHIB" will do, but this is the one that's used with CDXA games specifically
|
||||
DECLARE_DEVICE_TYPE(TOSHIBA_XM6402B_CDROM, toshiba_xm6402b_cdrom_device)
|
||||
|
||||
class toshiba_xm6402b_cdrom_device : public atapi_fixed_cdrom_device
|
||||
{
|
||||
public:
|
||||
toshiba_xm6402b_cdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: atapi_fixed_cdrom_device(mconfig, TOSHIBA_XM6402B_CDROM, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void device_start() override
|
||||
{
|
||||
atapi_fixed_cdrom_device::device_start();
|
||||
|
||||
std::fill_n(&m_identify_buffer[27], ' ', 47 - 27);
|
||||
|
||||
const char cdrom_ident_name[] = "TOSHIBA CD-ROM XM-6402B ";
|
||||
for (int i = 0; i < strlen(cdrom_ident_name) / 2; i++)
|
||||
m_identify_buffer[27 + i] = (cdrom_ident_name[i * 2] << 8) | cdrom_ident_name[i * 2 + 1];
|
||||
}
|
||||
};
|
||||
|
||||
DEFINE_DEVICE_TYPE(TOSHIBA_XM6402B_CDROM, toshiba_xm6402b_cdrom_device, "toshiba_xm6402b_cdrom", "Toshiba XM-6402B CD-ROM")
|
||||
|
||||
///
|
||||
|
||||
DEFINE_DEVICE_TYPE(NAMCOS12_CDXA, namcos12_cdxa_device, "namcos12_cdxa", "Namco System 12 CDXA PCB")
|
||||
|
||||
|
||||
namcos12_cdxa_device::namcos12_cdxa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
device_t(mconfig, NAMCOS12_CDXA, tag, owner, clock)
|
||||
, m_maincpu(*this, "cdxa_cpu")
|
||||
, m_cram(*this, "cram")
|
||||
, m_sram(*this, "sram")
|
||||
, m_ata(*this, "ata")
|
||||
, m_lc78836m(*this, "lc78836m")
|
||||
, m_mb87078(*this, "mb87078")
|
||||
, m_icd2061a(*this, "icd2061a")
|
||||
, m_psx_int10_cb(*this)
|
||||
{
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_ide_sh2_enabled));
|
||||
save_item(NAME(m_ide_ps1_enabled));
|
||||
save_item(NAME(m_sram_enabled));
|
||||
save_item(NAME(m_psx_int10_busy));
|
||||
save_item(NAME(m_audio_cur_bit));
|
||||
save_item(NAME(m_volume_write_counter));
|
||||
save_item(NAME(m_audio_lrck));
|
||||
|
||||
m_lc78836m->cksl1_w(1); // configure for 448 fs for 37800hz. setting to 0 gives 384 fs to make 44100hz
|
||||
m_lc78836m->cksl2_w(0); // these are all grounded
|
||||
m_lc78836m->fs1_w(0);
|
||||
m_lc78836m->fs2_w(0);
|
||||
m_lc78836m->emp_w(0);
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::device_reset()
|
||||
{
|
||||
m_ide_sh2_enabled = m_ide_ps1_enabled = false;
|
||||
m_sram_enabled = false;
|
||||
m_psx_int10_busy = false;
|
||||
m_audio_cur_bit = 0;
|
||||
m_volume_write_counter = 0;
|
||||
m_audio_lrck = 1; // start with left channel first
|
||||
|
||||
m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
SH2_SH7014(config, m_maincpu, XTAL(14'745'600));
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &namcos12_cdxa_device::sh7014_map);
|
||||
|
||||
ATA_INTERFACE(config, m_ata).options([] (device_slot_interface &device) { device.option_add("cdrom", TOSHIBA_XM6402B_CDROM); }, "cdrom", nullptr, true);
|
||||
|
||||
LC78836M(config, m_lc78836m, XTAL(16'934'400));
|
||||
|
||||
MB87078(config, m_mb87078);
|
||||
m_mb87078->gain_changed().set(FUNC(namcos12_cdxa_device::mb87078_gain_changed));
|
||||
|
||||
// fudge the input clock for clockgen slightly so the sample rate becomes an even 37800hz instead of 37806hz, otherwise audio has a slight crackle
|
||||
ICD2061A(config, m_icd2061a, 14'742'890);
|
||||
m_icd2061a->vclkout_changed().set([this] (uint32_t clock) {
|
||||
m_maincpu->sci_set_external_clock_period<0>(attotime::from_hz(clock * 16 / 448));
|
||||
m_lc78836m->set_clock(clock / 2);
|
||||
});
|
||||
|
||||
m_maincpu->sci_set_send_full_data_transmit_on_sync_hack<0>(true);
|
||||
m_maincpu->sci_tx_w<0>().set(FUNC(namcos12_cdxa_device::audio_dac_w));
|
||||
m_maincpu->write_portb().set(FUNC(namcos12_cdxa_device::portb_w));
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::sh7014_map(address_map &map)
|
||||
{
|
||||
map(0x00000000, 0x0003ffff).ram().share("cram"); // 128k x8 SRAM (x2) connected directly to both the SH2 and C448
|
||||
map(0x00400000, 0x0040ffff).ram().share("sram"); // 32k x8 SRAM (x2) connected via the C448 chip
|
||||
map(0x0041601c, 0x0041601f).w(FUNC(namcos12_cdxa_device::trigger_psx_int10_w));
|
||||
// 417000 ?
|
||||
map(0x0041c000, 0x0041c003).nopw().r(FUNC(namcos12_cdxa_device::cdrom_status_flag_r));
|
||||
map(0x00c00000, 0x00c1ffff).rw(FUNC(namcos12_cdxa_device::sh2_cdrom_cs0_r), FUNC(namcos12_cdxa_device::sh2_cdrom_cs0_w));
|
||||
|
||||
// Definitely is cs1 but hooking it up breaks the CD drive state seemingly due to timing issues.
|
||||
// The code sets cs1 control reg to 0xe, causing it go into the software reset routine immediately.
|
||||
// The game's code wants to immediately send a command for IDE_COMMAND_CHECK_POWER_MODE after setting cs1, but MAME rejects
|
||||
// all commands immediately after SRST is set so it gets stuck in an infinite loop waiting for the status register to become
|
||||
// 8 (IDE_STATUS_DRDY) so it can finish sending the rest of the check power mode command.
|
||||
// Things seem to work fine without it being hooked up so this is for documentation purposes.
|
||||
// map(0x00c20000, 0x00c3ffff).rw(FUNC(namcos12_cdxa_device::sh2_cdrom_cs1_r), FUNC(namcos12_cdxa_device::sh2_cdrom_cs1_w));
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::reset_sh2_w(uint16_t data)
|
||||
{
|
||||
if (data == 1)
|
||||
m_maincpu->pulse_input_line(INPUT_LINE_RESET, attotime::zero);
|
||||
}
|
||||
|
||||
uint32_t namcos12_cdxa_device::sh2_ram_r(offs_t offset)
|
||||
{
|
||||
auto r = m_sram_enabled ? m_sram : m_cram;
|
||||
return rotl_32(r[offset], 16);
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::sh2_ram_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
mem_mask = rotl_32(mem_mask, 16);
|
||||
data = rotl_32(data, 16);
|
||||
|
||||
if (!m_sram_enabled)
|
||||
COMBINE_DATA(&m_cram[offset]);
|
||||
|
||||
COMBINE_DATA(&m_sram[offset]);
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::sram_enabled_w(uint16_t data)
|
||||
{
|
||||
m_sram_enabled = data != 0;
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::ide_sh2_enabled_w(uint16_t data)
|
||||
{
|
||||
// The SH2 is allowed to use the IDE device
|
||||
// In the code it's one or the other so this and cdxa_ide_ps1_enabled_w might be mutually exclusive
|
||||
m_ide_sh2_enabled = data != 0;
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::ide_ps1_enabled_w(uint16_t data)
|
||||
{
|
||||
// The PS1 is allowed to access the CD-ROM directly, uses the 0x1f7e0000-0x1f7e000f registers
|
||||
// truckk does not use this feature so it can't be tested, but the code exists in truckk to use it so its usage can at least be confirmed
|
||||
m_ide_ps1_enabled = data != 0;
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::ps1_int10_finished_w(uint16_t data)
|
||||
{
|
||||
m_psx_int10_busy = false;
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::trigger_psx_int10_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
m_psx_int10_cb(1);
|
||||
m_psx_int10_busy = true;
|
||||
}
|
||||
|
||||
uint16_t namcos12_cdxa_device::cdrom_status_flag_r(offs_t offset, uint16_t mem_mask)
|
||||
{
|
||||
// Needs to return 0x800 for it to signal the interrupt for the PS1
|
||||
// Guessed
|
||||
return m_psx_int10_busy ? 0 : 0x800;
|
||||
}
|
||||
|
||||
uint16_t namcos12_cdxa_device::sh2_cdrom_cs0_r(offs_t offset, uint16_t mem_mask)
|
||||
{
|
||||
return m_ata->cs0_r(offset >> 13, mem_mask);
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::sh2_cdrom_cs0_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
m_ata->cs0_w(offset >> 13, data, mem_mask);
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::volume_w(offs_t offset, uint16_t data)
|
||||
{
|
||||
// The data/pins to be held low/high is encoded into the memory address
|
||||
m_volume_write_counter ^= 1;
|
||||
m_mb87078->data_w(m_volume_write_counter, offset & 0xff);
|
||||
}
|
||||
|
||||
uint16_t namcos12_cdxa_device::cdrom_cs0_r(offs_t offset, uint16_t mem_mask)
|
||||
{
|
||||
return m_ata->cs0_r(offset, mem_mask);
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::cdrom_cs0_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
m_ata->cs0_w(offset, data, mem_mask);
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::mb87078_gain_changed(offs_t offset, uint8_t data)
|
||||
{
|
||||
m_lc78836m->set_output_gain(offset, m_mb87078->gain_factor_r(offset));
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::audio_dac_w(int state)
|
||||
{
|
||||
m_lc78836m->bclk_w(0);
|
||||
m_lc78836m->lrck_w(m_audio_lrck);
|
||||
m_lc78836m->data_w(state);
|
||||
m_lc78836m->bclk_w(1);
|
||||
|
||||
m_audio_cur_bit++;
|
||||
|
||||
if (m_audio_cur_bit >= 16) {
|
||||
m_audio_lrck ^= 1;
|
||||
m_audio_cur_bit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::portb_w(uint16_t data)
|
||||
{
|
||||
m_lc78836m->mute_w(BIT(data, 6));
|
||||
}
|
||||
|
||||
void namcos12_cdxa_device::clockgen_w(offs_t offset, uint16_t data)
|
||||
{
|
||||
switch (offset) {
|
||||
case 0:
|
||||
m_icd2061a->data_w(0);
|
||||
break;
|
||||
case 1:
|
||||
m_icd2061a->data_w(1);
|
||||
break;
|
||||
case 2:
|
||||
m_icd2061a->clk_w(0);
|
||||
break;
|
||||
case 3:
|
||||
m_icd2061a->clk_w(1);
|
||||
break;
|
||||
}
|
||||
}
|
93
src/mame/namco/namcos12_cdxa.h
Normal file
93
src/mame/namco/namcos12_cdxa.h
Normal file
@ -0,0 +1,93 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
Namco System 12 CDXA PCB
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_NAMCO_NAMCOS12_CDXA_H
|
||||
#define MAME_NAMCO_NAMCOS12_CDXA_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bus/ata/ataintf.h"
|
||||
#include "cpu/sh/sh7014.h"
|
||||
#include "machine/icd2061a.h"
|
||||
#include "machine/mb87078.h"
|
||||
#include "sound/lc78836m.h"
|
||||
|
||||
|
||||
class namcos12_cdxa_device : public device_t
|
||||
{
|
||||
public:
|
||||
namcos12_cdxa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
template <typename... T> void add_route(T &&... args) { m_lc78836m.lookup()->add_route(std::forward<T>(args)...); }
|
||||
|
||||
auto psx_int10_callback() { return m_psx_int10_cb.bind(); }
|
||||
|
||||
void psx_map(address_map &map);
|
||||
|
||||
uint32_t sh2_ram_r(offs_t offset);
|
||||
void sh2_ram_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
|
||||
void reset_sh2_w(uint16_t data);
|
||||
|
||||
void ide_sh2_enabled_w(uint16_t data);
|
||||
|
||||
void ide_ps1_enabled_w(uint16_t data);
|
||||
|
||||
void sram_enabled_w(uint16_t data);
|
||||
|
||||
void ps1_int10_finished_w(uint16_t data);
|
||||
|
||||
void volume_w(offs_t offset, uint16_t data);
|
||||
|
||||
void clockgen_w(offs_t offset, uint16_t data);
|
||||
|
||||
uint16_t cdrom_cs0_r(offs_t offset, uint16_t mem_mask = ~0);
|
||||
void cdrom_cs0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
private:
|
||||
void sh7014_map(address_map &map);
|
||||
|
||||
void audio_dac_w(int state);
|
||||
|
||||
void portb_w(uint16_t data);
|
||||
|
||||
uint16_t cdrom_status_flag_r(offs_t offset, uint16_t mem_mask = ~0);
|
||||
void trigger_psx_int10_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint16_t sh2_cdrom_cs0_r(offs_t offset, uint16_t mem_mask = ~0);
|
||||
void sh2_cdrom_cs0_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
void mb87078_gain_changed(offs_t offset, uint8_t data);
|
||||
|
||||
required_device<sh2_sh7014_device> m_maincpu;
|
||||
required_shared_ptr<uint32_t> m_cram;
|
||||
required_shared_ptr<uint32_t> m_sram;
|
||||
required_device<ata_interface_device> m_ata;
|
||||
required_device<lc78836m_device> m_lc78836m;
|
||||
required_device <mb87078_device> m_mb87078;
|
||||
required_device <icd2061a_device> m_icd2061a;
|
||||
devcb_write_line m_psx_int10_cb;
|
||||
|
||||
bool m_ide_sh2_enabled, m_ide_ps1_enabled;
|
||||
bool m_sram_enabled;
|
||||
bool m_psx_int10_busy;
|
||||
|
||||
uint8_t m_audio_cur_bit;
|
||||
uint8_t m_audio_lrck;
|
||||
|
||||
uint8_t m_volume_write_counter;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(NAMCOS12_CDXA, namcos12_cdxa_device)
|
||||
|
||||
#endif // MAME_NAMCO_NAMCOS12_CDXA_H
|
Loading…
Reference in New Issue
Block a user