summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/cpu.lua20
-rw-r--r--scripts/target/mame/arcade.lua4
-rw-r--r--scripts/target/mame/mess.lua2
-rw-r--r--src/devices/cpu/avr8/avr8.cpp8
-rw-r--r--src/devices/cpu/dspp/dspp.cpp2646
-rw-r--r--src/devices/cpu/dspp/dspp.h337
-rw-r--r--src/devices/cpu/dspp/dsppdasm.cpp124
-rw-r--r--src/devices/cpu/dspp/dsppdasm.h22
-rw-r--r--src/devices/cpu/dspp/dsppdrc.cpp970
-rw-r--r--src/devices/cpu/dspp/dsppfe.cpp625
-rw-r--r--src/devices/cpu/dspp/dsppfe.h72
-rw-r--r--src/devices/cpu/powerpc/ppc.h2
-rw-r--r--src/devices/cpu/powerpc/ppccom.cpp49
-rw-r--r--src/devices/cpu/powerpc/ppccom.h5
-rw-r--r--src/devices/cpu/powerpc/ppcdrc.cpp37
-rw-r--r--src/devices/cpu/powerpc/ppcfe.cpp2
-rw-r--r--src/devices/machine/netlist.h6
-rw-r--r--src/devices/machine/spg2xx.cpp148
-rw-r--r--src/devices/machine/spg2xx.h56
-rw-r--r--src/devices/machine/t10mmc.cpp28
-rw-r--r--src/devices/sound/discrete.h7
-rw-r--r--src/devices/sound/okim6295.h10
-rw-r--r--src/mame/audio/mario.cpp30
-rw-r--r--src/mame/drivers/konamim2.cpp2211
-rw-r--r--src/mame/drivers/m14.cpp6
-rw-r--r--src/mame/drivers/norautp.cpp217
-rw-r--r--src/mame/drivers/osi.cpp90
-rw-r--r--src/mame/drivers/popeye.cpp3
-rw-r--r--src/mame/drivers/tattack.cpp6
-rw-r--r--src/mame/drivers/vii.cpp532
-rw-r--r--src/mame/drivers/vsmile.cpp383
-rw-r--r--src/mame/includes/mario.h2
-rw-r--r--src/mame/includes/norautp.h2
-rw-r--r--src/mame/machine/3dom2.cpp2091
-rw-r--r--src/mame/machine/3dom2.h1137
-rw-r--r--src/mame/machine/3dom2_defs.h695
-rw-r--r--src/mame/machine/3dom2_te.cpp3959
-rw-r--r--src/mame/mame.lst11
-rw-r--r--src/mame/mess.flt2
39 files changed, 14731 insertions, 1826 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua
index 081269edf63..08fe95f7f68 100644
--- a/scripts/src/cpu.lua
+++ b/scripts/src/cpu.lua
@@ -66,6 +66,26 @@ if (CPUS["8X300"]~=null or _OPTIONS["with-tools"]) then
end
--------------------------------------------------
+-- 3DO Don's Super Performing Processor (DSPP)
+--@src/devices/cpu/dspp/dspp.h,CPUS["DSPP"] = true
+--------------------------------------------------
+
+if (CPUS["DSPP"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/cpu/dspp/dspp.cpp",
+ MAME_DIR .. "src/devices/cpu/dspp/dspp.h",
+ MAME_DIR .. "src/devices/cpu/dspp/dsppdrc.cpp",
+ MAME_DIR .. "src/devices/cpu/dspp/dsppfe.cpp",
+ MAME_DIR .. "src/devices/cpu/dspp/dsppfe.h",
+ }
+end
+
+if (CPUS["DSPP"]~=null or _OPTIONS["with-tools"]) then
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/dspp/dsppdasm.cpp")
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/dspp/dsppdasm.h")
+end
+
+--------------------------------------------------
-- ARCangent A4
--@src/devices/cpu/arc/arc.h,CPUS["ARC"] = true
--------------------------------------------------
diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua
index 488ca2ce776..7d6828db223 100644
--- a/scripts/target/mame/arcade.lua
+++ b/scripts/target/mame/arcade.lua
@@ -132,6 +132,7 @@ CPUS["HMCS40"] = true
--CPUS["HPHYBRID"] = true
--CPUS["SM510"] = true
CPUS["ST62XX"] = true
+CPUS["DSPP"] = true
--------------------------------------------------
-- specify available sound cores
@@ -2360,6 +2361,9 @@ files {
MAME_DIR .. "src/mame/machine/konamigx.cpp",
MAME_DIR .. "src/mame/video/konamigx.cpp",
MAME_DIR .. "src/mame/drivers/konamim2.cpp",
+ MAME_DIR .. "src/mame/machine/3dom2.cpp",
+ MAME_DIR .. "src/mame/machine/3dom2.h",
+ MAME_DIR .. "src/mame/machine/3dom2_te.cpp",
MAME_DIR .. "src/mame/drivers/konblands.cpp",
MAME_DIR .. "src/mame/drivers/konmedal.cpp",
MAME_DIR .. "src/mame/drivers/konmedal68k.cpp",
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index d84b897709f..753c100681b 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -136,6 +136,7 @@ CPUS["MB86901"] = true
CPUS["NANOPROCESSOR"] = true
CPUS["CLIPPER"] = true
CPUS["CAPRICORN"] = true
+--CPUS["DSPP"] = true
--------------------------------------------------
-- specify available sound cores; some of these are
@@ -3607,6 +3608,7 @@ files {
MAME_DIR .. "src/mame/audio/socrates.cpp",
MAME_DIR .. "src/mame/audio/socrates.h",
MAME_DIR .. "src/mame/drivers/inteladv.cpp",
+ MAME_DIR .. "src/mame/drivers/vsmile.cpp",
}
createMESSProjects(_target, _subtarget, "wang")
diff --git a/src/devices/cpu/avr8/avr8.cpp b/src/devices/cpu/avr8/avr8.cpp
index 1ba0a67c2f3..5bc83e55511 100644
--- a/src/devices/cpu/avr8/avr8.cpp
+++ b/src/devices/cpu/avr8/avr8.cpp
@@ -877,8 +877,7 @@ void avr8_device::device_reset()
//-------------------------------------------------
// memory_space_config - return the configuration
-// of the specified address space, or nullptr if
-// the space doesn't exist
+// of the CPU's address spaces
//-------------------------------------------------
device_memory_interface::space_config_vector avr8_device::memory_space_config() const
@@ -915,11 +914,6 @@ void avr8_device::state_string_export(const device_state_entry &entry, std::stri
}
-//-------------------------------------------------
-// disassemble - call the disassembly
-// helper function
-//-------------------------------------------------
-
std::unique_ptr<util::disasm_interface> avr8_device::create_disassembler()
{
return std::make_unique<avr8_disassembler>();
diff --git a/src/devices/cpu/dspp/dspp.cpp b/src/devices/cpu/dspp/dspp.cpp
new file mode 100644
index 00000000000..d8d8e7055e1
--- /dev/null
+++ b/src/devices/cpu/dspp/dspp.cpp
@@ -0,0 +1,2646 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ dspp.c
+
+ Core implementation for the portable 3DO (M2) DSPP emulator.
+ DSPP = Don's Super Performing Processor
+
+***************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+#include "dspp.h"
+#include "dsppfe.h"
+#include "dsppdasm.h"
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+enum
+{
+ DSPP_PC = 1,
+ DSPP_ACC,
+ DSPP_FLAGS,
+ DSPP_CLOCK,
+};
+
+
+// DRC
+#define SINGLE_INSTRUCTION_MODE (0)
+
+
+#define CACHE_SIZE (4 * 1024 * 1024) // FIXME
+// FIXME!!!
+/* compilation boundaries -- how far back/forward does the analysis extend? */
+#define COMPILE_BACKWARDS_BYTES 128
+#define COMPILE_FORWARDS_BYTES 512
+#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4))
+#define COMPILE_MAX_SEQUENCE 64
+
+/* exit codes */
+#define EXECUTE_OUT_OF_CYCLES 0
+#define EXECUTE_MISSING_CODE 1
+#define EXECUTE_UNMAPPED_CODE 2
+#define EXECUTE_RESET_CACHE 3
+
+
+
+
+//**************************************************************************
+// MACROS
+//**************************************************************************
+
+//#define DSPI_FLAG_CC_CARRY 0x0001
+//#define DSPI_FLAG_CC_ZERO 0x0002
+//#define DSPI_FLAG_CC_NEG 0x0004
+//#define DSPI_FLAG_CC_OVER 0x0008
+//#define DSPI_FLAG_CC_EXACT 0x0010
+//#define DSPI_FLAG_AUDLOCK 0x0020
+//#define DSPI_FLAG_SLEEP 0x0040
+//#define DSPI_FLAG_CC_MASK 0x001f
+
+#define DSPX_CONTROL_GWILLING 0x0001
+#define DSPX_CONTROL_STEP_CYCLE 0x0002
+#define DSPX_CONTROL_STEP_PC 0x0004
+#define DSPX_CONTROL_SNOOP 0x0008
+
+#define DSPX_RESET_DSPP 0x0001
+#define DSPX_RESET_INPUT 0x0002
+#define DSPX_RESET_OUTPUT 0x0004
+
+#define DSPX_F_DMA_NEXTVALID 0x0001
+#define DSPX_F_DMA_GO_FOREVER 0x0002
+#define DSPX_F_INT_DMANEXT_EN 0x0004
+#define DSPX_F_SHADOW_SET_DMANEXT 0x00040000
+#define DSPX_F_SHADOW_SET_FOREVER 0x00020000
+#define DSPX_F_SHADOW_SET_NEXTVALID 0x00010000
+#define DSPX_F_SHADOW_SET_ADDRESS_COUNT 0x80000000
+
+#define DSPX_F_INT_TIMER 0x00000100
+#define DSPX_F_INT_INPUT_UNDER 0x00000080
+#define DSPX_F_INT_INPUT_OVER 0x00000040
+#define DSPX_F_INT_OUTPUT_UNDER 0x00000020
+#define DSPX_F_INT_OUTPUT_OVER 0x00000010
+#define DSPX_F_INT_UNDEROVER 0x00000008
+#define DSPX_F_INT_CONSUMED 0x00000002
+#define DSPX_F_INT_DMANEXT 0x00000001
+
+#define DSPX_F_INT_ALL_DMA (DSPX_F_INT_DMANEXT | DSPX_F_INT_CONSUMED | DSPX_F_INT_UNDEROVER)
+
+#define DSPX_FLD_INT_SOFT_WIDTH 16 /* width of the field and the number of interrupts */
+#define DSPX_FLD_INT_SOFT_SHIFT 16
+#define DSPX_FLD_INT_SOFT_MASK (0xffff0000)
+
+
+
+//**************************************************************************
+// INTERNAL MEMORY MAPS
+//**************************************************************************
+
+void dspp_device::code_map(address_map &map)
+{
+ map(0x000, 0x3ff).ram();
+}
+
+void dspp_device::data_map(address_map &map)
+{
+ map(0x000, 0x2df).ram();
+ map(0x2f0, 0x2f1).r(FUNC(dspp_device::input_r));
+ map(0x2e0, 0x2e7).w(FUNC(dspp_device::output_w));
+ map(0x300, 0x37f).rw(FUNC(dspp_device::fifo_osc_r), FUNC(dspp_device::fifo_osc_w));
+ map(0x3bc, 0x3bc).nopr(); // ?
+ map(0x3d6, 0x3d6).w(FUNC(dspp_device::input_control_w));
+ map(0x3d7, 0x3d7).w(FUNC(dspp_device::output_control_w));
+ map(0x3de, 0x3de).r(FUNC(dspp_device::input_status_r));
+ map(0x3df, 0x3df).r(FUNC(dspp_device::output_status_r));
+ map(0x3e6, 0x3e6).w(FUNC(dspp_device::cpu_int_w));
+ map(0x3ee, 0x3ee).rw(FUNC(dspp_device::pc_r), FUNC(dspp_device::pc_w));
+ map(0x3f6, 0x3f6).rw(FUNC(dspp_device::audlock_r), FUNC(dspp_device::audlock_w));
+ map(0x3f7, 0x3f7).rw(FUNC(dspp_device::clock_r), FUNC(dspp_device::clock_w));
+ map(0x3ff, 0x3ff).r(FUNC(dspp_device::noise_r));
+}
+
+
+
+//**************************************************************************
+// DEVICE INTERFACE
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(DSPP, dspp_device, "dspp", "3DO DSPP")
+
+//-------------------------------------------------
+// dspp_device - constructor
+//-------------------------------------------------
+
+dspp_device::dspp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : dspp_device(mconfig, DSPP, tag, owner, clock, address_map_constructor(FUNC(dspp_device::code_map), this),
+ address_map_constructor(FUNC(dspp_device::data_map), this))
+{
+}
+
+dspp_device::dspp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor code_map_ctor, address_map_constructor data_map_ctor)
+ : cpu_device(mconfig, type, tag, owner, clock),
+ m_int_handler(*this),
+ m_dma_read_handler(*this),
+ m_dma_write_handler(*this),
+ m_code_config("code", ENDIANNESS_BIG, 16, 10, -1, code_map_ctor),
+ m_data_config("data", ENDIANNESS_BIG, 16, 10, -1, data_map_ctor),
+ m_code(nullptr),
+ m_data(nullptr),
+ m_output_fifo_start(0),
+ m_output_fifo_count(0),
+ m_dspx_control(0),
+ m_dspx_reset(0),
+ m_dspx_int_enable(0),
+ m_dspx_channel_enable(0),
+ m_dspx_channel_complete(0),
+ m_dspx_channel_direction(0),
+ m_dspx_channel_8bit(0),
+ m_dspx_channel_sqxd(0),
+ m_dspx_shadow_current_addr(0),
+ m_dspx_shadow_current_count(0),
+ m_dspx_shadow_next_addr(0),
+ m_dspx_shadow_next_count(0),
+ m_dspx_dmanext_int(0),
+ m_dspx_dmanext_enable(0),
+ m_dspx_consumed_int(0),
+ m_dspx_consumed_enable(0),
+ m_dspx_underover_int(0),
+ m_dspx_underover_enable(0),
+ m_dspx_audio_time(0),
+ m_dspx_audio_duration(0),
+ m_cache(CACHE_SIZE),
+ m_drcuml(nullptr),
+ m_drcfe(nullptr),
+ m_drcoptions(0)
+{
+#if 0
+ memset(m_core->m_stack, 0, sizeof(m_core->m_stack));
+ memset(m_core->m_rbase, 0, sizeof(m_core->m_rbase));
+ memset(m_outputs, 0, sizeof(m_outputs));
+ memset(m_output_fifo, 0, sizeof(m_output_fifo));
+ memset(m_fifo_dma, 0, sizeof(m_fifo_dma));
+#endif
+}
+
+
+//-------------------------------------------------
+// device_start - start up the device
+//-------------------------------------------------
+
+void dspp_device::device_start()
+{
+ // DSPP DRC is not yet ready for prime time
+ m_isdrc = false;//allow_drc();
+
+ m_core = (dspp_internal_state *)m_cache.alloc_near(sizeof(dspp_internal_state));
+ memset(m_core, 0, sizeof(dspp_internal_state));
+
+ uint32_t flags = 0;
+ m_drcuml = std::make_unique<drcuml_state>(*this, m_cache, flags, 1, 16, 0);
+
+ m_drcfe = std::make_unique<dspp_frontend>(this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE);
+
+ // Resolve our callbacks
+ m_int_handler.resolve_safe();
+ m_dma_read_handler.resolve_safe(0);
+ m_dma_write_handler.resolve_safe();
+
+ // Get our address spaces
+ m_code = &space(AS_PROGRAM);
+ m_data = &space(AS_DATA);
+ auto code_cache = m_code->cache<1, -1, ENDIANNESS_BIG>();
+ m_code_cache = code_cache;
+ m_codeptr = [code_cache](offs_t address) -> const void * { return code_cache->read_ptr(address); };
+
+ // Register our state for the debugger
+ state_add(DSPP_PC, "PC", m_core->m_pc);
+ state_add(DSPP_ACC, "ACC", m_core->m_acc);
+ state_add(STATE_GENPC, "GENPC", m_core->m_pc).noshow();
+#if 0
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_core->m_flags).callimport().callexport().formatstr("%6s").noshow();
+ state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow();
+ state_add(STATE_GENSP, "GENSP", m_src2val[REGBASE + 31]).noshow();
+
+ state_add(DSPP_PS, "PS", m_core->m_flagsio).callimport().callexport();
+ for (int regnum = 0; regnum < 32; regnum++)
+ state_add(DSPP_R0 + regnum, tempstr.format("R%d", regnum), m_src2val[REGBASE + regnum]);
+#endif
+
+ // Register our state for saving
+ save_item(NAME(m_core->m_pc));
+ save_item(NAME(m_core->m_stack));
+ save_item(NAME(m_core->m_stack_ptr));
+ save_item(NAME(m_core->m_rbase));
+ save_item(NAME(m_core->m_acc));
+ save_item(NAME(m_core->m_tclock));
+
+ save_item(NAME(m_core->m_flag_carry));
+ save_item(NAME(m_core->m_flag_zero));
+ save_item(NAME(m_core->m_flag_neg));
+ save_item(NAME(m_core->m_flag_over));
+ save_item(NAME(m_core->m_flag_exact));
+ save_item(NAME(m_core->m_flag_audlock));
+ save_item(NAME(m_core->m_flag_sleep));
+
+ save_item(NAME(m_outputs));
+ save_item(NAME(m_output_fifo_start));
+ save_item(NAME(m_output_fifo_count));
+
+ for (uint32_t i = 0; i < NUM_DMA_CHANNELS; ++i)
+ {
+ save_item(NAME(m_fifo_dma[i].m_current_addr), i);
+ save_item(NAME(m_fifo_dma[i].m_current_count), i);
+ save_item(NAME(m_fifo_dma[i].m_next_addr), i);
+ save_item(NAME(m_fifo_dma[i].m_next_count), i);
+ save_item(NAME(m_fifo_dma[i].m_prev_value), i);
+ save_item(NAME(m_fifo_dma[i].m_prev_current), i);
+ save_item(NAME(m_fifo_dma[i].m_go_forever), i);
+ save_item(NAME(m_fifo_dma[i].m_next_valid), i);
+ save_item(NAME(m_fifo_dma[i].m_reserved), i);
+ save_item(NAME(m_fifo_dma[i].m_fifo), i);
+ save_item(NAME(m_fifo_dma[i].m_dma_ptr), i);
+ save_item(NAME(m_fifo_dma[i].m_dspi_ptr), i);
+ save_item(NAME(m_fifo_dma[i].m_depth), i);
+ }
+
+ save_item(NAME(m_last_frame_clock));
+ save_item(NAME(m_last_osc_count));
+ save_item(NAME(m_osc_phase));
+ save_item(NAME(m_osc_freq));
+
+ save_item(NAME(m_core->m_partial_int));
+
+ save_item(NAME(m_dspx_control));
+ save_item(NAME(m_dspx_reset));
+ save_item(NAME(m_dspx_int_enable));
+ save_item(NAME(m_dspx_channel_enable));
+ save_item(NAME(m_dspx_channel_complete));
+ save_item(NAME(m_dspx_channel_direction));
+ save_item(NAME(m_dspx_channel_8bit));
+ save_item(NAME(m_dspx_channel_sqxd));
+ save_item(NAME(m_dspx_shadow_current_addr));
+ save_item(NAME(m_dspx_shadow_current_count));
+ save_item(NAME(m_dspx_shadow_next_addr));
+ save_item(NAME(m_dspx_shadow_next_count));
+ save_item(NAME(m_dspx_dmanext_int));
+ save_item(NAME(m_dspx_dmanext_enable));
+ save_item(NAME(m_dspx_consumed_int));
+ save_item(NAME(m_dspx_consumed_enable));
+ save_item(NAME(m_dspx_underover_int));
+ save_item(NAME(m_dspx_underover_enable));
+ save_item(NAME(m_dspx_audio_time));
+ save_item(NAME(m_dspx_audio_duration));
+
+ // Set our instruction counter
+ set_icountptr(m_core->m_icount);
+
+ m_cache_dirty = true;
+}
+
+
+//-------------------------------------------------
+// device_reset - reset the device
+//-------------------------------------------------
+
+void dspp_device::device_reset()
+{
+ // initialize the state
+ m_core->m_pc = 0;
+ m_core->m_stack_ptr = 0;
+ m_output_fifo_start = 0;
+ m_output_fifo_count = 0;
+
+ m_core->m_flag_audlock = 0;
+ m_core->m_flag_sleep = 0;
+ m_core->m_stack_ptr = 0;
+ m_core->m_writeback = ~1; // TODO
+ set_rbase(0, 0);
+
+ // TODO: CLEAR DMA CHANNELS
+
+ // Clear interrupts
+ m_core->m_partial_int = 0;
+ update_host_interrupt();
+
+ m_cache_dirty = true;
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return the configuration
+// of the CPU's address spaces
+//-------------------------------------------------
+
+device_memory_interface::space_config_vector dspp_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_code_config),
+ std::make_pair(AS_DATA, &m_data_config)
+ };
+}
+
+
+//-------------------------------------------------
+// state_import - import state into the device,
+// after it has been set
+//-------------------------------------------------
+
+void dspp_device::state_import(const device_state_entry &entry)
+{
+
+}
+
+
+//-------------------------------------------------
+// state_export - export state from the device,
+// to a known location where it can be read
+//-------------------------------------------------
+
+void dspp_device::state_export(const device_state_entry &entry)
+{
+
+}
+
+
+//-------------------------------------------------
+// state_string_export - export state as a string
+// for the debugger
+//-------------------------------------------------
+
+void dspp_device::state_string_export(const device_state_entry &entry, std::string &str) const
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ str = string_format("%c%c.%c%c%c%c%c",
+ m_core->m_flag_audlock ? 'A' : '.',
+ m_core->m_flag_sleep ? 'S' : '.',
+ m_core->m_flag_carry ? 'C' : '.',
+ m_core->m_flag_zero ? 'Z' : '.',
+ m_core->m_flag_neg ? 'N' : '.',
+ m_core->m_flag_over ? 'V' : '.',
+ m_core->m_flag_exact ? 'E' : '.');
+ break;
+ }
+}
+
+std::unique_ptr<util::disasm_interface> dspp_device::create_disassembler()
+{
+ return std::make_unique<dspp_disassembler>();
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// update_pc -
+//-------------------------------------------------
+
+inline void dspp_device::update_pc()
+{
+ ++m_core->m_pc;
+}
+
+inline void dspp_device::update_ticks()
+{
+ --m_core->m_tclock;
+ --m_core->m_icount;
+}
+
+
+//-------------------------------------------------
+// readop - Read an opcode at the given address
+//-------------------------------------------------
+
+uint16_t dspp_device::read_op(offs_t pc)
+{
+ return m_code_cache->read_word(pc);
+}
+
+
+//-------------------------------------------------
+// read_data - Read a word from the data space
+//-------------------------------------------------
+
+inline uint16_t dspp_device::read_data(offs_t addr)
+{
+ return m_data->read_word(addr);
+}
+
+
+//-------------------------------------------------
+// write_data - Write a word to the data space
+//-------------------------------------------------
+
+inline void dspp_device::write_data(offs_t addr, uint16_t data)
+{
+ m_data->write_word(addr, data);
+}
+
+
+//-------------------------------------------------
+// get_interrupt_state -
+//-------------------------------------------------
+
+uint32_t dspp_device::get_interrupt_state()
+{
+ uint32_t host_int = m_core->m_partial_int;
+
+ if (m_dspx_dmanext_int & m_dspx_dmanext_enable)
+ host_int |= DSPX_F_INT_DMANEXT;
+
+ if (m_dspx_consumed_int & m_dspx_consumed_enable)
+ host_int |= DSPX_F_INT_CONSUMED;
+
+ return host_int;
+}
+
+
+//-------------------------------------------------
+// update_host_interrupt -
+//-------------------------------------------------
+
+void dspp_device::update_host_interrupt()
+{
+ // TODO: Underflow/overflow interrupts
+ m_int_handler(get_interrupt_state() & m_dspx_int_enable ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// parse_operand - Parse instruction operands
+//-------------------------------------------------
+
+void dspp_device::parse_operands(uint32_t numops)
+{
+ uint32_t addr, val = 0xBAD;
+ uint32_t opidx = 0;
+ uint32_t operand = 0;
+ uint32_t numregs = 0;
+
+ for (uint32_t i = 0; i < MAX_OPERANDS; ++i)
+ {
+ // Reset operands
+ m_operands[i].value = -1;
+ m_operands[i].addr = -1;
+ }
+
+ // Reset global op index
+ m_core->m_opidx = 0;
+
+ while (opidx < numops)
+ {
+ operand = read_op(m_core->m_pc);
+ update_pc();
+ update_ticks();
+
+ if (operand & 0x8000)
+ {
+ // Immediate value
+ if ((operand & 0xc000) == 0xc000)
+ {
+ val = operand & 0x1fff;
+
+ if (operand & 0x2000)
+ {
+ // Left justify
+ val = val << 3;
+ }
+ else
+ {
+ // Sign extend if right justified
+ if (val & 0x1000)
+ val |= 0xe000;
+ }
+ m_operands[opidx++].value = val;
+ }
+ else if((operand & 0xe000) == 0x8000)
+ {
+ // Address operand
+ addr = operand & 0x03ff;
+
+ if (operand & 0x0400)
+ {
+ // Indirect
+ addr = read_data(addr);
+ }
+ m_operands[opidx].addr = addr;
+
+ if (operand & 0x0800)
+ {
+ // Write Back
+ m_core->m_writeback = addr;
+ }
+ ++opidx;
+ }
+ else if ((operand & 0xe000) == 0xa000)
+ {
+ // 1 or 2 register operand
+ numregs = (operand & 0x0400) ? 2 : 1;
+ }
+ }
+ else
+ {
+ numregs = 3;
+ }
+
+ if (numregs > 0)
+ {
+ uint32_t shifter, regdi;
+
+ // Shift successive register operands from a single operand word
+ for (uint32_t i = 0; i < numregs; ++i)
+ {
+ shifter = ((numregs - i) - 1) * 5;
+ regdi = (operand >> shifter) & 0x1f;
+ addr = translate_reg(regdi & 0xf);
+
+ if (regdi & 0x0010)
+ {
+ // Indirect?
+ addr = read_data(addr);
+ }
+
+ if (numregs == 2)
+ {
+ if ((i == 0) && (operand & 0x1000))
+ m_core->m_writeback = addr;
+ else if ((i == 1) && (operand & 0x0800))
+ m_core->m_writeback = addr;
+ }
+ else if (numregs == 1)
+ {
+ if (operand & 0x800)
+ m_core->m_writeback = addr;
+ }
+
+ m_operands[opidx++].addr = addr;
+ }
+ numregs = 0;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// read_next_operand - Return the value encoded by
+// the next operand
+//-------------------------------------------------
+
+uint16_t dspp_device::read_next_operand()
+{
+ int32_t value = m_operands[m_core->m_opidx].value;
+
+ if (value < 0)
+ value = read_data(m_operands[m_core->m_opidx].addr);
+
+ // Next operand
+ ++m_core->m_opidx;
+
+ return value;
+}
+
+
+//-------------------------------------------------
+// write_next_operand - Write to the address
+// encoded by the next operand
+//-------------------------------------------------
+
+void dspp_device::write_next_operand(uint16_t value)
+{
+ int32_t addr = m_operands[m_core->m_opidx].addr;
+
+ assert(addr != -1);
+
+ write_data(addr, value);
+
+ // Advance to the next operand
+ ++m_core->m_opidx;
+}
+
+
+//-------------------------------------------------
+// push_pc - Push program counter onto the stack
+//-------------------------------------------------
+
+inline void dspp_device::push_pc()
+{
+ if (m_core->m_stack_ptr < PC_STACK_DEPTH)
+ m_core->m_stack[m_core->m_stack_ptr++] = m_core->m_pc;
+ else
+ fatalerror("DSPP stack overflow!");
+}
+
+
+//-------------------------------------------------
+// pop_pc - Pop program counter from the stack
+//-------------------------------------------------
+
+inline uint16_t dspp_device::pop_pc()
+{
+ if (m_core->m_stack_ptr == 0)
+ fatalerror("DSPP stack underflow!");
+
+ return m_core->m_stack[--m_core->m_stack_ptr];
+}
+
+
+//-------------------------------------------------
+// set_rbase - Set register address base
+//-------------------------------------------------
+
+inline void dspp_device::set_rbase(uint32_t base, uint32_t addr)
+{
+ switch (base)
+ {
+ case 4:
+ m_core->m_rbase[1] = addr + 4 - base;
+ break;
+ case 0:
+ m_core->m_rbase[0] = addr;
+ m_core->m_rbase[1] = addr + 4 - base;
+ // Intentional fall-through
+ case 8:
+ m_core->m_rbase[2] = addr + 8 - base;
+
+ case 12:
+ m_core->m_rbase[3] = addr + 12 - base;
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// translate_reg - Translate register address
+//-------------------------------------------------
+
+inline uint16_t dspp_device::translate_reg(uint16_t reg)
+{
+ uint32_t base = (reg >> 2) & 3;
+ return m_core->m_rbase[base] + reg - (reg & ~3);
+}
+
+
+
+//**************************************************************************
+// CORE EXECUTION
+//**************************************************************************
+
+//-------------------------------------------------
+// execute_min_cycles - return minimum number of
+// cycles it takes for one instruction to execute
+//-------------------------------------------------
+
+uint32_t dspp_device::execute_min_cycles() const
+{
+ return 1;
+}
+
+
+//-------------------------------------------------
+// execute_max_cycles - return maximum number of
+// cycles it takes for one instruction to execute
+//-------------------------------------------------
+
+uint32_t dspp_device::execute_max_cycles() const
+{
+ return 5; // TODO ?
+}
+
+
+//-------------------------------------------------
+// execute_run - core execution loop
+//-------------------------------------------------
+
+void dspp_device::execute_run()
+{
+ if (m_isdrc)
+ {
+ // TODO: TEMPORARY HACK!
+ if (m_dspx_control & DSPX_CONTROL_GWILLING)
+ execute_run_drc();
+ else
+ m_core->m_icount = 0;
+ return;
+ }
+
+ bool check_debugger = ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) != 0);
+
+ do
+ {
+ update_ticks();
+ update_fifo_dma();
+
+ // Only run if enabled
+ if (m_dspx_control & DSPX_CONTROL_GWILLING)
+ {
+ if (check_debugger)
+ debugger_instruction_hook(m_core->m_pc);
+
+ m_core->m_op = read_op(m_core->m_pc);
+ update_pc();
+
+ // Decode and execute
+ if (m_core->m_op & 0x8000)
+ exec_control();
+ else
+ exec_arithmetic();
+ }
+
+ } while (m_core->m_icount > 0);
+}
+
+
+
+//**************************************************************************
+// OPCODE IMPLEMENTATIONS
+//**************************************************************************
+
+//-------------------------------------------------
+// exec_super_special - Execute a super special
+// control op
+//-------------------------------------------------
+
+inline void dspp_device::exec_super_special()
+{
+ uint32_t sel = (m_core->m_op >> 7) & 7;
+
+ switch (sel)
+ {
+ case 1: // BAC
+ {
+ m_core->m_pc = m_core->m_acc >> 4;
+ break;
+ }
+ case 4: // RTS
+ {
+ m_core->m_pc = pop_pc();
+ break;
+ }
+ case 5: // OP_MASK
+ {
+ // TODO
+ break;
+ }
+
+ case 7: // SLEEP
+ {
+ // TODO: How does sleep work?
+ --m_core->m_pc;
+ m_core->m_flag_sleep = 1;
+ break;
+ }
+
+ case 0: // NOP
+ case 2: // Unused
+ case 3:
+ case 6:
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// exec_special - Execute a special control op
+//-------------------------------------------------
+
+inline void dspp_device::exec_special()
+{
+ switch ((m_core->m_op >> 10) & 7)
+ {
+ case 0:
+ {
+ exec_super_special();
+ break;
+ }
+ case 1: // JUMP
+ {
+ m_core->m_pc = m_core->m_op & 0x3ff;
+ break;
+ }
+ case 2: // JSR
+ {
+ push_pc();
+ m_core->m_pc = m_core->m_op & 0x3ff;
+ break;
+ }
+ case 3: // BFM
+ {
+ break;
+ }
+ case 4: // MOVEREG
+ {
+ uint32_t regdi = m_core->m_op & 0x3f;
+ uint32_t addr = translate_reg(regdi & 0xf);
+
+ // Indirect
+ if (regdi & 0x0010)
+ {
+ addr = read_data(addr);
+ break;
+ }
+
+ parse_operands(1);
+ write_data(addr, read_next_operand());
+ break;
+ }
+ case 5: // RBASE
+ {
+ set_rbase((m_core->m_op & 3) << 2, m_core->m_op & 0x3fc);
+ break;
+ }
+ case 6: // MOVED
+ {
+ parse_operands(1);
+ write_data(m_core->m_op & 0x3ff, read_next_operand());
+ break;
+ }
+ case 7: // MOVEI
+ {
+ parse_operands(1);
+ uint32_t addr = read_data(m_core->m_op & 0x3ff);
+ write_data(addr, read_next_operand());
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// exec_branch - Execute a branch control op
+//-------------------------------------------------
+
+void dspp_device::exec_branch()
+{
+ uint32_t mode = (m_core->m_op >> 13) & 3;
+ uint32_t select = (m_core->m_op >> 12) & 1;
+ uint32_t mask = (m_core->m_op >> 10) & 3;
+
+ bool flag0, flag1;
+
+ if (select == 0)
+ {
+ flag0 = m_core->m_flag_neg;
+ flag1 = m_core->m_flag_over;
+ }
+ else
+ {
+ flag0 = m_core->m_flag_carry;
+ flag1 = m_core->m_flag_zero;
+ }
+
+ bool mask0 = (mask & 2) != 0;
+ bool mask1 = (mask & 1) != 0;
+
+ bool branch = (flag0 || !mask0) && (flag1 || !mask1);
+
+ if (mode == 2)
+ branch = !branch;
+
+ if (branch)
+ m_core->m_pc = m_core->m_op & 0x3ff;
+}
+
+
+//-------------------------------------------------
+// exec_complex_branch - Execute a complex branch
+// control op
+//-------------------------------------------------
+
+inline void dspp_device::exec_complex_branch()
+{
+ uint32_t type = (m_core->m_op >> 10) & 7;
+
+ const bool c = m_core->m_flag_carry;
+ const bool z = m_core->m_flag_zero;
+ const bool n = m_core->m_flag_neg;
+ const bool v = m_core->m_flag_over;
+ const bool x = m_core->m_flag_exact;
+
+ bool branch = false;
+
+ switch (type)
+ {
+ case 0: // BLT
+ branch = (n && !v) || (!n && v);
+ break;
+ case 1: // BLE
+ branch = ((n && !v) || (!n && v)) || z;
+ break;
+ case 2: // BGE
+ branch = ((n && v) || (!n && !v));
+ break;
+ case 3: // BGT
+ branch = ((n && v) || (!n && !v)) && !z;
+ break;
+ case 4: // BHI
+ branch = c && !z;
+ break;
+ case 5: // BLS
+ branch = !c || z;
+ break;
+ case 6: // BXS
+ branch = x;
+ break;
+ case 7: // BXC
+ branch = !x;
+ break;
+ }
+
+ if (branch)
+ m_core->m_pc = m_core->m_op & 0x3ff;
+}
+
+
+//-------------------------------------------------
+// exec_control - Execute a control op
+//-------------------------------------------------
+
+inline void dspp_device::exec_control()
+{
+ uint32_t mode = (m_core->m_op >> 13) & 3;
+
+ switch (mode)
+ {
+ // Special
+ case 0:
+ {
+ exec_special();
+ break;
+ }
+
+ // Branches
+ case 1: case 2:
+ {
+ exec_branch();
+ break;
+ }
+
+ // Complex branches
+ case 3:
+ {
+ exec_complex_branch();
+ break;
+ }
+
+ default:
+ fatalerror("Invalid DSPP control instruction mode");
+ break;
+ }
+}
+
+//-------------------------------------------------
+// sign_extend8 - Sign extend 8-bits to 32-bits
+//-------------------------------------------------
+
+static inline int32_t sign_extend8(uint8_t val)
+{
+ return (int32_t)(int8_t)val;
+}
+
+
+//-------------------------------------------------
+// sign_extend16 - Sign extend 16-bits to 32-bits
+//-------------------------------------------------
+
+static inline int32_t sign_extend16(uint16_t val)
+{
+ return (int32_t)(int16_t)val;
+}
+
+
+//-------------------------------------------------
+// sign_extend20 - Sign extend 20-bits to 32-bits
+//-------------------------------------------------
+
+static inline int32_t sign_extend20(uint32_t val)
+{
+ if (val & 0x00080000)
+ return (int32_t)(0xfff00000 | val);
+ else
+ return (int32_t)val;
+}
+
+
+//-------------------------------------------------
+// exec_arithmetic - Execute an arithmetic op
+//-------------------------------------------------
+
+inline void dspp_device::exec_arithmetic()
+{
+ // Decode the various fields
+ uint32_t numops = (m_core->m_op >> 13) & 3;
+ uint32_t muxa = (m_core->m_op >> 10) & 3;
+ uint32_t muxb = (m_core->m_op >> 8) & 3;
+ uint32_t alu_op = (m_core->m_op >> 4) & 0xf;
+ uint32_t barrel_code = m_core->m_op & 0xf;
+
+ int32_t mul_res = 0;
+ uint32_t alu_res = 0;
+
+ // Check for operand overflow
+ if (numops == 0 && ((muxa == 1) || (muxa == 2) || (muxb == 1) || (muxb == 2)))
+ numops = 4;
+
+ // Implicit barrel shift
+ if (barrel_code == 8)
+ ++numops;
+
+ // Parse ops...
+ parse_operands(numops);
+
+ if (muxa == 3 || muxb == 3)
+ {
+ uint32_t mul_sel = (m_core->m_op >> 12) & 1;
+
+ int32_t op1 = sign_extend16(read_next_operand());
+ int32_t op2 = sign_extend16(mul_sel ? read_next_operand() : m_core->m_acc >> 4);
+
+ mul_res = (op1 * op2) >> 11;
+ }
+
+ int32_t alu_a, alu_b;
+
+ switch (muxa)
+ {
+ case 0:
+ {
+ alu_a = m_core->m_acc;
+ break;
+ }
+ case 1: case 2:
+ {
+ alu_a = read_next_operand() << 4;
+ break;
+ }
+ case 3:
+ {
+ alu_a = mul_res;
+ break;
+ }
+ }
+
+ switch (muxb)
+ {
+ case 0:
+ {
+ alu_b = m_core->m_acc;
+ break;
+ }
+ case 1: case 2:
+ {
+ alu_b = read_next_operand() << 4;
+ break;
+ }
+ case 3:
+ {
+ alu_b = mul_res;
+ break;
+ }
+ }
+
+ // For carry detection apparently
+ alu_a &= 0x00fffff;
+ alu_b &= 0x00fffff;
+
+ switch (alu_op)
+ {
+ case 0: // _TRA
+ {
+ alu_res = alu_a;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 1: // _NEG
+ {
+ alu_res = -alu_b;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 2: // _+
+ {
+ alu_res = alu_a + alu_b;
+ m_core->m_flag_over = (((alu_a & 0x80000) == (alu_b & 0x80000) && (alu_a & 0x80000) != (alu_res & 0x80000)));
+ m_core->m_flag_carry = (alu_res & 0x00100000) != 0;
+ break;
+ }
+ case 3: // _+C
+ {
+ alu_res = alu_a + (m_core->m_flag_carry << 4);
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = (alu_res & 0x00100000) != 0;
+ break;
+ }
+ case 4: // _-
+ {
+ alu_res = alu_a - alu_b;
+ m_core->m_flag_over = ((alu_a & 0x80000) == (~alu_b & 0x80000) && (alu_a & 0x80000) != (alu_res & 0x80000));
+ m_core->m_flag_carry = (alu_res & 0x00100000) != 0;
+ break;
+ }
+ case 5: // _-B
+ {
+ alu_res = alu_a - (m_core->m_flag_carry << 4);
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = (alu_res & 0x00100000) != 0;
+ break;
+ }
+ case 6: // _++
+ {
+ alu_res = alu_a + 1;
+ m_core->m_flag_over = !(alu_a & 0x80000) && (alu_res & 0x80000);
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 7: // _--
+ {
+ alu_res = alu_a - 1;
+ m_core->m_flag_over = (alu_a & 0x80000) && !(alu_res & 0x80000);
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 8: // _TRL
+ {
+ alu_res = alu_a;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 9: // _NOT
+ {
+ alu_res = ~alu_a;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 10: // _AND
+ {
+ alu_res = alu_a & alu_b;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 11: // _NAND
+ {
+ alu_res = ~(alu_a & alu_b);
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 12: // _OR
+ {
+ alu_res = alu_a | alu_b;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 13: // _NOR
+ {
+ alu_res = ~(alu_a | alu_b);
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 14: // _XOR
+ {
+ alu_res = alu_a ^ alu_b;
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ case 15: // _XNOR
+ {
+ alu_res = ~(alu_a ^ alu_b);
+ m_core->m_flag_over = 0;
+ m_core->m_flag_carry = 0;
+ break;
+ }
+ }
+
+ m_core->m_flag_neg = (alu_res & 0x00080000) != 0;
+ m_core->m_flag_zero = (alu_res & 0x000ffff0) == 0;
+ m_core->m_flag_exact = (alu_res & 0x0000000f) == 0;
+
+ // Barrel shift
+ static const int32_t shifts[8] = { 0, 1, 2, 3, 4, 5, 8, 16 };
+
+ if (barrel_code == 8)
+ barrel_code = read_next_operand();
+
+ if (barrel_code & 8)
+ {
+ // Right shift
+ uint32_t shift = shifts[(~barrel_code + 1) & 7];
+
+ if (alu_op < 8)
+ {
+ // Arithmetic
+ m_core->m_acc = sign_extend20(alu_res) >> shift;
+ }
+ else
+ {
+ // Logical
+ m_core->m_acc = (alu_res & 0xfffff) >> shift;
+ }
+
+ }
+ else
+ {
+ // Left shift
+ uint32_t shift = shifts[barrel_code];
+
+ if (shift == 16)
+ {
+ // Clip and saturate
+ if (m_core->m_flag_over)
+ m_core->m_acc = m_core->m_flag_neg ? 0x7ffff : 0xfff80000;
+ else
+ m_core->m_acc = sign_extend20(alu_res);
+ }
+ else
+ {
+ m_core->m_acc = sign_extend20(alu_res) << shift;
+ }
+ }
+
+ if (m_core->m_writeback >= 0)
+ {
+ write_data(m_core->m_writeback, m_core->m_acc >> 4);
+ m_core->m_writeback = -1;
+ }
+ else if (m_core->m_opidx < numops)
+ {
+ write_next_operand(m_core->m_acc >> 4);
+ }
+}
+
+
+
+//**************************************************************************
+// FIFO DMA
+//**************************************************************************
+
+//-------------------------------------------------
+// write_dma_to_fifo -
+//-------------------------------------------------
+
+void dspp_device::write_dma_to_fifo(int32_t channel, int16_t value)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ dma.m_fifo[dma.m_dma_ptr] = value;
+
+ if (dma.m_depth < DMA_FIFO_DEPTH)
+ {
+ dma.m_dma_ptr = (dma.m_dma_ptr + 1) & DMA_FIFO_MASK;
+ dma.m_depth += 1;
+ }
+ else
+ {
+ fatalerror("DMA TO FIFO OVERFLOW");
+ }
+}
+
+
+//-------------------------------------------------
+// write_dspp_to_fifo -
+//-------------------------------------------------
+
+void dspp_device::write_dspp_to_fifo(int32_t channel, int16_t value)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ dma.m_fifo[dma.m_dspi_ptr] = value;
+
+ if (dma.m_depth < DMA_FIFO_DEPTH)
+ {
+ dma.m_dspi_ptr = (dma.m_dspi_ptr + 1) & DMA_FIFO_MASK;
+ dma.m_depth += 1;
+ }
+ else
+ {
+ fatalerror("DSPP TO FIFO OVERFLOW");
+ }
+}
+
+
+//-------------------------------------------------
+// read_fifo_to_dspp -
+//-------------------------------------------------
+
+int16_t dspp_device::read_fifo_to_dspp(int32_t channel)
+{
+ int16_t data = 0;
+
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ if (dma.m_depth > 0)
+ {
+ data = dma.m_fifo[dma.m_dspi_ptr];
+
+ dma.m_dspi_ptr = (dma.m_dspi_ptr + 1) & DMA_FIFO_MASK;
+ --dma.m_depth;
+
+ if (dma.m_depth == 0)
+ {
+ // Set consumed interrupt
+ if (m_dspx_channel_complete & (1 << channel))
+ {
+ m_dspx_consumed_int |= 1 << channel;
+ update_host_interrupt();
+ }
+ }
+
+ dma.m_prev_current = data;
+ }
+ else
+ {
+ // TODO: Is this right?
+ m_dspx_underover_int |= 1 << channel;
+ update_host_interrupt();
+ data = dma.m_prev_current;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// read_fifo_to_dma -
+//-------------------------------------------------
+
+int16_t dspp_device::read_fifo_to_dma(int32_t channel)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ uint32_t data = dma.m_fifo[dma.m_dma_ptr];
+
+ if (dma.m_depth > 0)
+ {
+ dma.m_dma_ptr = (dma.m_dma_ptr + 1) & DMA_FIFO_MASK;
+ dma.m_depth -= 1;
+ }
+ else
+ {
+ //fatalerror("FIFO TO DMA UNDERFLOW");
+ }
+ return data;
+}
+
+
+//-------------------------------------------------
+// run_oscillator -
+//-------------------------------------------------
+
+void dspp_device::run_oscillator(int32_t channel)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ // Add phase increment
+ m_osc_phase += m_osc_freq;
+
+ // Extract two high bits to advance FIFO
+ uint32_t count = (m_osc_phase >> 15) & 3;
+
+ // Clip to positive phase
+ m_osc_phase &= 0x7fff;
+
+ // Advance FIFO if data present
+ if (count > dma.m_depth)
+ count = dma.m_depth;
+
+ for (uint32_t i = 0; i < count; ++i)
+ read_fifo_to_dspp(channel);
+
+ // Return count to program for counting samples
+ m_last_osc_count = count;
+}
+
+
+//-------------------------------------------------
+// advance_audio_timer -
+//-------------------------------------------------
+
+void dspp_device::advance_audio_timer()
+{
+ // Advance time on each frame count
+ ++m_dspx_audio_time;
+
+ // Interrupt on transition from 0 to 0xFFFF
+ if (--m_dspx_audio_duration == 0xffff)
+ {
+ m_core->m_partial_int |= DSPX_F_INT_TIMER;
+ update_host_interrupt();
+ }
+}
+
+
+//-------------------------------------------------
+// advance_audio_frame -
+//-------------------------------------------------
+
+void dspp_device::advance_audio_frame()
+{
+ m_last_frame_clock = m_clock;
+ advance_audio_timer();
+
+ if (m_core->m_flag_audlock)
+ {
+ device_reset();
+ }
+}
+
+
+//-------------------------------------------------
+// process_next_dma -
+//-------------------------------------------------
+
+void dspp_device::process_next_dma(int32_t channel)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ if (dma.m_current_count <= 0)
+ {
+ uint32_t chmask = 1 << channel;
+
+ if (dma.m_next_valid)
+ {
+ dma.m_current_addr = dma.m_next_addr;
+ dma.m_current_count = dma.m_next_count;
+
+ if (!dma.m_go_forever)
+ dma.m_next_valid = 0;
+
+ // Set completion bit
+ m_dspx_channel_complete &= ~chmask;
+ m_dspx_dmanext_int |= chmask;
+ update_host_interrupt();
+ }
+ else
+ {
+ // Disable the channel so we don't keep servicing it
+ m_dspx_channel_enable &= ~chmask;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// decode_sqxd - Decompress an SQXD coded sample
+//-------------------------------------------------
+
+int16_t dspp_device::decode_sqxd(int8_t data, int16_t prev)
+{
+ int16_t temp = sign_extend8(data & 0xfe);
+ int32_t expanded = (temp * abs(temp)) << 1;
+ int16_t output;
+
+ if (data & 1)
+ {
+ expanded = expanded >> 2;
+ output = expanded + prev;
+ }
+ else
+ {
+ output = expanded;
+ }
+
+ return output;
+}
+
+
+//-------------------------------------------------
+// service_output_dma -
+//-------------------------------------------------
+
+void dspp_device::service_output_dma(int32_t channel)
+{
+ fifo_dma & dma = m_fifo_dma[channel];
+
+ if (dma.m_current_count == 0)
+ return;
+
+ // Transfer a maximum of 4 samples per tick
+ uint32_t count = dma.m_current_count;
+
+ if (count > 4)
+ count = 4;
+
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ uint16_t sample = read_fifo_to_dma(channel);
+
+ m_dma_write_handler(dma.m_current_addr++, sample >> 8);
+ m_dma_write_handler(dma.m_current_addr++, sample & 0xff);
+ }
+
+ dma.m_current_count -= count;
+
+ process_next_dma(channel);
+}
+
+
+//-------------------------------------------------
+// service_input_dma -
+//-------------------------------------------------
+
+void dspp_device::service_input_dma(int32_t channel)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ if (dma.m_current_count == 0)
+ return;
+
+ // Transfer a maximum of 4 samples per tick
+ uint32_t count = dma.m_current_count;
+
+ if (count > 4)
+ count = 4;
+
+ // Determine sample format
+ bool is8bit = (m_dspx_channel_8bit & (1 << channel)) != 0;
+ bool isSQXD = (m_dspx_channel_sqxd & (1 << channel)) != 0;
+
+ if (is8bit)
+ {
+ // Fetch data from memory, {decompress}, and write to FIFO
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ int16_t sample;
+ int8_t curbyte = m_dma_read_handler(dma.m_current_addr++);
+
+ if (isSQXD)
+ {
+ printf("SQXD NOT TESTED!");
+
+ sample = decode_sqxd(curbyte, dma.m_prev_value);
+ dma.m_prev_value = sample;
+ }
+ else
+ {
+ sample = curbyte << 8;
+ }
+
+ write_dma_to_fifo(channel, sample);
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ int16_t sample;
+
+ sample = m_dma_read_handler(dma.m_current_addr++) << 8;
+ sample |= m_dma_read_handler(dma.m_current_addr++);
+
+ write_dma_to_fifo(channel, sample);
+ }
+ }
+
+ dma.m_current_count -= count;
+
+ process_next_dma(channel);
+}
+
+
+//-------------------------------------------------
+// update_fifo_dma -
+//-------------------------------------------------
+
+void dspp_device::update_fifo_dma()
+{
+ uint32_t mask = m_dspx_channel_enable & ~m_dspx_channel_complete;
+
+ while (mask != 0)
+ {
+ uint32_t channel = 31 - count_leading_zeros(mask);
+
+ const fifo_dma & dma = m_fifo_dma[channel];
+
+ if (m_dspx_channel_direction & (1 << channel))
+ {
+ if (dma.m_depth >= 4)
+ {
+ service_output_dma(channel);
+ break;
+ }
+ }
+ else
+ {
+ if (dma.m_depth <= 4)
+ {
+ service_input_dma(channel);
+ break;
+ }
+ }
+
+ mask &= (1 << channel) - 1;
+ }
+}
+
+
+//-------------------------------------------------
+// reset_channel
+//-------------------------------------------------
+
+void dspp_device::reset_channel(int32_t channel)
+{
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ m_dspx_channel_complete &= ~(1 << channel);
+
+ dma.m_dma_ptr = 0;
+ dma.m_dspi_ptr = 0;
+ dma.m_depth = 0;
+}
+
+
+
+//**************************************************************************
+// INTERNAL REGISTERS
+//**************************************************************************
+
+//-------------------------------------------------
+// input_r - Read digital input
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::input_r )
+{
+ // TODO
+ return 0;
+}
+
+
+//-------------------------------------------------
+// output_w - Write to the 8 output registers
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::output_w )
+{
+ m_outputs[offset] = data;
+}
+
+
+//-------------------------------------------------
+// fifo_osc_r -
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::fifo_osc_r )
+{
+ uint32_t data = 0;
+ uint32_t channel = offset / 8;
+
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ switch (offset & 7)
+ {
+ // DSPI_FIFO_OSC_OFFSET_CURRENT
+ case 0:
+ {
+ if (dma.m_depth == 0)
+ data = dma.m_prev_current;
+ else
+ data = dma.m_fifo[dma.m_dspi_ptr];
+
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_NEXT
+ case 1:
+ {
+ if (dma.m_depth == 0)
+ data = dma.m_prev_current;
+ else if (dma.m_depth == 1)
+ data = dma.m_fifo[dma.m_dspi_ptr];
+ else
+ data = dma.m_fifo[(dma.m_dspi_ptr + 1) & DMA_FIFO_MASK];
+
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_FREQUENCY
+ case 2:
+ {
+ data = m_last_osc_count;
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_PHASE
+ case 3:
+ {
+ data = m_osc_phase;
+ break;
+ }
+
+ // DSPI_FIFO_OFFSET_DATA
+ case 4:
+ {
+ data = read_fifo_to_dspp(channel);
+ break;
+ }
+
+ // DSPI_FIFO_OFFSET_CONTROL
+ case 5:
+ {
+ data = dma.m_depth;
+ break;
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// fifo_osc_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::fifo_osc_w )
+{
+ uint32_t channel = offset / 8;
+
+ switch (offset & 7)
+ {
+ // DSPI_FIFO_OSC_OFFSET_CURRENT
+ case 0:
+ {
+ // Read only
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_NEXT
+ case 1:
+ {
+ // Read only
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_FREQUENCY
+ case 2:
+ {
+ m_osc_freq = data;
+ run_oscillator(channel);
+ break;
+ }
+
+ // DSPI_FIFO_OSC_OFFSET_PHASE
+ case 3:
+ {
+ m_osc_phase = data;
+ break;
+ }
+
+ // DSPI_FIFO_OFFSET_DATA
+ case 4:
+ {
+ write_dspp_to_fifo(channel, data);
+ break;
+ }
+
+ // DSPI_FIFO_OFFSET_CONTROL
+ case 5:
+ {
+ // Read only
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// input_control_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::input_control_w )
+{
+ // TODO
+}
+
+
+//-------------------------------------------------
+// output_control_w -
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::output_control_w )
+{
+ // TODO
+ if (data & 1)
+ {
+ uint32_t end;
+
+ if (m_output_fifo_count == OUTPUT_FIFO_DEPTH)
+ {
+ // Overflow
+ end = (m_output_fifo_start + m_output_fifo_count) & OUTPUT_FIFO_MASK;
+
+ m_output_fifo_start = (m_output_fifo_start + 2) & OUTPUT_FIFO_MASK;
+
+ m_output_fifo[(end + 0) & OUTPUT_FIFO_MASK] = m_outputs[0];
+ m_output_fifo[(end + 1) & OUTPUT_FIFO_MASK] = m_outputs[1];
+ }
+ else
+ {
+ end = (m_output_fifo_start + m_output_fifo_count) & OUTPUT_FIFO_MASK;
+
+ m_output_fifo[(end + 0) & OUTPUT_FIFO_MASK] = m_outputs[0];
+ m_output_fifo[(end + 1) & OUTPUT_FIFO_MASK] = m_outputs[1];
+
+ // Advance and update FIFO status
+ m_output_fifo_count += 2;
+ }
+
+ advance_audio_frame();
+ }
+}
+
+
+//-------------------------------------------------
+// input_status_r - Read input state
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::input_status_r )
+{
+ // TODO: How should this work?
+ return 1;
+}
+
+
+//-------------------------------------------------
+// output_status_r - Return number of unread
+// entries in the output FIFO
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::output_status_r )
+{
+ return m_output_fifo_count;
+}
+
+
+//-------------------------------------------------
+// cpu_int_w - Host CPU soft interrupt
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::cpu_int_w )
+{
+ m_core->m_partial_int |= (data << DSPX_FLD_INT_SOFT_SHIFT) & DSPX_FLD_INT_SOFT_MASK;
+ update_host_interrupt();
+}
+
+
+//-------------------------------------------------
+// pc_r - Read program counter
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::pc_r )
+{
+ return m_core->m_pc;
+}
+
+
+//-------------------------------------------------
+// pc_w - Write program counter
+//-------------------------------------------------
+
+WRITE16_MEMBER(dspp_device:: pc_w )
+{
+ m_core->m_pc = data;
+}
+
+
+//-------------------------------------------------
+// audlock_r - Read Audio Lock status
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::audlock_r )
+{
+ return m_core->m_flag_audlock;
+}
+
+
+//-------------------------------------------------
+// audlock_w - Write Audio Lock status
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::audlock_w )
+{
+ m_core->m_flag_audlock = data & 1;
+}
+
+
+//-------------------------------------------------
+// clock_r - Read CPU tick counter
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::clock_r )
+{
+ return m_core->m_tclock;
+}
+
+
+//-------------------------------------------------
+// clock_w - Write CPU tick counter
+//-------------------------------------------------
+
+WRITE16_MEMBER( dspp_device::clock_w )
+{
+ m_core->m_tclock = data;
+}
+
+
+//-------------------------------------------------
+// noise_r - PRNG noise
+//-------------------------------------------------
+
+READ16_MEMBER( dspp_device::noise_r )
+{
+ // TODO: Obviously this isn't accurate
+ return machine().rand();
+}
+
+
+
+//**************************************************************************
+// EXTERNAL INTERFACE AND CONTROL REGISTERS
+//**************************************************************************
+
+//-------------------------------------------------
+// read_ext_control -
+//-------------------------------------------------
+
+uint32_t dspp_device::read_ext_control(offs_t offset)
+{
+ uint32_t data = 0;
+
+ switch (offset)
+ {
+ // DSPX_INTERRUPT_SET
+ case 0x4000/4:
+ // DSPX_INTERRUPT_CLR
+ case 0x4004/4:
+ {
+ data = get_interrupt_state();
+ break;
+ }
+
+ // DSPX_INTERRUPT_ENABLE
+ case 0x4008/4:
+ // DSPX_INTERRUPT_DISABLE
+ case 0x400C/4:
+ {
+ data = m_dspx_int_enable;
+ break;
+ }
+ // DSPX_INT_DMANEXT_SET
+ case 0x4010/4:
+ // DSPX_INT_DMANEXT_CLR
+ case 0x4014/4:
+ {
+ data = m_dspx_dmanext_int;
+ break;
+ }
+ // DSPX_INT_DMANEXT_ENABLE
+ case 0x4018/4:
+ {
+ data = m_dspx_dmanext_enable;
+ break;
+ }
+ // DSPX_INT_CONSUMED_SET
+ case 0x4020/4:
+ // DSPX_INT_CONSUMED_CLR
+ case 0x4024/4:
+ {
+ data = m_dspx_consumed_int;
+ break;
+ }
+ // DSPX_INT_CONSUMED_ENABLE
+ case 0x4028/4:
+ // DSPX_INT_CONSUMED_DISABLE
+ case 0x402c/4:
+ {
+ data = m_dspx_consumed_enable;
+ break;
+ }
+
+ // DSPX_INT_UNDEROVER_SET
+ case 0x4030/4:
+ // DSPX_INT_UNDEROVER_CLR
+ case 0x4034/4:
+ {
+ data = m_dspx_underover_int;
+ break;
+ }
+
+ // DSPX_INT_UNDEROVER_ENABLE
+ case 0x4038/4:
+ // DSPX_INT_UNDEROVER_DISABLE
+ case 0x403c/4:
+ {
+ data = m_dspx_underover_enable;
+ break;
+ }
+
+ // DSPX_CHANNEL_ENABLE
+ case 0x6000/4:
+ // DSPX_CHANNEL_DISABLE
+ case 0x6004/4:
+ {
+ data = m_dspx_channel_enable;
+ break;
+ }
+ // DSPX_CHANNEL_DIRECTION_SET
+ case 0x6008/4:
+ // DSPX_CHANNEL_DIRECTION_CLR
+ case 0x600c/4:
+ {
+ data = m_dspx_channel_direction;
+ break;
+ }
+ // DSPX_CHANNEL_8BIT_SET
+ case 0x6010/4:
+ // DSPX_CHANNEL_8BIT_CLR
+ case 0x6014/4:
+ {
+ data = m_dspx_channel_8bit;
+ break;
+ }
+ // DSPX_CHANNEL_SQXD_SET
+ case 0x6018/4:
+ // DSPX_CHANNEL_SQXD_CLR
+ case 0x601c/4:
+ {
+ data = m_dspx_channel_sqxd;
+ break;
+ }
+ // DSPX_CHANNEL_STATUS
+ case 0x603c/4:
+ {
+ data = m_dspx_channel_complete;
+ break;
+ }
+
+ // DSPX_FRAME_DOWN_COUNTER:
+ case 0x6040/4:
+ {
+ data = m_dspx_audio_duration;
+ break;
+ }
+ // DSPX_FRAME_UP_COUNTER:
+ case 0x6044/4:
+ {
+ data = m_dspx_audio_time;
+ break;
+ }
+
+ // AUDIO_CONFIG
+ case 0x6050/4:
+ {
+ break;
+ }
+ // AUDIN_CONFIG
+ case 0x6060/4:
+ {
+ break;
+ }
+ // AUDOUT_CONFIG
+ case 0x6068/4:
+ {
+ break;
+ }
+ // DSPX_CONTROL
+ case 0x6070/4:
+ {
+ data = m_dspx_control;
+ break;
+ }
+ default:
+ {
+ printf("DSPP: Unhandled external control read (%.4x)\n", offset << 2);
+ break;
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write_ext_control -
+//-------------------------------------------------
+
+void dspp_device::write_ext_control(offs_t offset, uint32_t data)
+{
+ switch (offset)
+ {
+ // DSPX_INTERRUPT_SET
+ case 0x4000/4:
+ {
+ m_core->m_partial_int |= data & ~DSPX_F_INT_ALL_DMA;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INTERRUPT_CLR
+ case 0x4004/4:
+ {
+ m_core->m_partial_int &= ~(data & ~DSPX_F_INT_ALL_DMA);
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INTERRUPT_ENABLE
+ case 0x4008/4:
+ {
+ m_dspx_int_enable |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INTERRUPT_DISABLE
+ case 0x400C/4:
+ {
+ m_dspx_int_enable &= ~data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_DMANEXT_SET
+ case 0x4010/4:
+ {
+ m_dspx_dmanext_int |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_DMANEXT_CLR
+ case 0x4014/4:
+ {
+ m_dspx_dmanext_int &= ~data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_DMANEXT_ENABLE
+ case 0x4018/4:
+ {
+ m_dspx_dmanext_enable |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_CONSUMED_SET
+ case 0x4020/4:
+ {
+ m_dspx_consumed_int |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_CONSUMED_CLR
+ case 0x4024/4:
+ {
+ m_dspx_consumed_int &= ~data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_CONSUMED_ENABLE
+ case 0x4028/4:
+ {
+ m_dspx_consumed_enable |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_CONSUMED_DISABLE
+ case 0x402c/4:
+ {
+ m_dspx_consumed_enable &= ~data;
+ update_host_interrupt();
+ break;
+ }
+
+ // DSPX_INT_UNDEROVER_SET
+ case 0x4030/4:
+ {
+ m_dspx_underover_int |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_UNDEROVER_CLR
+ case 0x4034/4:
+ {
+ m_dspx_underover_int &= ~data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_UNDEROVER_ENABLE
+ case 0x4038/4:
+ {
+ m_dspx_underover_enable |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_INT_UNDEROVER_DISABLE
+ case 0x403c/4:
+ {
+ m_dspx_underover_enable &= ~data;
+ update_host_interrupt();
+ break;
+ }
+
+ // DSPX_CHANNEL_ENABLE
+ case 0x6000/4:
+ {
+ m_dspx_channel_enable |= data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_CHANNEL_DISABLE
+ case 0x6004/4:
+ {
+ m_dspx_channel_enable &= ~data;
+ update_host_interrupt();
+ break;
+ }
+ // DSPX_CHANNEL_DIRECTION_SET
+ case 0x6008/4:
+ {
+ m_dspx_channel_direction |= data;
+ break;
+ }
+ // DSPX_CHANNEL_DIRECTION_CLR
+ case 0x600c/4:
+ {
+ m_dspx_channel_direction &= ~data;
+ break;
+ }
+ // DSPX_CHANNEL_8BIT_SET
+ case 0x6010/4:
+ {
+ m_dspx_channel_8bit |= data;
+ break;
+ }
+ // DSPX_CHANNEL_8BIT_CLR
+ case 0x6014/4:
+ {
+ m_dspx_channel_8bit &= ~data;
+ break;
+ }
+ // DSPX_CHANNEL_SQXD_SET
+ case 0x6018/4:
+ {
+ m_dspx_channel_sqxd |= data;
+ break;
+ }
+ // DSPX_CHANNEL_SQXD_CLR
+ case 0x601c/4:
+ {
+ m_dspx_channel_sqxd &= ~data;
+ break;
+ }
+ // DSPX_CHANNEL_RESET
+ case 0x6030/4:
+ {
+ for (uint32_t i = 0; i < NUM_DMA_CHANNELS; ++i)
+ {
+ if (data & (1 << i))
+ reset_channel(i);
+ }
+ break;
+ }
+
+ // DSPX_FRAME_DOWN_COUNTER:
+ case 0x6040/4:
+ {
+ m_dspx_audio_duration = data;
+ break;
+ }
+ // DSPX_FRAME_UP_COUNTER:
+ case 0x6044/4:
+ {
+ m_dspx_audio_time = data;
+ break;
+ }
+
+ // AUDIO_CONFIG
+ case 0x6050/4:
+ {
+ break;
+ }
+
+ // AUDIN_CONFIG
+ case 0x6060/4:
+ {
+ break;
+ }
+
+ // AUDOUT_CONFIG
+ case 0x6068/4:
+ {
+ break;
+ }
+
+ // DSPX_CONTROL
+ case 0x6070/4:
+ {
+ m_dspx_control = data;
+ break;
+ }
+
+ // DSPX_RESET
+ case 0x6074/4:
+ {
+ if (data & 1)
+ device_reset();
+
+ // TODO: DSPX_F_RESET_INPUT and DSPX_F_RESET_OUTPUT
+
+ break;
+ }
+ default:
+ {
+ printf("DSPP: Unhandled external control write (%.4x with %.8x)\n", offset << 2, data);
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// read - host CPU read from DSPP internals
+//-------------------------------------------------
+
+READ32_MEMBER( dspp_device::read )
+{
+ if (offset < 0x1000/4)
+ {
+ // 16-bit code memory
+ return m_code->read_word(offset);
+ }
+ else if (offset >= 0x1000/4 && offset < 0x2000/4)
+ {
+ // 16-bit data memory and registers
+ return m_data->read_word((offset - 0x1000/4));
+ }
+ else if(offset >= 0x5000/4 && offset < 0x6000/4)
+ {
+ // DMA registers
+ return read_dma_stack(offset - 0x5000/4);
+ }
+ else
+ {
+ // 32-bit control registers
+ return read_ext_control(offset);
+ }
+}
+
+
+//-------------------------------------------------
+// read_dma_stack -
+//-------------------------------------------------
+
+uint32_t dspp_device::read_dma_stack(offs_t offset)
+{
+ uint32_t data = 0;
+
+ if (offset < 0x200 / 4)
+ {
+ uint32_t channel = offset / (16/4);
+ uint32_t reg = offset & 3;
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ switch (reg)
+ {
+ case 0x00/4://DSPX_DMA_ADDR_OFFSET:
+ {
+ data = dma.m_current_addr;
+ break;
+ }
+ case 0x04/4://DSPX_DMA_COUNT_OFFSET:
+ {
+ data = dma.m_current_count;
+ break;
+ }
+ case 0x08/4://DSPX_DMA_NEXT_ADDR_OFFSET:
+ {
+ data = dma.m_next_addr;
+ break;
+ }
+ case 0x0c/4://DSPX_DMA_NEXT_COUNT_OFFSET:
+ {
+ data = dma.m_next_count;
+ break;
+ }
+ }
+ }
+ else if (offset >= 0x200/4 && offset < (0x200/4 + (NUM_DMA_CHANNELS * (16/4))))
+ {
+ uint32_t channel = (offset - 0x200/4) / (16/4);
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ data = dma.m_go_forever ? DSPX_F_DMA_GO_FOREVER : 0;
+ data |= dma.m_next_valid ? DSPX_F_DMA_NEXTVALID : 0;
+ }
+ else
+ {
+ fatalerror("Unhandled DMA stack read");
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write_dma_stack -
+//-------------------------------------------------
+
+void dspp_device::write_dma_stack(offs_t offset, uint32_t data)
+{
+ if (offset < 0x200 / 4)
+ {
+ switch (offset & 3)
+ {
+ case 0x00/4://DSPX_DMA_ADDR_OFFSET:
+ {
+ m_dspx_shadow_current_addr = data;
+ break;
+ }
+ case 0x04/4://DSPX_DMA_COUNT_OFFSET:
+ {
+ m_dspx_shadow_current_count = data;
+ break;
+ }
+ case 0x08/4://DSPX_DMA_NEXT_ADDR_OFFSET:
+ {
+ m_dspx_shadow_next_addr = data;
+ break;
+ }
+ case 0x0c/4://DSPX_DMA_NEXT_COUNT_OFFSET:
+ {
+ m_dspx_shadow_next_count = data;
+ break;
+ }
+ }
+ }
+ else if (offset >= 0x200/4 && offset < (0x200/4 + (NUM_DMA_CHANNELS * (16/4))))
+ {
+ uint32_t channel = (offset - 0x200/4) / (16/4);
+ fifo_dma &dma = m_fifo_dma[channel];
+
+ if (data & DSPX_F_SHADOW_SET_NEXTVALID)
+ {
+ dma.m_next_valid = (data & DSPX_F_DMA_NEXTVALID) != 0;
+ }
+ if (data & DSPX_F_SHADOW_SET_FOREVER)
+ {
+ dma.m_go_forever = (data & DSPX_F_DMA_GO_FOREVER) != 0;
+ }
+ if (data & DSPX_F_SHADOW_SET_DMANEXT)
+ {
+ if (data & DSPX_F_INT_DMANEXT_EN)
+ {
+ m_dspx_dmanext_enable |= (1 << channel);
+ }
+ else
+ {
+ m_dspx_dmanext_enable &= ~(1 << channel);
+ }
+ }
+ if (data & DSPX_F_SHADOW_SET_ADDRESS_COUNT)
+ {
+ if (offset & (8/4))
+ {
+ dma.m_next_addr = m_dspx_shadow_next_addr;
+ dma.m_next_count = m_dspx_shadow_next_count;
+ }
+ else
+ {
+ dma.m_current_addr = m_dspx_shadow_current_addr;
+ dma.m_current_count = m_dspx_shadow_current_count;
+ }
+ }
+ }
+ else
+ {
+ fatalerror("Unhandled DMA stack write");
+ }
+}
+
+
+//-------------------------------------------------
+// write - host CPU write to DSPP internals
+//-------------------------------------------------
+
+WRITE32_MEMBER( dspp_device::write )
+{
+ if (offset < 0x1000/4)
+ {
+ // 16-bit code memory
+ m_code->write_word(offset, data);
+ }
+ else if (offset >= 0x1000/4 && offset < 0x2000/4)
+ {
+ // 16-bit data memory and registers
+ m_data->write_word((offset - 0x1000/4), data);
+ }
+ else if(offset >= 0x5000/4 && offset < 0x6000/4)
+ {
+ // DMA registers
+ write_dma_stack(offset - 0x5000/4, data);
+
+ // Better safe than sorry...
+ machine().scheduler().synchronize();
+ }
+ else
+ {
+ // 32-bit control registers
+ write_ext_control(offset, data);
+
+ // Better safe than sorry...
+ machine().scheduler().synchronize();
+ }
+}
+
+
+//-------------------------------------------------
+// read_output_fifo - Get data for the DACs
+//-------------------------------------------------
+
+uint16_t dspp_device::read_output_fifo()
+{
+ uint16_t data = 0;
+
+ if (m_output_fifo_count == 0)
+ {
+ // Underflow
+ return m_output_fifo[m_output_fifo_start];
+ }
+
+ data = m_output_fifo[m_output_fifo_start];
+
+ m_output_fifo_start = (m_output_fifo_start + 1) & OUTPUT_FIFO_MASK;
+ --m_output_fifo_count;
+
+ return data;
+}
+
+// DEBUG!
+
+char * GetBinary(char * buffer, uint32_t val, uint32_t bits)
+{
+ uint32_t i;
+
+ for (i = 0; i < bits; ++i)
+ buffer[i] = (val >> (bits - 1 - i)) & 1 ? '1' : '0';
+
+ buffer[i] = '\0';
+
+ return buffer;
+}
+
+void dspp_device::dump_state()
+{
+ // DMA
+ for (uint32_t i = 0; i < NUM_DMA_CHANNELS; ++i)
+ {
+ printf("\n=== CHANNEL %02X ===\n", i);
+ printf("CURR_ADDRESS: %08X\n", m_fifo_dma[i].m_current_addr);
+ printf("CURR_COUNT: %08X\n", m_fifo_dma[i].m_current_count);
+ printf("NEXT_ADDR: %08X\n", m_fifo_dma[i].m_next_addr);
+ printf("NEXT_COUNT: %08X\n", m_fifo_dma[i].m_next_count);
+ printf("PREV_VALUE: %08X\n", m_fifo_dma[i].m_prev_value);
+ printf("PREV_CURRENT: %08X\n", m_fifo_dma[i].m_prev_current);
+ printf("GO_FOREVER: %X\n", m_fifo_dma[i].m_go_forever);
+ printf("NEXT_VALID: %X\n", m_fifo_dma[i].m_next_valid);
+ }
+
+ char buffer[64];
+
+ printf("\n=== GLOBAL REGISTER===\n");
+ printf("DSPX_CONTROL: %08X\n", m_dspx_control);
+ printf("DSPX_RESET: %08X\n", m_dspx_reset);
+ printf("DSPX_INT_ENABLE: %08X\n", m_dspx_int_enable);
+ printf("DSPX_CHANNEL_ENABLE: %08X %s\n", m_dspx_channel_enable, GetBinary(buffer, m_dspx_channel_enable, 32));
+ printf("DSPX_CHANNEL_COMPLETE: %08X %s\n", m_dspx_channel_complete, GetBinary(buffer, m_dspx_channel_complete, 32));
+ printf("DSPX_CHANNEL_DIRECTION: %08X %s\n", m_dspx_channel_direction, GetBinary(buffer, m_dspx_channel_direction, 32));
+ printf("DSPX_CHANNEL_8BIT: %08X %s\n", m_dspx_channel_8bit, GetBinary(buffer, m_dspx_channel_8bit, 32));
+ printf("DSPX_CHANNEL_SQXD: %08X %s\n", m_dspx_channel_sqxd, GetBinary(buffer, m_dspx_channel_sqxd, 32));
+
+#if 0
+ uint32_t m_dspx_shadow_current_addr;
+ uint32_t m_dspx_shadow_current_count;
+ uint32_t m_dspx_shadow_next_addr;
+ uint32_t m_dspx_shadow_next_count;
+ uint32_t m_dspx_dmanext_int;
+ uint32_t m_dspx_dmanext_enable;
+ uint32_t m_dspx_consumed_int;
+ uint32_t m_dspx_consumed_enable;
+ uint32_t m_dspx_underover_int;
+ uint32_t m_dspx_underover_enable;
+ uint32_t m_dspx_audio_time;
+ uint16_t m_dspx_audio_duration;
+#endif
+}
diff --git a/src/devices/cpu/dspp/dspp.h b/src/devices/cpu/dspp/dspp.h
new file mode 100644
index 00000000000..848c2931714
--- /dev/null
+++ b/src/devices/cpu/dspp/dspp.h
@@ -0,0 +1,337 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ dspp.h
+
+ Core implementation for the portable DSPP emulator.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __DSPP_H__
+#define __DSPP_H__
+
+#include "cpu/drcfe.h"
+#include "cpu/drcuml.h"
+#include "cpu/drcumlsh.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class dspp_frontend;
+
+// ======================> dspp_device
+
+class dspp_device : public cpu_device
+{
+ friend class dspp_frontend;
+public:
+ // Construction/destruction
+ dspp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor code_map_ctor,
+ address_map_constructor data_map_ctor);
+ dspp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // Static configuration helpers
+ auto int_handler() { return m_int_handler.bind(); }
+ auto dma_read_handler() { return m_dma_read_handler.bind(); }
+ auto dma_write_handler() { return m_dma_write_handler.bind(); }
+
+ // Public interfaces
+ DECLARE_READ32_MEMBER( read );
+ DECLARE_WRITE32_MEMBER( write );
+
+ uint16_t read_output_fifo();
+
+ void dump_state(); // TODO: DEBUG REMOVE ME
+
+ // Internal registers
+ DECLARE_READ16_MEMBER( input_r );
+ DECLARE_WRITE16_MEMBER( output_w );
+ DECLARE_READ16_MEMBER( fifo_osc_r );
+ DECLARE_WRITE16_MEMBER( fifo_osc_w );
+ DECLARE_WRITE16_MEMBER( input_control_w );
+ DECLARE_WRITE16_MEMBER( output_control_w );
+ DECLARE_READ16_MEMBER( input_status_r );
+ DECLARE_READ16_MEMBER( output_status_r );
+ DECLARE_WRITE16_MEMBER( cpu_int_w );
+ DECLARE_READ16_MEMBER( pc_r );
+ DECLARE_WRITE16_MEMBER( pc_w );
+ DECLARE_READ16_MEMBER( audlock_r );
+ DECLARE_WRITE16_MEMBER( audlock_w );
+ DECLARE_READ16_MEMBER( clock_r );
+ DECLARE_WRITE16_MEMBER( clock_w );
+ DECLARE_READ16_MEMBER( noise_r );
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_execute_interface overrides
+ virtual uint32_t execute_min_cycles() const override;
+ virtual uint32_t execute_max_cycles() const override;
+ virtual void execute_run() override;
+
+ // device_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+ // device_state_interface overrides
+ virtual void state_import(const device_state_entry &entry) override;
+ virtual void state_export(const device_state_entry &entry) override;
+ virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
+
+ // device_disasm_interface overrides
+ virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
+
+ void code_map(address_map &map);
+ void data_map(address_map &map);
+
+private:
+ // Constants
+ static const uint32_t PC_STACK_DEPTH = 4;
+ static const uint32_t MAX_OPERANDS = 8;
+
+ static const uint32_t NUM_DMA_CHANNELS = 32;
+ static const uint32_t DMA_FIFO_DEPTH = 8;
+ static const uint32_t DMA_FIFO_MASK = DMA_FIFO_DEPTH - 1;
+
+ static const uint32_t NUM_INPUTS = 2;
+ static const uint32_t NUM_OUTPUTS = 8;
+ static const uint32_t OUTPUT_FIFO_DEPTH = 8;
+ static const uint32_t OUTPUT_FIFO_MASK = OUTPUT_FIFO_DEPTH - 1;
+
+ // Handlers
+ devcb_write_line m_int_handler;
+ devcb_read8 m_dma_read_handler;
+ devcb_write8 m_dma_write_handler;
+
+ // Internal functions
+ uint16_t read_op(offs_t pc);
+ inline uint16_t read_data(offs_t addr);
+ inline void write_data(offs_t addr, uint16_t data);
+
+ inline void update_pc();
+ inline void update_ticks();
+ inline void exec_control();
+ inline void exec_super_special();
+ inline void exec_special();
+ inline void exec_branch();
+ inline void exec_complex_branch();
+ inline void exec_arithmetic();
+ void parse_operands(uint32_t numops);
+ uint16_t read_next_operand();
+ void write_next_operand(uint16_t value);
+ inline void push_pc();
+ inline uint16_t pop_pc();
+ inline void set_rbase(uint32_t base, uint32_t addr);
+ inline uint16_t translate_reg(uint16_t reg);
+
+ void update_fifo_dma();
+ void process_next_dma(int32_t channel);
+ void service_input_dma(int32_t channel);
+ void service_output_dma(int32_t channel);
+ int16_t read_fifo_to_dspp(int32_t channel);
+ int16_t read_fifo_to_dma(int32_t channel);
+ void write_dma_to_fifo(int32_t channel, int16_t value);
+ void write_dspp_to_fifo(int32_t channel, int16_t value);
+
+ void run_oscillator(int32_t channel);
+ void reset_channel(int32_t channel);
+ void advance_audio_timer();
+ void advance_audio_frame();
+ int16_t decode_sqxd(int8_t val, int16_t prev);
+
+ uint32_t get_interrupt_state();
+ void update_host_interrupt();
+
+ uint32_t read_dma_stack(offs_t offset);
+ void write_dma_stack(offs_t offset, uint32_t data);
+
+ uint32_t read_ext_control(offs_t offset);
+ void write_ext_control(offs_t offset, uint32_t data);
+
+ bool m_isdrc;
+
+ // Address spaces
+ const address_space_config m_code_config;
+ const address_space_config m_data_config;
+ address_space * m_code;
+ address_space * m_data;
+ memory_access_cache<1, -1, ENDIANNESS_BIG> *m_code_cache;
+ std::function<const void * (offs_t)> m_codeptr;
+
+ struct dspp_internal_state
+ {
+ // Internal state
+ int m_icount;
+ uint16_t m_pc;
+ uint16_t m_stack[PC_STACK_DEPTH];
+ uint32_t m_stack_ptr;
+ uint16_t m_rbase[4];
+ uint32_t m_acc;
+ uint32_t m_tclock;
+
+ uint32_t m_flag_carry;
+ uint32_t m_flag_zero;
+ uint32_t m_flag_neg;
+ uint32_t m_flag_over;
+ uint32_t m_flag_exact;
+ uint32_t m_flag_audlock;
+ uint32_t m_flag_sleep;
+
+ uint32_t m_partial_int;
+ uint16_t m_op;
+ uint32_t m_opidx;
+ int32_t m_writeback;
+
+ const char *m_format;
+ uint32_t m_arg0;
+ } * m_core;
+
+ struct
+ {
+ uint32_t value;
+ uint32_t addr;
+ } m_operands[MAX_OPERANDS];
+
+ // DMA
+ struct fifo_dma
+ {
+ uint32_t m_current_addr;
+ int32_t m_current_count;
+ uint32_t m_next_addr;
+ uint32_t m_next_count;
+ uint32_t m_prev_value;
+ uint32_t m_prev_current;
+ uint8_t m_go_forever;
+ uint8_t m_next_valid;
+ uint8_t m_reserved;
+ uint16_t m_fifo[DMA_FIFO_DEPTH];
+ uint32_t m_dma_ptr;
+ uint32_t m_dspi_ptr;
+ uint32_t m_depth;
+ } m_fifo_dma[NUM_DMA_CHANNELS];
+
+ // Oscillator
+ uint32_t m_last_frame_clock;
+ uint32_t m_last_osc_count;
+ uint32_t m_osc_phase;
+ uint32_t m_osc_freq;
+
+ // Output FIFO
+ uint16_t m_outputs[NUM_OUTPUTS];
+ uint16_t m_output_fifo[OUTPUT_FIFO_DEPTH];
+ uint32_t m_output_fifo_start;
+ uint32_t m_output_fifo_count;
+
+ // External control registers
+ uint32_t m_dspx_control;
+ uint32_t m_dspx_reset;
+ uint32_t m_dspx_int_enable;
+ uint32_t m_dspx_channel_enable;
+ uint32_t m_dspx_channel_complete;
+ uint32_t m_dspx_channel_direction;
+ uint32_t m_dspx_channel_8bit;
+ uint32_t m_dspx_channel_sqxd;
+ uint32_t m_dspx_shadow_current_addr;
+ uint32_t m_dspx_shadow_current_count;
+ uint32_t m_dspx_shadow_next_addr;
+ uint32_t m_dspx_shadow_next_count;
+ uint32_t m_dspx_dmanext_int;
+ uint32_t m_dspx_dmanext_enable;
+ uint32_t m_dspx_consumed_int;
+ uint32_t m_dspx_consumed_enable;
+ uint32_t m_dspx_underover_int;
+ uint32_t m_dspx_underover_enable;
+ uint32_t m_dspx_audio_time;
+ uint16_t m_dspx_audio_duration;
+
+ //
+ // DRC
+ //
+
+ // Core state
+ /* internal stuff */
+ bool m_cache_dirty;
+ drc_cache m_cache;
+ std::unique_ptr<drcuml_state> m_drcuml;
+ std::unique_ptr<dspp_frontend> m_drcfe;
+ uint32_t m_drcoptions;
+
+ /* internal compiler state */
+ struct compiler_state
+ {
+ uint32_t cycles; /* accumulated cycles */
+ uint8_t checkints; /* need to check interrupts before next instruction */
+ uint8_t checksoftints; /* need to check software interrupts before next instruction */
+ uml::code_label labelnum; /* index for local labels */
+ };
+
+public: // TODO
+ void alloc_handle(drcuml_state *drcuml, uml::code_handle **handleptr, const char *name);
+ void load_fast_iregs(drcuml_block &block);
+ void save_fast_iregs(drcuml_block &block);
+// void arm7_drc_init();
+// void arm7_drc_exit();
+ void execute_run_drc();
+// void arm7drc_set_options(uint32_t options);
+// void arm7drc_add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base);
+// void arm7drc_add_hotspot(offs_t pc, uint32_t opcode, uint32_t cycles);
+ void flush_cache();
+ void compile_block(offs_t pc);
+ void cfunc_get_cycles();
+ void cfunc_unimplemented();
+ void static_generate_entry_point();
+ void static_generate_nocode_handler();
+ void static_generate_out_of_cycles();
+ void static_generate_memory_accessor(int size, bool istlb, bool iswrite, const char *name, uml::code_handle **handleptr);
+ void generate_update_cycles(drcuml_block &block, compiler_state *compiler, uml::parameter param);
+ void generate_checksum_block(drcuml_block &block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast);
+ void generate_sequence_instruction(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc);
+
+ bool generate_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc);
+
+
+ /* subroutines */
+ uml::code_handle * m_entry; /* entry point */
+ uml::code_handle * m_nocode; /* nocode exception handler */
+ uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */
+};
+
+
+/***************************************************************************
+ COMPILER-SPECIFIC OPTIONS
+ ***************************************************************************/
+
+#define DSPPDRC_STRICT_VERIFY 0x0001 /* verify all instructions */
+#define DSPPDRC_FLUSH_PC 0x0002 /* flush the PC value before each memory access */
+
+#define DSPPDRC_COMPATIBLE_OPTIONS (DSPPDRC_STRICT_VERIFY | DSPPDRC_FLUSH_PC)
+#define DSPPDRC_FASTEST_OPTIONS (0)
+
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_DSPP_INT_HANDLER(_devcb) \
+ devcb = &dspp_device::set_int_handler(*device, DEVCB_##_devcb);
+
+#define MCFG_DSPP_DMA_READ_HANDLER(_devcb) \
+ devcb = &dspp_device::set_dma_read_handler(*device, DEVCB_##_devcb);
+
+#define MCFG_DSPP_DMA_WRITE_HANDLER(_devcb) \
+ devcb = &dspp_device::set_dma_write_handler(*device, DEVCB_##_devcb);
+
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(DSPP, dspp_device);
+
+
+#endif /* __DSPP_H__ */
diff --git a/src/devices/cpu/dspp/dsppdasm.cpp b/src/devices/cpu/dspp/dsppdasm.cpp
new file mode 100644
index 00000000000..6b43df5d452
--- /dev/null
+++ b/src/devices/cpu/dspp/dsppdasm.cpp
@@ -0,0 +1,124 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ dsppdasm.c
+ Disassembler for the portable DSPP emulator.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "dspp.h"
+#include "dsppdasm.h"
+
+
+/***************************************************************************
+ CODE CODE
+***************************************************************************/
+
+uint32_t dspp_disassembler::opcode_alignment() const
+{
+ return 2;
+}
+
+offs_t dspp_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
+{
+#if 0
+ uint32_t op = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24);
+ int opcode = op >> 27;
+ int cond = (op >> 21) & 1;
+ int rdst = (op >> 22) & 31;
+ int rsrc1 = (op >> 16) & 31;
+ int rsrc2 = op & 0xffff;
+ int rsrc2_iszero = (!rsrc2 || rsrc2 == 0xffe0);
+ uint32_t flags = 0;
+
+ switch (opcode)
+ {
+ case 0x00: sprintf(buffer, "trap $00"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x01: sprintf(buffer, "b%s $%08x", condition[rdst & 15], pc + ((INT32)(op << 10) >> 8)); break;
+ case 0x02: if ((op & 0x003fffff) == 3)
+ {
+ uint32_t nextop = oprom[4] | (oprom[5] << 8) | (oprom[6] << 16) | (oprom[7] << 24);
+ if ((nextop >> 27) == 0x10 && ((nextop >> 22) & 31) == rdst && (nextop & 0xffff) == 0)
+ {
+ uint32_t nextnextop = oprom[8] | (oprom[9] << 8) | (oprom[10] << 16) | (oprom[11] << 24);
+ sprintf(buffer, "llit%s $%08x,%s", setcond[cond], nextnextop, reg[rdst]);
+ return 12 | DASMFLAG_STEP_OVER | DASMFLAG_SUPPORTED;
+ }
+ }
+ if (rdst)
+ {
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ sprintf(buffer, "bsr %s,$%08x", reg[rdst], pc + ((INT32)(op << 10) >> 8));
+ }
+ else
+ sprintf(buffer, "bra $%08x", pc + ((INT32)(op << 10) >> 8));
+ break;
+ case 0x03: sprintf(buffer, "lea%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break;
+ case 0x04: sprintf(buffer, "leah%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x05: sprintf(buffer, "subr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x06: sprintf(buffer, "xor%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x07: sprintf(buffer, "xorn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x08: if (!rsrc1 && !rdst && rsrc2_iszero)
+ sprintf(buffer, "nop");
+ else if (!rsrc1)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], src2(op,0), reg[rdst]);
+ else if (rsrc2_iszero)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], reg[rsrc1], reg[rdst]);
+ else
+ sprintf(buffer, "add%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x09: sprintf(buffer, "sub%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0a: sprintf(buffer, "addc%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0b: sprintf(buffer, "subc%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0c: sprintf(buffer, "and%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0d: sprintf(buffer, "andn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0e: if (!rsrc1 && !rdst && rsrc2_iszero)
+ sprintf(buffer, "nop");
+ else if (!rsrc1)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], src2(op,0), reg[rdst]);
+ else if (rsrc2_iszero)
+ sprintf(buffer, "mov%s %s,%s", setcond[cond], reg[rsrc1], reg[rdst]);
+ else
+ sprintf(buffer, "or%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x0f: sprintf(buffer, "orn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x10: sprintf(buffer, "ld%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break;
+ case 0x11: sprintf(buffer, "ldh%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x12: sprintf(buffer, "lduh%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x13: sprintf(buffer, "sth%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break;
+ case 0x14: sprintf(buffer, "st%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break;
+ case 0x15: sprintf(buffer, "ldb%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x16: sprintf(buffer, "ldub%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x17: sprintf(buffer, "stb%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x18: sprintf(buffer, "ashr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x19: sprintf(buffer, "lshr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x1a: sprintf(buffer, "ashl%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x1b: sprintf(buffer, "rotl%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break;
+ case 0x1c: sprintf(buffer, "getps %s", reg[rdst]); break;
+ case 0x1d: sprintf(buffer, "putps %s", src2(op,0)); break;
+ case 0x1e: if (rdst && rsrc2_iszero)
+ {
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ sprintf(buffer, "jsr%s %s,%s", setcond[cond], reg[rdst], reg[rsrc1]);
+ }
+ else if (rdst)
+ {
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ sprintf(buffer, "jsr%s %s,%s[%s]", setcond[cond], reg[rdst], reg[rsrc1], src2(op,2));
+ }
+ else if (rsrc2_iszero)
+ {
+ if (rsrc1 == 28)
+ flags = DASMFLAG_STEP_OUT;
+ sprintf(buffer, "jmp%s %s", setcond[cond], reg[rsrc1]);
+ }
+ else
+ sprintf(buffer, "jmp%s %s[%s]", setcond[cond], reg[rsrc1], src2(op,2));
+ break;
+ case 0x1f: sprintf(buffer, "trap $1f"); flags = DASMFLAG_STEP_OVER; break;
+ }
+
+ sprintf(buffer, "????");
+#endif
+ return 4 | 2 | SUPPORTED;
+}
diff --git a/src/devices/cpu/dspp/dsppdasm.h b/src/devices/cpu/dspp/dsppdasm.h
new file mode 100644
index 00000000000..7f0c526e18a
--- /dev/null
+++ b/src/devices/cpu/dspp/dsppdasm.h
@@ -0,0 +1,22 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/*
+ DSPP disassembler shim
+*/
+
+#ifndef MAME_CPU_DSPP_DSPPDASM_H
+#define MAME_CPU_DSPP_DSPPDASM_H
+
+#pragma once
+
+class dspp_disassembler : public util::disasm_interface
+{
+public:
+ dspp_disassembler() = default;
+ virtual ~dspp_disassembler() = default;
+
+ virtual uint32_t opcode_alignment() const override;
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
+};
+
+#endif
diff --git a/src/devices/cpu/dspp/dsppdrc.cpp b/src/devices/cpu/dspp/dsppdrc.cpp
new file mode 100644
index 00000000000..6c1e60b4874
--- /dev/null
+++ b/src/devices/cpu/dspp/dsppdrc.cpp
@@ -0,0 +1,970 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+
+/******************************************************************************
+
+ DSPP UML recompiler core
+
+******************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+#include "dspp.h"
+#include "dsppfe.h"
+#include "cpu/drcfe.h"
+#include "cpu/drcuml.h"
+#include "cpu/drcumlsh.h"
+
+using namespace uml;
+
+#define USE_SWAPDQ 0
+
+
+// map variables
+#define MAPVAR_PC M0
+#define MAPVAR_CYCLES M1
+#define MAPVAR_ACC M2
+
+// exit codes
+#define EXECUTE_OUT_OF_CYCLES 0
+#define EXECUTE_MISSING_CODE 1
+#define EXECUTE_UNMAPPED_CODE 2
+#define EXECUTE_RESET_CACHE 3
+
+#define FLAG_C(reg) mem(&m_core->m_flag_carry)
+#define FLAG_Z(reg) mem(&m_core->m_flag_zero)
+#define FLAG_N(reg) mem(&m_core->m_flag_neg)
+#define FLAG_V(reg) mem(&m_core->m_flag_over)
+#define FLAG_X(reg) mem(&m_core->m_flag_exact)
+
+inline void dspp_device::alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name)
+{
+ if (*handleptr == nullptr)
+ *handleptr = drcuml->handle_alloc(name);
+}
+
+static inline uint32_t epc(const opcode_desc *desc)
+{
+ return desc->pc;
+}
+
+
+#if 0
+static void cfunc_unimplemented(void *param)
+{
+ dspp_device *dspp = (dspp_device *)param;
+ dspp->cfunc_unimplemented();
+}
+#endif
+
+void dspp_device::cfunc_unimplemented()
+{
+// uint64_t op = m_core->m_arg0;
+// fatalerror("PC=%08X: Unimplemented op %04X%08X\n", m_core->m_pc, (uint32_t)(op >> 32), (uint32_t)(op));
+}
+
+
+/*-------------------------------------------------
+load_fast_iregs - load any fast integer
+registers
+-------------------------------------------------*/
+
+inline void dspp_device::load_fast_iregs(drcuml_block &block)
+{
+#if 0 // TODO
+ for (uint32_t regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
+ {
+ if (m_regmap[regnum].is_int_register())
+ {
+ UML_MOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_core->r[regnum]));
+ }
+ }
+#endif
+}
+
+
+/*-------------------------------------------------
+save_fast_iregs - save any fast integer
+registers
+-------------------------------------------------*/
+
+void dspp_device::save_fast_iregs(drcuml_block &block)
+{
+#if 0 // TODO
+ int regnum;
+
+ for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
+ {
+ if (m_regmap[regnum].is_int_register())
+ {
+ UML_MOV(block, mem(&m_core->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0));
+ }
+ }
+#endif
+}
+
+#if 0
+void dspp_device::static_generate_memory_accessor(MEM_ACCESSOR_TYPE type, const char *name, code_handle *&handleptr)
+{
+ // I0 = read/write data
+ // I1 = address
+
+ drcuml_block &block = m_drcuml->begin_block(1024);
+
+ // add a global entry for this
+ alloc_handle(m_drcuml.get(), &handleptr, name);
+ UML_HANDLE(block, *handleptr); // handle *handleptr
+
+ switch (type)
+ {
+ case MEM_ACCESSOR_PM_READ48:
+ UML_SHL(block, I1, I1, 3);
+ UML_DREAD(block, I0, I1, SIZE_QWORD, SPACE_PROGRAM);
+ break;
+
+ case MEM_ACCESSOR_PM_WRITE48:
+ UML_SHL(block, I1, I1, 3);
+ UML_DWRITE(block, I1, I0, SIZE_QWORD, SPACE_PROGRAM);
+ UML_MOV(block, mem(&m_core->force_recompile), 1);
+ break;
+
+ case MEM_ACCESSOR_PM_READ32:
+ UML_SHL(block, I1, I1, 3);
+ UML_READ(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM);
+ break;
+
+ case MEM_ACCESSOR_PM_WRITE32:
+ UML_SHL(block, I1, I1, 3);
+ UML_WRITE(block, I1, I0, SIZE_DWORD, SPACE_PROGRAM);
+ UML_MOV(block, mem(&m_core->force_recompile), 1);
+ break;
+
+ case MEM_ACCESSOR_DM_READ32:
+ UML_SHL(block, I1, I1, 2);
+ UML_READ(block, I0, I1, SIZE_DWORD, SPACE_DATA);
+ break;
+
+ case MEM_ACCESSOR_DM_WRITE32:
+ UML_SHL(block, I1, I1, 2);
+ UML_WRITE(block, I1, I0, SIZE_DWORD, SPACE_DATA);
+ break;
+ }
+
+ UML_RET(block);
+
+ block.end();
+}
+#endif
+
+
+void dspp_device::execute_run_drc()
+{
+ drcuml_state *drcuml = m_drcuml.get();
+ int execute_result;
+
+ if (m_cache_dirty)
+ flush_cache();
+
+ m_cache_dirty = false;
+
+ do
+ {
+ execute_result = drcuml->execute(*m_entry);
+
+ /* if we need to recompile, do it */
+ if (execute_result == EXECUTE_MISSING_CODE)
+ {
+ compile_block(m_core->m_pc);
+ }
+ else if (execute_result == EXECUTE_UNMAPPED_CODE)
+ {
+ fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_core->m_pc);
+ }
+ else if (execute_result == EXECUTE_RESET_CACHE)
+ {
+ flush_cache();
+ }
+ } while (execute_result != EXECUTE_OUT_OF_CYCLES);
+}
+
+void dspp_device::compile_block(offs_t pc)
+{
+ drcuml_state *drcuml = m_drcuml.get();
+ compiler_state compiler = { 0 };
+ const opcode_desc *seqhead, *seqlast;
+ const opcode_desc *desclist;
+ int override = false;
+
+ g_profiler.start(PROFILER_DRC_COMPILE);
+
+ /* get a description of this sequence */
+ desclist = m_drcfe->describe_code(pc);
+
+ bool succeeded = false;
+ while (!succeeded)
+ {
+ try
+ {
+ /* start the block */
+ drcuml_block &block = drcuml->begin_block(4096);
+
+ /* loop until we get through all instruction sequences */
+ for (seqhead = desclist; seqhead != nullptr; seqhead = seqlast->next())
+ {
+ const opcode_desc *curdesc;
+ uint32_t nextpc;
+
+ /* add a code log entry */
+ if (drcuml->logging())
+ block.append_comment("-------------------------"); // comment
+
+ /* determine the last instruction in this sequence */
+ for (seqlast = seqhead; seqlast != nullptr; seqlast = seqlast->next())
+ if (seqlast->flags & OPFLAG_END_SEQUENCE)
+ break;
+ assert(seqlast != nullptr);
+
+ /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */
+ if (override || !drcuml->hash_exists(0, seqhead->pc))
+ UML_HASH(block, 0, seqhead->pc); // hash mode,pc
+
+ /* if we already have a hash, and this is the first sequence, assume that we */
+ /* are recompiling due to being out of sync and allow future overrides */
+ else if (seqhead == desclist)
+ {
+ override = true;
+ UML_HASH(block, 0, seqhead->pc); // hash mode,pc
+ }
+
+ /* otherwise, redispatch to that fixed PC and skip the rest of the processing */
+ else
+ {
+ UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc
+ UML_HASHJMP(block, 0, seqhead->pc, *m_nocode);
+ // hashjmp <0>,seqhead->pc,nocode
+ continue;
+ }
+
+ generate_checksum_block(block, &compiler, seqhead, seqlast);
+
+ /* label this instruction, if it may be jumped to locally */
+ if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET)
+ UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc
+
+ /* iterate over instructions in the sequence and compile them */
+ for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next())
+ generate_sequence_instruction(block, &compiler, curdesc);
+
+ /* if we need to return to the start, do it */
+ if (seqlast->flags & OPFLAG_RETURN_TO_START)
+ nextpc = pc;
+
+ /* otherwise we just go to the next instruction */
+ else
+ nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4;
+
+ /* count off cycles and go there */
+ generate_update_cycles(block, &compiler, nextpc); // <subtract cycles>
+
+ /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */
+ if (seqlast->next() == nullptr || seqlast->next()->pc != nextpc)
+ UML_HASHJMP(block, 0, nextpc, *m_nocode); // hashjmp <mode>,nextpc,nocode
+ }
+
+ /* end the sequence */
+ block.end();
+ g_profiler.stop();
+ succeeded = true;
+ }
+ catch (drcuml_block::abort_compilation &)
+ {
+ flush_cache();
+ }
+ }
+}
+
+void dspp_device::generate_checksum_block(drcuml_block &block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast)
+{
+ const opcode_desc *curdesc;
+ if (m_drcuml->logging())
+ block.append_comment("[Validation for %08X]", seqhead->pc); // comment
+
+ /* loose verify or single instruction: just compare and fail */
+ if (!(m_drcoptions & DSPPDRC_STRICT_VERIFY) || seqhead->next() == nullptr)
+ {
+ if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ uint32_t sum = seqhead->opptr.l[0];
+ uint32_t addr = seqhead->physpc;
+ const void *base = m_codeptr(addr);
+ UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword
+
+ if (seqhead->delay.first() != nullptr && seqhead->physpc != seqhead->delay.first()->physpc)
+ {
+ addr = seqhead->delay.first()->physpc;
+ base = m_codeptr(addr);
+ assert(base != nullptr);
+ UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+
+ sum += seqhead->delay.first()->opptr.l[0];
+ }
+
+ UML_CMP(block, I0, sum); // cmp i0,opptr[0]
+ UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
+ }
+ }
+
+ /* full verification; sum up everything */
+ else
+ {
+#if 0
+ for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
+ if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ void *base = m_code_direct->read_ptr(seqhead->physpc);
+ UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword
+ UML_CMP(block, I0, curdesc->opptr.l[0]); // cmp i0,opptr[0]
+ UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
+ }
+#else
+ uint32_t sum = 0;
+ uint32_t addr = seqhead->physpc;
+ const void *base = m_codeptr(addr);
+ UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword
+ sum += seqhead->opptr.l[0];
+ for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
+ if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ addr = curdesc->physpc;
+ base = m_codeptr(addr);
+ assert(base != nullptr);
+ UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+ sum += curdesc->opptr.l[0];
+
+ if (curdesc->delay.first() != nullptr && (curdesc == seqlast || (curdesc->next() != nullptr && curdesc->next()->physpc != curdesc->delay.first()->physpc)))
+ {
+ addr = curdesc->delay.first()->physpc;
+ base = m_codeptr(addr);
+ assert(base != nullptr);
+ UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword
+ UML_ADD(block, I0, I0, I1); // add i0,i0,i1
+ sum += curdesc->delay.first()->opptr.l[0];
+ }
+ }
+ UML_CMP(block, I0, sum); // cmp i0,sum
+ UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc
+#endif
+ }
+}
+
+
+void dspp_device::flush_cache()
+{
+ /* empty the transient cache contents */
+ m_drcuml->reset();
+
+ try
+ {
+ // generate the entry point and out-of-cycles handlers
+ static_generate_entry_point();
+ static_generate_nocode_handler();
+ static_generate_out_of_cycles();
+
+#if 0
+ // generate utility functions
+ static_generate_push_pc();
+ static_generate_pop_pc();
+ static_generate_push_loop();
+ static_generate_pop_loop();
+ static_generate_push_status();
+ static_generate_pop_status();
+ static_generate_mode1_ops();
+
+ // generate exception handlers
+ static_generate_exception(EXCEPTION_INTERRUPT, "exception_interrupt");
+
+ // generate memory accessors
+ static_generate_memory_accessor(MEM_ACCESSOR_PM_READ48, "pm_read48", m_pm_read48);
+ static_generate_memory_accessor(MEM_ACCESSOR_PM_WRITE48, "pm_write48", m_pm_write48);
+ static_generate_memory_accessor(MEM_ACCESSOR_PM_READ32, "pm_read32", m_pm_read32);
+ static_generate_memory_accessor(MEM_ACCESSOR_PM_WRITE32, "pm_write32", m_pm_write32);
+ static_generate_memory_accessor(MEM_ACCESSOR_DM_READ32, "dm_read32", m_dm_read32);
+ static_generate_memory_accessor(MEM_ACCESSOR_DM_WRITE32, "dm_write32", m_dm_write32);
+#endif
+ }
+ catch (drcuml_block::abort_compilation &)
+ {
+ fatalerror("Error generating dspp static handlers\n");
+ }
+}
+
+
+void dspp_device::static_generate_entry_point()
+{
+ /* begin generating */
+ drcuml_block &block = m_drcuml->begin_block(20);
+
+ /* forward references */
+ alloc_handle(m_drcuml.get(), &m_nocode, "nocode");
+// alloc_handle(m_drcuml.get(), &m_exception[EXCEPTION_INTERRUPT], "exception_interrupt");
+
+ alloc_handle(m_drcuml.get(), &m_entry, "entry");
+ UML_HANDLE(block, *m_entry); // handle entry
+
+ load_fast_iregs(block); // <load fastregs>
+
+#if 0 // TODO: No interrupts?
+ /* check for interrupts */
+ UML_CMP(block, mem(&m_core->irq_pending), 0); // cmp [irq_pending],0
+ UML_JMPc(block, COND_E, skip); // je skip
+ UML_CMP(block, mem(&m_core->interrupt_active), 0); // cmp [interrupt_active],0
+ UML_JMPc(block, COND_NE, skip); // jne skip
+ UML_TEST(block, mem(&m_core->irq_pending), IMASK); // test [irq_pending],IMASK
+ UML_JMPc(block, COND_Z, skip); // jz skip
+ UML_TEST(block, mem(&m_core->mode1), MODE1_IRPTEN); // test MODE1,MODE1_IRPTEN
+ UML_JMPc(block, COND_Z, skip); // jz skip
+#endif
+
+// UML_MOV(block, I0, mem(&m_core->m_pc)); // mov i0,nextpc
+// UML_MOV(block, I1, 0); // mov i1,0
+// UML_CALLH(block, *m_exception[EXCEPTION_INTERRUPT]); // callh m_exception[EXCEPTION_INTERRUPT]
+
+// UML_LABEL(block, skip);
+
+ /* generate a hash jump via the current mode and PC */
+ UML_HASHJMP(block, 0, mem(&m_core->m_pc), *m_nocode); // hashjmp <mode>,<pc>,nocode
+
+ block.end();
+}
+
+
+void dspp_device::static_generate_nocode_handler()
+{
+ /* begin generating */
+ drcuml_block &block = m_drcuml->begin_block(10);
+
+ /* generate a hash jump via the current mode and PC */
+ alloc_handle(m_drcuml.get(), &m_nocode, "nocode");
+ UML_HANDLE(block, *m_nocode); // handle nocode
+ UML_GETEXP(block, I0); // getexp i0
+ UML_MOV(block, mem(&m_core->m_pc), I0); // mov [pc],i0
+ save_fast_iregs(block); // <save fastregs>
+ UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE
+
+ block.end();
+}
+
+void dspp_device::static_generate_out_of_cycles()
+{
+ /* begin generating */
+ drcuml_block &block = m_drcuml->begin_block(10);
+
+ /* generate a hash jump via the current mode and PC */
+ alloc_handle(m_drcuml.get(), &m_out_of_cycles, "out_of_cycles");
+ UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles
+ UML_GETEXP(block, I0); // getexp i0
+ UML_MOV(block, mem(&m_core->m_pc), I0); // mov <pc>,i0
+ save_fast_iregs(block); // <save fastregs>
+ UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES
+
+ block.end();
+}
+
+
+void dspp_device::generate_sequence_instruction(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ /* add an entry for the log */
+// if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP))
+// log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]);
+
+ /* set the PC map variable */
+ UML_MAPVAR(block, MAPVAR_PC, desc->pc); // mapvar PC,desc->pc
+
+ /* accumulate total cycles */
+ compiler->cycles += desc->cycles;
+
+ /* update the icount map variable */
+ UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles
+
+ /* if we are debugging, call the debugger */
+ if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
+ {
+ UML_MOV(block, mem(&m_core->m_pc), desc->pc); // mov [pc],desc->pc
+ save_fast_iregs(block); // <save fastregs>
+ UML_DEBUG(block, desc->pc); // debug desc->pc
+ }
+
+ /* if we hit an unmapped address, fatal error */
+ if (desc->flags & OPFLAG_COMPILER_UNMAPPED)
+ {
+ UML_MOV(block, mem(&m_core->m_pc), desc->pc); // mov [pc],desc->pc
+ save_fast_iregs(block); // <save fastregs>
+ UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE
+ }
+
+ /* if this is an invalid opcode, generate the exception now */
+// if (desc->flags & OPFLAG_INVALID_OPCODE)
+// UML_EXH(block, *m_exception[EXCEPTION_PROGRAM], 0x80000); // exh exception_program,0x80000
+
+ /* unless this is a virtual no-op, it's a regular instruction */
+ if (!(desc->flags & OPFLAG_VIRTUAL_NOOP))
+ {
+ /* compile the instruction */
+ //if (!generate_opcode(block, compiler, desc))
+ {
+ UML_MOV(block, mem(&m_core->m_pc), desc->pc); // mov [pc],desc->pc
+ UML_DMOV(block, mem(&m_core->m_arg0), desc->opptr.q[0]); // dmov [m_arg0],*desc->opptr.q // FIXME
+// UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented,ppc
+ }
+ }
+}
+
+void dspp_device::generate_update_cycles(drcuml_block &block, compiler_state *compiler, uml::parameter param)
+{
+#if 0 // No interrupts
+ if (compiler->checkints)
+ {
+ code_label skip = compiler->labelnum++;
+ compiler->checkints = false;
+
+ UML_CMP(block, mem(&m_core->irq_pending), 0); // cmp [irq_pending],0
+ UML_JMPc(block, COND_E, skip); // je skip
+ UML_CMP(block, mem(&m_core->interrupt_active), 0); // cmp [interrupt_active],0
+ UML_JMPc(block, COND_NE, skip); // jne skip
+ UML_TEST(block, mem(&m_core->irq_pending), IMASK); // test [irq_pending],IMASK
+ UML_JMPc(block, COND_Z, skip); // jz skip
+ UML_TEST(block, mem(&m_core->mode1), MODE1_IRPTEN); // test MODE1,MODE1_IRPTEN
+ UML_JMPc(block, COND_Z, skip); // jz skip
+
+ UML_MOV(block, I0, param); // mov i0,nextpc
+ UML_MOV(block, I1, compiler->cycles); // mov i1,cycles
+ UML_CALLH(block, *m_exception[EXCEPTION_INTERRUPT]); // callh m_exception[EXCEPTION_INTERRUPT]
+
+ UML_LABEL(block, skip);
+ }
+#endif
+
+ /* account for cycles */
+ if (compiler->cycles > 0)
+ {
+ UML_SUB(block, mem(&m_core->m_icount), mem(&m_core->m_icount), MAPVAR_CYCLES); // sub icount,icount,cycles
+ UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0
+#if 0 // FIXME
+ if (allow_exception)
+ UML_EXHc(block, COND_S, *m_out_of_cycles, param); // exh out_of_cycles,nextpc
+#endif
+ }
+ compiler->cycles = 0;
+}
+
+#if 0
+bool dspp_device::generate_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ uint32_t op = desc->opptr.l[0];
+
+ if (op & 0x8000)
+ {
+ switch ((op >> 13) & 3)
+ {
+ case 0:
+ return generate_special_opcode(op, desc);
+
+ case 1:
+ case 2:
+ return generate_branch_opcode(op, desc);
+
+ case 3:
+ return generate_complex_branch_opcode(op, desc);
+ }
+
+ return false;
+ }
+ else
+ {
+ return generate_arithmetic_opcode(op, desc);
+ }
+
+ return false;
+}
+
+bool dspp_device::generate_special_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ return true;
+}
+
+bool dspp_device::generate_branch_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ uint32_t mode = (m_core->m_op >> 13) & 3;
+ uint32_t select = (m_core->m_op >> 12) & 1;
+ uint32_t mask = (m_core->m_op >> 10) & 3;
+
+ bool flag0, flag1;
+
+ if (select == 0)
+ {
+ flag0 = (m_core->m_flags & DSPI_FLAG_CC_NEG) != 0;
+ flag1 = (m_core->m_flags & DSPI_FLAG_CC_OVER) != 0;
+ }
+ else
+ {
+ flag0 = (m_core->m_flags & DSPI_FLAG_CC_CARRY) != 0;
+ flag1 = (m_core->m_flags & DSPI_FLAG_CC_ZERO) != 0;
+ }
+
+ bool mask0 = (mask & 2) != 0;
+ bool mask1 = (mask & 1) != 0;
+
+ bool branch = (flag0 || !mask0) && (flag1 || !mask1);
+
+ if (mode == 2)
+ branch = !branch;
+
+ if (branch)
+ m_core->m_pc = m_core->m_op & 0x3ff;
+
+ return true;
+}
+
+
+void adsp21062_device::generate_jump(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc, bool delayslot, bool loopabort, bool clearint)
+{
+ compiler_state compiler_temp = *compiler;
+
+ // save branch target
+ if (desc->targetpc == BRANCH_TARGET_DYNAMIC)
+ {
+ UML_MOV(block, mem(&m_core->jmpdest), I0); // mov [jmpdest],i0
+ }
+
+ // update cycles and hash jump
+ if (desc->targetpc != BRANCH_TARGET_DYNAMIC)
+ {
+ generate_update_cycles(block, &compiler_temp, desc->targetpc, true);
+ if (desc->flags & OPFLAG_INTRABLOCK_BRANCH)
+ UML_JMP(block, desc->targetpc | 0x80000000); // jmp targetpc | 0x80000000
+ else
+ UML_HASHJMP(block, 0, desc->targetpc, *m_nocode); // hashjmp 0,targetpc,nocode
+ }
+ else
+ {
+ generate_update_cycles(block, &compiler_temp, mem(&m_core->jmpdest), true);
+ UML_HASHJMP(block, 0, mem(&m_core->jmpdest), *m_nocode); // hashjmp 0,jmpdest,nocode
+ }
+
+ // update compiler label
+ compiler->labelnum = compiler_temp.labelnum;
+
+ /* reset the mapvar to the current cycles and account for skipped slots */
+// compiler->cycles += desc->skipslots;
+ UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles
+}
+
+bool dspp_device::generate_complex_branch_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ uint32_t op = desc->opptr.l[0];
+
+ code_label skip_label = compiler->labelnum++;
+
+// generate_branch_target(block, compiler, desc, op & 0x3ff, ef2);
+// generate_condition(block, compiler, desc, ef1, true, skip_label, true);
+ generate_branch(block, compiler, desc);
+ UML_LABEL(block, skip_label);
+
+ switch ((op >> 10) & 7)
+ {
+ case 0: // BLT
+ // branch = (n && !v) || (!n && v);
+ UML_XOR(I0, FLAG_N, 1);
+ UML_XOR(I1, FLAG_V, 1);
+ UML_AND(I0, I0, FLAG_V);
+ UML_AND(I1, FLAG_N, I1);
+ UML_OR(I0, I1, I2);
+ UML_CMP(block, I0, 1);
+ break;
+ case 1: // BLE
+ //branch = ((n && !v) || (!n && v)) || z;
+ break;
+ case 2: // BGE
+ //branch = ((n && v) || (!n && !v));
+ break;
+ case 3: // BGT
+ //branch = ((n && v) || (!n && !v)) && !z;
+ UML_AND(I2, FLAG_N, FLAG_V);
+ UML_XOR(I0, FLAG_N, 1);
+ UML_XOR(I1, FLAG_V, 1);
+ UML_AND(I0, I0, I1);
+ UML_OR(I0, I2, I0);
+ UML_XOR(I1, FLAG_Z, 1);
+ UML_AND(I0, I0, I1);
+ UML_CMP(I0, 1);
+ break;
+ case 4: // BHI
+ //branch = c && !z;
+ UML_XOR(I0, FLAG_Z, 1)
+ UML_AND(I0, FLAG_C, I0);
+ UML_CMP(I0, 1);
+ break;
+ case 5: // BLS
+ //branch = !c || z;
+ UML_XOR(I0, FLAG_C, 1);
+ UML_OR(I0, I0, FLAG_Z);
+ UML_CMP(block, I0, 1);
+ break;
+ case 6: // BXS
+ //branch = x;
+ UML_CMP(block, FLAG_X, 1);
+ break;
+ case 7: // BXC
+ //branch = !x;
+ UML_CMP(block, FLAG_X, 0);
+ break;
+ }
+
+ UML_JMPc(block, COND_E, skip_label);
+
+ return true;
+}
+
+bool dspp_device::generate_arithmetic_opcode(drcuml_block &block, compiler_state *compiler, const opcode_desc *desc)
+{
+ uint32_t numops = (m_core->m_op >> 13) & 3;
+ uint32_t muxa = (m_core->m_op >> 10) & 3;
+ uint32_t muxb = (m_core->m_op >> 8) & 3;
+ uint32_t alu_op = (m_core->m_op >> 4) & 0xf;
+ uint32_t barrel_code = m_core->m_op & 0xf;
+
+ int32_t mul_res = 0;
+ uint32_t alu_res = 0;
+
+ // Check for operand overflow
+ if (numops == 0 && ((muxa == 1) || (muxa == 2) || (muxb == 1) || (muxb == 2)))
+ numops = 4;
+
+ // Implicit barrel shift
+ if (barrel_code == 8)
+ ++numops;
+
+ // Parse ops...
+ parse_operands(numops);
+
+ if (muxa == 3 || muxb == 3)
+ {
+ uint32_t mul_sel = (m_core->m_op >> 12) & 1;
+
+ int32_t op1 = sign_extend16(read_next_operand());
+ int32_t op2 = sign_extend16(mul_sel ? read_next_operand() : m_core->m_acc >> 4);
+
+ mul_res = (op1 * op2) >> 11;
+
+#if 0
+ // SELECT
+ UML_DSEXT(block, I0, OP1, SIZE_WORD);
+ UML_DSEXT(block, I1, OP1, SIZE_WORD);
+ UML_MULS(block, I0, I1, I0, I1);
+ UML_SHR(block, I2, I0, 11);
+#endif
+ }
+
+ // MULRES = I2
+ // MUXA = I0
+ // MUXB = I1
+
+ // ALURES = I2
+ // ACC_RESULT = I1?
+ switch (alu_op)
+ {
+ case 0: // _TRA
+ // alu_res = alu_a;
+ UML_MOV(block, I2, I0);
+ break;
+
+ case 1: // _NEG
+ // alu_res = -alu_b;
+ UML_SUB(block, I2, 0, I1);
+ break;
+
+ case 2: // _+
+ // alu_res = alu_a + alu_b;
+ UML_ADD(block, I2, I0, I1);
+
+ // if ((alu_a & 0x80000) == (alu_b & 0x80000) &&
+ // (alu_a & 0x80000) != (alu_res & 0x80000))
+ // m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ // if (alu_res & 0x00100000)
+ // m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ // CC_V_MODIFIED(desc);
+ // CC_C_MODIFIED(desc);
+ break;
+
+ case 3: // _+C
+ UML_ADD(block, I2, I0, mew);
+ // alu_res = alu_a + (m_core->m_flags & DSPI_FLAG_CC_CARRY) ? (1 << 4) : 0;
+
+ // if (alu_res & 0x00100000)
+ // m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_USED(desc);
+ CC_C_MODIFIED(desc);
+ break;
+
+ case 4: // _-
+ // alu_res = alu_a - alu_b;
+ UML_SUB(block, I2, I0, I1);
+
+ // if ((alu_a & 0x80000) == (~alu_b & 0x80000) &&
+ // (alu_a & 0x80000) != (alu_res & 0x80000))
+ // m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ // if (alu_res & 0x00100000)
+ // m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_MODIFIED(desc);
+ CC_V_MODIFIED(desc);
+ break;
+
+ case 5: // _-B
+ // alu_res = alu_a - (m_core->m_flags & DSPI_FLAG_CC_CARRY) ? (1 << 4) : 0;
+
+ // if (alu_res & 0x00100000)
+ // m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_USED(desc);
+ CC_C_MODIFIED(desc);
+ break;
+
+ case 6: // _++
+ UML_ADD(block, I2, I0, 1);
+ // alu_res = alu_a + 1;
+
+ // if (!(alu_a & 0x80000) && (alu_res & 0x80000))
+ // m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ CC_V_MODIFIED(desc);
+ break;
+
+ case 7: // _--
+ // alu_res = alu_a - 1;
+ UML_SUB(block, I2, I0, 1);
+
+ // if ((alu_a & 0x80000) && !(alu_res & 0x80000))
+ // m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ CC_V_MODIFIED(desc);
+ break;
+
+ case 8: // _TRL
+ //alu_res = alu_a;
+ UML_MOV(block, I2, I0);
+ break;
+
+ case 9: // _NOT
+ //alu_res = ~alu_a;
+ UML_XOR(block, I2, I0, 0xffff);
+ break;
+
+ case 10: // _AND
+ //alu_res = alu_a & alu_b;
+ UML_AND(block, I2, I0, I1);
+ break;
+
+ case 11: // _NAND
+ //alu_res = ~(alu_a & alu_b);
+ UML_AND(block, I2, I0, I1);
+ UML_XOR(block, I2, 0xffff);
+ break;
+
+ case 12: // _OR
+ //alu_res = alu_a | alu_b;
+ UML_OR(block, I2, I0, I1);
+ break;
+
+ case 13: // _NOR
+ //alu_res = ~(alu_a | alu_b);
+ UML_OR(block, I2, I0, I1);
+ UML_XOR(block, I2, I2, 0xffff);
+ break;
+
+ case 14: // _XOR
+ //alu_res = alu_a ^ alu_b;
+ UML_XOR(block, I2, I0, I1);
+ break;
+
+ case 15: // _XNOR
+ //alu_res = ~(alu_a ^ alu_b);
+ UML_XOR(block, I2, I0, I1);
+ UML_XOR(block, I2, I0, 0xffff);
+ break;
+ }
+
+ // SET FLAGS
+ CC_SET_NEG(alu_res & 0x00080000);
+ CC_SET_ZERO((alu_res & 0x000ffff0) == 0);
+ CC_SET_EXACT((alu_res & 0x0000000f) == 0);
+
+ // Barrel shift
+ static const int32_t shifts[8] = { 0, 1, 2, 3, 4, 5, 8, 16 };
+
+ if (barrel_code == 8)
+ barrel_code = read_next_operand();
+
+ if (barrel_code & 8)
+ {
+ // Right shift
+ uint32_t shift = shifts[(~barrel_code + 1) & 7];
+
+ if (alu_op < 8)
+ {
+ // Arithmetic
+// m_core->m_acc = sign_extend20(alu_res) >> shift;
+
+ // TODO: Sign Extend to 20-bits
+ UML_SHR(block, I2, I2, shift);
+ UML_MAPVAR(block, MAPVAR_ACC, I2);
+ }
+ else
+ {
+ // Logical
+// m_core->m_acc = (alu_res & 0xfffff) >> shift;
+ UML_AND(block, I2, 0xfffff);
+ UML_SHR(block, I2, I2, shift);
+ UML_MAPVAR(block, MAPVAR_ACC, I2);
+ }
+
+ }
+ else
+ {
+ // Left shift
+ uint32_t shift = shifts[barrel_code];
+
+ if (shift == 16)
+ {
+ // Clip and saturate
+ if (m_core->m_flags & DSPI_FLAG_CC_OVER)
+ m_core->m_acc = (m_core->m_flags & DSPI_FLAG_CC_NEG) ? 0x7ffff : 0xfff80000;
+ else
+ m_core->m_acc = sign_extend20(alu_res);
+ }
+ else
+ {
+ m_core->m_acc = sign_extend20(alu_res) << shift;
+ }
+ }
+
+ if (m_core->m_writeback >= 0)
+ {
+ write_data(m_core->m_writeback, m_core->m_acc >> 4);
+ m_core->m_writeback = -1;
+ }
+ else if (m_core->m_opidx < numops)
+ {
+ write_next_operand(m_core->m_acc >> 4);
+ }
+
+ return true;
+}
+
+#endif
diff --git a/src/devices/cpu/dspp/dsppfe.cpp b/src/devices/cpu/dspp/dsppfe.cpp
new file mode 100644
index 00000000000..533a020ab89
--- /dev/null
+++ b/src/devices/cpu/dspp/dsppfe.cpp
@@ -0,0 +1,625 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+
+/******************************************************************************
+
+ Front-end for DSPP recompiler
+
+******************************************************************************/
+
+#include "emu.h"
+#include "dsppfe.h"
+
+
+//#define REG_USED(desc,x) do { (desc).regin[0] |= 1 << (x); } while(0)
+//#define REG_MODIFIED(desc,x) do { (desc).regout[0] |= 1 << (x); } while(0)
+
+#define CC_C_USED(desc) do { (desc).regin[0] |= 1 << 16; } while(0)
+#define CC_C_MODIFIED(desc) do { (desc).regout[0] |= 1 << 16; } while(0)
+#define CC_Z_USED(desc) do { (desc).regin[0] |= 1 << 16; } while(0)
+#define CC_Z_MODIFIED(desc) do { (desc).regout[0] |= 1 << 16; } while(0)
+#define CC_N_USED(desc) do { (desc).regin[0] |= 1 << 16; } while(0)
+#define CC_N_MODIFIED(desc) do { (desc).regout[0] |= 1 << 16; } while(0)
+#define CC_V_USED(desc) do { (desc).regin[0] |= 1 << 16; } while(0)
+#define CC_V_MODIFIED(desc) do { (desc).regout[0] |= 1 << 16; } while(0)
+#define CC_X_USED(desc) do { (desc).regin[0] |= 1 << 16; } while(0)
+#define CC_X_MODIFIED(desc) do { (desc).regout[0] |= 1 << 16; } while(0)
+
+#define CC_FLAGS_MODIFIED(desc) do { } while(0)
+//#define MULT_FLAGS_MODIFIED(desc) do { MN_MODIFIED(desc);MV_MODIFIED(desc);MU_MODIFIED(desc);MI_MODIFIED(desc); } while(0)
+//#define SHIFT_FLAGS_MODIFIED(desc) do { SZ_MODIFIED(desc);SV_MODIFIED(desc);SS_MODIFIED(desc); } while(0)
+
+dspp_frontend::dspp_frontend(dspp_device *dspp, uint32_t window_start, uint32_t window_end, uint32_t max_sequence)
+ : drc_frontend(*dspp, window_start, window_end, max_sequence),
+ m_dspp(dspp)
+{
+
+}
+
+
+#if 0
+// opcode branch flags
+const uint32_t OPFLAG_IS_UNCONDITIONAL_BRANCH = 0x00000001; // instruction is unconditional branch
+const uint32_t OPFLAG_IS_CONDITIONAL_BRANCH = 0x00000002; // instruction is conditional branch
+const uint32_t OPFLAG_IS_BRANCH = (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH);
+const uint32_t OPFLAG_IS_BRANCH_TARGET = 0x00000004; // instruction is the target of a branch
+const uint32_t OPFLAG_IN_DELAY_SLOT = 0x00000008; // instruction is in the delay slot of a branch
+const uint32_t OPFLAG_INTRABLOCK_BRANCH = 0x00000010; // instruction branches within the block
+
+// opcode exception flags
+const uint32_t OPFLAG_CAN_TRIGGER_SW_INT = 0x00000020; // instruction can trigger a software interrupt
+const uint32_t OPFLAG_CAN_EXPOSE_EXTERNAL_INT = 0x00000040; // instruction can expose an external interrupt
+const uint32_t OPFLAG_CAN_CAUSE_EXCEPTION = 0x00000080; // instruction may generate exception
+const uint32_t OPFLAG_WILL_CAUSE_EXCEPTION = 0x00000100; // instruction will generate exception
+const uint32_t OPFLAG_PRIVILEGED = 0x00000200; // instruction is privileged
+
+// opcode virtual->physical translation flags
+const uint32_t OPFLAG_VALIDATE_TLB = 0x00000400; // instruction must validate TLB before execution
+const uint32_t OPFLAG_MODIFIES_TRANSLATION = 0x00000800; // instruction modifies the TLB
+const uint32_t OPFLAG_COMPILER_PAGE_FAULT = 0x00001000; // compiler hit a page fault when parsing
+const uint32_t OPFLAG_COMPILER_UNMAPPED = 0x00002000; // compiler hit unmapped memory when parsing
+
+// opcode flags
+const uint32_t OPFLAG_INVALID_OPCODE = 0x00004000; // instruction is invalid
+const uint32_t OPFLAG_VIRTUAL_NOOP = 0x00008000; // instruction is a virtual no-op
+
+// opcode sequence flow flags
+const uint32_t OPFLAG_REDISPATCH = 0x00010000; // instruction must redispatch after completion
+const uint32_t OPFLAG_RETURN_TO_START = 0x00020000; // instruction must jump back to the beginning after completion
+const uint32_t OPFLAG_END_SEQUENCE = 0x00040000; // this is the last instruction in a sequence
+const uint32_t OPFLAG_CAN_CHANGE_MODES = 0x00080000; // instruction can change modes
+
+// execution semantics
+const uint32_t OPFLAG_READS_MEMORY = 0x00100000; // instruction reads memory
+const uint32_t OPFLAG_WRITES_MEMORY = 0x00200000; // instruction writes memory
+#endif
+
+bool dspp_frontend::describe(opcode_desc &desc, const opcode_desc *prev)
+{
+ uint16_t op = desc.opptr.w[0] = m_dspp->read_op(desc.physpc);
+
+ // TODO: NOOOOPE
+ desc.cycles = 1; // TODO: Extra cycles for extra operands
+ desc.length = 2;
+
+ // Decode and execute
+ if (op & 0x8000)
+ {
+ switch ((op >> 13) & 3)
+ {
+ case 0:
+ return describe_special(op, desc);
+
+ case 1:
+ case 2:
+ return describe_branch(op, desc);
+
+ case 3:
+ return describe_complex_branch(op, desc);
+ }
+
+ return false;
+ }
+ else
+ {
+ return describe_arithmetic(op, desc);
+ }
+
+ return false;
+}
+
+
+bool dspp_frontend::describe_special(uint16_t op, opcode_desc &desc)
+{
+ switch ((op >> 10) & 7)
+ {
+ case 0:
+ {
+ // Super-special
+ switch ((op >> 7) & 7)
+ {
+ case 1: // BAC - TODO: MERGE?
+ {
+ //desc.regin[0] = m_acc;
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ return true;
+ }
+ case 4: // RTS
+ {
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = BRANCH_TARGET_DYNAMIC;
+ return true;
+ }
+ case 5: // OP_MASK
+ {
+ // TODO
+ return true;
+ }
+
+ case 7: // SLEEP
+ {
+ // TODO
+ return true;
+ }
+
+ case 0: // NOP
+ case 2: // Unused
+ case 3:
+ case 6:
+ return true;
+ }
+
+ break;
+ }
+ case 1: // JUMP - TODO: MERGE?
+ {
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = op & 0x3ff;
+ return true;
+ }
+ case 2: // JSR
+ {
+ desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+ desc.targetpc = op & 0x3ff;
+ return true;
+ }
+ case 3: // BFM
+ {
+ // TODO: What sort of branch is this?
+// desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
+// desc.targetpc = 0; // FIXME
+ return false;
+ }
+ case 4: // MOVEREG
+ {
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+
+ // Indirect
+ if (op & 0x0010)
+ desc.flags |= OPFLAG_READS_MEMORY;
+
+ return true;
+ }
+ case 5: // RBASE
+ {
+ return true;
+ }
+ case 6: // MOVED
+ {
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ return true;
+ }
+ case 7: // MOVEI
+ {
+ desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_WRITES_MEMORY;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool dspp_frontend::describe_branch(uint16_t op, opcode_desc &desc)
+{
+ const uint32_t select = (op >> 12) & 1;
+
+ if (select == 0)
+ {
+ CC_N_USED(desc);
+ CC_V_USED(desc);
+ }
+ else
+ {
+ CC_C_USED(desc);
+ CC_Z_USED(desc);
+ }
+
+ // TODO: Can these be unconditional?
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc.targetpc = op & 0x3ff;
+
+ return true;
+}
+
+bool dspp_frontend::describe_complex_branch(uint16_t op, opcode_desc &desc)
+{
+ switch ((op >> 10) & 7)
+ {
+ case 0: // BLT
+ CC_N_USED(desc);
+ CC_V_USED(desc);
+ break;
+ case 1: // BLE
+ CC_N_USED(desc);
+ CC_V_USED(desc);
+ CC_Z_USED(desc);
+ break;
+ case 2: // BGE
+ CC_N_USED(desc);
+ CC_V_USED(desc);
+ break;
+ case 3: // BGT
+ CC_N_USED(desc);
+ CC_V_USED(desc);
+ CC_Z_USED(desc);
+ break;
+ case 4: // BHI
+ case 5: // BLS
+ CC_C_USED(desc);
+ CC_Z_USED(desc);
+ break;
+ case 6: // BXS
+ case 7: // BXC
+ CC_X_USED(desc);
+ break;
+ }
+
+ desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
+ desc.targetpc = op & 0x3ff;
+
+ return true;
+}
+
+bool dspp_frontend::describe_arithmetic(uint16_t op, opcode_desc &desc)
+{
+ #if 0
+ // Decode the various fields
+ uint32_t numops = (op >> 13) & 3;
+ uint32_t muxa = (op >> 10) & 3;
+ uint32_t muxb = (op >> 8) & 3;
+ uint32_t alu_op = (op >> 4) & 0xf;
+ uint32_t barrel_code = op & 0xf;
+
+ int32_t mul_res = 0;
+ uint32_t alu_res = 0;
+
+ // Check for operand overflow
+ if (numops == 0 && ((muxa == 1) || (muxa == 2) || (muxb == 1) || (muxb == 2)))
+ numops = 4;
+
+ // Implicit barrel shift
+ if (barrel_code == 8)
+ ++numops;
+
+ // TODO: We need to know:
+ // Number of cycles
+ // Number of bytes
+ // Registers read
+ // Registers written
+ // Does it read memory?
+ // Does it write memory?
+
+// parse_operands(numops);
+
+ if (muxa == 3 || muxb == 3)
+ {
+ uint32_t mul_sel = (op >> 12) & 1;
+
+ int32_t op1 = sign_extend16(read_next_operand());
+ int32_t op2 = sign_extend16(mul_sel ? read_next_operand() : m_core->m_acc >> 4);
+
+ mul_res = (op1 * op2) >> 11;
+ }
+
+ int32_t alu_a, alu_b;
+
+ switch (muxa)
+ {
+ case 0:
+ {
+ ACCUMULATOR_USED
+ alu_a = m_core->m_acc;
+ break;
+ }
+ case 1: case 2:
+ {
+ alu_a = read_next_operand() << 4;
+ break;
+ }
+ case 3:
+ {
+ alu_a = mul_res;
+ break;
+ }
+ }
+
+ switch (muxb)
+ {
+ case 0:
+ {
+ ACCUMULATOR_USED
+ alu_b = m_core->m_acc;
+ break;
+ }
+ case 1: case 2:
+ {
+ alu_b = read_next_operand() << 4;
+ break;
+ }
+ case 3:
+ {
+ alu_b = mul_res;
+ break;
+ }
+ }
+
+ // All flags ar emodifed
+ CC_FLAGS_MODIFIED(desc);
+
+ switch (alu_op)
+ {
+ case 0: // _TRA
+ {
+// alu_res = alu_a;
+ break;
+ }
+ case 1: // _NEG
+ {
+// alu_res = -alu_b;
+ break;
+ }
+ case 2: // _+
+ {
+// alu_res = alu_a + alu_b;
+
+// if ((alu_a & 0x80000) == (alu_b & 0x80000) &&
+// (alu_a & 0x80000) != (alu_res & 0x80000))
+// m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+// if (alu_res & 0x00100000)
+// m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+// CC_V_MODIFIED(desc);
+// CC_C_MODIFIED(desc);
+ break;
+ }
+ case 3: // _+C
+ {
+// alu_res = alu_a + (m_core->m_flags & DSPI_FLAG_CC_CARRY) ? (1 << 4) : 0;
+
+// if (alu_res & 0x00100000)
+// m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_USED(desc);
+ CC_C_MODIFIED(desc);
+ break;
+ }
+ case 4: // _-
+ {
+// alu_res = alu_a - alu_b;
+
+// if ((alu_a & 0x80000) == (~alu_b & 0x80000) &&
+// (alu_a & 0x80000) != (alu_res & 0x80000))
+// m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+// if (alu_res & 0x00100000)
+// m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_MODIFIED(desc);
+ CC_V_MODIFIED(desc);
+ break;
+ }
+ case 5: // _-B
+ {
+// alu_res = alu_a - (m_core->m_flags & DSPI_FLAG_CC_CARRY) ? (1 << 4) : 0;
+
+// if (alu_res & 0x00100000)
+// m_core->m_flags |= DSPI_FLAG_CC_CARRY;
+
+ CC_C_USED(desc);
+ CC_C_MODIFIED(desc);
+ break;
+ }
+ case 6: // _++
+ {
+// alu_res = alu_a + 1;
+
+// if (!(alu_a & 0x80000) && (alu_res & 0x80000))
+// m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ CC_V_MODIFIED(desc);
+ break;
+ }
+ case 7: // _--
+ {
+// alu_res = alu_a - 1;
+
+// if ((alu_a & 0x80000) && !(alu_res & 0x80000))
+// m_core->m_flags |= DSPI_FLAG_CC_OVER;
+
+ CC_V_MODIFIED(desc);
+ break;
+ }
+ case 8: // _TRL
+ {
+ //alu_res = alu_a;
+ break;
+ }
+ case 9: // _NOT
+ {
+ //alu_res = ~alu_a;
+ break;
+ }
+ case 10: // _AND
+ {
+ //alu_res = alu_a & alu_b;
+ break;
+ }
+ case 11: // _NAND
+ {
+ //alu_res = ~(alu_a & alu_b);
+ break;
+ }
+ case 12: // _OR
+ {
+ //alu_res = alu_a | alu_b;
+ break;
+ }
+ case 13: // _NOR
+ {
+ //alu_res = ~(alu_a | alu_b);
+ break;
+ }
+ case 14: // _XOR
+ {
+ //alu_res = alu_a ^ alu_b;
+ break;
+ }
+ case 15: // _XNOR
+ {
+ //alu_res = ~(alu_a ^ alu_b);
+ break;
+ }
+ }
+
+
+ if (alu_res & 0x00080000)
+ m_core->m_flags |= DSPI_FLAG_CC_NEG;
+
+ if ((alu_res & 0x000ffff0) == 0)
+ m_core->m_flags |= DSPI_FLAG_CC_ZERO;
+
+ if ((alu_res & 0x0000000f) == 0)
+ m_core->m_flags |= DSPI_FLAG_CC_EXACT;
+
+ CC_N_MODIFIED(desc);
+ CC_Z_MODIFIED(desc);
+ CC_X_MODIFIED(desc);
+
+ ACCUMULATOR_MODIFIED_ALWAYS;
+
+ // Barrel shift
+ static const int32_t shifts[8] = { 0, 1, 2, 3, 4, 5, 8, 16 };
+
+ if (barrel_code == 8)
+ barrel_code = read_next_operand();
+
+ if (barrel_code & 8)
+ {
+ // Right shift
+ uint32_t shift = shifts[(~barrel_code + 1) & 7];
+
+ if (alu_op < 8)
+ {
+ // Arithmetic
+ m_core->m_acc = sign_extend20(alu_res) >> shift;
+ }
+ else
+ {
+ // Logical
+ m_core->m_acc = (alu_res & 0xfffff) >> shift;
+ }
+ }
+ else
+ {
+ // Left shift
+ uint32_t shift = shifts[barrel_code];
+
+ if (shift == 16)
+ {
+ // Clip and saturate
+ if (m_core->m_flags & DSPI_FLAG_CC_OVER)
+ m_core->m_acc = (m_core->m_flags & DSPI_FLAG_CC_NEG) ? 0x7ffff : 0xfff80000;
+ else
+ m_core->m_acc = sign_extend20(alu_res);
+ }
+ else
+ {
+ m_core->m_acc = sign_extend20(alu_res) << shift;
+ }
+ }
+
+ if (m_core->m_writeback >= 0)
+ {
+ write_data(m_core->m_writeback, m_core->m_acc >> 4);
+ m_core->m_writeback = -1;
+ }
+ else if (opidx < numops)
+ {
+ write_next_operand(m_core->m_acc >> 4);
+ }
+#endif
+ return true;
+}
+
+
+#if 0
+void dspp_device::parse_operands(uint32_t numops)
+{
+ uint32_t addr, val = 0xBAD;
+ uint32_t opidx = 0;
+ uint32_t operand = 0;
+ uint32_t numregs = 0;
+
+ uint32_t opidx = 0;
+
+ while (opidx < numops)
+ {
+ uint16_t op = desc.opptr.w[opidx + 1] = m_dspp->read_op(desc.physpc + opidx * 2);
+
+ desc.length += 2;
+ ++desc.cycles;
+
+ if (op & 0x8000)
+ {
+ // Immediate value
+ if ((op & 0xc000) == 0xc000)
+ {
+ // Nothing?-
+ }
+ else if((op & 0xe000) == 0x8000)
+ {
+ if (op & 0x0400) // Indirect
+ desc.flags |= OPFLAG_READS_MEMORY;
+
+ if (op & 0x0800 )// Write Back
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+
+ ++opidx;
+ }
+ else if ((op & 0xe000) == 0xa000)
+ {
+ // 1 or 2 register operand
+ numregs = (op & 0x0400) ? 2 : 1;
+ }
+ }
+ else
+ {
+ numregs = 3;
+ }
+
+ if (numregs > 0)
+ {
+ // Shift successive register operands from a single operand word
+ for (uint32_t i = 0; i < numregs; ++i)
+ {
+ uint32_t shift = ((numregs - i) - 1) * 5;
+ uint32_t regdi = (operand >> shift) & 0x1f;
+ // OP USES REGBASE?
+
+ if (regdi & 0x0010)
+ {
+ // Indirect
+ desc.flags |= OPFLAG_READS_MEMORY;
+ }
+
+ if (numregs == 2)
+ {
+ // Write back
+ if ((i == 0) && (operand & 0x1000))
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ else if ((i == 1) && (operand & 0x0800))
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ }
+ else if (numregs == 1)
+ {
+ if (operand & 0x800)
+ desc.flags |= OPFLAG_WRITES_MEMORY;
+ }
+ }
+ numregs = 0;
+ }
+ }
+}
+#endif
diff --git a/src/devices/cpu/dspp/dsppfe.h b/src/devices/cpu/dspp/dsppfe.h
new file mode 100644
index 00000000000..a90dc5d0225
--- /dev/null
+++ b/src/devices/cpu/dspp/dsppfe.h
@@ -0,0 +1,72 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ dsppfe.h
+
+ Front-end for DSPP recompiler
+
+***************************************************************************/
+
+#ifndef DEVICES_CPU_DSPP_DSPPFE_H
+#define DEVICES_CPU_DSPP_DSPPFE_H
+
+#include "dspp.h"
+#include "cpu/drcfe.h"
+
+
+//**************************************************************************
+// MACROS
+//**************************************************************************
+
+// register flags 0
+#define REGFLAG_R(n) (1 << (n))
+#define REGFLAG_RZ(n) (((n) == 0) ? 0 : REGFLAG_R(n))
+
+// register flags 1
+#define REGFLAG_FR(n) (1 << (n))
+
+// register flags 2
+#define REGFLAG_CR(n) (0xf0000000 >> (4 * (n)))
+#define REGFLAG_CR_BIT(n) (0x80000000 >> (n))
+
+// register flags 3
+#define REGFLAG_XER_CA (1 << 0)
+#define REGFLAG_XER_OV (1 << 1)
+#define REGFLAG_XER_SO (1 << 2)
+#define REGFLAG_XER_COUNT (1 << 3)
+#define REGFLAG_CTR (1 << 4)
+#define REGFLAG_LR (1 << 5)
+#define REGFLAG_FPSCR(n) (1 << (6 + (n)))
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class dspp_frontend : public drc_frontend
+{
+public:
+ // construction/destruction
+ dspp_frontend(dspp_device *dspp, uint32_t window_start, uint32_t window_end, uint32_t max_sequence);
+
+protected:
+ // required overrides
+ virtual bool describe(opcode_desc &desc, const opcode_desc *prev) override;
+
+private:
+ // inlines
+
+ // internal helpers
+ bool describe_special(uint16_t op, opcode_desc &desc);
+ bool describe_branch(uint16_t op, opcode_desc &desc);
+ bool describe_complex_branch(uint16_t op, opcode_desc &desc);
+ bool describe_arithmetic(uint16_t op, opcode_desc &desc);
+
+ // internal state
+ dspp_device *m_dspp;
+};
+
+
+#endif /* DEVICES_CPU_DSPP_DSPPFE_H */
diff --git a/src/devices/cpu/powerpc/ppc.h b/src/devices/cpu/powerpc/ppc.h
index cf3ecdef61f..4e4e1e144e2 100644
--- a/src/devices/cpu/powerpc/ppc.h
+++ b/src/devices/cpu/powerpc/ppc.h
@@ -208,6 +208,7 @@ protected:
public:
virtual ~ppc_device() override;
+ void set_cache_dirty() { m_cache_dirty = true; }
void set_bus_frequency(uint32_t bus_frequency) { c_bus_frequency = bus_frequency; }
void set_bus_frequency(const XTAL &xtal) { set_bus_frequency(xtal.value()); }
@@ -227,6 +228,7 @@ public:
void ppc_cfunc_printf_debug();
void ppc_cfunc_printf_probe();
void ppc_cfunc_unimplemented();
+ void ppc_cfunc_ppccom_mismatch();
void ppccom_tlb_fill();
void ppccom_update_fprf();
void ppccom_dcstore_callback();
diff --git a/src/devices/cpu/powerpc/ppccom.cpp b/src/devices/cpu/powerpc/ppccom.cpp
index 50881d922a4..4a8a071f903 100644
--- a/src/devices/cpu/powerpc/ppccom.cpp
+++ b/src/devices/cpu/powerpc/ppccom.cpp
@@ -1162,7 +1162,10 @@ void ppc_device::device_reset()
/* initialize the 602 HID0 register */
if (m_flavor == PPC_MODEL_602)
+ {
+ m_core->spr[SPR602_ESASRR] = 0;
m_core->spr[SPR603_HID0] = 1;
+ }
/* time base starts here */
m_tb_zero_cycles = total_cycles();
@@ -1326,6 +1329,15 @@ uint32_t ppc_device::ppccom_translate_address_internal(int intention, offs_t &ad
}
}
+#if 1
+ /* 602-specific Protection-Only mode */
+ if (m_flavor == PPC_MODEL_602 && m_core->spr[SPR603_HID0] & 0x00000080)
+ {
+ // TODO
+ return 0x001;
+ }
+#endif
+
/* look up the segment register */
segreg = m_core->sr[address >> 28];
if (transtype == TRANSLATE_FETCH && (segreg & 0x10000000))
@@ -1508,6 +1520,9 @@ void ppc_device::ppccom_execute_tlbl()
vtlb_entry flags;
int entrynum;
+ if (m_flavor == PPC_MODEL_602) // TODO
+ return;
+
/* determine entry number; we use machine().rand() for associativity */
entrynum = ((address >> 12) & 0x1f) | (machine().rand() & 0x20) | (isitlb ? 0x40 : 0);
@@ -1589,6 +1604,23 @@ void ppc_device::ppccom_execute_mfspr()
}
}
+ /* handle 602 SPRs */
+ if (m_flavor == PPC_MODEL_602)
+ { // TODO: Which are read/write only?
+ switch (m_core->param0)
+ {
+ case SPR602_TCR:
+ case SPR602_IBR:
+ case SPR602_ESASRR:
+ case SPR602_SEBR:
+ case SPR602_SER:
+ case SPR602_SP:
+ case SPR602_LT:
+ m_core->param1 = m_core->spr[m_core->param0];
+ return;
+ }
+ }
+
/* handle 603 SPRs */
if (m_cap & PPCCAP_603_MMU)
{
@@ -1715,6 +1747,23 @@ void ppc_device::ppccom_execute_mtspr()
}
}
+ /* handle 602 SPRs */
+ if (m_flavor == PPC_MODEL_602)
+ {
+ switch (m_core->param0)
+ { // TODO: Which are read/write only?
+ case SPR602_TCR:
+ case SPR602_IBR:
+ case SPR602_ESASRR:
+ case SPR602_SEBR:
+ case SPR602_SER:
+ case SPR602_SP:
+ case SPR602_LT:
+ m_core->spr[m_core->param0] = m_core->param1;
+ return;
+ }
+ }
+
/* handle 603 SPRs */
if (m_cap & PPCCAP_603_MMU)
{
diff --git a/src/devices/cpu/powerpc/ppccom.h b/src/devices/cpu/powerpc/ppccom.h
index 3492ce19b9d..ef3f917c426 100644
--- a/src/devices/cpu/powerpc/ppccom.h
+++ b/src/devices/cpu/powerpc/ppccom.h
@@ -302,6 +302,11 @@ enum
/* Machine State Register bits - 603 */
#define MSR603_TGPR 0x00020000 /* Temporary GPR Remapping */
+/* ESA Save and Restore Register bits - 602 */
+#define SPR602_ESASRR_EE 0x00000001 /* External Interrupt Enable */
+#define SPR602_ESASRR_SA 0x00000002 /* Supervisor access mode */
+#define SPR602_ESASRR_AP 0x00000004 /* Access privilege state */
+#define SPR602_ESASRR_PR 0x00000008 /* Privilege Level */
/* DSISR bits for DSI/alignment exceptions */
#define DSISR_DIRECT 0x80000000 /* DSI: direct-store error interrupt */
diff --git a/src/devices/cpu/powerpc/ppcdrc.cpp b/src/devices/cpu/powerpc/ppcdrc.cpp
index e41d1d5dd8d..e783328bf4b 100644
--- a/src/devices/cpu/powerpc/ppcdrc.cpp
+++ b/src/devices/cpu/powerpc/ppcdrc.cpp
@@ -533,6 +533,7 @@ static void cfunc_printf_probe(void *param)
void ppc_device::ppc_cfunc_printf_probe()
{
printf(" PC=%08X\n", m_core->pc);
+ printf(" LR=%08X\n", m_core->spr[SPR_LR]);
printf(" r0=%08X r1=%08X r2=%08X r3=%08X\n",
m_core->r[0], m_core->r[1], m_core->r[2], m_core->r[3]);
printf(" r4=%08X r5=%08X r6=%08X r7=%08X\n",
@@ -569,6 +570,17 @@ void ppc_device::ppc_cfunc_unimplemented()
fatalerror("PC=%08X: Unimplemented op %08X\n", m_core->pc, opcode);
}
+static void cfunc_ppccom_mismatch(void *param)
+{
+ ppc_device *ppc = (ppc_device *)param;
+ ppc->ppc_cfunc_ppccom_mismatch();
+}
+
+void ppc_device::ppc_cfunc_ppccom_mismatch()
+{
+// printf("cfunc_ppccom_mismatch %08X\n", m_core->pc);
+}
+
static void cfunc_ppccom_tlb_fill(void *param)
{
ppc_device *ppc = (ppc_device *)param;
@@ -767,6 +779,7 @@ void ppc_device::static_generate_tlb_mismatch()
UML_LOAD(block, I2, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4); // load i2,[vtlb],i1,dword
UML_MOV(block, mem(&m_core->param0), I0); // mov [param0],i0
UML_MOV(block, mem(&m_core->param1), TRANSLATE_FETCH); // mov [param1],TRANSLATE_FETCH
+ UML_CALLC(block, (c_function)cfunc_ppccom_mismatch, this);
UML_CALLC(block, (c_function)cfunc_ppccom_tlb_fill, this); // callc tlbfill,ppc
UML_LOAD(block, I1, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4); // load i1,[vtlb],i1,dword
UML_TEST(block, I1, VTLB_FETCH_ALLOWED); // test i1,VTLB_FETCH_ALLOWED
@@ -3456,8 +3469,30 @@ bool ppc_device::generate_instruction_1f(drcuml_block &block, compiler_state *co
return true;
case 0x254: /* ESA */
+ assert(m_flavor == PPC_MODEL_602);
+
+ // TODO: SE bit page attribute checking
+ UML_TEST(block, MSR32, MSR602_SA); // test [msr],MSR602_SA
+ UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_PROGRAM], 0x20000); // exh program,0x20000,nz
+ UML_ROLINS(block, SPR32(SPR602_ESASRR), MSR32, 17, SPR602_ESASRR_EE); // rolins msr32,esasrr,17,1
+ UML_ROLINS(block, SPR32(SPR602_ESASRR), MSR32, 11, SPR602_ESASRR_SA); // rolins msr32,esasrr,11,2
+ UML_ROLINS(block, SPR32(SPR602_ESASRR), MSR32, 11, SPR602_ESASRR_AP); // rolins msr32,esasrr,11,4
+ UML_ROLINS(block, SPR32(SPR602_ESASRR), MSR32, 21, SPR602_ESASRR_PR); // rolins msr32,esasrr,21,8
+ UML_AND(block, MSR32, MSR32, ~(MSR602_AP | MSR_EE | MSR_PR)); // and msr,msr,~(MSR_EE | MSR_PR | MSR_AP)
+ UML_OR(block, MSR32, MSR32, MSR602_SA); // or msr,msr,MSR_SA
+ generate_update_mode(block); // <update mode>
+ return true;
+
case 0x274: /* DSA */
- /* no-op for now */
+ assert(m_flavor == PPC_MODEL_602);
+
+ UML_TEST(block, MSR32, MSR602_SA); // test [msr],MSR602_SA
+ UML_EXHc(block, COND_Z, *m_exception[EXCEPTION_PROGRAM], 0x20000); // exh program,0x20000,z
+ UML_ROLINS(block, MSR32, SPR32(SPR602_ESASRR), 15, MSR_EE); // rolins msr32,esasrr,15,0x00008000
+ UML_ROLINS(block, MSR32, SPR32(SPR602_ESASRR), 21, MSR602_SA); // rolins msr32,esasrr,21,0x00400000
+ UML_ROLINS(block, MSR32, SPR32(SPR602_ESASRR), 21, MSR602_AP); // rolins msr32,esasrr,21,0x00800000
+ UML_ROLINS(block, MSR32, SPR32(SPR602_ESASRR), 11, MSR_PR); // rolins msr32,esasrr,11,0x00004000
+ generate_update_mode(block); // <update mode>
return true;
}
diff --git a/src/devices/cpu/powerpc/ppcfe.cpp b/src/devices/cpu/powerpc/ppcfe.cpp
index 23270357f06..fbb6ae3a313 100644
--- a/src/devices/cpu/powerpc/ppcfe.cpp
+++ b/src/devices/cpu/powerpc/ppcfe.cpp
@@ -1148,7 +1148,7 @@ bool ppc_device::frontend::describe_1f(uint32_t op, opcode_desc &desc, const opc
case 0x274: // DSA
if (!is_602_class())
return false;
- desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION;
+ desc.flags |= OPFLAG_CAN_CHANGE_MODES | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_END_SEQUENCE;
return true;
}
diff --git a/src/devices/machine/netlist.h b/src/devices/machine/netlist.h
index 1c00aeec8f5..51819e7f701 100644
--- a/src/devices/machine/netlist.h
+++ b/src/devices/machine/netlist.h
@@ -377,6 +377,12 @@ class netlist_mame_int_input_device : public device_t, public netlist_mame_sub_i
{
public:
// construction/destruction
+ netlist_mame_int_input_device(const machine_config &mconfig, const char *tag, device_t *owner, const char *param_name, const uint32_t mask,
+ const uint32_t shift)
+ : netlist_mame_int_input_device(mconfig, tag, owner, (uint32_t)0)
+ {
+ set_params(param_name, mask, shift);
+ }
netlist_mame_int_input_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
void set_params(const char *param_name, const uint32_t mask, const uint32_t shift);
diff --git a/src/devices/machine/spg2xx.cpp b/src/devices/machine/spg2xx.cpp
index 848149c784d..a325346558d 100644
--- a/src/devices/machine/spg2xx.cpp
+++ b/src/devices/machine/spg2xx.cpp
@@ -48,29 +48,12 @@ DEFINE_DEVICE_TYPE(SPG28X, spg28x_device, "spg28x", "SPG280-series System-on-a-C
#define LOG_PPU (LOG_PPU_READS | LOG_PPU_WRITES | LOG_UNKNOWN_PPU)
#define LOG_ALL (LOG_IO | LOG_SPU | LOG_PPU | LOG_VLINES | LOG_SEGMENT)
-#define VERBOSE (0)
+#define VERBOSE (LOG_UART | LOG_UNKNOWN_IO)
#include "logmacro.h"
#define SPG_DEBUG_VIDEO (0)
#define SPG_DEBUG_AUDIO (0)
-#if SPG2XX_VISUAL_AUDIO_DEBUG
-static const uint32_t s_visual_debug_palette[8] = {
- 0xff000000,
- 0xff0000ff,
- 0xff00ff00,
- 0xff00ffff,
- 0xffff0000,
- 0xffff00ff,
- 0xffffff00,
- 0xffffffff
-};
-#define SPG_VDB_BLACK 0
-#define SPG_VDB_WAVE 1
-#define SPG_VDB_EDD 2
-#define SPG_VDB_VOL 4
-#endif
-
#define IO_IRQ_ENABLE m_io_regs[0x21]
#define IO_IRQ_STATUS m_io_regs[0x22]
#define VIDEO_IRQ_ENABLE m_video_regs[0x62]
@@ -94,9 +77,6 @@ spg2xx_device::spg2xx_device(const machine_config &mconfig, device_type type, co
, m_scrollram(*this, "scrollram")
, m_paletteram(*this, "paletteram")
, m_spriteram(*this, "spriteram")
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- , m_audio_screen(*this, finder_base::DUMMY_TAG)
-#endif
{
}
@@ -123,9 +103,6 @@ void spg2xx_device::map(address_map &map)
void spg2xx_device::device_start()
{
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- m_audio_debug_buffer = std::make_unique<uint8_t[]>(1024*768);
-#endif
m_porta_out.resolve_safe();
m_portb_out.resolve_safe();
m_portc_out.resolve_safe();
@@ -170,6 +147,10 @@ void spg2xx_device::device_reset()
m_io_regs[0x23] = 0x0028;
m_uart_rx_available = false;
+ memset(m_uart_rx_fifo, 0, ARRAY_LENGTH(m_uart_rx_fifo));
+ m_uart_rx_fifo_start = 0;
+ m_uart_rx_fifo_end = 0;
+ m_uart_rx_fifo_count = 0;
m_video_regs[0x36] = 0xffff;
m_video_regs[0x37] = 0xffff;
@@ -506,30 +487,6 @@ void spg2xx_device::apply_fade(const rectangle &cliprect)
}
}
-#if SPG2XX_VISUAL_AUDIO_DEBUG
-uint32_t spg2xx_device::debug_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
-{
- bitmap.fill(0, cliprect);
- for (int y = 0; y < 768; y++)
- {
- for (int x = 0; x < 1024; x++)
- {
- bitmap.pix32(y, x) = s_visual_debug_palette[m_audio_debug_buffer[y*1024+x]];
- }
- }
- return 0;
-}
-
-void spg2xx_device::advance_debug_pos()
-{
- m_audio_debug_x++;
- if (m_audio_debug_x == 1024)
- {
- m_audio_debug_x = 0;
- }
-}
-#endif
-
uint32_t spg2xx_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
memset(&m_screenbuf[320 * cliprect.min_y], 0, 3 * 320 * ((cliprect.max_y - cliprect.min_y) + 1));
@@ -861,12 +818,19 @@ void spg2xx_device::uart_rx(uint8_t data)
IO_IRQ_STATUS |= 0x0100;
check_irqs(0x0100);
}
+ m_uart_rx_available = true;
}
}
- else
+ else if (m_uart_rx_fifo_count == ARRAY_LENGTH(m_uart_rx_fifo))
{
m_io_regs[0x37] |= 0x4000;
}
+ else
+ {
+ m_uart_rx_fifo[m_uart_rx_fifo_end] = data;
+ m_uart_rx_fifo_end = (m_uart_rx_fifo_end + 1) % ARRAY_LENGTH(m_uart_rx_fifo);
+ m_uart_rx_fifo_count++;
+ }
}
READ16_MEMBER(spg2xx_device::io_r)
@@ -947,21 +911,29 @@ READ16_MEMBER(spg2xx_device::io_r)
break;
case 0x31: // UART Status
- val |= 0x81;//(m_uart_rx_available ? 0x81 : 0);
+ val |= (m_uart_rx_available ? 0x81 : 0);
LOGMASKED(LOG_UART, "io_r: UART Status = %04x\n", val);
break;
case 0x36: // UART RX Data
if (m_uart_rx_available)
{
- m_uart_rx_available = false;
- m_io_regs[0x36] = 0;
+ if (m_uart_rx_fifo_count)
+ {
+ m_io_regs[0x36] = m_uart_rx_fifo[m_uart_rx_fifo_start];
+ m_uart_rx_fifo_start = (m_uart_rx_fifo_start + 1) % ARRAY_LENGTH(m_uart_rx_fifo);
+ m_uart_rx_fifo_count--;
+ }
+ else
+ {
+ m_uart_rx_available = false;
+ }
}
else
{
m_io_regs[0x37] |= 0x2000;
}
- LOGMASKED(LOG_UART, "io_r: UART Rx Data = %04x\n", val);
+ LOGMASKED(LOG_UART, "%s: io_r: UART Rx Data = %04x\n", machine().describe_context(), val);
break;
case 0x37: // UART Rx FIFO Control
@@ -1319,10 +1291,14 @@ WRITE16_MEMBER(spg2xx_device::io_w)
m_io_regs[offset] &= ~data;
break;
- case 0x33: // UART Baud Rate
- LOGMASKED(LOG_UART, "io_w: UART Baud Rate = %d\n", 27000000 / (0x10000 - data));
+ case 0x33: // UART Baud Rate (low byte)
+ case 0x34: // UART Baud Rate (high byte)
+ {
m_io_regs[offset] = data;
+ const uint32_t divisor = 16 * (0x10000 - ((m_io_regs[0x34] << 8) | m_io_regs[0x33]));
+ LOGMASKED(LOG_UART, "io_w: UART Baud Rate (%s byte): Baud rate = %d\n", offset == 0x33 ? "low" : "high", 27000000 / divisor);
break;
+ }
case 0x35: // UART TX Data
LOGMASKED(LOG_UART, "io_w: UART Tx Data = %02x\n", data & 0x00ff);
@@ -2234,39 +2210,10 @@ void spg2xx_device::sound_stream_update(sound_stream &stream, stream_sample_t **
int32_t right_total = 0;
int32_t active_count = 0;
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- for (int y = 0; y < 768; y++)
- {
- m_audio_debug_buffer[y*1024 + m_audio_debug_x] = 0;
- }
-#endif
for (uint32_t ch_index = 0; ch_index < 16; ch_index++)
{
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- uint32_t debug_y = 0;
- if (m_channel_debug < 0)
- debug_y = ch_index * 48;
-#endif
if (!get_channel_status(ch_index))
{
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- if (m_channel_debug == -1)
- {
- m_audio_debug_buffer[(debug_y + 47)*1024 + m_audio_debug_x] |= SPG_VDB_WAVE;
- int edd_y = (int)((float)get_edd(ch_index) * 0.375f);
- m_audio_debug_buffer[(debug_y + (47 - edd_y))*1024 + m_audio_debug_x] |= SPG_VDB_EDD;
- int vol_y = (int)((float)get_volume(ch_index) * 0.375f);
- m_audio_debug_buffer[(debug_y + (47 - vol_y))*1024 + m_audio_debug_x] |= SPG_VDB_VOL;
- }
- else if (ch_index == m_channel_debug)
- {
- m_audio_debug_buffer[(debug_y + 767)*1024 + m_audio_debug_x] |= SPG_VDB_WAVE;
- int edd_y = (int)((float)get_edd(ch_index) * 3.74f);
- m_audio_debug_buffer[(debug_y + (767 - edd_y))*1024 + m_audio_debug_x] |= SPG_VDB_EDD;
- int vol_y = (int)((float)get_volume(ch_index) * 3.74f);
- m_audio_debug_buffer[(debug_y + (767 - vol_y))*1024 + m_audio_debug_x] |= SPG_VDB_VOL;
- }
-#endif
continue;
}
@@ -2276,26 +2223,6 @@ void spg2xx_device::sound_stream_update(sound_stream &stream, stream_sample_t **
if (playing)
{
int32_t sample = (int16_t)(m_audio_regs[(ch_index << 4) | AUDIO_WAVE_DATA] ^ 0x8000);
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- if (m_channel_debug == -1)
- {
- int sample_y = (int)((float)m_audio_regs[(ch_index << 4) | AUDIO_WAVE_DATA] / 1365.0f);
- m_audio_debug_buffer[(debug_y + (47 - sample_y))*1024 + m_audio_debug_x] |= SPG_VDB_WAVE;
- int edd_y = (int)((float)get_edd(ch_index) * 0.375f);
- m_audio_debug_buffer[(debug_y + (47 - edd_y))*1024 + m_audio_debug_x] |= SPG_VDB_EDD;
- int vol_y = (int)((float)get_volume(ch_index) * 0.375f);
- m_audio_debug_buffer[(debug_y + (47 - vol_y))*1024 + m_audio_debug_x] |= SPG_VDB_VOL;
- }
- else if (ch_index == m_channel_debug)
- {
- int sample_y = (int)((float)m_audio_regs[(ch_index << 4) | AUDIO_WAVE_DATA] / 136.0f);
- m_audio_debug_buffer[(debug_y + (767 - sample_y))*1024 + m_audio_debug_x] |= SPG_VDB_WAVE;
- int edd_y = (int)((float)get_edd(ch_index) * 0.375f);
- m_audio_debug_buffer[(debug_y + (767 - edd_y))*1024 + m_audio_debug_x] |= SPG_VDB_EDD;
- int vol_y = (int)((float)get_volume(ch_index) * 0.375f);
- m_audio_debug_buffer[(debug_y + (767 - vol_y))*1024 + m_audio_debug_x] |= SPG_VDB_VOL;
- }
-#endif
if (!(m_audio_regs[AUDIO_CONTROL] & AUDIO_CONTROL_NOINT_MASK))
{
int32_t prev_sample = (int16_t)(m_audio_regs[(ch_index << 4) | AUDIO_WAVE_DATA_PREV] ^ 0x8000);
@@ -2329,10 +2256,6 @@ void spg2xx_device::sound_stream_update(sound_stream &stream, stream_sample_t **
}
}
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- advance_debug_pos();
-#endif
-
if (active_count)
{
left_total /= active_count;
@@ -2345,15 +2268,7 @@ void spg2xx_device::sound_stream_update(sound_stream &stream, stream_sample_t **
*out_l++ = 0;
*out_r++ = 0;
}
-
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- for (int y = 0; y < 768; y++)
- {
- m_audio_debug_buffer[y*1024 + m_audio_debug_x] = 7;
- }
-#endif
}
- //printf("\n");
}
inline void spg2xx_device::stop_channel(const uint32_t channel)
@@ -2519,7 +2434,6 @@ bool spg2xx_device::fetch_sample(address_space &space, const uint32_t channel)
inline void spg2xx_device::loop_channel(const uint32_t channel)
{
- //printf("Looping from %08x to %08x\n", m_sample_addr[channel], get_loop_addr(channel));
m_sample_addr[channel] = get_loop_addr(channel);
m_sample_shift[channel] = 0;
}
diff --git a/src/devices/machine/spg2xx.h b/src/devices/machine/spg2xx.h
index c4967efdaf8..e851531693f 100644
--- a/src/devices/machine/spg2xx.h
+++ b/src/devices/machine/spg2xx.h
@@ -9,6 +9,30 @@
- I2C
- SPI
+ Known SunPlus SPG2xx/u'nSP-based systems:
+
+ D - SPG240 - Radica Skateboarder (Sunplus QL8041C die)
+ ND - SPG243 - Some form of Leapfrog "edutainment" system
+ ND - SPG243 - Star Wars: Clone Wars
+ ND - SPG243 - Toy Story
+ ND - SPG243 - Animal Art Studio
+ ND - SPG243 - Finding Nemo
+ D - SPG243 - The Batman
+ D - SPG243 - Wall-E
+ D - SPG243 - KenSingTon / Siatronics / Jungle Soft Vii
+ Partial D - SPG200 - VTech V.Smile
+ ND - unknown - Zone 40
+ D - SPG243 - Zone 60
+ D - SPG243 - Wireless 60
+ ND - unknown - Wireless Air 60
+ ND - Likely many more
+
+ Also on this hardware:
+
+ name PCB ID ROM width TSOP pads ROM size SEEPROM die markings
+ Radica Play TV Football 2 L7278 x16 48 not dumped no Sunplus
+ Dream Life ? x16 48 not dumped no Sunplus
+
**********************************************************************/
#ifndef MAME_MACHINE_SPG2XX_H
@@ -20,8 +44,6 @@
#include "sound/okiadpcm.h"
#include "screen.h"
-#define SPG2XX_VISUAL_AUDIO_DEBUG (0)
-
class spg2xx_device : public device_t, public device_sound_interface
{
public:
@@ -48,10 +70,6 @@ public:
void uart_rx(uint8_t data);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- void advance_debug_pos();
- uint32_t debug_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
-#endif
DECLARE_WRITE_LINE_MEMBER(vblank);
protected:
@@ -438,6 +456,10 @@ protected:
uint16_t m_audio_curr_beat_base_count;
uint16_t m_io_regs[0x200];
+ uint8_t m_uart_rx_fifo[8];
+ uint8_t m_uart_rx_fifo_start;
+ uint8_t m_uart_rx_fifo_end;
+ uint8_t m_uart_rx_fifo_count;
bool m_uart_rx_available;
uint16_t m_video_regs[0x100];
@@ -472,12 +494,6 @@ protected:
required_shared_ptr<uint16_t> m_paletteram;
required_shared_ptr<uint16_t> m_spriteram;
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- std::unique_ptr<uint8_t[]> m_audio_debug_buffer;
- uint16_t m_audio_debug_x;
- required_device<screen_device> m_audio_screen;
-#endif
-
static const uint32_t s_rampdown_frame_counts[8];
static const uint32_t s_envclk_frame_counts[16];
};
@@ -485,20 +501,12 @@ protected:
class spg24x_device : public spg2xx_device
{
public:
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- template <typename T, typename U, typename V>
- spg24x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag, V &&debug_screen_tag)
-#else
template <typename T, typename U>
spg24x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag)
-#endif
: spg24x_device(mconfig, tag, owner, clock)
{
m_cpu.set_tag(std::forward<T>(cpu_tag));
m_screen.set_tag(std::forward<U>(screen_tag));
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- m_audio_screen.set_tag(std::forward<V>(debug_screen_tag));
-#endif
}
spg24x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -507,20 +515,12 @@ public:
class spg28x_device : public spg2xx_device
{
public:
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- template <typename T, typename U, typename V>
- spg28x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag, V &&debug_screen_tag)
-#else
template <typename T, typename U>
spg28x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag, U &&screen_tag)
-#endif
: spg28x_device(mconfig, tag, owner, clock)
{
m_cpu.set_tag(std::forward<T>(cpu_tag));
m_screen.set_tag(std::forward<U>(screen_tag));
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- m_audio_screen.set_tag(std::forward<V>(debug_screen_tag));
-#endif
}
spg28x_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
diff --git a/src/devices/machine/t10mmc.cpp b/src/devices/machine/t10mmc.cpp
index 73de91d7f97..82754b229f0 100644
--- a/src/devices/machine/t10mmc.cpp
+++ b/src/devices/machine/t10mmc.cpp
@@ -116,7 +116,7 @@ void t10mmc::ExecCommand()
switch ( command[0] )
{
case T10SPC_CMD_INQUIRY:
- m_device->logerror("T10MMC: INQUIRY\n");
+ //m_device->logerror("T10MMC: INQUIRY\n");
m_phase = SCSI_PHASE_DATAIN;
m_status_code = SCSI_STATUS_CODE_GOOD;
m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] );
@@ -125,7 +125,7 @@ void t10mmc::ExecCommand()
break;
case T10SPC_CMD_MODE_SELECT_6:
- m_device->logerror("T10MMC: MODE SELECT(6) length %x control %x\n", command[4], command[5]);
+ //m_device->logerror("T10MMC: MODE SELECT(6) length %x control %x\n", command[4], command[5]);
m_phase = SCSI_PHASE_DATAOUT;
m_status_code = SCSI_STATUS_CODE_GOOD;
m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] );
@@ -160,7 +160,7 @@ void t10mmc::ExecCommand()
m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
m_blocks = SCSILengthFromUINT16( &command[7] );
- m_device->logerror("T10MMC: READ(10) at LBA %x for %d blocks (%d bytes)\n", m_lba, m_blocks, m_blocks * m_sector_bytes);
+ //m_device->logerror("T10MMC: READ(10) at LBA %x for %d blocks (%d bytes)\n", m_lba, m_blocks, m_blocks * m_sector_bytes);
if (m_num_subblocks > 1)
{
@@ -234,7 +234,7 @@ void t10mmc::ExecCommand()
m_device->logerror("T10MMC: play audio from current not implemented!\n");
}
- m_device->logerror("T10MMC: PLAY AUDIO(10) at LBA %x for %x blocks\n", m_lba, m_blocks);
+ //m_device->logerror("T10MMC: PLAY AUDIO(10) at LBA %x for %x blocks\n", m_lba, m_blocks);
trk = cdrom_get_track(m_cdrom, m_lba);
@@ -268,8 +268,8 @@ void t10mmc::ExecCommand()
m_device->logerror("T10MMC: play audio from current not implemented!\n");
}
- m_device->logerror("T10MMC: PLAY AUDIO MSF at LBA %x for %x blocks (MSF %i:%i:%i - %i:%i:%i)\n",
- m_lba, m_blocks, command[3], command[4], command[5], command[6], command[7], command[8]);
+ //m_device->logerror("T10MMC: PLAY AUDIO MSF at LBA %x for %x blocks (MSF %i:%i:%i - %i:%i:%i)\n",
+ //m_lba, m_blocks, command[3], command[4], command[5], command[6], command[7], command[8]);
trk = cdrom_get_track(m_cdrom, m_lba);
@@ -300,7 +300,7 @@ void t10mmc::ExecCommand()
{
// be careful: tracks here are zero-based, but the SCSI command
// uses the real CD track number which is 1-based!
- m_device->logerror("T10MMC: PLAY AUDIO T/I: strk %d idx %d etrk %d idx %d frames %d\n", command[4], command[5], command[7], command[8], m_blocks);
+ //m_device->logerror("T10MMC: PLAY AUDIO T/I: strk %d idx %d etrk %d idx %d frames %d\n", command[4], command[5], command[7], command[8], m_blocks);
int end_track = cdrom_get_last_track(m_cdrom);
if (end_track > command[7])
end_track = command[7];
@@ -341,7 +341,7 @@ void t10mmc::ExecCommand()
m_cdda->pause_audio((command[8] & 0x01) ^ 0x01);
}
- m_device->logerror("T10MMC: PAUSE/RESUME: %s\n", command[8]&1 ? "RESUME" : "PAUSE");
+ //m_device->logerror("T10MMC: PAUSE/RESUME: %s\n", command[8]&1 ? "RESUME" : "PAUSE");
m_phase = SCSI_PHASE_STATUS;
m_status_code = SCSI_STATUS_CODE_GOOD;
m_transfer_length = 0;
@@ -350,14 +350,14 @@ void t10mmc::ExecCommand()
case T10MMC_CMD_STOP_PLAY_SCAN:
abort_audio();
- m_device->logerror("T10MMC: STOP_PLAY_SCAN\n");
+ //m_device->logerror("T10MMC: STOP_PLAY_SCAN\n");
m_phase = SCSI_PHASE_STATUS;
m_status_code = SCSI_STATUS_CODE_GOOD;
m_transfer_length = 0;
break;
case T10SPC_CMD_MODE_SELECT_10:
- m_device->logerror("T10MMC: MODE SELECT length %x control %x\n", command[7]<<8 | command[8], command[1]);
+ //m_device->logerror("T10MMC: MODE SELECT length %x control %x\n", command[7]<<8 | command[8], command[1]);
m_phase = SCSI_PHASE_DATAOUT;
m_status_code = SCSI_STATUS_CODE_GOOD;
m_transfer_length = SCSILengthFromUINT16( &command[ 7 ] );
@@ -383,7 +383,7 @@ void t10mmc::ExecCommand()
m_device->logerror("T10MMC: play audio from current not implemented!\n");
}
- m_device->logerror("T10MMC: PLAY AUDIO(12) at LBA %x for %x blocks\n", m_lba, m_blocks);
+ //m_device->logerror("T10MMC: PLAY AUDIO(12) at LBA %x for %x blocks\n", m_lba, m_blocks);
trk = cdrom_get_track(m_cdrom, m_lba);
@@ -407,7 +407,7 @@ void t10mmc::ExecCommand()
m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5];
m_blocks = command[7]<<16 | command[8]<<8 | command[9];
- m_device->logerror("T10MMC: READ(12) at LBA %x for %x blocks (%x bytes)\n", m_lba, m_blocks, m_blocks * m_sector_bytes);
+ //m_device->logerror("T10MMC: READ(12) at LBA %x for %x blocks (%x bytes)\n", m_lba, m_blocks, m_blocks * m_sector_bytes);
if (m_num_subblocks > 1)
{
@@ -482,7 +482,7 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
case T10SBC_CMD_READ_10:
case T10SBC_CMD_READ_12:
- m_device->logerror("T10MMC: read %x dataLength, \n", dataLength);
+ //m_device->logerror("T10MMC: read %x dataLength, \n", dataLength);
if ((m_cdrom) && (m_blocks))
{
while (dataLength > 0)
@@ -492,7 +492,7 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
m_device->logerror("T10MMC: CD read error!\n");
}
- m_device->logerror("True LBA: %d, buffer half: %d\n", m_lba, m_cur_subblock * m_sector_bytes);
+ //m_device->logerror("True LBA: %d, buffer half: %d\n", m_lba, m_cur_subblock * m_sector_bytes);
memcpy(data, &tmp_buffer[m_cur_subblock * m_sector_bytes], m_sector_bytes);
diff --git a/src/devices/sound/discrete.h b/src/devices/sound/discrete.h
index 97d33b33e03..d06a18bf3a5 100644
--- a/src/devices/sound/discrete.h
+++ b/src/devices/sound/discrete.h
@@ -4252,13 +4252,6 @@ public:
};
//**************************************************************************
-// INTERFACE CONFIGURATION MACROS
-//**************************************************************************
-
-#define MCFG_DISCRETE_INTF(_intf) \
- downcast<discrete_device &>(*device).set_intf(_intf);
-
-//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
diff --git a/src/devices/sound/okim6295.h b/src/devices/sound/okim6295.h
index 88a72dbe61c..536c76b3b10 100644
--- a/src/devices/sound/okim6295.h
+++ b/src/devices/sound/okim6295.h
@@ -15,16 +15,6 @@
#include "sound/okiadpcm.h"
-
-
-//**************************************************************************
-// INTERFACE CONFIGURATION MACROS
-//**************************************************************************
-
-#define MCFG_OKIM6295_PIN7(pin7) \
- downcast<okim6295_device &>(*device).config_pin7((okim6295_device::pin7));
-
-
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
diff --git a/src/mame/audio/mario.cpp b/src/mame/audio/mario.cpp
index 7759a09c720..95c073be458 100644
--- a/src/mame/audio/mario.cpp
+++ b/src/mame/audio/mario.cpp
@@ -635,8 +635,8 @@ void mario_state::masao_sound_map(address_map &map)
*
*************************************/
-MACHINE_CONFIG_START(mario_state::mario_audio)
-
+void mario_state::mario_audio(machine_config &config)
+{
#if USE_8039
i8039_device &audiocpu(I8039(config, "audiocpu", I8035_CLOCK)); /* 730 kHz */
#else
@@ -659,24 +659,22 @@ MACHINE_CONFIG_START(mario_state::mario_audio)
GENERIC_LATCH_8(config, m_soundlatch4);
#if OLD_SOUND
- MCFG_DEVICE_ADD("discrete", DISCRETE)
- MCFG_DISCRETE_INTF(mario_discrete)
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1)
+ DISCRETE(config, m_discrete);
+ m_discrete->set_intf(mario_discrete);
+ m_discrete->add_route(ALL_OUTPUTS, "mono", 1);
#else
- MCFG_DEVICE_ADD("snd_nl", NETLIST_SOUND, 48000)
- MCFG_NETLIST_SETUP(mario)
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
+ netlist_mame_sound_device &snd_nl(NETLIST_SOUND(config, "snd_nl", 48000));
+ snd_nl.set_constructor(netlist_mario);
+ snd_nl.add_route(ALL_OUTPUTS, "mono", 1.0);
- MCFG_NETLIST_LOGIC_INPUT("snd_nl", "snd0", "SOUND0.IN", 0)
- MCFG_NETLIST_LOGIC_INPUT("snd_nl", "snd1", "SOUND1.IN", 0)
- MCFG_NETLIST_LOGIC_INPUT("snd_nl", "snd7", "SOUND7.IN", 0)
- MCFG_NETLIST_INT_INPUT("snd_nl", "dac", "DAC.VAL", 0, 255)
+ NETLIST_LOGIC_INPUT(config, m_audio_snd0, "SOUND0.IN", 0);
+ NETLIST_LOGIC_INPUT(config, m_audio_snd1, "SOUND1.IN", 0);
+ NETLIST_LOGIC_INPUT(config, m_audio_snd7, "SOUND7.IN", 0);
+ NETLIST_INT_INPUT(config, m_audio_dac, "DAC.VAL", 0, 255);
- MCFG_NETLIST_STREAM_OUTPUT("snd_nl", 0, "ROUT.1")
- MCFG_NETLIST_ANALOG_MULT_OFFSET(150000.0, 0.0)
+ NETLIST_STREAM_OUTPUT(config, "snd_nl:cout0", 0, "ROUT.1").set_mult_offset(150000.0, 0.0);
#endif
-
-MACHINE_CONFIG_END
+}
void mario_state::masao_audio(machine_config &config)
{
diff --git a/src/mame/drivers/konamim2.cpp b/src/mame/drivers/konamim2.cpp
index 25167ee3156..787438f75b2 100644
--- a/src/mame/drivers/konamim2.cpp
+++ b/src/mame/drivers/konamim2.cpp
@@ -1,8 +1,45 @@
// license:BSD-3-Clause
-// copyright-holders:Ville Linde
-/*
-Konami M2 Hardware
-Preliminary driver by Ville Linde
+// copyright-holders:Phil Bennett
+
+/***************************************************************************
+
+ Konami M2 hardware
+
+ driver by Phil Bennett
+
+ NOTE:
+
+ * All games are marked MACHINE_NOT_WORKING due to the rare case
+ where the PowerPC DRC blows up, causing MAME to crash. In reality,
+ there is a good chance of being able to play through a round or
+ three with no issues on all of the parent sets.
+
+ TODO:
+
+ * Fix DRC crashes
+ o Crashes on DRC translation of 0x40028604
+ * Fix texture compression
+ * Sort out CD images
+ * Fix Polystars blending issues
+ * Fix PowerPC 602 Protection Only mode handling.
+ * Implement CDDA muting
+
+ DONE
+ * Fix Polystars blending
+ * Fix missing music in Polystars
+ * Fix music playing too early
+ * Fix missing music and sound in Hell Night/Evil Night
+ * Fix incorrect speed in Heat of 11 and Total Vice (partially)
+
+ // Polystars/Total Vice
+ if (pc == 0x40035958)
+ gpr[11] = 1;
+
+ // Everything else
+ if (pc == 0x400385c8)
+ gpr[11] = 0;
+
+
Konami M2 Hardware Overview
@@ -12,14 +49,14 @@ This hardware is 3DO-based with two IBM Power PC CPUs.
There were only 5 known games on this hardware. They include....
-Game Year CD Codes Konami Part#
--------------------------------------------------------------------------------------------------
+Game Year CD Codes Konami Part#
+-------------------------------------------------------------------------------------------------------------------
Battle Tryst 1998 636JAC02
Evil Night 1998 810UBA02
Hell Night (alt. Region title, same as Evil Night) 1998 810EAA02
Heat Of Eleven '98 1998 703EAA02
-Tobe! Polystars 1997 623JAA02 003894
-Total Vice 1997 639UAC01, 639JAD01, 639AAB01
+Tobe! Polystars 1997 623JAA02 003894
+Total Vice 1997 639UAC01, 639EAD01, 639JAD01, 639AAB01
PCB Layouts
@@ -57,7 +94,7 @@ Notes:
*2 - Motorola MC44200FT
*3 - [M] BIG BODY 2 BU6244KS 704 157 (QFP56)
*4 - Unknown BGA chip (Graphics Engine, with heatsink attached)
- DSW - 2 position dip switch
+ DSW - 2 position DIP switch
Bottom Board
@@ -81,15 +118,15 @@ PWB403045B (C) 1997 KONAMI CO., LTD.
| |
|----------------------------------------------------------|
Notes:
- 056879 - Konami custom IC, location 10E (TQFP120)
- 058232 - Konami custom ceramic flat pack IC, DAC? (SIP14)
+ 056879 - Konami custom IC, location 10E (QFP120)
+ 058232 - Konami custom ceramic flat pack IC, DAC?
003461 - Konami custom IC, location 11K (QFP100)
CN16 - 4 pin connector for CD-DA in from CDROM
CN15 - Standard (PC-compatible) 40 pin IDE CDROM flat cable connector and 4 pin power plug connector,
connected to Panasonic CR-583 8-speed CDROM drive.
LA4705 - LA4705 Power Amplifier
DSW - 8 position dip switch
- BOOTROM.8Q - 16MBit mask ROM. Location 8Q (DIP42)
+ BOOTROM.8Q - 16MBit MASKROM. Location 8Q (DIP42)
Battle Tryst - 636A01.8Q
Evil Night - .8Q
Heat Of Eleven '98 - .8Q
@@ -185,1170 +222,1087 @@ Notes:
M48T58Y - ST M48T58Y-70PC1 NonVolatile TimeKeeping RAM
CN3 - 4-pin sound cable tied to CN16 (CD-DA Input) on main lower board
CN4 - 4-pin sound cable tied to CDROM analog audio output connector
-*/
+***************************************************************************/
#include "emu.h"
-#include "cdrom.h"
#include "cpu/powerpc/ppc.h"
-#include "imagedev/chd_cd.h"
-#include "machine/terminal.h"
-#include "emupal.h"
+#include "machine/3dom2.h"
+#include "machine/ataintf.h"
+#include "machine/cr589.h"
+#include "machine/eepromser.h"
+#include "machine/timekpr.h"
+#include "sound/dac.h"
+#include "sound/volt_reg.h"
+#include "sound/ymz280b.h"
+#include "cdrom.h"
+#include "debug/debugcon.h"
+#include "debug/debugcmd.h"
+#include "debugger.h"
#include "romload.h"
-#include "softlist.h"
#include "screen.h"
+#include "speaker.h"
-struct CDE_DMA
-{
- uint32_t dst_addr;
- int length;
- uint32_t next_dst_addr;
- int next_length;
- int dma_done;
-};
+#define M2_CLOCK XTAL(66'666'700)
+
+#define ENABLE_SDBG 0
+
+
+/*************************************
+ *
+ * ROM definition(s)
+ *
+ *************************************/
class konamim2_state : public driver_device
{
public:
konamim2_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag),
- m_main_ram(*this, "main_ram"),
- m_terminal(*this, "terminal"),
- m_in_country(*this, "COUNTRY"),
- m_in_card(*this, "CARD"),
- m_in_monitor(*this, "MONITOR"),
- m_maincpu(*this, "maincpu"),
- m_subcpu(*this, "sub") { }
+ m_ppc1(*this, "ppc1"),
+ m_ppc2(*this, "ppc2"),
+ m_bda(*this, "bda"),
+ m_cde(*this, "cde"),
+ m_eeprom(*this, "eeprom"),
+ m_ldac(*this, "ldac"),
+ m_rdac(*this, "rdac"),
+ m_ata(*this, "ata"),
+ m_screen(*this, "screen"),
+ m_m48t58(*this, "m48t58"),
+ m_ymz280b(*this, "ymz")
+ {
+ }
- void m2(machine_config &config);
- void _3do_m2(machine_config &config);
+ void konamim2(machine_config &config);
+ void set_ntsc(machine_config &config);
+ void set_ntsc2(machine_config &config);
+ void set_arcres(machine_config &config);
+ void add_ymz280b(machine_config &config);
+ void add_mt48t58(machine_config &config);
+ void polystar(machine_config &config);
+ void totlvice(machine_config &config);
+ void btltryst(machine_config &config);
+ void heatof11(machine_config &config);
+ void evilngt(machine_config &config);
+ void hellngt(machine_config &config);
+
+ static void cr589_config(device_t *device);
+
+ void m2_map(address_map &map);
+
+protected:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
- void init_m2();
+ void update_disc();
-private:
- required_shared_ptr<uint64_t> m_main_ram;
- required_device<generic_terminal_device> m_terminal;
- required_ioport m_in_country;
- required_ioport m_in_card;
- required_ioport m_in_monitor;
-
- uint32_t m_vdl0_address;
- uint32_t m_vdl1_address;
- uint32_t m_irq_enable;
- uint32_t m_irq_active;
- uint64_t m_unk3;
- uint32_t m_unk20004;
- int m_counter1;
- int m_cde_num_status_bytes;
- uint32_t m_cde_status_bytes[16];
- int m_cde_status_byte_ptr;
- uint32_t m_cde_command_bytes[16];
- int m_cde_command_byte_ptr;
- int m_cde_response;
- int m_cde_drive_state;
- int m_cde_enable_qchannel_reports;
- int m_cde_enable_seek_reports;
- int m_cde_qchannel_offset;
- cdrom_toc m_cde_toc;
- CDE_DMA m_cde_dma[2];
- DECLARE_READ64_MEMBER(irq_enable_r);
- DECLARE_WRITE64_MEMBER(irq_enable_w);
- DECLARE_READ64_MEMBER(irq_active_r);
- DECLARE_READ64_MEMBER(unk1_r);
- DECLARE_READ64_MEMBER(unk3_r);
- DECLARE_READ64_MEMBER(unk4_r);
- DECLARE_WRITE64_MEMBER(unk4_w);
- DECLARE_READ64_MEMBER(unk30000_r);
- DECLARE_READ64_MEMBER(unk30030_r);
- DECLARE_WRITE64_MEMBER(video_w);
- DECLARE_WRITE32_MEMBER(video_irq_ack_w);
- DECLARE_READ64_MEMBER(unk4000280_r);
- DECLARE_WRITE8_MEMBER(serial_w);
- DECLARE_WRITE64_MEMBER(unk4000418_w);
- DECLARE_WRITE64_MEMBER(reset_w);
- DECLARE_READ64_MEMBER(cde_r);
- DECLARE_WRITE64_MEMBER(cde_w);
- DECLARE_READ64_MEMBER(device2_r);
- template<bool maincpu> DECLARE_READ64_MEMBER(cpu_r);
- DECLARE_READ8_MEMBER(id3_r);
- DECLARE_READ8_MEMBER(id4_r);
- DECLARE_READ8_MEMBER(id5_r);
- DECLARE_READ8_MEMBER(id6_r);
- DECLARE_READ8_MEMBER(id7_r);
-
- virtual void video_start() override;
- virtual void machine_reset() override;
- uint32_t screen_update_m2(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
- INTERRUPT_GEN_MEMBER(m2_irq);
- void cde_init();
- void cde_handle_command();
- void cde_handle_reports();
- void cde_dma_transfer(address_space &space, int channel, int next);
- required_device<ppc602_device> m_maincpu;
- required_device<ppc602_device> m_subcpu;
- void _3do_m2_main(address_map &map);
- void _3do_m2_main_m(address_map &map);
- void _3do_m2_main_s(address_map &map);
- void m2_main(address_map &map);
- void m2_main_m(address_map &map);
- void m2_main_s(address_map &map);
-};
+public:
+ DECLARE_WRITE_LINE_MEMBER(ppc1_int);
+ DECLARE_WRITE_LINE_MEMBER(ppc2_int);
+ DECLARE_WRITE32_MEMBER(cde_sdbg_out);
-void konamim2_state::video_start()
-{
-}
+ DECLARE_WRITE16_MEMBER(ldac_out);
+ DECLARE_WRITE16_MEMBER(rdac_out);
-uint32_t konamim2_state::screen_update_m2(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
-{
- int i, j;
- uint32_t fb_start = 0xffffffff;
- uint32_t fb_size;
- //uint32_t config;
- int height = 384,width = 512;
+ DECLARE_WRITE_LINE_MEMBER(ata_int);
- if (m_vdl0_address != 0)
- {
- uint32_t cur_vdl_address = screen.frame_number() & 1 ? m_vdl0_address : m_vdl1_address;
- // TODO: this looks more likely to be a framebuffer copy, with parameters!
- fb_start = *(uint32_t*)&m_main_ram[(cur_vdl_address - 0x40000000) / 8] - 0x40000000;
- fb_size = m_main_ram[((cur_vdl_address - 0x40000000) / 8) + 2] >> 32;
- //config = m_main_ram[(cur_vdl_address - 0x40000000) / 8] >> 32;
- //popmessage("%08x",config);
-
- height = fb_size & 0x1ff;
- width = (fb_size >> 24) * 16;
- }
+ DECLARE_READ16_MEMBER(konami_io0_r);
+ DECLARE_WRITE16_MEMBER(konami_io0_w);
+ DECLARE_READ16_MEMBER(konami_sio_r);
+ DECLARE_WRITE16_MEMBER(konami_sio_w);
+ DECLARE_READ16_MEMBER(konami_io1_r);
+ DECLARE_WRITE16_MEMBER(konami_io1_w);
+ DECLARE_WRITE16_MEMBER(konami_eeprom_w);
+
+ void init_totlvice();
+ void init_btltryst();
+ void init_hellngt();
- if (fb_start <= 0x800000)
+ DECLARE_WRITE16_MEMBER(konami_atapi_unk_w)
{
- uint16_t *frame = (uint16_t*)&m_main_ram[fb_start/8];
- for (j=0; j < height; j++)
+ // 8000 = /Reset
+ // 4000 = C000 ... DOIO DMA ... 4000
+// m_ata->write_dmack(data & 0x4000 ? ASSERT_LINE : CLEAR_LINE);
+
+ if (!(data & 0x8000))
{
- uint16_t *fb = &frame[(j*width)];
- uint16_t *d = &bitmap.pix16(j);
- for (i=0; i < width; i++)
- {
- d[i^3] = *fb++ & 0x7fff;
- }
+ logerror("ATAPI RESET!\n");
+
+ // TODO: Do we need any of this?
+ update_disc();
}
}
- else
- {
- bitmap.fill(0, cliprect);
- }
- return 0;
-}
-READ64_MEMBER(konamim2_state::irq_enable_r)
-{
- uint64_t r = 0;
-
- if (ACCESSING_BITS_32_63)
+ DECLARE_READ16_MEMBER(konami_ide_r)
{
- r |= (uint64_t)(m_irq_enable) << 32;
+ return swapendian_int16(m_ata->read_cs0(offset, mem_mask));
}
- return r;
-}
-
-WRITE64_MEMBER(konamim2_state::irq_enable_w)
-{
- if (ACCESSING_BITS_32_63)
+ DECLARE_WRITE16_MEMBER(konami_ide_w)
{
- m_irq_enable |= (uint32_t)(data >> 32);
+ m_ata->write_cs0(offset, swapendian_int16(data), mem_mask);
}
-}
-READ64_MEMBER(konamim2_state::irq_active_r)
-{
- uint64_t r = 0;
-
- if (ACCESSING_BITS_32_63)
- {
- r |= (uint64_t)(m_irq_active) << 32;
- }
+private:
+ void install_ymz280b();
+ void install_m48t58();
- return r;
-}
+ required_device<ppc602_device> m_ppc1;
+ optional_device<ppc602_device> m_ppc2;
+ required_device<m2_bda_device> m_bda;
+ required_device<m2_cde_device> m_cde;
+ required_device<eeprom_serial_93cxx_device> m_eeprom;
+ required_device<dac_word_interface> m_ldac;
+ required_device<dac_word_interface> m_rdac;
+ required_device<ata_interface_device> m_ata;
+ required_device<screen_device> m_screen;
+ optional_device<m48t58_device> m_m48t58;
+ optional_device<ymz280b_device> m_ymz280b;
+ // ATAPI
+ cdrom_file *m_available_cdroms;
-READ64_MEMBER(konamim2_state::unk1_r)
-{
- return 0xffffffffffffffffU;
- //return 0;
-}
+ // Konami SIO
+ uint16_t m_sio_data;
-#ifdef UNUSED_FUNCTION
-READ64_MEMBER(konamim2_state::unk2_r)
-{
- if (ACCESSING_BITS_32_63)
- {
- return (uint64_t)0xa5 << 32;
- }
- return 0;
-}
-#endif
+ uint32_t m_ata_int; // TEST
+ emu_timer *m_atapi_timer;
-READ64_MEMBER(konamim2_state::unk3_r)
-{
- //return 0xffffffffffffffffU;
- return m_unk3;
-}
-
-READ64_MEMBER(konamim2_state::unk4_r)
-{
- uint64_t r = 0;
-// logerror("unk4_r: %08X, %08X%08X %s\n", offset, (uint32_t)(mem_mask>>32), (uint32_t)(mem_mask), machine().describe_context());
-
- if (ACCESSING_BITS_32_63)
+ TIMER_CALLBACK_MEMBER( atapi_delay )
{
- // MCfg
- r |= (uint64_t)((0 << 13) | (5 << 10)) << 32;
+ m_atapi_timer->adjust( attotime::never );
+ m_ata_int = param;
}
- if (ACCESSING_BITS_0_31)
- {
- r |= m_unk20004 & ~0x800000;
- }
- return r;
-}
-WRITE64_MEMBER(konamim2_state::unk4_w)
-{
-// logerror("unk4_w: %08X%08X, %08X, %08X%08X %s\n", (uint32_t)(data >> 32), (uint32_t)(data),
-// offset, (uint32_t)(mem_mask>>32), (uint32_t)(mem_mask), machine().describe_context());
+ void debug_help_command(int ref, const std::vector<std::string> &params);
+ void debug_commands(int ref, const std::vector<std::string> &params);
- if (ACCESSING_BITS_0_31)
- {
- if (data & 0x800000)
- {
- m_subcpu->set_input_line(PPC_IRQ, ASSERT_LINE);
- }
+ void dump_task_command(int ref, const std::vector<std::string> &params);
+};
- m_unk20004 = (uint32_t)(data);
- return;
- }
-}
-READ64_MEMBER(konamim2_state::unk30000_r)
-{
- m_counter1++;
- return (uint64_t)(m_counter1 & 0x7f) << 32;
-}
-READ64_MEMBER(konamim2_state::unk30030_r)
-{
- if (ACCESSING_BITS_0_31)
- {
- return 1;
- }
- return 0;
-}
+/*************************************
+ *
+ * Trampolines - Remove ME
+ *
+ *************************************/
-WRITE64_MEMBER(konamim2_state::video_w)
+WRITE_LINE_MEMBER(konamim2_state::ppc1_int)
{
- if (ACCESSING_BITS_32_63)
- {
- m_vdl0_address = (uint32_t)(data >> 32);
- }
- if (ACCESSING_BITS_0_31)
- {
- m_vdl1_address = (uint32_t)(data);
- }
+ m_ppc1->set_input_line(INPUT_LINE_IRQ0, state ? ASSERT_LINE : CLEAR_LINE);
}
-WRITE32_MEMBER(konamim2_state::video_irq_ack_w)
+WRITE_LINE_MEMBER(konamim2_state::ppc2_int)
{
- if (data & 0x8000)
- {
- m_irq_active &= ~0x800000;
- m_maincpu->set_input_line(PPC_IRQ, CLEAR_LINE);
- }
+ m_ppc2->set_input_line(INPUT_LINE_IRQ0, state ? ASSERT_LINE : CLEAR_LINE);
}
-
-
-READ64_MEMBER(konamim2_state::unk4000280_r)
+WRITE32_MEMBER(konamim2_state::cde_sdbg_out)
{
- // SysCfg
-
- uint32_t sys_config = 0x03600000;
-
- sys_config |= 0 << 0; // Bit 0: PAL/NTSC switch (default is selected by encoder)
- sys_config |= 0 << 2; // Bit 2-3: Video Encoder (0 = MEIENC, 1 = VP536, 2 = BT9103, 3 = DENC)
- sys_config |= m_in_country->read() << 11; // Bit 11-12: Country
- // 0 = ???
- // 1 = UK
- // 2 = Japan
- // 3 = US
- sys_config |= m_in_card->read() << 15; // Bit 15-18: 0x8 = AC-DevCard
- // 0xb = AC-CoreBoard
- // 0xc = DevCard (not allowed)
- // 0xe = Upgrade (not allowed)
- // 0xf = Multiplayer (not allowed)
- sys_config |= 3 << 29; // Bit 29-30: Audio chip (1 = CS4216, 3 = Asahi AK4309)
-
- return ((uint64_t)(sys_config) << 32);
+ if (data == 0xd)
+ putc('\n', stdout);
+ else if (data != 0)
+ putc(data, stdout);
-}
+ fflush(stdout);
-WRITE8_MEMBER(konamim2_state::serial_w)
-{
- m_terminal->write(space,0,data & 0xff);
+#if ENABLE_SDBG
+ // Dummy write to enable serial out
+ if (data == 0x3c)
+ m_cde->sdbg_in(space, 0, 0xffffffff);
+#endif
}
-WRITE64_MEMBER(konamim2_state::unk4000418_w)
+WRITE16_MEMBER( konamim2_state::ldac_out )
{
+ m_ldac->write(data);
}
-WRITE64_MEMBER(konamim2_state::reset_w)
+WRITE16_MEMBER( konamim2_state::rdac_out )
{
- if (ACCESSING_BITS_32_63)
- {
- if (data & 0x100000000U)
- {
- m_maincpu->pulse_input_line(INPUT_LINE_RESET, attotime::zero);
- m_unk3 = 0;
- }
- }
+ m_rdac->write(data);
}
-/*****************************************************************************/
-/* CDE */
-
-#define CDE_DRIVE_STATE_PAUSED 0x02
-#define CDE_DRIVE_STATE_SEEK_DONE 0x03
-
-
-
-
-
+/*************************************
+ *
+ * ATAPI (Temporary - remove)
+ *
+ *************************************/
+WRITE_LINE_MEMBER( konamim2_state::ata_int )
+{
+// m_atapi_timer->adjust( attotime::from_msec(10), state );
+ m_ata_int = state;
+}
+/*************************************
+ *
+ * Konami I/O
+ *
+ *************************************/
-void konamim2_state::cde_init()
+READ16_MEMBER( konamim2_state::konami_io0_r )
{
- cdrom_file *cdfile = cdrom_open(machine().rom_load().get_disk_handle(":cdrom"));
-
- const cdrom_toc *toc = cdrom_get_toc(cdfile);
+// printf("IO R: %08X\n", offset);
- if (cdfile)
+ switch (offset)
{
- memcpy(&m_cde_toc, toc, sizeof(cdrom_toc));
-
/*
- printf("%d tracks\n", toc->numtrks);
- for (int i=0; i < toc->numtrks; i++)
- {
- const cdrom_track_info *track = &toc->tracks[i];
- printf("Track %d: type %d, subtype %d, datasize %d, subsize %d, frames %d, extraframes %d, physframeofs %d\n",
- i, track->trktype, track->subtype, track->datasize, track->subsize,track->frames, track->extraframes, track->physframeofs);
- }
- */
+ 0 = 160
+ 1 = 32
+ 2 = -96
+ 10 = -1888
+ FF = -32480
- cdrom_close(cdfile);
- }
+ 100 = 160
+ 1FF = -32480
- m_cde_drive_state = CDE_DRIVE_STATE_PAUSED;
+ 200 = 159
+ 2FF = -32481
- m_cde_num_status_bytes = 0;
- m_cde_status_byte_ptr = 0;
- m_cde_command_byte_ptr = 0;
+ 300 = 159
+ 3FF = -32481
- m_cde_response = 0;
+ 400 = 158
- m_cde_enable_qchannel_reports = 0;
- m_cde_enable_seek_reports = 0;
+ 800 = 156
- m_cde_qchannel_offset = 0;
-}
+ C00 = 154
-void konamim2_state::cde_handle_command()
-{
- switch (m_cde_command_bytes[0])
- {
- case 0x04: // Set Speed
- {
- m_cde_num_status_bytes = 1;
+ E00
+ F00 = 153
- m_cde_status_bytes[0] = 0x04;
- m_cde_status_byte_ptr = 0;
+ 1000 = 152
+ 2000 = 144
+ 4000 = 128
+ 8000 = 96
-// osd_printf_debug("CDE: SET SPEED %02X, %02X\n", m_cde_command_bytes[1], m_cde_command_bytes[2]);
- break;
- }
- case 0x06: // Audio Format / Data Format
- {
- m_cde_num_status_bytes = 1;
-
- m_cde_status_bytes[0] = 0x06;
- m_cde_status_byte_ptr = 0;
-
- if (m_cde_command_bytes[1] == 0x00) // Audio Format
- {
-// osd_printf_debug("CDE: AUDIO FORMAT\n");
- }
- else if (m_cde_command_bytes[1] == 0x78) // Data Format
- {
-// osd_printf_debug("CDE: DATA FORMAT\n");
- }
- else
- {
- fatalerror("CDE: unknown command %02X, %02X\n", m_cde_command_bytes[0], m_cde_command_bytes[1]);
- }
- break;
- }
- case 0x08: // Pause / Eject / Play
- {
- m_cde_num_status_bytes = 1;
-
- m_cde_status_bytes[0] = 0x08;
- m_cde_status_byte_ptr = 0;
-
- if (m_cde_command_bytes[1] == 0x00) // Eject
- {
-// osd_printf_debug("CDE: EJECT command\n");
- }
- else if (m_cde_command_bytes[1] == 0x02) // Pause
- {
-// osd_printf_debug("CDE: PAUSE command\n");
- m_cde_drive_state = CDE_DRIVE_STATE_PAUSED;
- }
- else if (m_cde_command_bytes[1] == 0x03) // Play
- {
-// osd_printf_debug("CDE: PLAY command\n");
- }
- else
- {
- fatalerror("CDE: unknown command %02X, %02X\n", m_cde_command_bytes[0], m_cde_command_bytes[1]);
- }
- break;
- }
- case 0x09: // Seek
- {
- m_cde_num_status_bytes = 1;
-
- m_cde_status_bytes[0] = 0x1b;
- m_cde_status_byte_ptr = 0;
-
- m_cde_drive_state = CDE_DRIVE_STATE_SEEK_DONE;
+ E000 = 48
+ F000 = 40
+ FF00 = 33
-// osd_printf_debug("CDE: SEEK %08X\n", (m_cde_command_bytes[1] << 16) | (m_cde_command_bytes[2] << 8) | (m_cde_command_bytes[3]));
- break;
- }
- case 0x0b: // Get Drive State
+ 7FFF = -32543
+ FFFF = -32607
+ */
+ case 0:
{
- m_cde_num_status_bytes = 0x3;
-
- m_cde_status_bytes[0] = 0x0b;
- m_cde_status_bytes[1] = 0x1b;
- m_cde_status_bytes[2] = m_cde_drive_state;
- m_cde_status_byte_ptr = 0;
-
- if (m_cde_command_bytes[1] & 0x02)
- {
- m_cde_enable_seek_reports = 1;
- }
- else
- {
- m_cde_enable_seek_reports = 0;
- }
-
-// osd_printf_debug("CDE: GET DRIVE STATE %02X\n", m_cde_command_bytes[1]);
- break;
+ return swapendian_int16((int16_t)ioport("GUNX1")->read());
}
- case 0x0c: // ?
+ case 1: return 0;
+ case 2: return 0; // P3 X?
+ case 3: return 0xffff; // ?
+ case 4:
{
- m_cde_num_status_bytes = 1;
-
- m_cde_status_bytes[0] = 0x0c;
- m_cde_status_byte_ptr = 0;
-
- if (m_cde_command_bytes[1] == 0x02)
- {
- m_cde_enable_qchannel_reports = 1;
- m_cde_drive_state = CDE_DRIVE_STATE_PAUSED;
- }
- else if (m_cde_command_bytes[0] == 0x00)
- {
- m_cde_enable_qchannel_reports = 0;
- }
-
-// osd_printf_debug("CDE: UNKNOWN CMD 0x0c %02X\n", m_cde_command_bytes[1]);
- break;
+ return swapendian_int16((int16_t)ioport("GUNY1")->read());
}
- case 0x0d: // Get Switch State
- {
- m_cde_num_status_bytes = 0x4;
+ case 5: return 0; // P2 Y
+ case 6: return 0; // P3 Y?
+ case 7: return 0; //??
+ case 8: return ioport("P5")->read();
+ }
- m_cde_status_bytes[0] = 0x0d;
- m_cde_status_bytes[1] = 0x1d;
- m_cde_status_bytes[2] = 0x02;
- m_cde_status_byte_ptr = 0;
+ //return rand();
+ return 0;
+}
-// osd_printf_debug("CDE: GET SWITCH STATE %02X\n", m_cde_command_bytes[1]);
- break;
- }
- case 0x21: // Mech type
- {
- m_cde_num_status_bytes = 0x8;
+WRITE16_MEMBER( konamim2_state::konami_io0_w )
+{
+ // 9: 0000, 0xFFF
+// printf("IO W: %08x %08x\n", offset, data);
+}
- m_cde_status_bytes[0] = 0x21;
- m_cde_status_bytes[1] = 0xff;
- m_cde_status_bytes[2] = 0x08; // Max Speed
- m_cde_status_bytes[3] = 0xff;
- m_cde_status_bytes[4] = 0xff;
- m_cde_status_bytes[5] = 0xff;
- m_cde_status_bytes[6] = 0xff;
- m_cde_status_bytes[7] = 0xff;
+/*
+ FEDCBA98 76543210
+ 0: |........ ........|
- m_cde_status_byte_ptr = 0;
+ 1: |........ ........|
-// osd_printf_debug("CDE: MECH TYPE %02X, %02X, %02X\n", m_cde_command_bytes[1], m_cde_command_bytes[2], m_cde_command_bytes[3]);
- break;
- }
- case 0x83: // Read ID
- {
- m_cde_num_status_bytes = 0xc;
-
- m_cde_status_bytes[0] = 0x03;
- m_cde_status_bytes[1] = 0xff;
- m_cde_status_bytes[2] = 0xff;
- m_cde_status_bytes[3] = 0xff;
- m_cde_status_bytes[4] = 0xff;
- m_cde_status_bytes[5] = 0xff;
- m_cde_status_bytes[6] = 0xff;
- m_cde_status_bytes[7] = 0xff;
- m_cde_status_bytes[8] = 0xff;
- m_cde_status_bytes[9] = 0xff;
- m_cde_status_bytes[10] = 0xff;
- m_cde_status_bytes[11] = 0xff;
-
- m_cde_status_byte_ptr = 0;
-
-// osd_printf_debug("CDE: READ ID\n");
- break;
- }
- default:
- {
- fatalerror("CDE: unknown command %08X\n", m_cde_command_bytes[0]);
- }
- }
-}
+ 2: |........ ........|
-void konamim2_state::cde_handle_reports()
-{
- switch (m_cde_command_bytes[0])
- {
- case 0x09:
- {
- if (m_cde_enable_seek_reports)
- {
- m_cde_num_status_bytes = 0x2;
- m_cde_status_bytes[0] = 0x02;
+ 3: |........ .......x| Coin 1
+ |........ ......x.| Coin 2
+ |........ ....x...| Service coin
+ |.......x ........| EEPROM D0
+ |.....x.. ........| ADC
+ |...xx... ........| SIO related? (set to 3 NOTE: Total Vice doesn't like this!)
+ |..x..... ........| ATAPI/CD status?
- m_cde_status_byte_ptr = 0;
+ 4: |........ ........| Player 1/2 inputs
- m_cde_command_bytes[0] = 0x0c;
+ 5: |........ ........| Unknown
-// osd_printf_debug("CDE: SEEK REPORT\n");
- }
- break;
- }
+ 6: |........ ........| Unknown
- case 0x0b:
- {
- if (m_cde_enable_qchannel_reports)
- {
- int track, num_tracks;
-
- num_tracks = m_cde_toc.numtrks;
- track = m_cde_qchannel_offset % (num_tracks+3);
-
- m_cde_num_status_bytes = 0xb;
- m_cde_status_bytes[0] = 0x1c;
-
- /*
- m_cde_status_bytes[1] = 0x0; // q-Mode
- m_cde_status_bytes[2] = 0x0; // TNO
- m_cde_status_bytes[3] = 0x0; // Index / Pointer
- m_cde_status_bytes[4] = 0x0; // Min
- m_cde_status_bytes[5] = 0x0; // Sec
- m_cde_status_bytes[6] = 0x0; // Frac
- m_cde_status_bytes[7] = 0x0; // Zero
- m_cde_status_bytes[8] = 0x0; // A-Min
- m_cde_status_bytes[9] = 0x0; // A-Sec
- m_cde_status_bytes[10] = 0x0; // A-Frac
- */
-
- if (track < num_tracks)
- {
- int time = lba_to_msf(m_cde_toc.tracks[track].physframeofs);
-
- m_cde_status_bytes[1] = 0x41; // q-Mode
- m_cde_status_bytes[2] = 0x0; // TNO (Lead-in track)
- m_cde_status_bytes[3] = track+1; // Pointer
- m_cde_status_bytes[4] = 0x0; // Min
- m_cde_status_bytes[5] = 0x0; // Sec
- m_cde_status_bytes[6] = 0x0; // Frac
- m_cde_status_bytes[7] = 0x0; // Zero
- m_cde_status_bytes[8] = (time >> 16) & 0xff; // P-Min
- m_cde_status_bytes[9] = (time >> 8) & 0xff; // P-Sec
- m_cde_status_bytes[10] = time & 0xff; // P-Frac
- }
- else
- {
- if (track == num_tracks+0)
- {
- m_cde_status_bytes[1] = 0x41; // q-Mode / Control
- m_cde_status_bytes[2] = 0x0; // TNO (Lead-in track)
- m_cde_status_bytes[3] = 0xa0; // Pointer
- m_cde_status_bytes[4] = 0x0; // Min
- m_cde_status_bytes[5] = 0x0; // Sec
- m_cde_status_bytes[6] = 0x0; // Frac
- m_cde_status_bytes[7] = 0x0; // Zero
- m_cde_status_bytes[8] = 1; // P-Min
- m_cde_status_bytes[9] = 0x0; // P-Sec
- m_cde_status_bytes[10] = 0x0; // P-Frac
- }
- else if (track == num_tracks+1)
- {
- m_cde_status_bytes[1] = 0x41; // q-Mode / Control
- m_cde_status_bytes[2] = 0x0; // TNO (Lead-in track)
- m_cde_status_bytes[3] = 0xa1; // Pointer
- m_cde_status_bytes[4] = 0x0; // Min
- m_cde_status_bytes[5] = 0x0; // Sec
- m_cde_status_bytes[6] = 0x0; // Frac
- m_cde_status_bytes[7] = 0x0; // Zero
- m_cde_status_bytes[8] = num_tracks; // P-Min
- m_cde_status_bytes[9] = 0x0; // P-Sec
- m_cde_status_bytes[10] = 0x0; // P-Frac
- }
- else
- {
- int leadout_lba = m_cde_toc.tracks[num_tracks-1].physframeofs + m_cde_toc.tracks[num_tracks-1].frames;
- int leadout_time = lba_to_msf(leadout_lba);
-
- m_cde_status_bytes[1] = 0x41; // q-Mode / Control
- m_cde_status_bytes[2] = 0x0; // TNO (Lead-in track)
- m_cde_status_bytes[3] = 0xa2; // Pointer
- m_cde_status_bytes[4] = 0x0; // Min
- m_cde_status_bytes[5] = 0x0; // Sec
- m_cde_status_bytes[6] = 0x0; // Frac
- m_cde_status_bytes[7] = 0x0; // Zero
- m_cde_status_bytes[8] = (leadout_time >> 16) & 0xff; // P-Min
- m_cde_status_bytes[9] = (leadout_time >> 8) & 0xff; // P-Sec
- m_cde_status_bytes[10] = leadout_time & 0xff; // P-Frac
- }
- }
-
- m_cde_qchannel_offset++;
-
- m_cde_status_byte_ptr = 0;
- m_cde_command_bytes[0] = 0x0c;
-
-// osd_printf_debug("CDE: QCHANNEL REPORT\n");
- break;
- }
- }
- }
-}
+ 7: |........ ........| Unknown
+*/
-void konamim2_state::cde_dma_transfer(address_space &space, int channel, int next)
+READ16_MEMBER( konamim2_state::konami_io1_r )
{
- uint32_t address;
- //int length;
- int i;
+ uint16_t data = 0;
- if (next)
- {
- address = m_cde_dma[channel].next_dst_addr;
- //length = m_cde_dma[channel].next_length;
- }
- else
- {
- address = m_cde_dma[channel].dst_addr;
- //length = m_cde_dma[channel].length;
- }
+// printf("%s: PORT R: [%x] MASK:%.8x\n", machine().describe_context(), offset, mem_mask);
- for (i=0; i < m_cde_dma[channel].next_length; i++)
+ switch (offset)
{
- space.write_byte(address, 0xff); // TODO: do the real transfer...
- address++;
- }
-}
+ case 0:
+ data = 0xffff;
+ break;
-READ64_MEMBER(konamim2_state::cde_r)
-{
- uint32_t r = 0;
- int reg = offset * 2;
+ case 1:
+ data = 0xffff;
+ break;
- if (ACCESSING_BITS_0_31)
- reg++;
+ case 2: // DIP switches
+ data = ioport("P2")->read();
+ break;
- switch (reg)
- {
- case 0x000/4:
+ case 3:
{
- r = (0x01) << 16; // Device identifier, 1 = CDE
+ data = ioport("P1")->read();
+#if M2_BAD_TIMING
+ static uint32_t d = 0;
+ data |= d;
+ d ^= 0x2000;
+#else
+ data |= m_ata_int ? 0x2000 : 0;
+#endif
+ data |= (1 << 10);
+ data |= (3 << 11); // TODO: 3 normally
break;
}
- case 0x018/4:
- {
- r = 0x100038;
- r |= m_cde_dma[0].dma_done ? 0x400 : 0;
- r |= m_cde_dma[1].dma_done ? 0x800 : 0;
+ case 4: // Buttons
+ data = ioport("P4")->read();
break;
- }
- case 0x02c/4:
- {
- r = m_cde_status_bytes[m_cde_status_byte_ptr++];
-
- if (m_cde_status_byte_ptr <= m_cde_num_status_bytes)
- {
- r |= 0x100;
- }
- else
- {
- //if (cde_enable_reports &&
- // !m_cde_response &&
- // m_cde_command_bytes[0] != ((cde_report_type >> 8) & 0xff))
-
- if (!m_cde_response)
- {
- cde_handle_reports();
-
- // m_cde_command_byte_ptr = 0;
- // m_cde_command_bytes[m_cde_command_byte_ptr++] = 0x1c;
-
- // m_cde_response = 1;
- }
- }
-
- // printf("status byte %d\n", m_cde_status_byte_ptr);
+
+ case 5: // Changing this has a tendency to stop evilngt from booting...
+ data = 0xffff;
break;
- }
- case 0x2a0/4:
- {
- r = 0x20;
+ case 6: // Buttons
+ data = ioport("P6")->read();
+ break;
+
+ case 7:
+ data = 0xffff;
break;
- }
default:
- {
+ logerror("%s: Unknown read: %x\n", machine().describe_context(), offset);
break;
- }
}
- if (reg & 1)
- {
- return (uint64_t)(r);
- }
- else
- {
- return (uint64_t)(r) << 32;
- }
+ return data;
}
-WRITE64_MEMBER(konamim2_state::cde_w)
+WRITE16_MEMBER( konamim2_state::konami_io1_w )
{
- int reg = offset * 2;
- uint32_t d;
+ // 0x0200 = ADC?
+ // 0x0800 = Coin counter 1
+ // 0x1000 = Coin counter 2
+ // 0x2000 = CD-MUTE
+ // 0x8000 = ?
+ logerror("%s: PORT W: [%x] %x, MASK:%.8x\n", machine().describe_context(), offset, data, mem_mask);
- if (ACCESSING_BITS_0_31)
- {
- reg++;
- d = (uint32_t)(data);
- }
- else
- {
- d = (uint32_t)(data >> 32);
- }
+// printf("CDDA is: %s\n", data & 0x2000 ? "ENABLED" : "MUTE");
- switch (reg)
- {
- case 0x028/4: // Command write
- {
- if (d == 0x0180)
- {
- if (m_cde_response)
- {
- cde_handle_command();
+ machine().bookkeeping().coin_counter_w(0, (data >> 11) & 1);
+ machine().bookkeeping().coin_counter_w(1, (data >> 12) & 1);
- m_cde_response = 0;
- }
+// m_cdda->set_output_gain(0, data & 0x2000 ? 1.0 : 0.0);
+// m_cdda->set_output_gain(1, data & 0x2000 ? 1.0 : 0.0);
+}
- m_cde_command_byte_ptr = 0;
- }
- else if (m_cde_command_byte_ptr == 0)
- {
- m_cde_num_status_bytes = 1;
- m_cde_status_bytes[0] = d & 0xff;
- m_cde_status_byte_ptr = 0;
- m_cde_response = 1;
- }
+/**************************************
+ *
+ * Konami 003461 SIO
+ *
+ *************************************/
- if (d != 0x180)
- {
- m_cde_command_bytes[m_cde_command_byte_ptr++] = d;
- }
+/*
+ FEDCBA98 76543210
+ 0: |xxxxxxxx xxxxxxxx| Data R/W
- break;
- }
+ 1: |........ ........|
- case 0x300/4: // DMA Channel 0 enable
- {
-// osd_printf_debug("CDE: DMA0 enable %08X\n", d);
+ 2: |........ ........|
- if (d & 0x20)
- {
- m_cde_dma[0].dma_done = 1;
+ 3: |........ ........|
- cde_dma_transfer(space, 0, 0);
- }
- if (d & 0x40)
- {
- m_cde_dma[0].dma_done = 1;
+ 4: |........ ........|
- cde_dma_transfer(space, 0, 1);
- }
- break;
- }
- case 0x308/4: // DMA Channel 0 destination address
- {
-// osd_printf_debug("CDE: DMA0 dst addr %08X\n", d);
+ 5: |........ ..x.....| Transmit ready
- m_cde_dma[0].dst_addr = d;
- break;
- }
- case 0x30c/4: // DMA Channel 0 length?
- {
-// osd_printf_debug("CDE: DMA0 length %08X\n", d);
+ 6: |........ ........|
- m_cde_dma[0].length = d;
- break;
- }
- case 0x318/4: // DMA Channel 0 next destination address
- {
-// osd_printf_debug("CDE: DMA0 next dst addr %08X\n", d);
-
- m_cde_dma[0].next_dst_addr = d;
- break;
- }
- case 0x31c/4: // DMA Channel 0 next length?
- {
-// osd_printf_debug("CDE: DMA0 next length %08X\n", d);
+ 7: |xxxxxxxx xxxxxxxx| Register R/W
+*/
- m_cde_dma[0].next_length = d;
- break;
- }
+READ16_MEMBER( konamim2_state::konami_sio_r )
+{
+ uint16_t data = 0;
- case 0x320/4: // DMA Channel 1 enable
- {
-// osd_printf_debug("CDE: DMA1 enable %08X\n", d);
+ switch (offset)
+ {
+ case 7:
+ data = m_sio_data;
break;
- }
- case 0x328/4: // DMA Channel 1 destination address
- {
-// osd_printf_debug("CDE: DMA1 dst addr %08X\n", d);
+ //default:
+ //logerror("%s: SIO_R: %x %x\n", machine().describe_context(), offset, mem_mask);
+ }
- m_cde_dma[1].dst_addr = d;
- break;
- }
- case 0x32c/4: // DMA Channel 1 length?
- {
-// osd_printf_debug("CDE: DMA1 length %08X\n", d);
+ return data;
+}
- m_cde_dma[1].length = d;
+WRITE16_MEMBER( konamim2_state::konami_sio_w )
+{
+ switch (offset)
+ {
+ case 7:
+ m_sio_data = data;
break;
- }
- case 0x338/4: // DMA Channel 1 next destination address
- {
-// osd_printf_debug("CDE: DMA1 next dst addr %08X\n", d);
+ //default:
+ //printf("%s: SIO_W: %x %x %x\n", machine().describe_context(), offset, data, mem_mask);
+ }
+}
- m_cde_dma[1].next_dst_addr = d;
- break;
- }
- case 0x33c/4: // DMA Channel 1 next length?
- {
-// osd_printf_debug("CDE: DMA1 next length %08X\n", d);
+// TODO: Use output port
+WRITE16_MEMBER( konamim2_state::konami_eeprom_w )
+{
+ // 3 = CS
+ // 2 = CLK
+ // 1 = DATA
+ // 0 = ? (From Port)
+ m_eeprom->cs_write(data & 0x80 ? ASSERT_LINE : CLEAR_LINE);
+ m_eeprom->di_write(data & 0x20 ? 1 : 0);
+ m_eeprom->clk_write(data & 0x40 ? ASSERT_LINE : CLEAR_LINE);
+}
- m_cde_dma[1].next_length = d;
- break;
- }
- case 0x418/4: // ???
- {
- if (d & 0x80000000)
- {
- m_irq_active &= ~0x8;
- }
- if (d & 0x60000000)
- {
- m_cde_dma[0].dma_done = 0;
- m_cde_dma[1].dma_done = 0;
- }
- break;
- }
- default:
- {
- break;
- }
- }
-}
+/*************************************
+ *
+ * Machine initialization
+ *
+ *************************************/
-READ64_MEMBER(konamim2_state::device2_r)
+void konamim2_state::machine_start()
{
- uint32_t r = 0;
- int reg = offset * 2;
+ m_ppc1->ppcdrc_set_options(PPCDRC_COMPATIBLE_OPTIONS);
+ m_ppc2->ppcdrc_set_options(PPCDRC_COMPATIBLE_OPTIONS);
- if (ACCESSING_BITS_0_31)
- reg++;
-
- switch (reg)
+ // Breakpoints don't wortk with fast RAM
+ if ((machine().debug_flags & DEBUG_FLAG_ENABLED) == 0)
{
- case 0x000/4:
- {
- r = (0x02) << 16; // Device identifier
- break;
- }
- default:
- {
- break;
- }
+ m_ppc1->ppcdrc_add_fastram(m_bda->ram_start(), m_bda->ram_end(), false, m_bda->ram_ptr());
+ m_ppc2->ppcdrc_add_fastram(m_bda->ram_start(), m_bda->ram_end(), false, m_bda->ram_ptr());
}
- if (reg & 1)
- {
- return (uint64_t)(r);
- }
- else
- {
- return (uint64_t)(r) << 32;
- }
-}
+ m_available_cdroms = cdrom_open(machine().rom_load().get_disk_handle(":cdrom"));
-template<bool maincpu> READ64_MEMBER(konamim2_state::cpu_r)
-{
- uint64_t r = 0;
+ // TODO: REMOVE
+ m_atapi_timer = machine().scheduler().timer_alloc( timer_expired_delegate( FUNC( konamim2_state::atapi_delay ),this ) );
+ m_atapi_timer->adjust( attotime::never );
- if (ACCESSING_BITS_32_63)
+ if (machine().debug_flags & DEBUG_FLAG_ENABLED)
{
- r = (uint64_t)(maincpu ? 0 : 0x80000000);
- r |= m_in_monitor->read() << 30;
- return r << 32;
+ using namespace std::placeholders;
+ machine().debugger().console().register_command("m2", CMDFLAG_NONE, 0, 1, 4, std::bind(&konamim2_state::debug_commands, this, _1, _2));
}
-
- return 0;
}
-READ8_MEMBER(konamim2_state::id3_r)
+void konamim2_state::machine_reset()
{
- return 0x03;
+ update_disc();
}
-READ8_MEMBER(konamim2_state::id4_r)
+void konamim2_state::update_disc()
{
- return 0x04;
-}
+ cdrom_file *new_cdrom = m_available_cdroms;
-READ8_MEMBER(konamim2_state::id5_r)
-{
- return 0x05;
-}
+ atapi_hle_device *image = subdevice<atapi_hle_device>("ata:0:cr589");
+ if (image != nullptr)
+ {
+ void *current_cdrom = nullptr;
+ image->GetDevice(&current_cdrom);
-READ8_MEMBER(konamim2_state::id6_r)
-{
- return 0x06;
+ if (current_cdrom != new_cdrom)
+ {
+ current_cdrom = new_cdrom;
+
+ image->SetDevice(new_cdrom);
+ }
+ }
+ else
+ {
+ abort();
+ }
}
-READ8_MEMBER(konamim2_state::id7_r)
+/*************************************
+ *
+ * Address map
+ *
+ *************************************/
+
+void konamim2_state::m2_map(address_map &map)
{
- return 0x07;
+ map(0x20000000, 0x201fffff).rom().region("boot", 0); // BIOBUS Slot 0
+ map(0xfff00000, 0xffffffff).rom().region("boot", 0);
+ map(0x37400000, 0x37400007).w(FUNC(konamim2_state::konami_eeprom_w)).umask64(0xffff000000000000ULL);
+ map(0x37600000, 0x3760000f).w(FUNC(konamim2_state::konami_atapi_unk_w)).umask64(0xffff000000000000ULL);
+ map(0x37a00020, 0x37a0003f).rw(FUNC(konamim2_state::konami_io0_r), FUNC(konamim2_state::konami_io0_w));
+ map(0x37c00010, 0x37c0001f).rw(FUNC(konamim2_state::konami_sio_r), FUNC(konamim2_state::konami_sio_w));
+ map(0x37e00000, 0x37e0000f).rw(FUNC(konamim2_state::konami_io1_r), FUNC(konamim2_state::konami_io1_w));
+ map(0x3f000000, 0x3fffffff).rw(FUNC(konamim2_state::konami_ide_r), FUNC(konamim2_state::konami_ide_w)); // Endian flipped???
+// map(0x3f000000, 0x3fffffff).rw("ata", FUNC(ata_interface_device::read_cs0), FUNC(ata_interface_device::write_cs0));
+
+#if 0
+ map(0x36c00000, 0x36cfffff).rw(m48t58_r, m48t58_w)
+ map(0x37200000, 0x37200003).w(led_w)
+ map(0x37400000, 0x37400003).w(eeprom_w)
+ map(0x37600000, 0x37600000).w(atapi_dma_w)
+ map(0x37a00000, 0x37a0003f).rw(kacio_r, kacio_w)
+ map(0x37c00010, 0x37c0001f).rw(sio_r, sio_w) // Konami 11k
+ map(0x37e00000, 0x37e0000f).rw(port_r, port_w) // Konami? - 37e00006 = Read
+ map(0x3e000000, 0x3effffff).rw(ymz0_r, ymz0_w) // Konami - Evil Night / Total Vice
+ map(0x3e900000, 0x3e9fffff).rw(ymz1_r, ymz1_w) // Konami
+#endif
}
-void konamim2_state::m2_main(address_map &map)
-{
- map(0x00000000, 0x0000007f).ram(); // ???
- map(0x00010040, 0x00010047).rw(FUNC(konamim2_state::irq_enable_r), FUNC(konamim2_state::irq_enable_w));
- map(0x00010050, 0x00010057).r(FUNC(konamim2_state::irq_active_r));
- map(0x00020000, 0x00020007).rw(FUNC(konamim2_state::unk4_r), FUNC(konamim2_state::unk4_w));
- map(0x00020400, 0x000207ff).ram(); // ???
- map(0x00020800, 0x00020807).ram(); // ???
- map(0x00030000, 0x00030007).r(FUNC(konamim2_state::unk30000_r));
- map(0x00030010, 0x00030017).w(FUNC(konamim2_state::video_w));
- map(0x00030030, 0x00030037).r(FUNC(konamim2_state::unk30030_r));
- map(0x00030404, 0x00030407).w(FUNC(konamim2_state::video_irq_ack_w));
- map(0x01000000, 0x01000fff).rw(FUNC(konamim2_state::cde_r), FUNC(konamim2_state::cde_w));
- map(0x02000000, 0x02000fff).r(FUNC(konamim2_state::device2_r));
+/*************************************
+ *
+ * Port definitions
+ *
+ *************************************/
+
+static INPUT_PORTS_START( konamim2 )
+ PORT_START("DSW")
+ PORT_DIPNAME( 0x01, 0x00, "Video Res" )
+ PORT_DIPSETTING( 0x00, "High Res" )
+ PORT_DIPSETTING( 0x01, "Low Res" )
+
+ PORT_START("P1")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_COIN1 )
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_COIN2 )
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_SERVICE1 )
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("eeprom", eeprom_serial_93cxx_device, do_read)
+ PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_UNUSED ) // ATAPI?
+ PORT_BIT( 0xDE00, IP_ACTIVE_HIGH, IPT_UNUSED )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( btltryst )
+ PORT_INCLUDE( konamim2 )
+
+ PORT_MODIFY("DSW")
+ PORT_DIPNAME( 0x01, 0x01, "Video Res" )
+ PORT_DIPSETTING( 0x00, "High Res" )
+ PORT_DIPSETTING( 0x01, "Low Res" )
+
+ PORT_START("P2")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Flip_Screen ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("P4")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START1 )
+
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START2 )
+
+ PORT_START("P5")
+ PORT_BIT( 0xffff, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("P6")
+ PORT_SERVICE_NO_TOGGLE( 0x0004, IP_ACTIVE_LOW )
+ PORT_BIT( 0xfffb, IP_ACTIVE_LOW, IPT_UNUSED )
+INPUT_PORTS_END
- map(0x03000001, 0x03000001).r(FUNC(konamim2_state::id3_r));
+static INPUT_PORTS_START( polystar )
+ PORT_INCLUDE( konamim2 )
+
+ PORT_MODIFY("DSW")
+ PORT_DIPNAME( 0x01, 0x01, "Video Res" )
+ PORT_DIPSETTING( 0x00, "High Res" )
+ PORT_DIPSETTING( 0x01, "Low Res" )
+
+ PORT_START("P2")
+ PORT_DIPNAME( 0x01, 0x01, "Sound Output" )
+ PORT_DIPSETTING( 0x01, "Mono" )
+ PORT_DIPSETTING( 0x00, "Stereo" )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Flip_Screen ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("P4")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START1 )
+
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START2 )
+
+ PORT_START("P5")
+ PORT_BIT( 0xffff, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("P6")
+ PORT_SERVICE_NO_TOGGLE( 0x0004, IP_ACTIVE_LOW )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( totlvice )
+ PORT_INCLUDE( konamim2 )
+
+ PORT_START("P2") // TODO: VERIFY
+ PORT_DIPNAME( 0x01, 0x00, "Sound Output" )
+ PORT_DIPSETTING( 0x01, "Mono" )
+ PORT_DIPSETTING( 0x00, "Stereo" )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Flip_Screen ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("P4")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_SERVICE2 )
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_SERVICE3 )
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_START3 )
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_COIN3 )
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START1 )
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START2 )
+
+ PORT_START("GUNX1")
+ PORT_BIT( 0xffff, 0x0000, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_MINMAX(0, 640) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1)
+
+ PORT_START("GUNY1")
+ PORT_BIT( 0xffff, 0x0000, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_MINMAX(0, 240) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1)
+
+ PORT_START("P5") // Gun switches
+ PORT_BIT( 0x00ff, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(3)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(3)
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("P6")
+ PORT_SERVICE_NO_TOGGLE( 0x0004, IP_ACTIVE_LOW )
+ PORT_BIT( 0xfffb, IP_ACTIVE_LOW, IPT_UNUSED )
+INPUT_PORTS_END
- map(0x04000001, 0x04000001).r(FUNC(konamim2_state::id4_r));
- map(0x04000017, 0x04000017).w(FUNC(konamim2_state::serial_w));
- map(0x04000018, 0x0400001f).r(FUNC(konamim2_state::unk1_r)); // serial status
- map(0x04000020, 0x04000027).w(FUNC(konamim2_state::reset_w));
- map(0x04000418, 0x0400041f).w(FUNC(konamim2_state::unk4000418_w)); // serial status ack
- map(0x04000208, 0x0400020f).r(FUNC(konamim2_state::unk3_r));
- map(0x04000280, 0x04000287).r(FUNC(konamim2_state::unk4000280_r));
+static INPUT_PORTS_START( heatof11 )
+ PORT_INCLUDE( konamim2 )
+
+ PORT_MODIFY("DSW")
+ PORT_DIPNAME( 0x01, 0x00, "Video Res" )
+ PORT_DIPSETTING( 0x00, "High Res" )
+ PORT_DIPSETTING( 0x01, "Low Res" )
+
+ PORT_START("P2")
+ PORT_DIPNAME( 0x01, 0x00, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Flip_Screen ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("P4")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START1 )
+
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START2 )
+
+ PORT_START("P5")
+ PORT_BIT( 0xffff, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("P6")
+ PORT_SERVICE_NO_TOGGLE( 0x0004, IP_ACTIVE_LOW )
+INPUT_PORTS_END
- map(0x05000001, 0x05000001).r(FUNC(konamim2_state::id5_r));
+static INPUT_PORTS_START( hellngt )
+ PORT_INCLUDE( konamim2 )
+
+ PORT_START("P2")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Flip_Screen ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unused ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("P4")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_SERVICE2 )
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_SERVICE3 )
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_START3 )
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_COIN3 )
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START1 )
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START2 )
+
+ PORT_START("GUNX1")
+ PORT_BIT( 0xffff, 0x0000, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_MINMAX( 0, 320*2 ) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1)
+
+ PORT_START("GUNY1")
+ PORT_BIT( 0xffff, 0x0000, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_MINMAX( 0, 240 ) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1)
+
+ PORT_START("P5") // Gun switches
+ PORT_BIT( 0x00ff, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(3)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(3)
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("P6")
+ PORT_SERVICE_NO_TOGGLE( 0x0004, IP_ACTIVE_LOW )
+ PORT_BIT( 0xfffb, IP_ACTIVE_LOW, IPT_UNUSED )
+INPUT_PORTS_END
- map(0x06000001, 0x06000001).r(FUNC(konamim2_state::id6_r));
- map(0x07000001, 0x07000001).r(FUNC(konamim2_state::id7_r));
- map(0x10000008, 0x10001007).noprw(); // ???
+/*************************************
+ *
+ * Machine driver
+ *
+ *************************************/
- map(0x20000000, 0x201fffff).rom().share("share2");
- map(0x40000000, 0x407fffff).ram().share("main_ram");
- map(0xfff00000, 0xffffffff).rom().region("boot", 0).share("share2");
+void konamim2_state::cr589_config(device_t *device)
+{
+ device->subdevice<cdda_device>("cdda")->add_route(0, ":lspeaker", 1.0);
+ device->subdevice<cdda_device>("cdda")->add_route(1, ":rspeaker", 1.0);
+ device = device->subdevice("cdda");
}
-void konamim2_state::m2_main_m(address_map &map)
+void konamim2_state::konamim2(machine_config &config)
{
- m2_main(map);
- map(0x10000000, 0x10000007).r(FUNC(konamim2_state::cpu_r<true>));
+ // Basic machine hardware
+ PPC602(config, m_ppc1, M2_CLOCK);
+ m_ppc1->set_bus_frequency(M2_CLOCK / 2);
+ m_ppc1->set_addrmap(AS_PROGRAM, &konamim2_state::m2_map);
+
+ PPC602(config, m_ppc2, M2_CLOCK);
+ m_ppc2->set_bus_frequency(M2_CLOCK / 2);
+ m_ppc2->set_addrmap(AS_PROGRAM, &konamim2_state::m2_map);
+
+ // M2 hardware
+ M2_BDA(config, m_bda, M2_CLOCK, m_ppc1, m_ppc2);
+ m_bda->set_ram_size(m2_bda_device::RAM_8MB, m2_bda_device::RAM_8MB);
+ m_bda->subdevice<m2_powerbus_device>("powerbus")->int_handler().set(FUNC(konamim2_state::ppc1_int));
+ m_bda->subdevice<m2_memctl_device>("memctl")->gpio_out_handler<3>().set(FUNC(konamim2_state::ppc2_int)).invert();
+ m_bda->subdevice<m2_vdu_device>("vdu")->set_screen("screen");
+ m_bda->videores_in().set_ioport("DSW");
+ m_bda->ldac_handler().set(FUNC(konamim2_state::ldac_out));
+ m_bda->rdac_handler().set(FUNC(konamim2_state::rdac_out));
+
+ M2_CDE(config, m_cde, M2_CLOCK, m_ppc1);
+ m_cde->int_handler().set(":bda:powerbus", FUNC(m2_powerbus_device::int_line<BDAINT_EXTD4_LINE>));
+ m_cde->set_syscfg(SYSCONFIG_ARCADE);
+ m_cde->sdbg_out().set(FUNC(konamim2_state::cde_sdbg_out));
+
+ // Common devices
+ EEPROM_93C46_16BIT(config, m_eeprom);
+
+ ATA_INTERFACE(config, m_ata, 0);
+ m_ata->irq_handler().set(FUNC(konamim2_state::ata_int));
+
+ m_ata->slot(0).option_add("cr589", CR589);
+ m_ata->slot(0).set_option_machine_config("cr589", cr589_config);
+ m_ata->slot(0).set_default_option("cr589");
+
+ // Video hardware
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_screen_update("bda:vdu", FUNC(m2_vdu_device::screen_update));
+
+ /* Sound hardware */
+ SPEAKER(config, "lspeaker").front_left();
+ SPEAKER(config, "rspeaker").front_right();
+
+ // TODO!
+ DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_ldac, 0).add_route(ALL_OUTPUTS, "lspeaker", 2.0);
+ DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_rdac, 0).add_route(ALL_OUTPUTS, "rspeaker", 2.0); // FIXME
+
+ voltage_regulator_device &vref(VOLTAGE_REGULATOR(config, "vref", 0));
+ vref.set_output(5.0);
+ vref.add_route(0, "ldac", 1.0, DAC_VREF_POS_INPUT);
+ vref.add_route(0, "ldac", -1.0, DAC_VREF_NEG_INPUT);
+ vref.add_route(0, "rdac", 1.0, DAC_VREF_POS_INPUT);
+ vref.add_route(0, "rdac", -1.0, DAC_VREF_NEG_INPUT);
}
-void konamim2_state::m2_main_s(address_map &map)
+
+
+/*************************************
+ *
+ * Machine fragments
+ *
+ *************************************/
+
+void konamim2_state::set_ntsc(machine_config &config)
{
- m2_main(map);
- map(0x10000000, 0x10000007).r(FUNC(konamim2_state::cpu_r<false>));
+// m_screen->set_raw(11750000, 766, 126, 126+640, 260, 20, 20+240); // TODO
+ m_screen->set_refresh_hz(59.360001);
+ m_screen->set_size(768, 262);
+ m_screen->set_visarea(126, 126+640-1, 20, 20+240-1);
}
-void konamim2_state::_3do_m2_main(address_map &map)
+void konamim2_state::set_ntsc2(machine_config &config)
{
-// ADDRESS_MAP_UNMAP_HIGH
- m2_main(map);
+ //m_screen->set_raw(11750000, 766, 126, 126+640, 260, 20, 20+240); // TODO
+ m_screen->set_refresh_hz(59.360001);
+ m_screen->set_size(768, 262*2); // TOTAL VICE ONLY WORKS WITH THIS!
+ m_screen->set_visarea(126, 126+640-1, 20, 20+240-1);
+}
-// AM_RANGE(0x00000000, 0x000cffff) devices?
+void konamim2_state::set_arcres(machine_config &config)
+{
+ m_screen->set_raw(16934500, 684, 104, 104+512, 416, 26, 26+384);
}
-void konamim2_state::_3do_m2_main_m(address_map &map)
+void konamim2_state::add_ymz280b(machine_config &config)
{
- _3do_m2_main(map);
- map(0x10000000, 0x10000007).r(FUNC(konamim2_state::cpu_r<true>));
+ YMZ280B(config, m_ymz280b, XTAL(16'934'400));
+ m_ymz280b->add_route(0, "lspeaker", 1.0);
+ m_ymz280b->add_route(1, "rspeaker", 1.0);
}
-void konamim2_state::_3do_m2_main_s(address_map &map)
+void konamim2_state::add_mt48t58(machine_config &config)
{
- _3do_m2_main(map);
- map(0x10000000, 0x10000007).r(FUNC(konamim2_state::cpu_r<false>));
+ M48T58(config, m_m48t58);
}
-static INPUT_PORTS_START( m2 )
- // TODO: it's unknown if these are actual dip-switches or internal to something
- PORT_START("COUNTRY")
- PORT_CONFNAME( 0x03, 0x03, "Country" )
- PORT_CONFSETTING( 0x00, "<Invalid>" )
- PORT_CONFSETTING( 0x01, "UK" )
- PORT_CONFSETTING( 0x02, "Japan" )
- PORT_CONFSETTING( 0x03, "US" )
-
- PORT_START("CARD")
- PORT_CONFNAME( 0x0f, 0x0b, "Card Type" )
- PORT_CONFSETTING( 0x08, "AC-DevCard" )
- PORT_CONFSETTING( 0x0b, "AC-CoreBoard" )
- PORT_CONFSETTING( 0x0c, "DevCard (not allowed)" )
- PORT_CONFSETTING( 0x0e, "Upgrade (not allowed)" )
- PORT_CONFSETTING( 0x0f, "Multiplayer (not allowed)" )
-
- PORT_START("MONITOR")
- PORT_CONFNAME( 0x01, 0x00, "Monitor Type" )
- PORT_CONFSETTING( 0x01, "15 KHz" )
- PORT_CONFSETTING( 0x00, "24 KHz" )
-INPUT_PORTS_END
+/*************************************
+ *
+ * Machine drivers
+ *
+ *************************************/
-INTERRUPT_GEN_MEMBER(konamim2_state::m2_irq)
+void konamim2_state::polystar(machine_config &config)
{
- /*
- 0x000001
- 0x000008
- 0x200000
- 0x800000 VBlank irq
- */
-
- if (m_irq_enable & 0x800000)
- {
- //m_irq_enable |= 0x800000;
- m_irq_active |= 0x800000;
- device.execute().set_input_line(PPC_IRQ, ASSERT_LINE);
- }
-
- /*if (m_irq_enable & 0x8)
- {
- m_irq_active |= 0x8;
- }*/
-
+ konamim2(config);
+ m_bda->set_ram_size(m2_bda_device::RAM_4MB, m2_bda_device::RAM_4MB);
+ set_ntsc(config);
+}
+void konamim2_state::totlvice(machine_config &config)
+{
+ konamim2(config);
+ add_ymz280b(config);
+// set_arcres(config);
+ set_ntsc2(config);
}
-void konamim2_state::machine_reset()
+void konamim2_state::btltryst(machine_config &config)
{
- m_unk3 = 0xffffffffffffffffU;
- m_unk20004 = 0;
- cde_init();
+ konamim2(config);
+ add_mt48t58(config);
+ set_ntsc(config);
}
-void konamim2_state::m2(machine_config &config)
+void konamim2_state::heatof11(machine_config &config)
{
- /* basic machine hardware */
- PPC602(config, m_maincpu, 66000000);
- m_maincpu->set_bus_frequency(33000000); /* Multiplier 2, Bus = 33MHz, Core = 66MHz */
- m_maincpu->set_addrmap(AS_PROGRAM, &konamim2_state::m2_main_m);
- m_maincpu->set_vblank_int("screen", FUNC(konamim2_state::m2_irq));
-
- PPC602(config, m_subcpu, 66000000); /* actually PPC602, 66MHz */
- m_subcpu->set_bus_frequency(33000000); /* Multiplier 2, Bus = 33MHz, Core = 66MHz */
- m_subcpu->set_addrmap(AS_PROGRAM, &konamim2_state::m2_main_s);
-
- // TODO: declaring as second screen causes palette confusion (wants to use palette from the other screen?)
- GENERIC_TERMINAL(config, m_terminal, 0);
-
- /* video hardware */
- screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
- screen.set_refresh_hz(60);
- screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500));
- screen.set_size(704, 512);
- screen.set_visarea(0, 511, 0, 383);
- screen.set_screen_update(FUNC(konamim2_state::screen_update_m2));
- screen.set_palette("palette");
-
- PALETTE(config, "palette", 32768).set_init("palette", FUNC(palette_device::palette_init_RRRRRGGGGGBBBBB));
-
- /*cd-rom*/
- CDROM(config, "cdrom", 0).set_interface("3do_m2_cdrom");
+ konamim2(config);
+ add_mt48t58(config);
+ set_arcres(config);
}
-void konamim2_state::_3do_m2(machine_config &config)
+void konamim2_state::evilngt(machine_config &config)
{
- m2(config);
- m_maincpu->set_addrmap(AS_PROGRAM, &konamim2_state::_3do_m2_main_m);
- m_subcpu->set_addrmap(AS_PROGRAM, &konamim2_state::_3do_m2_main_s);
+ konamim2(config);
+ add_mt48t58(config);
+ add_ymz280b(config);
+ set_ntsc(config);
+}
- SOFTWARE_LIST(config, "cd_list").set_original("3do_m2");
+void konamim2_state::hellngt(machine_config &config)
+{
+ konamim2(config);
+ add_mt48t58(config);
+ add_ymz280b(config);
+ set_arcres(config);
}
+
+/*************************************
+ *
+ * ROM definition(s)
+ *
+ *************************************/
+
ROM_START( polystar )
ROM_REGION64_BE( 0x200000, "boot", 0 )
ROM_LOAD16_WORD( "623b01.8q", 0x000000, 0x200000, CRC(bd879f93) SHA1(e2d63bfbd2b15260a2664082652442eadea3eab6) )
- ROM_REGION( 0x80, "eeprom", 0 )
- ROM_LOAD( "93c46.7k", 0x000000, 0x000080, CRC(66d02984) SHA1(d07c57d198c611b6ff67a783c20a3d038ba34cd1) )
+ ROM_REGION( 0x80, "eeprom", 0 ) /* EEPROM default contents */
+ ROM_LOAD( "93c46.7k", 0x000000, 0x000080, CRC(2d8d1594) SHA1(b7bae873a6487023bdacdd09e7a5724e18efa30b) )
DISK_REGION( "cdrom" )
DISK_IMAGE( "623jaa02", 0, SHA1(e7d9e628a3e0e085e084e4e3630fa5e3a7345547) )
@@ -1358,16 +1312,36 @@ ROM_START( btltryst )
ROM_REGION64_BE( 0x200000, "boot", 0 )
ROM_LOAD16_WORD( "636a01.8q", 0x000000, 0x200000, CRC(7b1dc738) SHA1(32ae8e7ddd38fcc70b4410275a2cc5e9a0d7d33b) )
+ ROM_REGION16_BE( 0x80, "eeprom", 0 )
+ ROM_LOAD( "93c46.7k", 0x000000, 0x000080, CRC(cc2c5640) SHA1(694cf2b3700f52ed80252b013052c90020e58ce6) )
+
+ ROM_REGION( 0x2000, "m48t58", 0 ) /* timekeeper SRAM */
+ ROM_LOAD( "m48t58", 0x000000, 0x002000, CRC(71ee073b) SHA1(cc8002d7ee8d1695aebbbb2a3a1e97a7e16948c1) )
+
DISK_REGION( "cdrom" )
DISK_IMAGE( "636jac02", 0, SHA1(d36556a3a4b91058100924a9e9f1a58983399c6e) )
ROM_END
+ROM_START( btltrysta )
+ ROM_REGION64_BE( 0x200000, "boot", 0 )
+ ROM_LOAD16_WORD( "636a01.8q", 0x000000, 0x200000, CRC(7b1dc738) SHA1(32ae8e7ddd38fcc70b4410275a2cc5e9a0d7d33b) )
+
+ ROM_REGION( 0x2000, "m48t58", 0 ) /* timekeeper SRAM */
+ ROM_LOAD( "m48t58y", 0x000000, 0x002000, CRC(8611ff09) SHA1(6410236947d99c552c4a1f7dd5fd8c7a5ae4cba1) )
+
+ DISK_REGION( "cdrom" )
+ DISK_IMAGE( "636jaa02", 0, SHA1(d36556a3a4b91058100924a9e9f1a58983399c6e) )
+ROM_END
+
ROM_START( heatof11 )
ROM_REGION64_BE( 0x200000, "boot", 0 ) /* boot rom */
ROM_LOAD16_WORD( "636a01.8q", 0x000000, 0x200000, CRC(7b1dc738) SHA1(32ae8e7ddd38fcc70b4410275a2cc5e9a0d7d33b) )
- ROM_REGION( 0x2000, "timekeep", 0 ) /* timekeeper SRAM */
- ROM_LOAD( "dallas.5e", 0x000000, 0x002000, CRC(8611ff09) SHA1(6410236947d99c552c4a1f7dd5fd8c7a5ae4cba1) )
+ ROM_REGION16_BE( 0x80, "eeprom", 0 ) /* EEPROM default contents */
+ ROM_LOAD( "93c46.7k", 0x000000, 0x000080, CRC(e7029938) SHA1(ae41340dbcb600debe246629dc36fb371d1a5b05) )
+
+ ROM_REGION( 0x2000, "m48t58", 0 ) /* timekeeper SRAM */
+ ROM_LOAD( "dallas.5e", 0x000000, 0x002000, CRC(5b74eafd) SHA1(afbf5f1f5a27407fd6f17c764bbb7fae4ab779f5) )
DISK_REGION( "cdrom" )
DISK_IMAGE( "heatof11", 0, BAD_DUMP SHA1(5a0a2782cd8676d3f6dfad4e0f805b309e230d8b) )
@@ -1377,14 +1351,14 @@ ROM_START( evilngt )
ROM_REGION64_BE( 0x200000, "boot", 0 )
ROM_LOAD16_WORD( "636a01.8q", 0x000000, 0x200000, CRC(7b1dc738) SHA1(32ae8e7ddd38fcc70b4410275a2cc5e9a0d7d33b) )
- ROM_REGION( 0x2000, "timekeep", 0 ) /* timekeeper SRAM */
- ROM_LOAD( "m48t58y.9n", 0x000000, 0x002000, CRC(e887ca1f) SHA1(54205f01b1ceba1d5f4d979fc30be1add8116e90) )
+ ROM_REGION( 0x2000, "m48t58", 0 ) /* timekeeper SRAM */
+ ROM_LOAD( "m48t58y.9n", 0x000000, 0x002000, CRC(e887ca1f) SHA1(54205f01b1ceba1d5f4d979fc30be1add8116e90) )
- ROM_REGION( 0x400000, "ymz", 0 ) /* YMZ280B sound rom on sub board */
- ROM_LOAD( "810a03.16h", 0x000000, 0x400000, CRC(4cd79d98) SHA1(12fea41cfc5c1b883ffbeda7e428dd1d1bf54d7f) )
+ ROM_REGION16_BE( 0x80, "eeprom", 0 ) /* EEPROM default contents */
+ ROM_LOAD( "93c46.7k", 0x000000, 0x000080, CRC(d7ba2e5e) SHA1(d729557555c6fc1cd433b14017952cc63ec73573) )
- ROM_REGION( 0x80, "eeprom", 0 ) /* EEPROM default contents */
- ROM_LOAD( "93c46.7k", 0x000000, 0x000080, CRC(d7ba2e5e) SHA1(d729557555c6fc1cd433b14017952cc63ec73573) )
+ ROM_REGION( 0x400000, "ymz", 0 ) /* YMZ280B sound rom on sub board */
+ ROM_LOAD( "810a03.16h", 0x000000, 0x400000, CRC(4cd79d98) SHA1(12fea41cfc5c1b883ffbeda7e428dd1d1bf54d7f) )
DISK_REGION( "cdrom" )
DISK_IMAGE( "810uba02", 0, SHA1(e570470c1cbfe187d5bba8125616412f386264ba) )
@@ -1394,11 +1368,11 @@ ROM_START( evilngte )
ROM_REGION64_BE( 0x200000, "boot", 0 )
ROM_LOAD16_WORD( "636a01.8q", 0x000000, 0x200000, CRC(7b1dc738) SHA1(32ae8e7ddd38fcc70b4410275a2cc5e9a0d7d33b) )
- ROM_REGION( 0x1000, "timekeep", 0 ) /* timekeeper SRAM */
- ROM_LOAD( "m48t58y.u1", 0x000000, 0x001000, CRC(169bb8f4) SHA1(55c0bafab5d309fe69156489186e232aa87ca0dd) )
+ ROM_REGION( 0x2000, "m48t58", 0 ) /* timekeeper SRAM */
+ ROM_LOAD( "m48t58y.u1", 0x000000, 0x001000, CRC(169bb8f4) SHA1(55c0bafab5d309fe69156489186e232aa87ca0dd) )
ROM_REGION( 0x400000, "ymz", 0 ) /* YMZ280B sound rom on sub board */
- ROM_LOAD( "810a03.16h", 0x000000, 0x400000, CRC(4cd79d98) SHA1(12fea41cfc5c1b883ffbeda7e428dd1d1bf54d7f) )
+ ROM_LOAD( "810a03.16h", 0x000000, 0x400000, CRC(4cd79d98) SHA1(12fea41cfc5c1b883ffbeda7e428dd1d1bf54d7f) )
// TODO: Add CHD
ROM_END
@@ -1407,20 +1381,29 @@ ROM_START( hellngt )
ROM_REGION64_BE( 0x200000, "boot", 0 )
ROM_LOAD16_WORD( "636a01.8q", 0x000000, 0x200000, CRC(7b1dc738) SHA1(32ae8e7ddd38fcc70b4410275a2cc5e9a0d7d33b) )
- ROM_REGION( 0x1000, "timekeep", 0 ) /* timekeeper SRAM */
- ROM_LOAD( "m48t58y.u1", 0x000000, 0x001000, CRC(169bb8f4) SHA1(55c0bafab5d309fe69156489186e232aa87ca0dd) )
+ ROM_REGION16_BE( 0x80, "eeprom", 0 ) /* EEPROM default contents */
+ ROM_LOAD( "93c46.7k", 0x000000, 0x000080, CRC(53b41f68) SHA1(f75f59808a5b04b1e49f2cca0592a2466b82f019) )
+
+ ROM_REGION( 0x2000, "m48t58", 0 )
+ ROM_LOAD( "m48t58y.9n", 0x000000, 0x002000, CRC(ff8e78a1) SHA1(02e56f55264dd0bf3a08808726a6366e9cb6031e) )
ROM_REGION( 0x400000, "ymz", 0 ) /* YMZ280B sound rom on sub board */
ROM_LOAD( "810a03.16h", 0x000000, 0x400000, CRC(4cd79d98) SHA1(12fea41cfc5c1b883ffbeda7e428dd1d1bf54d7f) )
DISK_REGION( "cdrom" )
- DISK_IMAGE( "810eaa02", 0, SHA1(d701b900eddc7674015823b2cb33e887bf107fa8) )
+ DISK_IMAGE_READONLY( "810eaa02", 0, SHA1(d701b900eddc7674015823b2cb33e887bf107fa8) )
ROM_END
ROM_START( totlvice )
ROM_REGION64_BE( 0x200000, "boot", 0 )
ROM_LOAD16_WORD( "623b01.8q", 0x000000, 0x200000, CRC(bd879f93) SHA1(e2d63bfbd2b15260a2664082652442eadea3eab6) )
+ ROM_REGION16_BE( 0x80, "eeprom", 0 ) /* EEPROM default contents */
+ ROM_LOAD( "93c46.7k", 0x000000, 0x000080, CRC(8cc7f9c0) SHA1(43b40fe420ebbec73eed09f55e52c5fe1445bdc5) )
+
+ ROM_REGION( 0x2000, "m48t58", 0 ) /* timekeeper SRAM */
+ ROM_LOAD( "m48t58", 0x000000, 0x002000, CRC(4013176f) SHA1(8d0536e1c9a00696198f063f29c1640d811aeec0) )
+
ROM_REGION( 0x100000, "ymz", 0 ) /* YMZ280B sound rom on sub board */
ROM_LOAD( "639jaa02.bin", 0x000000, 0x100000, CRC(c6163818) SHA1(b6f8f2d808b98610becc0a5be5443ece3908df0b) )
@@ -1431,6 +1414,20 @@ ROM_START( totlvice )
DISK_IMAGE( "639eba01", 0, BAD_DUMP SHA1(d95c13575e015169b126f7e8492d150bd7e5ebda) )
ROM_END
+#if 0
+// NB: Dumped by Phil, hasn't been converted to CHD yet
+ROM_START( totlvicd )
+ ROM_REGION64_BE( 0x200000, "boot", 0 )
+ ROM_LOAD16_WORD( "623b01.8q", 0x000000, 0x200000, CRC(bd879f93) SHA1(e2d63bfbd2b15260a2664082652442eadea3eab6) )
+
+ ROM_REGION( 0x100000, "ymz", 0 ) /* YMZ280B sound rom on sub board */
+ ROM_LOAD( "639jaa02.bin", 0x000000, 0x100000, CRC(c6163818) SHA1(b6f8f2d808b98610becc0a5be5443ece3908df0b) )
+
+ DISK_REGION( "cdrom" )
+ DISK_IMAGE_READONLY( "639ead01", 0, SHA1(9d1085281aeb14185e2e78f3f21e7004a591039c) )
+ROM_END
+#endif
+
ROM_START( totlvicu )
ROM_REGION64_BE( 0x200000, "boot", 0 )
ROM_LOAD16_WORD( "623b01.8q", 0x000000, 0x200000, CRC(bd879f93) SHA1(e2d63bfbd2b15260a2664082652442eadea3eab6) )
@@ -1464,21 +1461,259 @@ ROM_START( totlvicj )
DISK_IMAGE( "639jad01", 0, BAD_DUMP SHA1(39d41d5a9d1c40636d174c8bb8172b1121e313f8) )
ROM_END
-ROM_START(3do_m2)
+#if 0 // FIXME
+ROM_START( 3do_m2 )
ROM_REGION64_BE( 0x100000, "boot", 0 )
ROM_SYSTEM_BIOS( 0, "panafz35", "Panasonic FZ-35S (3DO M2)" )
- ROMX_LOAD( "fz35_jpn.bin", 0x000000, 0x100000, CRC(e1c5bfd3) SHA1(0a3e27d672be79eeee1d2dc2da60d82f6eba7934), ROM_BIOS(0) )
+ ROMX_LOAD( "fz35_jpn.bin", 0x000000, 0x100000, CRC(e1c5bfd3) SHA1(0a3e27d672be79eeee1d2dc2da60d82f6eba7934), ROM_BIOS(1) )
ROM_END
+#endif
+
+/*************************************
+ *
+ * Driver initialization
+ *
+ *************************************/
+
+void konamim2_state::install_m48t58()
+{
+ read8_delegate read_delegate(FUNC(m48t58_device::read), &(*m_m48t58));
+ write8_delegate write_delegate(FUNC(m48t58_device::write), &(*m_m48t58));
+
+ m_ppc1->space(AS_PROGRAM).install_readwrite_handler(0x36c00000, 0x36c03fff, read_delegate, write_delegate, 0xff00ff00ff00ff00ULL);
+ m_ppc2->space(AS_PROGRAM).install_readwrite_handler(0x36c00000, 0x36c03fff, read_delegate, write_delegate, 0xff00ff00ff00ff00ULL);
+}
+
+void konamim2_state::install_ymz280b()
+{
+ read8_delegate read_delegate(FUNC(ymz280b_device::read), &(*m_ymz280b));
+ write8_delegate write_delegate(FUNC(ymz280b_device::write), &(*m_ymz280b));
+
+ m_ppc1->space(AS_PROGRAM).install_readwrite_handler(0x3e800000, 0x3e80000f, read_delegate, write_delegate, 0xff00ff0000000000ULL);
+ m_ppc2->space(AS_PROGRAM).install_readwrite_handler(0x3e800000, 0x3e80000f, read_delegate, write_delegate, 0xff00ff0000000000ULL);
+}
+
+void konamim2_state::init_totlvice()
+{
+ install_ymz280b();
+}
+
+void konamim2_state::init_btltryst()
+{
+ install_m48t58();
+}
+
+void konamim2_state::init_hellngt()
+{
+ install_m48t58();
+ install_ymz280b();
+}
+
+
+
+/*************************************
+ *
+ * Game driver(s)
+ *
+ *************************************/
+
+GAME( 1997, polystar, 0, polystar, polystar, konamim2_state, empty_init, ROT0, "Konami", "Tobe! Polystars (ver JAA)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND )
+GAME( 1997, totlvice, 0, totlvice, totlvice, konamim2_state, init_totlvice, ROT0, "Konami", "Total Vice (ver EBA)", MACHINE_NOT_WORKING )
+//GAME( 1997, totlvicd, totlvice, totlvice, totlvice, konamim2_state, init_totlvice, ROT0, "Konami", "Total Vice (ver EAD)", MACHINE_NOT_WORKING )
+GAME( 1997, totlvicj, totlvice, totlvice, totlvice, konamim2_state, init_totlvice, ROT0, "Konami", "Total Vice (ver JAD)", MACHINE_NOT_WORKING )
+GAME( 1997, totlvica, totlvice, totlvice, totlvice, konamim2_state, init_totlvice, ROT0, "Konami", "Total Vice (ver AAB)", MACHINE_NOT_WORKING )
+GAME( 1997, totlvicu, totlvice, totlvice, totlvice, konamim2_state, init_totlvice, ROT0, "Konami", "Total Vice (ver UAC)", MACHINE_NOT_WORKING )
+GAME( 1998, btltryst, 0, btltryst, btltryst, konamim2_state, init_btltryst, ROT0, "Konami", "Battle Tryst (ver JAC)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
+//GAME( 1998, btltrysta, btltryst, btltryst, btltryst, konamim2_state, init_btltryst, ROT0, "Konami", "Battle Tryst (ver JAA)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1998, heatof11, 0, heatof11, heatof11, konamim2_state, init_btltryst, ROT0, "Konami", "Heat of Eleven '98 (ver EAA)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS)
+GAME( 1998, evilngt, 0, evilngt, hellngt, konamim2_state, init_hellngt, ROT0, "Konami", "Evil Night (ver UBA)", MACHINE_NOT_WORKING )
+GAME( 1998, evilngte, evilngt, evilngt, hellngt, konamim2_state, init_hellngt, ROT0, "Konami", "Evil Night (ver EAA)", MACHINE_NOT_WORKING )
+GAME( 1998, hellngt, evilngt, hellngt, hellngt, konamim2_state, init_hellngt, ROT0, "Konami", "Hell Night (ver EAA)", MACHINE_NOT_WORKING )
+
+//CONS( 199?, 3do_m2, 0, 0, 3do_m2, m2, driver_device, 0, "3DO", "3DO M2", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
+
+
+/*************************************
+ *
+ * Debugging Aids
+ *
+ *************************************/
+
+void konamim2_state::debug_help_command(int ref, const std::vector<std::string> &params)
+{
+ debugger_console &con = machine().debugger().console();
+
+ con.printf("Available M2 commands:\n");
+ con.printf(" konm2 dump_task,<address> -- Dump task object at <address>\n");
+ con.printf(" konm2 dump_dspp,<address> -- Dump DSPP object at <address>\n");
+}
-GAME( 1997, polystar, 0, m2, m2, konamim2_state, empty_init, ROT0, "Konami", "Tobe! Polystars (ver JAA)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 1997, totlvice, 0, m2, m2, konamim2_state, empty_init, ROT0, "Konami", "Total Vice (ver EBA)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 1997, totlvicu, totlvice, m2, m2, konamim2_state, empty_init, ROT0, "Konami", "Total Vice (ver UAC)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 1997, totlvicj, totlvice, m2, m2, konamim2_state, empty_init, ROT0, "Konami", "Total Vice (ver JAD)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 1997, totlvica, totlvice, m2, m2, konamim2_state, empty_init, ROT0, "Konami", "Total Vice (ver AAB)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 1998, btltryst, 0, m2, m2, konamim2_state, empty_init, ROT0, "Konami", "Battle Tryst (ver JAC)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 1998, heatof11, 0, m2, m2, konamim2_state, empty_init, ROT0, "Konami", "Heat of Eleven '98 (ver EAA)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 1998, evilngt, 0, m2, m2, konamim2_state, empty_init, ROT0, "Konami", "Evil Night (ver UBA)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 1998, evilngte, evilngt, m2, m2, konamim2_state, empty_init, ROT0, "Konami", "Evil Night (ver EAA)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 1998, hellngt, evilngt, m2, m2, konamim2_state, empty_init, ROT0, "Konami", "Hell Night (ver EAA)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-
-CONS( 199?, 3do_m2, 0, 0, _3do_m2, m2, konamim2_state, empty_init, "3DO", "3DO M2", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
+void konamim2_state::debug_commands(int ref, const std::vector<std::string> &params)
+{
+ if (params.size() < 1)
+ return;
+
+ if (params[0] == "help")
+ debug_help_command(ref, params);
+ else if (params[0] == "dump_task")
+ dump_task_command(ref, params);
+ else if (params[0] == "dump_dspp")
+ subdevice<dspp_device>("bda:dspp")->dump_state();
+}
+
+void konamim2_state::dump_task_command(int ref, const std::vector<std::string> &params)
+{
+ typedef uint32_t Item;
+ typedef uint32_t m2ptr;
+
+ typedef struct TimerTicks
+ {
+ uint32_t tt_Hi;
+ uint32_t tt_Lo;
+ } TimerTicks;
+
+ struct ItemNode
+ {
+ m2ptr pn_Next; /* pointer to next in list */ // 0
+ m2ptr pn_Prev; /* pointer to previous in list */ // 4
+ uint8_t n_SubsysType; /* what component manages this node */ // 8
+ uint8_t n_Type; /* what type of node for the component */ // 9
+ uint8_t n_Priority; /* queueing priority */ // A
+ uint8_t n_Flags; /* misc flags, see below */ // B
+ int32_t n_Size; /* total size of node including hdr */ // C
+ m2ptr pn_Name; /* name of item, or NULL */ // 10
+ uint8_t n_Version; /* version of of this Item */ // 14
+ uint8_t n_Revision; /* revision of this Item */ // 15
+ uint8_t n_Reserved0; /* reserved for future use */ // 16
+ uint8_t n_ItemFlags; /* additional system item flags */ // 17
+ Item n_Item; /* Item number representing this struct */ //18
+ Item n_Owner; /* creator, present owner, disposer */ // 1C
+ m2ptr pn_Reserved1; /* reserved for future use */ // 20
+ };
+
+ struct Task
+ {
+ ItemNode t;
+ m2ptr pt_ThreadTask; /* I am a thread of what task? */
+ uint32_t t_WaitBits; /* signals being waited for */
+ uint32_t t_SigBits; /* signals received */
+ uint32_t t_AllocatedSigs; /* signals allocated */
+ m2ptr pt_StackBase; /* base of stack */
+ int32_t t_StackSize; /* size of stack */
+ uint32_t t_MaxUSecs; /* quantum length in usecs */
+ TimerTicks t_ElapsedTime; /* time spent running this task */
+ uint32_t t_NumTaskLaunch; /* # times launched this task */
+ uint32_t t_Flags; /* task flags */
+ Item t_Module; /* the module we live within */
+ Item t_DefaultMsgPort; /* default task msgport */
+ m2ptr pt_UserData; /* user-private data */
+ };
+
+ debugger_cpu &cpu = machine().debugger().cpu();
+ debugger_console &con = machine().debugger().console();
+ address_space &space = m_ppc1->space();
+ uint64_t addr;
+ offs_t address;
+
+ if (params.size() < 1)
+ return;
+
+ if (!machine().debugger().commands().validate_number_parameter(params[1], addr))
+ return;
+
+ address = (offs_t)addr;
+ address = 0x40FB54E8;
+ if (!m_ppc1->translate(AS_PROGRAM, TRANSLATE_READ_DEBUG, address))
+ {
+ con.printf("Address is unmapped.\n");
+ return;
+ }
+
+ Task task;
+
+ task.t.pn_Next = cpu.read_dword(space, address + offsetof(ItemNode, pn_Next), true);
+ task.t.pn_Prev = cpu.read_dword(space, address + offsetof(ItemNode, pn_Prev), true);
+ task.t.n_SubsysType = cpu.read_byte(space, address + offsetof(ItemNode, n_SubsysType), true);
+ task.t.n_Type = cpu.read_byte(space, address + offsetof(ItemNode, n_Type), true);
+ task.t.n_Priority = cpu.read_byte(space, address + offsetof(ItemNode, n_Priority), true);
+ task.t.n_Flags = cpu.read_byte(space, address + offsetof(ItemNode, n_Flags), true);
+ task.t.n_Size = cpu.read_dword(space, address + offsetof(ItemNode, n_Size), true);
+ task.t.pn_Name = cpu.read_dword(space, address + offsetof(ItemNode, pn_Name), true);
+
+ char name[128];
+ char *ptr = name;
+ uint32_t nameptr = task.t.pn_Name;
+
+ do
+ {
+ *ptr = cpu.read_byte(space, nameptr++, true);
+ } while (*ptr++ != 0);
+
+ task.t.n_Version = cpu.read_byte(space, address + offsetof(ItemNode, n_Version), true);
+ task.t.n_Revision = cpu.read_byte(space, address + offsetof(ItemNode, n_Revision), true);
+ task.t.n_Reserved0 = cpu.read_byte(space, address + offsetof(ItemNode, n_Reserved0), true);
+ task.t.n_ItemFlags = cpu.read_byte(space, address + offsetof(ItemNode, n_ItemFlags), true);
+ task.t.n_Item = cpu.read_dword(space, address + offsetof(ItemNode, n_Item), true);
+ task.t.n_Owner = cpu.read_dword(space, address + offsetof(ItemNode, n_Owner), true);
+ task.t.pn_Reserved1 = cpu.read_dword(space, address + offsetof(ItemNode, pn_Reserved1), true);
+
+ task.pt_ThreadTask = cpu.read_dword(space, address + offsetof(Task, pt_ThreadTask), true);
+ task.t_WaitBits = cpu.read_dword(space, address + offsetof(Task, t_WaitBits), true);
+ task.t_SigBits = cpu.read_dword(space, address + offsetof(Task, t_SigBits), true);
+ task.t_AllocatedSigs = cpu.read_dword(space, address + offsetof(Task, t_AllocatedSigs), true);
+ task.pt_StackBase = cpu.read_dword(space, address + offsetof(Task, pt_StackBase), true);
+ task.t_StackSize = cpu.read_dword(space, address + offsetof(Task, t_StackSize), true);
+ task.t_MaxUSecs = cpu.read_dword(space, address + offsetof(Task, t_MaxUSecs), true);
+ task.t_ElapsedTime.tt_Hi = cpu.read_dword(space, address + offsetof(Task, t_ElapsedTime)+0, true);
+ task.t_ElapsedTime.tt_Lo = cpu.read_dword(space, address + offsetof(Task, t_ElapsedTime)+4, true);
+ task.t_NumTaskLaunch = cpu.read_dword(space, address + offsetof(Task, t_NumTaskLaunch), true);
+ task.t_Flags = cpu.read_dword(space, address + offsetof(Task, t_Flags), true);
+ task.t_Module = cpu.read_dword(space, address + offsetof(Task, t_Module), true);
+ task.t_DefaultMsgPort = cpu.read_dword(space, address + offsetof(Task, t_DefaultMsgPort), true);
+ task.pt_UserData = cpu.read_dword(space, address + offsetof(Task, pt_UserData), true);
+
+// m2ptr pt_ThreadTask; /* I am a thread of what task? */
+// uint32_t t_WaitBits; /* signals being waited for */
+// uint32_t t_SigBits; /* signals received */
+// uint32_t t_AllocatedSigs; /* signals allocated */
+// m2ptr pt_StackBase; /* base of stack */
+// int32_t t_StackSize; /* size of stack */
+// uint32_t t_MaxUSecs; /* quantum length in usecs */
+// TimerTicks t_ElapsedTime; /* time spent running this task */
+// uint32_t t_NumTaskLaunch; /* # times launched this task */
+// uint32_t t_Flags; /* task flags */
+// Item t_Module; /* the module we live within */
+// Item t_DefaultMsgPort; /* default task msgport */
+// m2ptr pt_UserData; /* user-private data */
+
+ con.printf("**** Task Info @ %08X ****\n", address);
+ con.printf("Next: %08X\n", task.t.pn_Next);
+ con.printf("Prev: %08X\n", task.t.pn_Prev);
+ con.printf("SubsysType: %X\n", task.t.n_SubsysType);
+ con.printf("Type: %X\n", task.t.n_Type);
+ con.printf("Priority: %X\n", task.t.n_Priority);
+ con.printf("Flags: %X\n", task.t.n_Flags);
+ con.printf("Size: %08X\n", task.t.n_Size);
+ con.printf("Name: %s\n", name);
+ con.printf("Version: %X\n", task.t.n_Version);
+ con.printf("Revision: %X\n", task.t.n_Revision);
+ con.printf("Reserved0: %X\n", task.t.n_Reserved0);
+ con.printf("ItemFlags: %X\n", task.t.n_ItemFlags);
+ con.printf("Item: %08X\n", task.t.n_Item);
+ con.printf("Owner: %08X\n", task.t.n_Owner);
+ con.printf("Reserved1: %08X\n", task.t.pn_Reserved1);
+ con.printf("ThreadTask: %08X\n", task.pt_ThreadTask);
+ con.printf("WaitBits: %08X\n", task.t_WaitBits);
+ con.printf("SigBits: %08X\n", task.t_SigBits);
+ con.printf("AllocSigs: %08X\n", task.t_AllocatedSigs);
+ con.printf("StackBase: %08X\n", task.pt_StackBase);
+ con.printf("StackSize: %08X\n", task.t_StackSize);
+ con.printf("MaxUSecs: %08X\n", task.t_MaxUSecs);
+ con.printf("ElapsedTime: %016llu\n", (uint64_t)task.t_ElapsedTime.tt_Lo + ((uint64_t)task.t_ElapsedTime.tt_Hi << 32ull));
+ con.printf("NumTaskLaunch: %u\n", task.t_NumTaskLaunch);
+ con.printf("Flags: %08X\n", task.t_Flags);
+ con.printf("Module: %08X\n", task.t_Module);
+ con.printf("DefaultMsgPort: %08X\n", task.t_DefaultMsgPort);
+ con.printf("UserData: %08X\n", task.pt_UserData);
+ con.printf("\n");
+}
diff --git a/src/mame/drivers/m14.cpp b/src/mame/drivers/m14.cpp
index 4bd7334a609..1f25cdd1f3f 100644
--- a/src/mame/drivers/m14.cpp
+++ b/src/mame/drivers/m14.cpp
@@ -460,9 +460,9 @@ void m14_state::m14(machine_config &config)
m_samples->set_samples_names(m14_sample_names);
m_samples->add_route(ALL_OUTPUTS, "mono", 0.6);
-// MCFG_DEVICE_ADD("discrete", DISCRETE)
-// MCFG_DISCRETE_INTF(m14)
-// MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
+// DISCRETE(config, m_discrete);
+// m_discrete->set_intf(m14);
+// m_discrete->add_route(ALL_OUTPUTS, "mono", 1.0);
}
/***************************************************************************
diff --git a/src/mame/drivers/norautp.cpp b/src/mame/drivers/norautp.cpp
index f4e118814d6..744a417e9c3 100644
--- a/src/mame/drivers/norautp.cpp
+++ b/src/mame/drivers/norautp.cpp
@@ -1240,12 +1240,12 @@ GFXDECODE_END
* Machine Drivers *
*************************/
-MACHINE_CONFIG_START(norautp_state::noraut_base)
-
+void norautp_state::noraut_base(machine_config &config)
+{
/* basic machine hardware */
- MCFG_DEVICE_ADD("maincpu", Z80, NORAUT_CPU_CLOCK)
- MCFG_DEVICE_PROGRAM_MAP(norautp_map)
- MCFG_DEVICE_IO_MAP(norautp_portmap)
+ Z80(config, m_maincpu, NORAUT_CPU_CLOCK);
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::norautp_map);
+ m_maincpu->set_addrmap(AS_IO, &norautp_state::norautp_portmap);
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); /* doesn't work if placed at derivative drivers */
@@ -1271,198 +1271,183 @@ MACHINE_CONFIG_START(norautp_state::noraut_base)
Port C as hshk regs, and P0-P2 as input (norautp, norautjp) or output (other sets). */
/* video hardware */
- MCFG_SCREEN_ADD("screen", RASTER)
- MCFG_SCREEN_REFRESH_RATE(60)
- MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0))
- MCFG_SCREEN_SIZE(32*16, 32*16)
- MCFG_SCREEN_VISIBLE_AREA(2*16, 31*16-1, (0*16) + 8, 16*16-1) /* the hardware clips the top 8 pixels */
- MCFG_SCREEN_UPDATE_DRIVER(norautp_state, screen_update_norautp)
- MCFG_SCREEN_PALETTE("palette")
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_refresh_hz(60);
+ m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0));
+ m_screen->set_size(32*16, 32*16);
+ m_screen->set_visarea(2*16, 31*16-1, (0*16) + 8, 16*16-1); /* the hardware clips the top 8 pixels */
+ m_screen->set_screen_update(FUNC(norautp_state::screen_update_norautp));
+ m_screen->set_palette(m_palette);
- MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "palette", gfx_norautp)
+ GFXDECODE(config, m_gfxdecode, m_palette, gfx_norautp);
- MCFG_PALETTE_ADD("palette", 8)
- MCFG_PALETTE_INIT_OWNER(norautp_state, norautp)
+ PALETTE(config, m_palette, 8);
+ m_palette->set_init(FUNC(norautp_state::palette_init_norautp));
/* sound hardware */
SPEAKER(config, "mono").front_center();
- MCFG_DEVICE_ADD("discrete", DISCRETE, norautp_discrete)
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
-MACHINE_CONFIG_END
-
+ DISCRETE(config, m_discrete, norautp_discrete);
+ m_discrete->add_route(ALL_OUTPUTS, "mono", 1.0);
+}
-MACHINE_CONFIG_START(norautp_state::norautp)
+void norautp_state::norautp(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_MODIFY("maincpu")
- MCFG_DEVICE_VBLANK_INT_DRIVER("screen", norautp_state, irq0_line_hold)
-MACHINE_CONFIG_END
-
+ m_maincpu->set_vblank_int("screen", FUNC(norautp_state::irq0_line_hold));
+}
-MACHINE_CONFIG_START(norautp_state::norautpl)
+void norautp_state::norautpl(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_MODIFY("maincpu")
- MCFG_DEVICE_VBLANK_INT_DRIVER("screen", norautp_state, irq0_line_hold)
+ m_maincpu->set_vblank_int("screen", FUNC(norautp_state::irq0_line_hold));
/* sound hardware */
- MCFG_DEVICE_MODIFY("discrete")
- MCFG_DISCRETE_INTF(kimble_discrete)
-MACHINE_CONFIG_END
-
+ m_discrete->set_intf(kimble_discrete);
+}
-MACHINE_CONFIG_START(norautp_state::norautxp)
+void norautp_state::norautxp(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_MODIFY("maincpu")
- MCFG_DEVICE_PROGRAM_MAP(norautxp_map)
- MCFG_DEVICE_VBLANK_INT_DRIVER("screen", norautp_state, irq0_line_hold)
-MACHINE_CONFIG_END
-
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::norautxp_map);
+ m_maincpu->set_vblank_int("screen", FUNC(norautp_state::irq0_line_hold));
+}
-MACHINE_CONFIG_START(norautp_state::nortest1)
+void norautp_state::nortest1(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_MODIFY("maincpu")
- MCFG_DEVICE_PROGRAM_MAP(nortest1_map)
- MCFG_DEVICE_VBLANK_INT_DRIVER("screen", norautp_state, irq0_line_hold)
-MACHINE_CONFIG_END
-
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::nortest1_map);
+ m_maincpu->set_vblank_int("screen", FUNC(norautp_state::irq0_line_hold));
+}
-MACHINE_CONFIG_START(norautp_state::norautx4)
+void norautp_state::norautx4(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_MODIFY("maincpu")
- MCFG_DEVICE_PROGRAM_MAP(norautx4_map)
- MCFG_DEVICE_VBLANK_INT_DRIVER("screen", norautp_state, irq0_line_hold)
-MACHINE_CONFIG_END
-
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::norautx4_map);
+ m_maincpu->set_vblank_int("screen", FUNC(norautp_state::irq0_line_hold));
+}
#ifdef UNUSED_CODE
-static MACHINE_CONFIG_START( norautx8 )
+void norautp_state::norautx8(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_MODIFY("maincpu")
- MCFG_DEVICE_PROGRAM_MAP(norautx8_map)
- MCFG_DEVICE_VBLANK_INT_DRIVER("screen", norautp_state, irq0_line_hold)
-MACHINE_CONFIG_END
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::norautx8_map);
+ m_maincpu->set_vblank_int("screen", FUNC(norautp_state::irq0_line_hold));
+}
#endif
-
-MACHINE_CONFIG_START(norautp_state::kimble)
+void norautp_state::kimble(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_MODIFY("maincpu")
- MCFG_DEVICE_PROGRAM_MAP(kimble_map)
- MCFG_DEVICE_VBLANK_INT_DRIVER("screen", norautp_state, irq0_line_hold)
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::kimble_map);
+ m_maincpu->set_vblank_int("screen", FUNC(norautp_state::irq0_line_hold));
/* sound hardware */
- MCFG_DEVICE_MODIFY("discrete")
- MCFG_DISCRETE_INTF(kimble_discrete)
-MACHINE_CONFIG_END
+ m_discrete->set_intf(kimble_discrete);
+}
-MACHINE_CONFIG_START(norautp_state::newhilop)
+void norautp_state::newhilop(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_MODIFY("maincpu")
- MCFG_DEVICE_PROGRAM_MAP(newhilop_map)
-// MCFG_DEVICE_IO_MAP(newhilop_portmap)
- MCFG_DEVICE_VBLANK_INT_DRIVER("screen", norautp_state, irq0_line_hold)
-MACHINE_CONFIG_END
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::newhilop_map);
+// m_maincpu->set_addrmap(AS_IO, &norautp_state::newhilop_portmap);
+ m_maincpu->set_vblank_int("screen", FUNC(norautp_state::irq0_line_hold));
+}
/********** 8080 based **********/
-
-MACHINE_CONFIG_START(norautp_state::dphl)
+void norautp_state::dphl(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_REPLACE("maincpu", I8080, DPHL_CPU_CLOCK)
- MCFG_DEVICE_PROGRAM_MAP(dphl_map)
- MCFG_DEVICE_IO_MAP(norautp_portmap)
+ I8080(config.replace(), m_maincpu, DPHL_CPU_CLOCK);
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::dphl_map);
+ m_maincpu->set_addrmap(AS_IO, &norautp_state::norautp_portmap);
/* sound hardware */
- MCFG_DEVICE_MODIFY("discrete")
- MCFG_DISCRETE_INTF(dphl_discrete)
-MACHINE_CONFIG_END
-
+ m_discrete->set_intf(dphl_discrete);
+}
-MACHINE_CONFIG_START(norautp_state::dphla)
+void norautp_state::dphla(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_REPLACE("maincpu", I8080, DPHL_CPU_CLOCK)
- MCFG_DEVICE_PROGRAM_MAP(dphla_map)
- MCFG_DEVICE_IO_MAP(norautp_portmap)
+ I8080(config.replace(), m_maincpu, DPHL_CPU_CLOCK);
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::dphla_map);
+ m_maincpu->set_addrmap(AS_IO, &norautp_state::norautp_portmap);
/* sound hardware */
- MCFG_DEVICE_MODIFY("discrete")
- MCFG_DISCRETE_INTF(dphl_discrete)
-MACHINE_CONFIG_END
-
+ m_discrete->set_intf(dphl_discrete);
+}
-MACHINE_CONFIG_START(norautp_state::kimbldhl)
+void norautp_state::kimbldhl(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_REPLACE("maincpu", I8080, DPHL_CPU_CLOCK)
- MCFG_DEVICE_PROGRAM_MAP(kimbldhl_map)
- MCFG_DEVICE_IO_MAP(norautp_portmap)
+ I8080(config.replace(), m_maincpu, DPHL_CPU_CLOCK);
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::kimbldhl_map);
+ m_maincpu->set_addrmap(AS_IO, &norautp_state::norautp_portmap);
/* sound hardware */
- MCFG_DEVICE_MODIFY("discrete")
- MCFG_DISCRETE_INTF(kimble_discrete)
-MACHINE_CONFIG_END
-
+ m_discrete->set_intf(kimble_discrete);
+}
-MACHINE_CONFIG_START(norautp_state::dphltest)
+void norautp_state::dphltest(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_REPLACE("maincpu", I8080, DPHL_CPU_CLOCK)
- MCFG_DEVICE_PROGRAM_MAP(dphltest_map)
- MCFG_DEVICE_IO_MAP(norautp_portmap)
+ I8080(config.replace(), m_maincpu, DPHL_CPU_CLOCK);
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::dphltest_map);
+ m_maincpu->set_addrmap(AS_IO, &norautp_state::norautp_portmap);
/* sound hardware */
- MCFG_DEVICE_MODIFY("discrete")
- MCFG_DISCRETE_INTF(dphl_discrete)
-MACHINE_CONFIG_END
-
+ m_discrete->set_intf(dphl_discrete);
+}
-MACHINE_CONFIG_START(norautp_state::drhl)
+void norautp_state::drhl(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_REPLACE("maincpu", I8080, DPHL_CPU_CLOCK)
- MCFG_DEVICE_PROGRAM_MAP(drhl_map)
- MCFG_DEVICE_IO_MAP(norautp_portmap)
+ I8080(config.replace(), m_maincpu, DPHL_CPU_CLOCK);
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::drhl_map);
+ m_maincpu->set_addrmap(AS_IO, &norautp_state::norautp_portmap);
/* sound hardware */
- MCFG_DEVICE_MODIFY("discrete")
- MCFG_DISCRETE_INTF(dphl_discrete)
-MACHINE_CONFIG_END
-
+ m_discrete->set_intf(dphl_discrete);
+}
-MACHINE_CONFIG_START(norautp_state::ssjkrpkr)
+void norautp_state::ssjkrpkr(machine_config &config)
+{
noraut_base(config);
/* basic machine hardware */
- MCFG_DEVICE_REPLACE("maincpu", I8080, DPHL_CPU_CLOCK)
- MCFG_DEVICE_PROGRAM_MAP(ssjkrpkr_map)
- MCFG_DEVICE_IO_MAP(norautp_portmap)
+ I8080(config.replace(), m_maincpu, DPHL_CPU_CLOCK);
+ m_maincpu->set_addrmap(AS_PROGRAM, &norautp_state::ssjkrpkr_map);
+ m_maincpu->set_addrmap(AS_IO, &norautp_state::norautp_portmap);
/* sound hardware */
- MCFG_DEVICE_MODIFY("discrete")
- MCFG_DISCRETE_INTF(dphl_discrete)
-MACHINE_CONFIG_END
+ m_discrete->set_intf(dphl_discrete);
+}
/*************************
diff --git a/src/mame/drivers/osi.cpp b/src/mame/drivers/osi.cpp
index bb16530dc6f..f7108b28c6b 100644
--- a/src/mame/drivers/osi.cpp
+++ b/src/mame/drivers/osi.cpp
@@ -711,74 +711,78 @@ GFXDECODE_END
/* Machine Drivers */
-MACHINE_CONFIG_START(sb2m600_state::osi600)
+void sb2m600_state::osi600(machine_config &config)
+{
/* basic machine hardware */
- MCFG_DEVICE_ADD(M6502_TAG, M6502, X1/4) // .98304 MHz
- MCFG_DEVICE_PROGRAM_MAP(osi600_mem)
+ M6502(config, m_maincpu, X1/4); // .98304 MHz
+ m_maincpu->set_addrmap(AS_PROGRAM, &sb2m600_state::osi600_mem);
/* video hardware */
osi600_video(config);
- MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "palette", gfx_osi)
+ GFXDECODE(config, "gfxdecode", "palette", gfx_osi);
/* sound hardware */
SPEAKER(config, "mono").front_center();
- MCFG_DEVICE_ADD(DISCRETE_TAG, DISCRETE)
- MCFG_DISCRETE_INTF(osi600_discrete_interface)
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+ DISCRETE(config, m_discrete);
+ m_discrete->set_intf(osi600_discrete_interface);
+ m_discrete->add_route(ALL_OUTPUTS, "mono", 0.50);
/* cassette ACIA */
ACIA6850(config, m_acia_0, 0);
m_acia_0->txd_handler().set(FUNC(sb2m600_state::cassette_tx));
- MCFG_DEVICE_ADD("cassette_clock", CLOCK, X1/32)
- MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(*this, sb2m600_state, write_cassette_clock))
+ CLOCK(config, "cassette_clock", X1/32).signal_handler().set(FUNC(sb2m600_state::write_cassette_clock));
/* cassette */
- MCFG_CASSETTE_ADD("cassette")
+ CASSETTE(config, m_cassette);
/* internal ram */
- RAM(config, m_ram).set_default_size("4K").set_extra_options("8K");
-MACHINE_CONFIG_END
+ RAM(config, m_ram);
+ m_ram->set_default_size("4K");
+ m_ram->set_extra_options("8K");
+}
-MACHINE_CONFIG_START(uk101_state::uk101)
+void uk101_state::uk101(machine_config &config)
+{
/* basic machine hardware */
- MCFG_DEVICE_ADD(M6502_TAG, M6502, UK101_X1/8) // 1 MHz
- MCFG_DEVICE_PROGRAM_MAP(uk101_mem)
+ M6502(config, m_maincpu, UK101_X1/8); // 1 MHz
+ m_maincpu->set_addrmap(AS_PROGRAM, &uk101_state::uk101_mem);
/* video hardware */
uk101_video(config);
- MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "palette", gfx_osi)
+ GFXDECODE(config, "gfxdecode", "palette", gfx_osi);
/* cassette ACIA */
ACIA6850(config, m_acia_0, 0);
m_acia_0->txd_handler().set(FUNC(sb2m600_state::cassette_tx));
- MCFG_DEVICE_ADD("cassette_clock", CLOCK, 500000)
- MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(*this, sb2m600_state, write_cassette_clock))
+ CLOCK(config, "cassette_clock", 500000).signal_handler().set(FUNC(sb2m600_state::write_cassette_clock));
/* cassette */
- MCFG_CASSETTE_ADD("cassette")
+ CASSETTE(config, m_cassette);
/* internal ram */
- RAM(config, m_ram).set_default_size("4K").set_extra_options("8K");
-MACHINE_CONFIG_END
+ RAM(config, m_ram);
+ m_ram->set_default_size("4K");
+ m_ram->set_extra_options("8K");
+}
-MACHINE_CONFIG_START(c1p_state::c1p)
+void c1p_state::c1p(machine_config &config)
+{
/* basic machine hardware */
- MCFG_DEVICE_ADD(M6502_TAG, M6502, X1/4) // .98304 MHz
- MCFG_DEVICE_PROGRAM_MAP(c1p_mem)
+ M6502(config, m_maincpu, X1/4); // .98304 MHz
+ m_maincpu->set_addrmap(AS_PROGRAM, &c1p_state::c1p_mem);
/* video hardware */
osi630_video(config);
- MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "palette", gfx_osi)
+ GFXDECODE(config, "gfxdecode", "palette", gfx_osi);
/* sound hardware */
SPEAKER(config, "mono").front_center();
- MCFG_DEVICE_ADD(DISCRETE_TAG, DISCRETE)
- MCFG_DISCRETE_INTF(osi600c_discrete_interface)
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
- MCFG_DEVICE_ADD("beeper", BEEP, 300)
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+ DISCRETE(config, m_discrete);
+ m_discrete->set_intf(osi600c_discrete_interface);
+ m_discrete->add_route(ALL_OUTPUTS, "mono", 0.50);
+ BEEP(config, "beeper", 300).add_route(ALL_OUTPUTS, "mono", 0.50);
PIA6821(config, "pia_1", 0);
PIA6821(config, "pia_2", 0);
@@ -788,20 +792,21 @@ MACHINE_CONFIG_START(c1p_state::c1p)
ACIA6850(config, m_acia_0, 0);
m_acia_0->txd_handler().set(FUNC(sb2m600_state::cassette_tx));
- MCFG_DEVICE_ADD("cassette_clock", CLOCK, X1/32)
- MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(*this, sb2m600_state, write_cassette_clock))
+ CLOCK(config, "cassette_clock", X1/32).signal_handler().set(FUNC(sb2m600_state::write_cassette_clock));
/* cassette */
- MCFG_CASSETTE_ADD("cassette")
+ CASSETTE(config, m_cassette);
/* internal ram */
- RAM(config, m_ram).set_default_size("8K").set_extra_options("20K");
-MACHINE_CONFIG_END
+ RAM(config, m_ram);
+ m_ram->set_default_size("8K");
+ m_ram->set_extra_options("20K");
+}
-MACHINE_CONFIG_START(c1pmf_state::c1pmf)
+void c1pmf_state::c1pmf(machine_config &config)
+{
c1p(config);
- MCFG_DEVICE_MODIFY(M6502_TAG)
- MCFG_DEVICE_PROGRAM_MAP(c1pmf_mem)
+ m_maincpu->set_addrmap(AS_PROGRAM, &c1pmf_state::c1pmf_mem);
pia6821_device &pia0(PIA6821(config, "pia_0", 0));
pia0.readpa_handler().set(FUNC(c1pmf_state::osi470_pia_pa_r));
@@ -812,15 +817,14 @@ MACHINE_CONFIG_START(c1pmf_state::c1pmf)
/* floppy ACIA */
ACIA6850(config, "acia_1", 0);
- MCFG_DEVICE_ADD("floppy_clock", CLOCK, XTAL(4'000'000)/8) // 250 kHz
- MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE("acia_1", acia6850_device, write_txc))
+ CLOCK(config, "floppy_clock", XTAL(4'000'000)/8).signal_handler().set("acia_1", FUNC(acia6850_device::write_txc)); // 250 kHz
- MCFG_FLOPPY_DRIVE_ADD("floppy0", osi_floppies, "ssdd", floppy_image_device::default_floppy_formats)
- MCFG_FLOPPY_DRIVE_ADD("floppy1", osi_floppies, nullptr, floppy_image_device::default_floppy_formats)
+ FLOPPY_CONNECTOR(config, "floppy0", osi_floppies, "ssdd", floppy_image_device::default_floppy_formats);
+ FLOPPY_CONNECTOR(config, "floppy1", osi_floppies, nullptr, floppy_image_device::default_floppy_formats);
/* internal ram */
m_ram->set_default_size("20K");
-MACHINE_CONFIG_END
+}
/* ROMs */
diff --git a/src/mame/drivers/popeye.cpp b/src/mame/drivers/popeye.cpp
index 89087ba1c05..05ae6f1a538 100644
--- a/src/mame/drivers/popeye.cpp
+++ b/src/mame/drivers/popeye.cpp
@@ -636,8 +636,7 @@ void tpp2_state::config(machine_config &config)
NETLIST_STREAM_INPUT(config, "snd_nl:cin1", 1, "R_AY1_2.R");
NETLIST_STREAM_INPUT(config, "snd_nl:cin2", 2, "R_AY1_3.R");
- netlist_mame_stream_output_device &nl_out(NETLIST_STREAM_OUTPUT(config, "snd_nl:cout0", 0, "ROUT.1"));
- nl_out.set_mult_offset(30000.0, -65000.0);
+ NETLIST_STREAM_OUTPUT(config, "snd_nl:cout0", 0, "ROUT.1").set_mult_offset(30000.0, -65000.0);
}
diff --git a/src/mame/drivers/tattack.cpp b/src/mame/drivers/tattack.cpp
index 30cccbb4b30..fd03de90f76 100644
--- a/src/mame/drivers/tattack.cpp
+++ b/src/mame/drivers/tattack.cpp
@@ -432,9 +432,9 @@ void tattack_state::tattack(machine_config &config)
m_samples->add_route(ALL_OUTPUTS, "mono", 0.6);
/* Discrete ???? */
-// MCFG_DEVICE_ADD("discrete", DISCRETE)
-// MCFG_DISCRETE_INTF(tattack)
-// MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
+// DISCRETE(config, m_discrete);
+// m_discrete->set_intf(tattack);
+// m_discrete->add_route(ALL_OUTPUTS, "mono", 1.0);
}
/***************************************************************************
diff --git a/src/mame/drivers/vii.cpp b/src/mame/drivers/vii.cpp
index ebad019ebef..0fd09f99796 100644
--- a/src/mame/drivers/vii.cpp
+++ b/src/mame/drivers/vii.cpp
@@ -12,72 +12,32 @@
To-Do:
- Audio (SPG243)
-
- Known u'nSP-Based Systems:
-
- D - SPG240 - Radica Skateboarder (Sunplus QL8041C die)
- ND - SPG243 - Some form of Leapfrog "edutainment" system
- ND - SPG243 - Star Wars: Clone Wars
- ND - SPG243 - Toy Story
- ND - SPG243 - Animal Art Studio
- ND - SPG243 - Finding Nemo
- D - SPG243 - The Batman
- D - SPG243 - Wall-E
- D - SPG243 - KenSingTon / Siatronics / Jungle Soft Vii
- Partial D - SPG200 - VTech V.Smile
- ND - unknown - Zone 40
- D - SPG243 - Zone 60
- D - SPG243 - Wireless 60
- ND - unknown - Wireless Air 60
- ND - Likely many more
-
-
-Similar Systems: ( from http://en.wkikpedia.org/wiki/V.Smile )
-- V.Smile by VTech, a system designed for children under the age of 10
-- V.Smile Pocket (2 versions)
-- V.Smile Cyber Pocket
-- V.Smile PC Pal
-- V-Motion Active Learning System
-- Leapster
-- V.Smile Baby Infant Development System
-- V.Flash
-
-also on this hardware
-
- name PCB ID ROM width TSOP pads ROM size SEEPROM die markings
- Radica Play TV Football 2 L7278 x16 48 not dumped no Sunplus
- Dream Life ? x16 48 not dumped no Sunplus
-
-Detailed list of bugs:
-
-- all systems:
- Various inaccuracies in samples/envelopes.
-- vsmile:
- Games loop the first legal screen rather than continuing.
-- walle:
- Voice sample on the title screen is continually retriggered by the game code.
- Title screen lacks New Game / Continue Game menu options.
-- rad_skat:
- Palette issues on the High Score screen.
-- vii:
- Music does not loop.
- When loading a cart from file manager, sometimes MAME will crash.
- The "MOTOR" option in the diagnostic menu does nothing when selected.
- The "SPEECH IC" option in the diagnostic menu does nothing when selected.
- On 'vii_vc1' & 'vii_vc2' cart, the left-right keys are transposed with the up-down keys.
- This is not a bug per se, as the games are played with the controller physically rotated 90 degrees.
-- zone60/wirels60:
- All Games: Music does not loop.
- Basketball: MAME fatalerrors when starting the game due to jumping to invalid code.
-
+ Proper driver_device inheritance to untangle the mess of members
+
+ Detailed list of bugs:
+
+ All systems:
+ Various inaccuracies in samples/envelopes.
+
+ walle:
+ Game seems unhappy with NVRAM, clears contents on each boot.
+ rad_skat:
+ Palette issues on the High Score screen.
+ vii:
+ When loading a cart from file manager, sometimes MAME will crash.
+ The "MOTOR" option in the diagnostic menu does nothing when selected.
+ The "SPEECH IC" option in the diagnostic menu does nothing when selected.
+ On 'vii_vc1' & 'vii_vc2' cart, the left-right keys are transposed with the up-down keys.
+ - This is not a bug per se, as the games are played with the controller physically rotated 90 degrees.
+ When entering a game in Basketball, MAME fatalerrors when starting the game due to jumping to invalid code.
+ zone60/wirels60:
+ When entering a game in Basketball, MAME fatalerrors when starting the game due to jumping to invalid code.
*******************************************************************************/
#include "emu.h"
#include "cpu/unsp/unsp.h"
-#include "machine/bankdev.h"
#include "machine/i2cmem.h"
#include "machine/nvram.h"
#include "machine/spg2xx.h"
@@ -85,7 +45,6 @@ Detailed list of bugs:
#include "bus/generic/slot.h"
#include "bus/generic/carts.h"
-#include "emupal.h"
#include "screen.h"
#include "softlist.h"
#include "speaker.h"
@@ -97,17 +56,11 @@ public:
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_screen(*this, "screen")
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- , m_debug_screen(*this, "debug_screen")
-#endif
, m_spg(*this, "spg")
, m_bank(*this, "cartbank")
, m_io_p1(*this, "P1")
, m_io_p2(*this, "P2")
, m_io_p3(*this, "P3")
- , m_io_motionx(*this, "MOTIONX")
- , m_io_motiony(*this, "MOTIONY")
- , m_io_motionz(*this, "MOTIONZ")
, m_i2cmem(*this, "i2cmem")
, m_nvram(*this, "nvram")
{ }
@@ -125,9 +78,10 @@ public:
void init_rad_crik();
protected:
- void switch_bank(uint32_t bank);
-
virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+ void switch_bank(uint32_t bank);
DECLARE_WRITE8_MEMBER(eeprom_w);
DECLARE_READ8_MEMBER(eeprom_r);
@@ -139,39 +93,25 @@ protected:
required_device<cpu_device> m_maincpu;
required_device<screen_device> m_screen;
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- required_device<screen_device> m_debug_screen;
-#endif
required_device<spg2xx_device> m_spg;
optional_memory_bank m_bank;
-protected:
- DECLARE_WRITE_LINE_MEMBER(poll_controls);
-
DECLARE_READ16_MEMBER(walle_portc_r);
DECLARE_WRITE16_MEMBER(walle_portc_w);
- virtual void machine_reset() override;
-
virtual void mem_map(address_map &map);
uint32_t m_current_bank;
std::unique_ptr<uint8_t[]> m_serial_eeprom;
- uint8_t m_controller_input[8];
uint8_t m_w60_controller_input;
uint16_t m_w60_porta_data;
uint16_t m_walle_portc_data;
- inline void verboselog(int n_level, const char *s_fmt, ...) ATTR_PRINTF(3, 4);
-
required_ioport m_io_p1;
optional_ioport m_io_p2;
optional_ioport m_io_p3;
- optional_ioport m_io_motionx;
- optional_ioport m_io_motiony;
- optional_ioport m_io_motionz;
optional_device<i2cmem_device> m_i2cmem;
optional_device<nvram_device> m_nvram;
@@ -179,96 +119,43 @@ protected:
DECLARE_READ16_MEMBER(rad_crik_hack_r);
};
-class vsmile_state : public spg2xx_game_state
+class vii_state : public spg2xx_game_state
{
public:
- vsmile_state(const machine_config &mconfig, device_type type, const char *tag)
+ vii_state(const machine_config &mconfig, device_type type, const char *tag)
: spg2xx_game_state(mconfig, type, tag)
, m_cart(*this, "cartslot")
- , m_bankdev(*this, "bank")
- , m_system_region(*this, "maincpu")
+ , m_io_motionx(*this, "MOTIONX")
+ , m_io_motiony(*this, "MOTIONY")
+ , m_io_motionz(*this, "MOTIONZ")
+ , m_cart_region(nullptr)
+ , m_ctrl_poll_timer(nullptr)
{ }
- void vsmile(machine_config &config);
- void vsmilep(machine_config &config);
+ void vii(machine_config &config);
private:
virtual void machine_start() override;
virtual void machine_reset() override;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-
- static const device_timer_id TIMER_PAD = 0;
-
- virtual void mem_map(address_map &map) override;
- void banked_map(address_map &map);
- DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart);
-
- DECLARE_READ16_MEMBER(portb_r);
- DECLARE_READ16_MEMBER(portc_r);
- DECLARE_WRITE16_MEMBER(portb_w);
- DECLARE_WRITE16_MEMBER(portc_w);
-
- DECLARE_WRITE8_MEMBER(chip_sel_w);
-
- DECLARE_WRITE8_MEMBER(uart_tx);
-
- DECLARE_READ16_MEMBER(bank0_r);
- DECLARE_READ16_MEMBER(bank1_r);
- DECLARE_READ16_MEMBER(bank2_r);
- DECLARE_READ16_MEMBER(bank3_r);
- optional_device<generic_slot_device> m_cart;
- required_device<address_map_bank_device> m_bankdev;
- memory_region *m_cart_region;
- required_memory_region m_system_region;
-
- emu_timer *m_pad_timer;
- uint8_t m_pad_counter;
-
- uint16_t m_portb_data;
- uint16_t m_portc_data;
-};
-
-class spg2xx_cart_state : public spg2xx_game_state
-{
-public:
- spg2xx_cart_state(const machine_config &mconfig, device_type type, const char *tag)
- : spg2xx_game_state(mconfig, type, tag)
- , m_cart(*this, "cartslot")
- { }
-
- void vii(machine_config &config);
+ static const device_timer_id TIMER_CTRL_POLL = 0;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
-private:
DECLARE_WRITE16_MEMBER(vii_portb_w);
DECLARE_DEVICE_IMAGE_LOAD_MEMBER(vii_cart);
- virtual void machine_start() override;
- virtual void machine_reset() override;
+ virtual void poll_controls();
- optional_device<generic_slot_device> m_cart;
+ required_device<generic_slot_device> m_cart;
+ required_ioport m_io_motionx;
+ required_ioport m_io_motiony;
+ required_ioport m_io_motionz;
memory_region *m_cart_region;
-};
-#define VERBOSE_LEVEL (4)
-
-#define ENABLE_VERBOSE_LOG (1)
-
-inline void spg2xx_game_state::verboselog(int n_level, const char *s_fmt, ...)
-{
-#if ENABLE_VERBOSE_LOG
- if (VERBOSE_LEVEL >= n_level)
- {
- va_list v;
- char buf[32768];
- va_start(v, s_fmt);
- vsprintf(buf, s_fmt, v);
- logerror("%s", buf);
- va_end(v);
- }
-#endif
-}
+ emu_timer *m_ctrl_poll_timer;
+ uint8_t m_controller_input[8];
+};
/*************************
* Machine Hardware *
@@ -326,117 +213,23 @@ WRITE16_MEMBER(spg2xx_game_state::wireless60_portb_w)
switch_bank(data & 7);
}
-WRITE16_MEMBER(spg2xx_cart_state::vii_portb_w)
+void vii_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
- if (data == 0x7c) machine().debug_break();
- switch_bank(((data & 0x80) >> 7) | ((data & 0x20) >> 4));
-}
-
-void vsmile_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- if (id == TIMER_PAD)
+ switch (id)
{
- m_pad_counter++;
- if (m_pad_counter >= 100)
- {
- m_pad_counter = 0;
- //m_spg->uart_rx(0x55);
- }
+ case TIMER_CTRL_POLL:
+ poll_controls();
+ break;
+ default:
+ logerror("Unknown timer ID: %d\n", id);
+ break;
}
}
-#define VSMILE_PORTB_CS1 0x0001
-#define VSMILE_PORTB_CS2 0x0002
-#define VSMILE_PORTB_CART 0x0004
-#define VSMILE_PORTB_RESET 0x0008
-#define VSMILE_PORTB_FRONT24 0x0010
-#define VSMILE_PORTB_OFF 0x0020
-#define VSMILE_PORTB_OFF_SW 0x0040
-#define VSMILE_PORTB_ON_SW 0x0080
-
-#define VSMILE_PORTC_VER 0x000f
-#define VSMILE_PORTC_LOGO 0x0010
-#define VSMILE_PORTC_TEST 0x0020
-#define VSMILE_PORTC_AMP 0x0040
-#define VSMILE_PORTC_SYSRESET 0x0080
-
-READ16_MEMBER(vsmile_state::bank0_r)
-{
- return ((uint16_t*)m_cart_region->base())[offset];
-}
-
-READ16_MEMBER(vsmile_state::bank1_r)
-{
- return ((uint16_t*)m_cart_region->base())[offset + 0x100000];
-}
-
-READ16_MEMBER(vsmile_state::bank2_r)
-{
- return ((uint16_t*)m_cart_region->base())[offset + 0x200000];
-}
-
-READ16_MEMBER(vsmile_state::bank3_r)
-{
- return ((uint16_t*)m_system_region->base())[offset];
-}
-
-READ16_MEMBER(vsmile_state::portb_r)
-{
- //const uint8_t inputs = m_io_p2->read();
- //const uint16_t input_bits = BIT(inputs, 0) ? VSMILE_PORTB_ON_SW : 0;
- //const uint16_t data = VSMILE_PORTB_ON_SW | VSMILE_PORTB_OFF_SW | (m_cart && m_cart->exists() ? VSMILE_PORTB_CART : 0);
- //logerror("V.Smile Port B read %04x, mask %04x\n", data, mem_mask);
- //printf("V.Smile Port B read %04x, mask %04x\n", data, mem_mask);
- return m_portb_data;// | data;
-}
-
-READ16_MEMBER(vsmile_state::portc_r)
-{
- uint16_t data = 0x0004;
- if (m_portc_data & 0x0100)
- data |= 0x0400;
- if (m_portc_data & 0x0200)
- data |= 0x1000;
- //logerror("V.Smile Port C read %04x, mask %04x\n", data, mem_mask);
- return (m_portc_data & ~0x000f) | data;
-}
-
-WRITE16_MEMBER(vsmile_state::portb_w)
-{
- m_portb_data = data;//(m_portb_data &~ mem_mask) | (data & mem_mask);
- //logerror("V.Smile Port B write %04x, mask %04x\n", m_portb_data, mem_mask);
- //printf("V.Smile Port B write %04x, mask %04x\n", m_portb_data, mem_mask);
-}
-
-WRITE16_MEMBER(vsmile_state::portc_w)
-{
- m_portc_data = data;//(m_portc_data &~ mem_mask) | (data & mem_mask);
- //logerror("V.Smile Port C write %04x, mask %04x\n", m_portc_data, mem_mask);
- //printf("V.Smile Port C write %04x, mask %04x\n", m_portc_data, mem_mask);
- //printf("%02x ", data >> 8);
-}
-
-WRITE8_MEMBER(vsmile_state::uart_tx)
-{
- logerror("UART Tx: %02x\n", data);
-}
-
-WRITE8_MEMBER(vsmile_state::chip_sel_w)
+WRITE16_MEMBER(vii_state::vii_portb_w)
{
- const uint16_t cart_offset = m_cart && m_cart->exists() ? 4 : 0;
- switch (data)
- {
- case 0:
- m_bankdev->set_bank(cart_offset);
- break;
- case 1:
- m_bankdev->set_bank(1 + cart_offset);
- break;
- case 2:
- case 3:
- m_bankdev->set_bank(2 + cart_offset);
- break;
- }
+ if (data == 0x7c) machine().debug_break();
+ switch_bank(((data & 0x80) >> 7) | ((data & 0x20) >> 4));
}
READ16_MEMBER(spg2xx_game_state::walle_portc_r)
@@ -474,40 +267,6 @@ void spg2xx_game_state::mem_map(address_map &map)
map(0x000000, 0x003fff).m(m_spg, FUNC(spg2xx_device::map));
}
-void vsmile_state::banked_map(address_map &map)
-{
- map(0x0000000, 0x00fffff).rom().region("maincpu", 0);
- map(0x0100000, 0x01fffff).rom().region("maincpu", 0);
- map(0x0200000, 0x02fffff).rom().region("maincpu", 0);
- map(0x0300000, 0x03fffff).rom().region("maincpu", 0);
-
- map(0x0400000, 0x04fffff).rom().region("maincpu", 0);
- map(0x0500000, 0x05fffff).rom().region("maincpu", 0);
- map(0x0600000, 0x06fffff).rom().region("maincpu", 0);
- map(0x0700000, 0x07fffff).rom().region("maincpu", 0);
-
- map(0x0800000, 0x08fffff).rom().region("maincpu", 0);
- map(0x0900000, 0x09fffff).rom().region("maincpu", 0);
- map(0x0a00000, 0x0afffff).rom().region("maincpu", 0);
- map(0x0b00000, 0x0bfffff).rom().region("maincpu", 0);
-
- map(0x1000000, 0x13fffff).r(FUNC(vsmile_state::bank0_r));
-
- map(0x1400000, 0x15fffff).r(FUNC(vsmile_state::bank0_r));
- map(0x1600000, 0x17fffff).r(FUNC(vsmile_state::bank1_r));
-
- map(0x1800000, 0x18fffff).r(FUNC(vsmile_state::bank0_r));
- map(0x1900000, 0x19fffff).r(FUNC(vsmile_state::bank1_r));
- map(0x1a00000, 0x1afffff).nopr();
- map(0x1b00000, 0x1bfffff).r(FUNC(vsmile_state::bank3_r));
-}
-
-void vsmile_state::mem_map(address_map &map)
-{
- map(0x000000, 0x3fffff).r(m_bankdev, FUNC(address_map_bank_device::read16));
- map(0x000000, 0x003fff).m(m_spg, FUNC(spg2xx_device::map));
-}
-
static INPUT_PORTS_START( vii )
PORT_START("P1")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_NAME("Joypad Up")
@@ -541,26 +300,6 @@ static INPUT_PORTS_START( batman )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("X Button")
INPUT_PORTS_END
-static INPUT_PORTS_START( vsmile )
- PORT_START("P1")
- PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_NAME("Joypad Up")
- PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_NAME("Joypad Down")
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_NAME("Joypad Left")
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_NAME("Joypad Right")
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("A Button")
- PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("Menu")
- PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("B Button")
- PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("X Button")
-
- PORT_START("P2")
- PORT_DIPNAME( 0x0001, 0x0001, "POWER ON" )
- PORT_DIPSETTING( 0x0001, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
- PORT_DIPNAME( 0x0002, 0x0002, "POWER OFF" )
- PORT_DIPSETTING( 0x0002, DEF_STR( Off ) )
- PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
-INPUT_PORTS_END
-
static INPUT_PORTS_START( walle )
PORT_START("P1")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_NAME("Joypad Up")
@@ -738,7 +477,7 @@ static INPUT_PORTS_START( rad_crik )
PORT_BIT( 0xffff, IP_ACTIVE_LOW, IPT_UNKNOWN )
INPUT_PORTS_END
-void spg2xx_cart_state::machine_start()
+void vii_state::machine_start()
{
spg2xx_game_state::machine_start();
@@ -747,50 +486,29 @@ void spg2xx_cart_state::machine_start()
{
std::string region_tag;
m_cart_region = memregion(region_tag.assign(m_cart->tag()).append(GENERIC_ROM_REGION_TAG).c_str());
- m_bank->configure_entries(0, ceilf((float)m_cart_region->bytes() / 0x800000), m_cart_region->base(), 0x800000);
+ m_bank->configure_entries(0, (m_cart_region->bytes() + 0x7fffff) / 0x800000, m_cart_region->base(), 0x800000);
m_bank->set_entry(0);
}
-}
-
-void vsmile_state::machine_start()
-{
- // if there's a cart, override the standard banking
- if (m_cart && m_cart->exists())
- {
- std::string region_tag;
- m_cart_region = memregion(region_tag.assign(m_cart->tag()).append(GENERIC_ROM_REGION_TAG).c_str());
- }
-
- m_bankdev->set_bank(m_cart && m_cart->exists() ? 4 : 0);
-
- m_serial_eeprom = std::make_unique<uint8_t[]>(0x400);
- if (m_nvram)
- m_nvram->set_base(&m_serial_eeprom[0], 0x400);
- m_pad_timer = timer_alloc(TIMER_PAD);
- m_pad_timer->adjust(attotime::never);
+ m_ctrl_poll_timer = timer_alloc(TIMER_CTRL_POLL);
+ m_ctrl_poll_timer->adjust(attotime::never);
}
-void vsmile_state::machine_reset()
+void vii_state::machine_reset()
{
- m_portb_data = 0;
- m_portc_data = 0;
+ spg2xx_game_state::machine_reset();
- m_pad_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100));
- m_pad_counter = 0;
-}
-
-void spg2xx_cart_state::machine_reset()
-{
m_controller_input[0] = 0;
m_controller_input[4] = 0;
m_controller_input[6] = 0xff;
m_controller_input[7] = 0;
+
+ m_ctrl_poll_timer->adjust(attotime::from_hz(60), 0, attotime::from_hz(60));
}
void spg2xx_game_state::machine_start()
{
- m_bank->configure_entries(0, ceilf((float)memregion("maincpu")->bytes() / 0x800000), memregion("maincpu")->base(), 0x800000);
+ m_bank->configure_entries(0, (memregion("maincpu")->bytes() + 0x7fffff) / 0x800000, memregion("maincpu")->base(), 0x800000);
m_bank->set_entry(0);
m_serial_eeprom = std::make_unique<uint8_t[]>(0x400);
@@ -806,11 +524,8 @@ void spg2xx_game_state::machine_reset()
m_w60_porta_data = 0;
}
-WRITE_LINE_MEMBER(spg2xx_game_state::poll_controls)
+void vii_state::poll_controls()
{
- if (!state)
- return;
-
int32_t x = m_io_motionx ? ((int32_t)m_io_motionx->read() - 0x200) : 0;
int32_t y = m_io_motiony ? ((int32_t)m_io_motiony->read() - 0x200) : 0;
int32_t z = m_io_motionz ? ((int32_t)m_io_motionz->read() - 0x200) : 0;
@@ -837,7 +552,7 @@ WRITE_LINE_MEMBER(spg2xx_game_state::poll_controls)
}
}
-DEVICE_IMAGE_LOAD_MEMBER(spg2xx_cart_state, vii_cart)
+DEVICE_IMAGE_LOAD_MEMBER(vii_state, vii_cart)
{
uint32_t size = m_cart->common_get_size("rom");
@@ -853,16 +568,6 @@ DEVICE_IMAGE_LOAD_MEMBER(spg2xx_cart_state, vii_cart)
return image_init_result::PASS;
}
-DEVICE_IMAGE_LOAD_MEMBER(vsmile_state, cart)
-{
- uint32_t size = m_cart->common_get_size("rom");
-
- m_cart->rom_alloc(size, GENERIC_ROM16_WIDTH, ENDIANNESS_LITTLE);
- m_cart->common_load_rom(m_cart->get_rom_base(), size, "rom");
-
- return image_init_result::PASS;
-}
-
void spg2xx_game_state::spg2xx_base(machine_config &config)
{
UNSP(config, m_maincpu, XTAL(27'000'000));
@@ -875,14 +580,6 @@ void spg2xx_game_state::spg2xx_base(machine_config &config)
m_screen->set_screen_update("spg", FUNC(spg2xx_device::screen_update));
m_screen->screen_vblank().set(m_spg, FUNC(spg2xx_device::vblank));
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- SCREEN(config, m_debug_screen, SCREEN_TYPE_RASTER);
- m_debug_screen->set_refresh_hz(60);
- m_debug_screen->set_size(1024, 768);
- m_debug_screen->set_visarea(0, 1024-1, 0, 768-1);
- m_debug_screen->set_screen_update("spg", FUNC(spg2xx_device::debug_screen_update));
-#endif
-
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
m_spg->add_route(ALL_OUTPUTS, "lspeaker", 0.5);
@@ -891,11 +588,7 @@ void spg2xx_game_state::spg2xx_base(machine_config &config)
void spg2xx_game_state::non_spg_base(machine_config &config)
{
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen, m_debug_screen);
-#else
SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen);
-#endif
spg2xx_base(config);
}
@@ -908,76 +601,29 @@ void spg2xx_game_state::spg2xx_basep(machine_config &config)
m_screen->set_size(320, 312);
}
-void spg2xx_cart_state::vii(machine_config &config)
+void vii_state::vii(machine_config &config)
{
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen, m_debug_screen);
-#else
SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen);
-#endif
spg2xx_base(config);
- m_screen->screen_vblank().append(FUNC(spg2xx_cart_state::poll_controls));
- m_spg->portb_out().set(FUNC(spg2xx_cart_state::vii_portb_w));
- m_spg->eeprom_w().set(FUNC(spg2xx_cart_state::eeprom_w));
- m_spg->eeprom_r().set(FUNC(spg2xx_cart_state::eeprom_r));
+ m_spg->portb_out().set(FUNC(vii_state::vii_portb_w));
+ m_spg->eeprom_w().set(FUNC(vii_state::eeprom_w));
+ m_spg->eeprom_r().set(FUNC(vii_state::eeprom_r));
NVRAM(config, m_nvram, nvram_device::DEFAULT_ALL_1);
GENERIC_CARTSLOT(config, m_cart, generic_plain_slot, "vii_cart");
m_cart->set_width(GENERIC_ROM16_WIDTH);
- m_cart->set_device_load(device_image_load_delegate(&spg2xx_cart_state::device_image_load_vii_cart, this));
+ m_cart->set_device_load(device_image_load_delegate(&vii_state::device_image_load_vii_cart, this));
SOFTWARE_LIST(config, "vii_cart").set_original("vii");
}
-void vsmile_state::vsmile(machine_config &config)
-{
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen, m_debug_screen);
-#else
- SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen);
-#endif
- spg2xx_base(config);
- m_maincpu->set_addrmap(AS_PROGRAM, &vsmile_state::mem_map);
-
- m_spg->portb_in().set(FUNC(vsmile_state::portb_r));
- m_spg->portc_in().set(FUNC(vsmile_state::portc_r));
- m_spg->portb_out().set(FUNC(vsmile_state::portb_w));
- m_spg->portc_out().set(FUNC(vsmile_state::portc_w));
- m_spg->chip_select().set(FUNC(vsmile_state::chip_sel_w));
- m_spg->uart_tx().set(FUNC(vsmile_state::uart_tx));
-
- GENERIC_CARTSLOT(config, m_cart, generic_plain_slot, "vsmile_cart");
- m_cart->set_width(GENERIC_ROM16_WIDTH);
- m_cart->set_device_load(device_image_load_delegate(&vsmile_state::device_image_load_cart, this));
-
- ADDRESS_MAP_BANK(config, m_bankdev);
- m_bankdev->set_addrmap(AS_PROGRAM, &vsmile_state::banked_map);
- m_bankdev->set_endianness(ENDIANNESS_LITTLE);
- m_bankdev->set_data_width(16);
- m_bankdev->set_shift(-1);
- m_bankdev->set_stride(0x400000);
-
- SOFTWARE_LIST(config, "cart_list").set_original("vsmile_cart");
-}
-
-void vsmile_state::vsmilep(machine_config &config)
-{
- vsmile(config);
- m_spg->set_pal(true);
-}
-
void spg2xx_game_state::wireless60(machine_config &config)
{
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen, m_debug_screen);
-#else
SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen);
-#endif
spg2xx_base(config);
- m_screen->screen_vblank().append(FUNC(spg2xx_game_state::poll_controls));
m_spg->porta_out().set(FUNC(spg2xx_game_state::wireless60_porta_w));
m_spg->portb_out().set(FUNC(spg2xx_game_state::wireless60_portb_w));
@@ -986,14 +632,10 @@ void spg2xx_game_state::wireless60(machine_config &config)
void spg2xx_game_state::jakks(machine_config &config)
{
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen, m_debug_screen);
-#else
SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen);
-#endif
spg2xx_base(config);
- m_spg->porta_in().set(FUNC(spg2xx_cart_state::jakks_porta_r));
+ m_spg->porta_in().set(FUNC(spg2xx_game_state::jakks_porta_r));
I2CMEM(config, m_i2cmem, 0).set_data_size(0x200);
}
@@ -1008,11 +650,7 @@ void spg2xx_game_state::walle(machine_config &config)
void spg2xx_game_state::rad_skat(machine_config &config)
{
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen, m_debug_screen);
-#else
SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen);
-#endif
spg2xx_base(config);
m_spg->porta_in().set_ioport("P1");
@@ -1032,11 +670,7 @@ void spg2xx_game_state::rad_skatp(machine_config &config)
void spg2xx_game_state::rad_crik(machine_config &config)
{
-#if SPG2XX_VISUAL_AUDIO_DEBUG
- SPG28X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen, m_debug_screen);
-#else
SPG28X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen);
-#endif
spg2xx_base(config);
m_spg->porta_in().set_ioport("P1");
@@ -1073,26 +707,6 @@ ROM_START( batmantv )
ROM_LOAD16_WORD_SWAP( "batman.bin", 0x000000, 0x400000, CRC(46f848e5) SHA1(5875d57bb3fe0cac5d20e626e4f82a0e5f9bb94c) )
ROM_END
-ROM_START( vsmile )
- ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASEFF )
- ROM_LOAD( "vsmilebios.bin", 0x000000, 0x200000, CRC(11f1b416) SHA1(11f77c4973d29c962567390e41879c86a759c93b) )
-ROM_END
-
-ROM_START( vsmileg )
- ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASEFF )
- ROM_LOAD16_WORD_SWAP( "bios german.bin", 0x000000, 0x200000, CRC(205c5296) SHA1(7fbcf761b5885c8b1524607aabaf364b4559c8cc) )
-ROM_END
-
-ROM_START( vsmilef )
- ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASEFF )
- ROM_LOAD16_WORD_SWAP( "sysrom_france", 0x000000, 0x200000, CRC(0cd0bdf5) SHA1(5c8d1eada1b6b545555b8d2b09325d7127681af8) )
-ROM_END
-
-ROM_START( vsmileb )
- ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASEFF )
- ROM_LOAD( "vbabybios.bin", 0x000000, 0x800000, CRC(ddc7f845) SHA1(2c17d0f54200070176d03d44a40c7923636e596a) )
-ROM_END
-
ROM_START( walle )
ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASEFF )
ROM_LOAD16_WORD_SWAP( "walle.bin", 0x000000, 0x400000, BAD_DUMP CRC(bd554cba) SHA1(6cd06a036ab12e7b0e1fd8003db873b0bb783868) )
@@ -1252,14 +866,8 @@ ROM_END
// year, name, parent, compat, machine, input, class, init, company, fullname, flags
-// VTech systems
-CONS( 2005, vsmile, 0, 0, vsmile, vsmile, vsmile_state, empty_init, "VTech", "V.Smile (US)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING )
-CONS( 2005, vsmileg, vsmile, 0, vsmilep, vsmile, vsmile_state, empty_init, "VTech", "V.Smile (Germany)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING )
-CONS( 2005, vsmilef, vsmile, 0, vsmilep, vsmile, vsmile_state, empty_init, "VTech", "V.Smile (France)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING )
-CONS( 2005, vsmileb, 0, 0, vsmile, vsmile, vsmile_state, empty_init, "VTech", "V.Smile Baby (US)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING )
-
// Jungle Soft TV games
-CONS( 2007, vii, 0, 0, vii, vii, spg2xx_cart_state, empty_init, "Jungle Soft / KenSingTon / Siatronics", "Vii", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) // motion controls are awkward, but playable for the most part
+CONS( 2007, vii, 0, 0, vii, vii, vii_state, empty_init, "Jungle Soft / KenSingTon / Siatronics", "Vii", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) // motion controls are awkward, but playable for the most part
CONS( 2010, zone60, 0, 0, wireless60, wirels60, spg2xx_game_state, empty_init, "Jungle's Soft / Ultimate Products (HK) Ltd", "Zone 60", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS )
CONS( 2010, wirels60, 0, 0, wireless60, wirels60, spg2xx_game_state, empty_init, "Jungle Soft / Kids Station Toys Inc", "Wireless 60", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS )
diff --git a/src/mame/drivers/vsmile.cpp b/src/mame/drivers/vsmile.cpp
new file mode 100644
index 00000000000..79a318ec6af
--- /dev/null
+++ b/src/mame/drivers/vsmile.cpp
@@ -0,0 +1,383 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/******************************************************************************
+
+ V-Tech V.Smile console emulat
+
+ Status:
+
+ Most games boot but lack controls
+
+ To-Do:
+
+ Proper UART support (SPG2xx) for controller
+
+ Similar Systems: ( from http://en.wkikpedia.org/wiki/V.Smile )
+
+ V.Smile by VTech, a system designed for children under the age of 10
+ V.Smile Pocket (2 versions)
+ V.Smile Cyber Pocket
+ V.Smile PC Pal
+ V-Motion Active Learning System
+ Leapster
+ V.Smile Baby Infant Development System
+ V.Flash
+
+*******************************************************************************/
+
+#include "emu.h"
+
+#include "bus/generic/slot.h"
+#include "bus/generic/carts.h"
+
+#include "cpu/unsp/unsp.h"
+
+#include "machine/bankdev.h"
+#include "machine/spg2xx.h"
+
+#include "screen.h"
+#include "softlist.h"
+#include "speaker.h"
+
+class vsmile_state : public driver_device
+{
+public:
+ vsmile_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_screen(*this, "screen")
+ , m_spg(*this, "spg")
+ , m_cart(*this, "cartslot")
+ , m_bankdev(*this, "bank")
+ , m_system_region(*this, "maincpu")
+ , m_io_p1(*this, "P1")
+ , m_io_p2(*this, "P2")
+ , m_cart_region(nullptr)
+ , m_pad_timer(nullptr)
+ , m_pad_counter(0)
+ , m_portb_data(0)
+ , m_portc_data(0)
+ { }
+
+ void vsmile(machine_config &config);
+ void vsmilep(machine_config &config);
+
+private:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ static const device_timer_id TIMER_UART_TX = 0;
+ static const device_timer_id TIMER_PAD = 1;
+
+ void mem_map(address_map &map);
+ void banked_map(address_map &map);
+
+ DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart);
+
+ DECLARE_READ16_MEMBER(portb_r);
+ DECLARE_READ16_MEMBER(portc_r);
+ DECLARE_WRITE16_MEMBER(portb_w);
+ DECLARE_WRITE16_MEMBER(portc_w);
+
+ DECLARE_WRITE8_MEMBER(chip_sel_w);
+
+ DECLARE_WRITE8_MEMBER(uart_tx);
+
+ DECLARE_READ16_MEMBER(bank0_r);
+ DECLARE_READ16_MEMBER(bank1_r);
+ DECLARE_READ16_MEMBER(bank2_r);
+ DECLARE_READ16_MEMBER(bank3_r);
+
+ enum
+ {
+ VSMILE_PORTB_CS1 = 0x01,
+ VSMILE_PORTB_CS2 = 0x02,
+ VSMILE_PORTB_CART = 0x04,
+ VSMILE_PORTB_RESET = 0x08,
+ VSMILE_PORTB_FRONT24 = 0x10,
+ VSMILE_PORTB_OFF = 0x20,
+ VSMILE_PORTB_OFF_SW = 0x40,
+ VSMILE_PORTB_ON_SW = 0x80,
+
+ VSMILE_PORTC_VER = 0x0f,
+ VSMILE_PORTC_LOGO = 0x10,
+ VSMILE_PORTC_TEST = 0x20,
+ VSMILE_PORTC_AMP = 0x40,
+ VSMILE_PORTC_SYSRESET = 0x80
+ };
+
+ required_device<cpu_device> m_maincpu;
+ required_device<screen_device> m_screen;
+ required_device<spg2xx_device> m_spg;
+ required_device<generic_slot_device> m_cart;
+ required_device<address_map_bank_device> m_bankdev;
+ required_memory_region m_system_region;
+ required_ioport m_io_p1;
+ required_ioport m_io_p2;
+ memory_region *m_cart_region;
+
+ emu_timer *m_pad_timer;
+ uint8_t m_pad_counter;
+
+ uint16_t m_portb_data;
+ uint16_t m_portc_data;
+};
+
+void vsmile_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_UART_TX:
+ break;
+ case TIMER_PAD:
+ m_pad_counter++;
+ if (m_pad_counter >= 100)
+ {
+ m_pad_counter = 0;
+ //m_spg->uart_rx(0x55);
+ }
+ break;
+ default:
+ logerror("Unknown timer ID: %d\n", id);
+ break;
+ }
+}
+
+READ16_MEMBER(vsmile_state::bank0_r)
+{
+ return ((uint16_t*)m_cart_region->base())[offset];
+}
+
+READ16_MEMBER(vsmile_state::bank1_r)
+{
+ return ((uint16_t*)m_cart_region->base())[offset + 0x100000];
+}
+
+READ16_MEMBER(vsmile_state::bank2_r)
+{
+ return ((uint16_t*)m_cart_region->base())[offset + 0x200000];
+}
+
+READ16_MEMBER(vsmile_state::bank3_r)
+{
+ return ((uint16_t*)m_system_region->base())[offset];
+}
+
+READ16_MEMBER(vsmile_state::portb_r)
+{
+ //const uint8_t inputs = m_io_p2->read();
+ //const uint16_t input_bits = BIT(inputs, 0) ? VSMILE_PORTB_ON_SW : 0;
+ //const uint16_t data = VSMILE_PORTB_ON_SW | VSMILE_PORTB_OFF_SW | (m_cart && m_cart->exists() ? VSMILE_PORTB_CART : 0);
+ //logerror("V.Smile Port B read %04x, mask %04x\n", data, mem_mask);
+ //printf("V.Smile Port B read %04x, mask %04x\n", data, mem_mask);
+ return m_portb_data;// | data;
+}
+
+READ16_MEMBER(vsmile_state::portc_r)
+{
+ uint16_t data = 0x0004;
+ if (m_portc_data & 0x0100)
+ data |= 0x0400;
+ if (m_portc_data & 0x0200)
+ data |= 0x1000;
+ //logerror("V.Smile Port C read %04x, mask %04x\n", data, mem_mask);
+ return (m_portc_data & ~0x000f) | data;
+}
+
+WRITE16_MEMBER(vsmile_state::portb_w)
+{
+ m_portb_data = data;//(m_portb_data &~ mem_mask) | (data & mem_mask);
+ //logerror("V.Smile Port B write %04x, mask %04x\n", m_portb_data, mem_mask);
+ //printf("V.Smile Port B write %04x, mask %04x\n", m_portb_data, mem_mask);
+}
+
+WRITE16_MEMBER(vsmile_state::portc_w)
+{
+ m_portc_data = data;//(m_portc_data &~ mem_mask) | (data & mem_mask);
+ //logerror("V.Smile Port C write %04x, mask %04x\n", m_portc_data, mem_mask);
+ //printf("V.Smile Port C write %04x, mask %04x\n", m_portc_data, mem_mask);
+ //printf("%02x ", data >> 8);
+}
+
+WRITE8_MEMBER(vsmile_state::uart_tx)
+{
+ logerror("UART Tx: %02x\n", data);
+}
+
+WRITE8_MEMBER(vsmile_state::chip_sel_w)
+{
+ const uint16_t cart_offset = m_cart && m_cart->exists() ? 4 : 0;
+ switch (data)
+ {
+ case 0:
+ m_bankdev->set_bank(cart_offset);
+ break;
+ case 1:
+ m_bankdev->set_bank(1 + cart_offset);
+ break;
+ case 2:
+ case 3:
+ m_bankdev->set_bank(2 + cart_offset);
+ break;
+ }
+}
+
+void vsmile_state::machine_start()
+{
+ // if there's a cart, override the standard banking
+ if (m_cart && m_cart->exists())
+ {
+ std::string region_tag;
+ m_cart_region = memregion(region_tag.assign(m_cart->tag()).append(GENERIC_ROM_REGION_TAG).c_str());
+ }
+
+ m_bankdev->set_bank(m_cart && m_cart->exists() ? 4 : 0);
+
+ m_pad_timer = timer_alloc(TIMER_PAD);
+ m_pad_timer->adjust(attotime::never);
+}
+
+void vsmile_state::machine_reset()
+{
+ m_portb_data = 0;
+ m_portc_data = 0;
+
+ m_pad_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100));
+ m_pad_counter = 0;
+}
+
+DEVICE_IMAGE_LOAD_MEMBER(vsmile_state, cart)
+{
+ uint32_t size = m_cart->common_get_size("rom");
+
+ m_cart->rom_alloc(size, GENERIC_ROM16_WIDTH, ENDIANNESS_LITTLE);
+ m_cart->common_load_rom(m_cart->get_rom_base(), size, "rom");
+
+ return image_init_result::PASS;
+}
+
+void vsmile_state::banked_map(address_map &map)
+{
+ map(0x0000000, 0x00fffff).rom().region("maincpu", 0);
+ map(0x0100000, 0x01fffff).rom().region("maincpu", 0);
+ map(0x0200000, 0x02fffff).rom().region("maincpu", 0);
+ map(0x0300000, 0x03fffff).rom().region("maincpu", 0);
+
+ map(0x0400000, 0x04fffff).rom().region("maincpu", 0);
+ map(0x0500000, 0x05fffff).rom().region("maincpu", 0);
+ map(0x0600000, 0x06fffff).rom().region("maincpu", 0);
+ map(0x0700000, 0x07fffff).rom().region("maincpu", 0);
+
+ map(0x0800000, 0x08fffff).rom().region("maincpu", 0);
+ map(0x0900000, 0x09fffff).rom().region("maincpu", 0);
+ map(0x0a00000, 0x0afffff).rom().region("maincpu", 0);
+ map(0x0b00000, 0x0bfffff).rom().region("maincpu", 0);
+
+ map(0x1000000, 0x13fffff).r(FUNC(vsmile_state::bank0_r));
+
+ map(0x1400000, 0x15fffff).r(FUNC(vsmile_state::bank0_r));
+ map(0x1600000, 0x17fffff).r(FUNC(vsmile_state::bank1_r));
+
+ map(0x1800000, 0x18fffff).r(FUNC(vsmile_state::bank0_r));
+ map(0x1900000, 0x19fffff).r(FUNC(vsmile_state::bank1_r));
+ map(0x1a00000, 0x1afffff).nopr();
+ map(0x1b00000, 0x1bfffff).r(FUNC(vsmile_state::bank3_r));
+}
+
+void vsmile_state::mem_map(address_map &map)
+{
+ map(0x000000, 0x3fffff).r(m_bankdev, FUNC(address_map_bank_device::read16));
+ map(0x000000, 0x003fff).m(m_spg, FUNC(spg2xx_device::map));
+}
+
+static INPUT_PORTS_START( vsmile )
+ PORT_START("P1")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_NAME("Joypad Up")
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_NAME("Joypad Down")
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_NAME("Joypad Left")
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_NAME("Joypad Right")
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("A Button")
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("Menu")
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("B Button")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("X Button")
+
+ PORT_START("P2")
+ PORT_DIPNAME( 0x0001, 0x0001, "POWER ON" )
+ PORT_DIPSETTING( 0x0001, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+ PORT_DIPNAME( 0x0002, 0x0002, "POWER OFF" )
+ PORT_DIPSETTING( 0x0002, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
+INPUT_PORTS_END
+
+void vsmile_state::vsmile(machine_config &config)
+{
+ UNSP(config, m_maincpu, XTAL(27'000'000));
+ m_maincpu->set_addrmap(AS_PROGRAM, &vsmile_state::mem_map);
+
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_refresh_hz(60);
+ m_screen->set_size(320, 262);
+ m_screen->set_visarea(0, 320-1, 0, 240-1);
+ m_screen->set_screen_update("spg", FUNC(spg2xx_device::screen_update));
+ m_screen->screen_vblank().set(m_spg, FUNC(spg2xx_device::vblank));
+
+ SPEAKER(config, "lspeaker").front_left();
+ SPEAKER(config, "rspeaker").front_right();
+
+ SPG24X(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen);
+ m_spg->portb_in().set(FUNC(vsmile_state::portb_r));
+ m_spg->portc_in().set(FUNC(vsmile_state::portc_r));
+ m_spg->portb_out().set(FUNC(vsmile_state::portb_w));
+ m_spg->portc_out().set(FUNC(vsmile_state::portc_w));
+ m_spg->chip_select().set(FUNC(vsmile_state::chip_sel_w));
+ m_spg->uart_tx().set(FUNC(vsmile_state::uart_tx));
+ m_spg->add_route(ALL_OUTPUTS, "lspeaker", 0.5);
+ m_spg->add_route(ALL_OUTPUTS, "rspeaker", 0.5);
+
+ ADDRESS_MAP_BANK(config, m_bankdev);
+ m_bankdev->set_addrmap(AS_PROGRAM, &vsmile_state::banked_map);
+ m_bankdev->set_endianness(ENDIANNESS_LITTLE);
+ m_bankdev->set_data_width(16);
+ m_bankdev->set_shift(-1);
+ m_bankdev->set_stride(0x400000);
+
+ GENERIC_CARTSLOT(config, m_cart, generic_plain_slot, "vsmile_cart");
+ m_cart->set_width(GENERIC_ROM16_WIDTH);
+ m_cart->set_device_load(device_image_load_delegate(&vsmile_state::device_image_load_cart, this));
+
+ SOFTWARE_LIST(config, "cart_list").set_original("vsmile_cart");
+}
+
+void vsmile_state::vsmilep(machine_config &config)
+{
+ vsmile(config);
+ m_spg->set_pal(true);
+}
+
+ROM_START( vsmile )
+ ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASEFF )
+ ROM_LOAD( "vsmilebios.bin", 0x000000, 0x200000, CRC(11f1b416) SHA1(11f77c4973d29c962567390e41879c86a759c93b) )
+ROM_END
+
+ROM_START( vsmileg )
+ ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASEFF )
+ ROM_LOAD16_WORD_SWAP( "bios german.bin", 0x000000, 0x200000, CRC(205c5296) SHA1(7fbcf761b5885c8b1524607aabaf364b4559c8cc) )
+ROM_END
+
+ROM_START( vsmilef )
+ ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASEFF )
+ ROM_LOAD16_WORD_SWAP( "sysrom_france", 0x000000, 0x200000, CRC(0cd0bdf5) SHA1(5c8d1eada1b6b545555b8d2b09325d7127681af8) )
+ROM_END
+
+ROM_START( vsmileb )
+ ROM_REGION( 0x800000, "maincpu", ROMREGION_ERASEFF )
+ ROM_LOAD( "vbabybios.bin", 0x000000, 0x800000, CRC(ddc7f845) SHA1(2c17d0f54200070176d03d44a40c7923636e596a) )
+ROM_END
+
+// year, name, parent, compat, machine, input, class, init, company, fullname, flags
+CONS( 2005, vsmile, 0, 0, vsmile, vsmile, vsmile_state, empty_init, "VTech", "V.Smile (US)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING )
+CONS( 2005, vsmileg, vsmile, 0, vsmilep, vsmile, vsmile_state, empty_init, "VTech", "V.Smile (Germany)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING )
+CONS( 2005, vsmilef, vsmile, 0, vsmilep, vsmile, vsmile_state, empty_init, "VTech", "V.Smile (France)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING )
+CONS( 2005, vsmileb, 0, 0, vsmile, vsmile, vsmile_state, empty_init, "VTech", "V.Smile Baby (US)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING )
diff --git a/src/mame/includes/mario.h b/src/mame/includes/mario.h
index e5839bbc42a..d02c919a841 100644
--- a/src/mame/includes/mario.h
+++ b/src/mame/includes/mario.h
@@ -89,7 +89,7 @@ private:
optional_device<generic_latch_8_device> m_soundlatch3;
optional_device<generic_latch_8_device> m_soundlatch4;
#if OLD_SOUND
- optional_device<discrete_device> m_discrete;
+ optional_device<discrete_sound_device> m_discrete;
#else
optional_device<netlist_mame_logic_input_device> m_audio_snd0;
optional_device<netlist_mame_logic_input_device> m_audio_snd1;
diff --git a/src/mame/includes/norautp.h b/src/mame/includes/norautp.h
index 6ff08a24bb2..9768787f3da 100644
--- a/src/mame/includes/norautp.h
+++ b/src/mame/includes/norautp.h
@@ -81,7 +81,7 @@ private:
std::unique_ptr<uint16_t[]> m_np_vram;
required_device<cpu_device> m_maincpu;
required_device_array<i8255_device, 3> m_ppi8255;
- required_device<discrete_device> m_discrete;
+ required_device<discrete_sound_device> m_discrete;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
diff --git a/src/mame/machine/3dom2.cpp b/src/mame/machine/3dom2.cpp
new file mode 100644
index 00000000000..82487d46c9b
--- /dev/null
+++ b/src/mame/machine/3dom2.cpp
@@ -0,0 +1,2091 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ 3DO M2 Bulldog ASIC
+
+***************************************************************************/
+
+#include "emu.h"
+#include "3dom2.h"
+#include <algorithm> // std::min
+#include "screen.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+// Device type definitions
+DEFINE_DEVICE_TYPE(M2_BDA, m2_bda_device, "m2bda", "3DO M2 Bulldog ASIC")
+DEFINE_DEVICE_TYPE(M2_POWERBUS, m2_powerbus_device, "m2powerbus", "BDA PowerBus Controller")
+DEFINE_DEVICE_TYPE(M2_MEMCTL, m2_memctl_device, "m2memctl", "BDA Memory Controller")
+DEFINE_DEVICE_TYPE(M2_VDU, m2_vdu_device, "m2vdu", "BDA VDU")
+DEFINE_DEVICE_TYPE(M2_CTRLPORT, m2_ctrlport_device, "m2ctrlport", "BDA Control Ports")
+DEFINE_DEVICE_TYPE(M2_MPEG, m2_mpeg_device, "m2mpeg", "3DO MPEG Decoder")
+DEFINE_DEVICE_TYPE(M2_CDE, m2_cde_device, "m2cde", "3DO M2 CDE ASIC")
+
+
+
+//**************************************************************************
+// VDU REGISTER DEFINITIONS
+//**************************************************************************
+
+#define VDU_VLOC 0x00
+#define VDU_VINT 0x04
+#define VDU_VDC0 0x08
+#define VDU_VDC1 0x0c
+#define VDU_FV0A 0x10
+#define VDU_FV1A 0x14
+#define VDU_AVDI 0x1c
+#define VDU_VDLI 0x20
+#define VDU_VCFG 0x24
+#define VDU_DMT0 0x28
+#define VDU_DMT1 0x2c
+#define VDU_LFSR 0x30
+#define VDU_VRST 0x34
+
+//-------------------------------------------------
+// VLOC
+//-------------------------------------------------
+#define VDU_VLOC_VCOUNT_MASK 0x00003FF8
+#define VDU_VLOC_VCOUNT_SHIFT 3
+#define VDU_VLOC_VIDEOFIELD 0x00004000
+#define VDU_VLOC_RESERVED 0xFFFF8007
+
+//-------------------------------------------------
+// VINT
+//-------------------------------------------------
+#define VDU_VINT_VINT0 0x80000000
+#define VDU_VINT_VLINE0_MASK 0x7FF00000
+#define VDU_VINT_VLINE0_SHIFT 20
+#define VDU_VINT_VINT1 0x00008000
+#define VDU_VINT_VLINE1_MASK 0x00007FF0
+#define VDU_VINT_VLINE1_SHIFT 4
+#define VDU_VINT_RESERVED 0x000F000F
+
+//-------------------------------------------------
+// VDC0/VDC1
+//-------------------------------------------------
+#define VDU_VDC_HINT 0x02000000
+#define VDU_VDC_VINT 0x01000000
+#define VDU_VDC_DITHER 0x00400000
+#define VDU_VDC_MTXBYP 0x00200000
+#define VDU_VDC_RESERVED 0xFC9FFFFF
+
+//-------------------------------------------------
+// AVDI
+//-------------------------------------------------
+#define VDU_AVDI_HSTART_MASK 0xFFE00000
+#define VDU_AVDI_HWIDTH_MASK 0x0003FF80
+#define VDU_AVDI_HDOUBLE 0x00000008
+#define VDU_AVDI_VDOUBLE 0x00000004
+#define VDU_AVDI_RESERVED 0x001C0073
+#define VDU_AVDI_HSTART_SHIFT 21
+#define VDU_AVDI_HWIDTH_SHIFT 7
+
+//-------------------------------------------------
+// VDLI
+//-------------------------------------------------
+#define VDU_VDLI_BYPASSTYPE 0x10000000
+#define VDU_VDLI_FBFORMAT 0x04000000
+#define VDU_VDLI_ONEVINTDIS 0x00400000
+#define VDU_VDLI_RANDOMDITHER 0x00200000
+#define VDU_VDLI_RESERVED 0xEB9FFFFF
+#define VDU_VDLI_BYPASSTYPE_MSB 0
+#define VDU_VDLI_BYPASSTYPE_LSB 0x10000000
+#define VDU_VDLI_FBFORMAT_16 0
+#define VDU_VDLI_FBFORMAT_32 0x04000000
+
+//-------------------------------------------------
+// VCFG
+//-------------------------------------------------
+
+//-------------------------------------------------
+// VRST
+//-------------------------------------------------
+#define VDU_VRST_DVERESET 0x00000002
+#define VDU_VRST_VIDRESET 0x00000001
+#define VDU_VRST_RESERVED 0xFFFFFFFC
+
+
+//-------------------------------------------------
+// VDL DMA CONTROL WORD
+//-------------------------------------------------
+#define VDL_DMA_MOD_MASK 0xFF000000
+#define VDL_DMA_ENABLE 0x00200000
+#define VDL_DMA_NOBUCKET 0x00020000
+#define VDL_DMA_LDLOWER 0x00010000
+#define VDL_DMA_LDUPPER 0x00008000
+#define VDL_DMA_NWORDS_MASK 0x00007E00
+#define VDL_DMA_NLINES_MASK 0x000001FF
+#define VDL_DMA_RESERVED 0x00DC0000
+#define VDL_DMA_NWORDS_SHIFT 9
+#define VDL_DMA_MOD_SHIFT 24
+#define VDL_DMA_NLINES_SHIFT 0
+
+//-------------------------------------------------
+// VDL DC CONTROL WORD
+//-------------------------------------------------
+#define VDL_DC 0x80000000
+#define VDL_DC_0 0x00000000
+#define VDL_DC_1 0x10000000
+#define VDL_DC_HINTCTL_MASK 0x00060000
+#define VDL_DC_HINTCTL_SHIFT 17
+#define VDL_DC_VINTCTL_MASK 0x00018000
+#define VDL_DC_VINTCTL_SHIFT 15
+#define VDL_DC_DITHERCTL_MASK 0x00001800
+#define VDL_DC_DITHERCTL_SHIFT 11
+#define VDL_DC_MTXBYPCTL_MASK 0x00000600
+#define VDL_DC_MTXBYPCTL_SHIFT 9
+#define VDL_DC_RESERVED 0x0FF861FF
+#define VDL_CTL_DISABLE 0
+#define VDL_CTL_ENABLE 1
+#define VDL_CTL_NOP 2
+
+//-------------------------------------------------
+// VDL AV CONTROL WORD
+//-------------------------------------------------
+#define VDL_AV 0xA0000000
+#define VDL_AV_HSTART_MASK 0x1FFC0000
+#define VDL_AV_HSTART_SHIFT 18
+#define VDL_AV_LD_HSTART 0x00020000
+#define VDL_AV_HWIDTH_MASK 0x0001FFC0
+#define VDL_AV_HWIDTH_SHIFT 6
+#define VDL_AV_LD_HWIDTH 0x00000020
+#define VDL_AV_HDOUBLE 0x00000010
+#define VDL_AV_VDOUBLE 0x00000008
+#define VDL_AV_LD_HDOUBLE 0x00000004
+#define VDL_AV_LD_VDOUBLE 0x00000002
+#define VDL_AV_RESERVED 0x00000001
+
+//-------------------------------------------------
+// VDL LC CONTROL WORD
+//-------------------------------------------------
+#define VDL_LC 0xC0000000
+#define VDL_LC_BYPASSTYPE 0x02000000
+#define VDL_LC_FBFORMAT 0x00800000
+#define VDL_LC_ONEVINTDIS 0x00080000
+#define VDL_LC_RANDOMDITHER 0x00040000
+#define VDL_LC_LD_BYPASSTYPE 0x00002000
+#define VDL_LC_LD_FBFORMAT 0x00001000
+#define VDL_LC_RESERVED 0x1D73CFFF
+#define VDL_LC_BYPASSTYPE_MSB 0x00000000
+#define VDL_LC_BYPASSTYPE_LSB 0x02000000
+#define VDL_LC_FBFORMAT_16 0x00000000
+#define VDL_LC_FBFORMAT_32 0x00800000
+
+//-------------------------------------------------
+// VDL DMA CONTROL WORD
+//-------------------------------------------------
+
+#define VDL_NOP 0xe1000000
+
+
+
+/***************************************************************************
+ SUPPORT FUNCTIONS
+***************************************************************************/
+
+static void write_m2_reg(uint32_t &reg, uint32_t data, reg_wmode mode)
+{
+ switch (mode)
+ {
+ case REG_WRITE: reg = data; break;
+ case REG_SET: reg |= data; break;
+ case REG_CLEAR: reg &= ~data; break;
+ default:
+ assert_always(false, "Bad register write mode");
+ }
+}
+
+
+
+//**************************************************************************
+// BDA DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// m2_bda_device - constructor
+//-------------------------------------------------
+
+m2_bda_device::m2_bda_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, M2_BDA, tag, owner, clock),
+ m_cpu1(*this, finder_base::DUMMY_TAG),
+ m_cpu2(*this, finder_base::DUMMY_TAG),
+ m_videores_in(*this),
+ m_memctl(*this, "memctl"),
+ m_powerbus(*this, "powerbus"),
+ m_vdu(*this, "vdu"),
+ m_ctrlport(*this, "ctrlport"),
+ m_dspp(*this, "dspp"),
+ m_mpeg(*this, "mpeg"),
+ m_te(*this, "te"),
+ m_dac_l(*this),
+ m_dac_r(*this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_bda_device::device_start()
+{
+ // Resolve callbacks
+ m_videores_in.resolve_safe(0);
+ m_dac_l.resolve_safe();
+ m_dac_r.resolve_safe();
+
+ // Allocate RAM
+ uint32_t ram_size = (m_rambank_size[0] + m_rambank_size[1]) * 1024 * 1024;
+ m_ram = auto_alloc_array(machine(), uint32_t, ram_size / sizeof(uint32_t));
+ m_ram_mask = ram_size - 1;
+
+ // Install RAM and handlers into the CPU address spaces
+ configure_ppc_address_map(m_cpu1->space(AS_PROGRAM));
+ configure_ppc_address_map(m_cpu2->space(AS_PROGRAM));
+
+ // Register state for saving
+ save_pointer(NAME(m_ram), ram_size / sizeof(uint32_t));
+
+ // Set a timer to pull data from the DSPP FIFO into the DACs
+ m_dac_timer = timer_alloc(0);
+ m_dac_timer->adjust(attotime::from_hz(16.9345));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_bda_device::device_reset()
+{
+
+}
+
+
+//-------------------------------------------------
+// device_post_load - device-specific post-load
+//-------------------------------------------------
+
+void m2_bda_device::device_post_load()
+{
+
+}
+
+
+//-------------------------------------------------
+// machine_config_fragment - declare sub-devices
+//-------------------------------------------------
+
+void m2_bda_device::device_add_mconfig(machine_config &config)
+{
+ M2_MEMCTL(config, m_memctl, DERIVED_CLOCK(1, 1));
+
+ M2_POWERBUS(config, m_powerbus, DERIVED_CLOCK(1, 1));
+
+ M2_VDU(config, m_vdu, DERIVED_CLOCK(1, 1));
+ m_vdu->vint0_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_VINT0_LINE>));
+ m_vdu->vint1_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_VINT1_LINE>));
+
+ M2_CTRLPORT(config, m_ctrlport, DERIVED_CLOCK(1, 1));
+
+ M2_MPEG(config, m_mpeg, DERIVED_CLOCK(1, 1));
+// m_mpeg->int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_MPEG_LINE>));
+
+ DSPP(config, m_dspp, DERIVED_CLOCK(1, 1));
+ m_dspp->int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_DSP_LINE>));
+ m_dspp->dma_read_handler().set(FUNC(m2_bda_device::read_bus8));
+ m_dspp->dma_write_handler().set(FUNC(m2_bda_device::write_bus8));
+
+ M2_TE(config, m_te, DERIVED_CLOCK(1, 1));
+ m_te->general_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_TRIGEN_LINE>));
+ m_te->dfinstr_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_TRIDFINST_LINE>));
+ m_te->iminstr_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_TRIDMINST_LINE>));
+ m_te->listend_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_TRILISTEND_LINE>));
+ m_te->winclip_int_handler().set(m_powerbus, FUNC(m2_powerbus_device::int_line<BDAINT_TRIWINCLIP_LINE>));
+}
+
+
+//-------------------------------------------------
+// device_timer - device-specific timers
+//-------------------------------------------------
+
+void m2_bda_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case 0:
+ {
+ m_dac_l(m_dspp->read_output_fifo());
+ m_dac_r(m_dspp->read_output_fifo());
+ m_dac_timer->adjust(attotime::from_hz(44100));
+ break;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// cpu_id_r - read from CPU ID register
+//-------------------------------------------------
+
+READ32_MEMBER( m2_bda_device::cpu_id_r )
+{
+ uint32_t data = 0;
+
+ // .x...... ........ ........ ........ - Video type (0 = Arcade, 1 = NTSC/PAL)
+ // x....... ........ ........ ........ - CPU ID (0 = CPU1, 1 = CPU2)
+
+ if (&space.device() == m_cpu2)
+ data |= 0x80000000;
+
+ if (m_videores_in() != 0)
+ data |= 0x40000000;
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// cpu_id_w - Write to CPU ID register
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_bda_device::cpu_id_w )
+{
+ // TODO: How should this work?
+ logerror("%s: CPUID: %x\n", machine().describe_context(), data);
+}
+
+
+//-------------------------------------------------
+// read_bus8 - Read 8-bit data from the PowerBus
+//-------------------------------------------------
+
+uint8_t m2_bda_device::read_bus8(offs_t offset)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + BYTE8_XOR_BE(offset);
+ return *ptr;
+}
+
+
+//-------------------------------------------------
+// read_bus16 - Read 16-bit data from the PowerBus
+//-------------------------------------------------
+
+uint16_t m2_bda_device::read_bus16(offs_t offset)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + WORD2_XOR_BE(offset);
+ return *reinterpret_cast<uint16_t *>(ptr);
+}
+
+
+//-------------------------------------------------
+// read_bus32 - Read 32-bit data from the PowerBus
+//-------------------------------------------------
+
+uint32_t m2_bda_device::read_bus32(offs_t offset)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + DWORD_XOR_BE(offset);
+ return *reinterpret_cast<uint32_t *>(ptr);
+}
+
+
+//-------------------------------------------------
+// write_bus8 - Write 8-bit data to the PowerBus
+//-------------------------------------------------
+
+void m2_bda_device::write_bus8(offs_t offset, uint8_t data)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + BYTE8_XOR_BE(offset);
+ *ptr = data;
+}
+
+
+//-------------------------------------------------
+// write_bus16 - Write 16-bit data to the PowerBus
+//-------------------------------------------------
+
+void m2_bda_device::write_bus16(offs_t offset, uint16_t data)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + WORD2_XOR_BE(offset);
+ *reinterpret_cast<uint16_t *>(ptr) = data;
+}
+
+
+//-------------------------------------------------
+// write_bus32 - Write 32-bit data to the PowerBus
+//-------------------------------------------------
+
+void m2_bda_device::write_bus32(offs_t offset, uint32_t data)
+{
+ assert(offset >= RAM_BASE && offset <= RAM_BASE + m_ram_mask);
+
+ offset &= m_ram_mask;
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_ram[0]) + DWORD_XOR_BE(offset);
+ *reinterpret_cast<uint32_t *>(ptr) = data;
+}
+
+
+
+/***************************************************************************
+ PRIVATE FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// configure_ppc_address_map -
+//-------------------------------------------------
+
+void m2_bda_device::configure_ppc_address_map(address_space &space)
+{
+ // Install shared RAM
+ space.install_ram(RAM_BASE, RAM_BASE + m_ram_mask, m_ram);
+
+ // Install TE texture RAM window
+ space.install_ram(TE_TRAM_BASE, TE_TRAM_BASE + TE_TRAM_MASK, m_te->tram_ptr());
+
+ // Install BDA sub-devices
+ space.install_readwrite_handler(POWERBUS_BASE, POWERBUS_BASE + DEVICE_MASK,read32_delegate(FUNC(m2_powerbus_device::read), &(*m_powerbus)), write32_delegate(FUNC(m2_powerbus_device::write), &(*m_powerbus)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(MEMCTL_BASE, MEMCTL_BASE + DEVICE_MASK, read32_delegate(FUNC(m2_memctl_device::read), &(*m_memctl)), write32_delegate(FUNC(m2_memctl_device::write), &(*m_memctl)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(VDU_BASE, VDU_BASE + DEVICE_MASK, read32_delegate(FUNC(m2_vdu_device::read), &(*m_vdu)), write32_delegate(FUNC(m2_vdu_device::write), &(*m_vdu)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(TE_BASE, TE_BASE + DEVICE_MASK, read32_delegate(FUNC(m2_te_device::read), &(*m_te)), write32_delegate(FUNC(m2_te_device::write), &(*m_te)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(DSP_BASE, DSP_BASE + DEVICE_MASK, read32_delegate(FUNC(dspp_device::read), &(*m_dspp)), write32_delegate(FUNC(dspp_device::write), &(*m_dspp)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(CTRLPORT_BASE, CTRLPORT_BASE + DEVICE_MASK,read32_delegate(FUNC(m2_ctrlport_device::read), &(*m_ctrlport)), write32_delegate(FUNC(m2_ctrlport_device::write), &(*m_ctrlport)), 0xffffffffffffffffULL);
+ space.install_readwrite_handler(MPEG_BASE, MPEG_BASE + DEVICE_MASK, read32_delegate(FUNC(m2_mpeg_device::read), &(*m_mpeg)), write32_delegate(FUNC(m2_mpeg_device::write), &(*m_mpeg)), 0xffffffffffffffffULL);
+
+ space.install_readwrite_handler(CPUID_BASE, CPUID_BASE + DEVICE_MASK, read32_delegate(FUNC(m2_bda_device::cpu_id_r), this), write32_delegate(FUNC(m2_bda_device::cpu_id_w), this), 0xffffffffffffffffULL);
+
+
+ // Find and install the CDE
+ m2_cde_device *cde = downcast<m2_cde_device *>(machine().device("cde"));
+
+ if (cde == NULL)
+ throw emu_fatalerror("BDA: Could not find the CDE device!");
+
+ space.install_readwrite_handler(SLOT4_BASE, SLOT4_BASE + SLOT_MASK, read32_delegate(FUNC(m2_cde_device::read), cde), write32_delegate(FUNC(m2_cde_device::write), cde), 0xffffffffffffffffULL);
+}
+
+
+
+//**************************************************************************
+// POWERBUS DEVICE
+//**************************************************************************
+
+
+//-------------------------------------------------
+// m2_powerbus_device - constructor
+//-------------------------------------------------
+
+m2_powerbus_device::m2_powerbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, M2_POWERBUS, tag, owner, clock),
+ m_int_handler(*this)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_powerbus_device::device_start()
+{
+ // Resolve callbacks
+ m_int_handler.resolve();
+
+ // Register state for saving
+ save_item(NAME(m_ctrl));
+ save_item(NAME(m_int_enable));
+ save_item(NAME(m_int_status));
+ save_item(NAME(m_err_status));
+ save_item(NAME(m_err_address));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_powerbus_device::device_reset()
+{
+ m_ctrl = 0;
+ m_int_enable = 0;
+ m_int_status = 0;
+ m_err_status = 0;
+ m_err_address = 0;
+}
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ32_MEMBER( m2_powerbus_device::read )
+{
+ const uint32_t byte_offs = offset << 2;
+ uint32_t data = 0;
+
+ switch (byte_offs)
+ {
+ case BDAPCTL_PBINTENSET:
+ {
+ data = m_int_enable;
+ break;
+ }
+ case BDAPCTL_PBINTSTAT:
+ {
+ data = m_int_status;
+ break;
+ }
+ default:
+ logerror("%s: POWERBUS R: [%x] %x\n", machine().describe_context(), byte_offs, data);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_powerbus_device::write )
+{
+ uint32_t byte_offs = offset << 2;
+
+ switch (byte_offs & ~0x400)
+ {
+ case BDAPCTL_PBINTENSET:
+ {
+ write_m2_reg(m_int_enable, data, byte_offs & 0x400 ? REG_CLEAR : REG_SET);
+ update_interrupts();
+ break;
+ }
+ case BDAPCTL_ERRSTAT:
+ {
+#if 1 // TODO
+ if (byte_offs & 0x400)
+ {
+ write_m2_reg(m_int_status, data, REG_CLEAR);
+ }
+ else
+ {
+ if (data == 1)
+ write_m2_reg(m_int_status, data, REG_SET);
+ }
+ update_interrupts();
+#endif
+ break;
+ }
+ default:
+ logerror("%s: POWERBUS W: [%x] %x (PC:%x)\n", machine().describe_context(), byte_offs, data);
+ }
+}
+
+
+/***************************************************************************
+ PRIVATE FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// update_interrupts -
+//-------------------------------------------------
+
+void m2_powerbus_device::update_interrupts()
+{
+ m_int_handler(m_int_status & m_int_enable ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+
+//**************************************************************************
+// MEMORY CONTROLLER DEVICE
+//**************************************************************************
+
+
+//-------------------------------------------------
+// m2_memctl_device - constructor
+//-------------------------------------------------
+
+m2_memctl_device::m2_memctl_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, M2_MEMCTL, tag, owner, clock),
+ m_gpio_in{{*this}, {*this}, {*this}, {*this}},
+ m_gpio_out{{*this}, {*this}, {*this}, {*this}}
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_memctl_device::device_start()
+{
+ // Resolve our callbacks
+ for (int i = 0; i < 4; i++)
+ {
+ m_gpio_in[i].resolve_safe(0);
+ m_gpio_out[i].resolve_safe();
+ }
+
+ // TODO: DELETE ME
+ m2_bda_device *m_bda = (m2_bda_device*)owner(); // TEMP
+
+ // Configure the memory configuration register
+ uint32_t bank1 = m_bda->get_rambank_size(0);
+ uint32_t bank2 = m_bda->get_rambank_size(1);
+
+ m_mcfg = (ramsize_to_mcfg_field(bank2) << MCFG_SS1_SHIFT) | (ramsize_to_mcfg_field(bank1) << MCFG_SS0_SHIFT);
+
+ // Register state for saving
+ save_item(NAME(m_mcfg));
+ save_item(NAME(m_mref));
+ save_item(NAME(m_mcntl));
+ save_item(NAME(m_reset));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_memctl_device::device_reset()
+{
+ // TODO: Need postload to set GPIO also?
+ m_mref = 0;
+}
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ32_MEMBER( m2_memctl_device::read )
+{
+ uint32_t byte_offs = offset << 2;
+ uint32_t data = 0;
+
+ switch (byte_offs)
+ {
+ case MCTL_MCONFIG:
+ {
+ data = m_mcfg;
+ break;
+ }
+ case MCTL_MREF:
+ {
+ if ((m_mref & MREF_GPIO0_GP) && !(m_mref & MREF_GPIO0_OUT))
+ {
+ if (m_gpio_in[0]())
+ m_mref |= MREF_GPIO0_VALUE;
+ else
+ m_mref &= ~MREF_GPIO0_VALUE;
+ }
+
+ if ((m_mref & MREF_GPIO1_GP) && !(m_mref & MREF_GPIO1_OUT))
+ {
+ if (m_gpio_in[1]())
+ m_mref |= MREF_GPIO1_VALUE;
+ else
+ m_mref &= ~MREF_GPIO1_VALUE;
+ }
+
+ if ((m_mref & MREF_GPIO2_GP) && !(m_mref & MREF_GPIO2_OUT))
+ {
+ if (m_gpio_in[2]())
+ m_mref |= MREF_GPIO2_VALUE;
+ else
+ m_mref &= ~MREF_GPIO2_VALUE;
+ }
+
+ if ((m_mref & MREF_GPIO3_GP) && !(m_mref & MREF_GPIO3_OUT))
+ {
+ if (m_gpio_in[3]())
+ m_mref |= MREF_GPIO3_VALUE;
+ else
+ m_mref &= ~MREF_GPIO3_VALUE;
+ }
+
+ data = m_mref;
+ break;
+ }
+ case MCTL_MCNTL:
+ case MCTL_MRESET:
+ //logerror("%s: MEMCTL READ: %x %x\n", machine().describe_context(), byte_offs, mem_mask);
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_memctl_device::write )
+{
+ uint32_t byte_offs = offset << 2;
+
+ switch (byte_offs)
+ {
+ case MCTL_MCONFIG:
+ {
+ m_mcfg = data;
+ break;
+ }
+ case MCTL_MREF:
+ {
+ // Set any general purpose outputs
+ if (data & (MREF_GPIO0_GP | MREF_GPIO0_OUT))
+ m_gpio_out[0](data & MREF_GPIO0_VALUE ? 1 : 0);
+
+ if (data & (MREF_GPIO1_GP | MREF_GPIO1_OUT))
+ m_gpio_out[1](data & MREF_GPIO1_VALUE ? 1 : 0);
+
+ if (data & (MREF_GPIO2_GP | MREF_GPIO2_OUT))
+ m_gpio_out[2](data & MREF_GPIO2_VALUE ? 1 : 0);
+
+ if (data & (MREF_GPIO3_GP | MREF_GPIO3_OUT))
+ m_gpio_out[3](data & MREF_GPIO3_VALUE ? 1 : 0);
+
+ m_mref = data;
+ break;
+ }
+ case MCTL_MCNTL:
+ case MCTL_MRESET:
+ //logerror("%s: MEMCTL WRITE: %x %x %x\n", machine().describe_context(), data, byte_offs);
+ break;
+ }
+}
+
+
+
+//**************************************************************************
+// VDU DEVICE
+//**************************************************************************
+
+
+//-------------------------------------------------
+// m2_vdu_device - constructor
+//-------------------------------------------------
+
+m2_vdu_device::m2_vdu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, M2_VDU, tag, owner, clock),
+ m_screen(*this, finder_base::DUMMY_TAG),
+ m_vint0_int_handler(*this),
+ m_vint1_int_handler(*this)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_vdu_device::device_start()
+{
+ // Resolve callbacks
+ m_vint0_int_handler.resolve_safe();
+ m_vint1_int_handler.resolve_safe();
+
+ // Initialize line interrupt timers
+ m_vint0_timer = timer_alloc(TIMER_ID_VINT0);
+ m_vint1_timer = timer_alloc(TIMER_ID_VINT1);
+
+ // Calculate H/V count bias values (1 = start of blanking)
+ const rectangle visarea = m_screen->visible_area();
+
+ m_hstart = visarea.min_x;
+ m_htotal = visarea.max_x + 1;
+
+ m_vstart = visarea.min_y;
+ m_vtotal = visarea.max_y + 1;
+
+ // Register state for saving
+ save_item(NAME(m_vint));
+ save_item(NAME(m_vdc0));
+ save_item(NAME(m_vdc1));
+ save_item(NAME(m_fv0a));
+ save_item(NAME(m_fv1a));
+ save_item(NAME(m_avdi));
+ save_item(NAME(m_vdli));
+ save_item(NAME(m_vcfg));
+ save_item(NAME(m_dmt0));
+ save_item(NAME(m_dmt1));
+ save_item(NAME(m_vrst));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_vdu_device::device_reset()
+{
+ m_fv0a = 0;
+ m_fv1a = 0;
+ m_avdi = 0;
+ m_vdli = 0;
+ m_vint = 0;
+ m_vcfg = 0;
+ m_dmt0 = 0;
+ m_dmt1 = 0;
+
+ m_vint0_timer->adjust(attotime::never);
+ m_vint1_timer->adjust(attotime::never);
+}
+
+
+//-------------------------------------------------
+// device_timer - device-specific timers
+//-------------------------------------------------
+
+void m2_vdu_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_ID_VINT0:
+ {
+ m_vint |= VDU_VINT_VINT0;
+ m_vint0_int_handler(ASSERT_LINE);
+ set_vint_timer(0);
+ break;
+ }
+ case TIMER_ID_VINT1:
+ {
+ m_vint |= VDU_VINT_VINT1;
+ m_vint1_int_handler(ASSERT_LINE);
+ set_vint_timer(1);
+ break;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ32_MEMBER( m2_vdu_device::read )
+{
+ uint32_t byte_offs = offset << 2;
+ uint32_t data = 0;
+
+ switch (byte_offs)
+ {
+ case VDU_VLOC:
+ {
+ // TODO: Check me
+ uint32_t mpos = m_screen->vpos();
+ uint32_t vpos = ((mpos + m_vstart) % m_vtotal) + 1;
+ data = vpos << VDU_VLOC_VCOUNT_SHIFT;
+ break;
+ }
+ case VDU_VINT:
+ {
+ data = m_vint;
+ break;
+ }
+ case VDU_VDC0:
+ case VDU_VDC1:
+ case VDU_FV0A:
+ case VDU_FV1A:
+ case VDU_AVDI:
+ case VDU_VDLI:
+ case VDU_VCFG:
+ case VDU_DMT0:
+ case VDU_DMT1:
+ case VDU_LFSR:
+ {
+ //logerror("%s: VDU READ: %x %x\n", machine().describe_context(), byte_offs, mem_mask);
+ break;
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_vdu_device::write )
+{
+ uint32_t byte_offs = offset << 2;
+ reg_wmode wmode = byte_offs & 0x400 ? REG_CLEAR : REG_WRITE;
+
+// logerror("%s: VDU WRITE: %03x %08x %x\n", machine().describe_context(), byte_offs, data, mem_mask);
+ byte_offs &= ~0x400;
+ switch (byte_offs)
+ {
+ case VDU_VINT:
+ {
+ uint32_t old = m_vint;
+ write_m2_reg(m_vint, data, wmode);
+
+ // Update line interrupts if changed
+ if ((m_vint & VDU_VINT_VLINE0_MASK) != (old & VDU_VINT_VLINE0_MASK))
+ set_vint_timer(0);
+
+ if ((m_vint & VDU_VINT_VLINE1_MASK) != (old & VDU_VINT_VLINE1_MASK))
+ set_vint_timer(1);
+
+ // Clear interrupt bits
+ if ((old & VDU_VINT_VINT0) && !(m_vint & VDU_VINT_VINT0))
+ m_vint0_int_handler(CLEAR_LINE);
+
+ if ((old & VDU_VINT_VINT1) && !(m_vint & VDU_VINT_VINT1))
+ m_vint1_int_handler(CLEAR_LINE);
+
+ break;
+ }
+ case VDU_FV0A:
+ {
+ m_fv0a = data;
+ break;
+ }
+ case VDU_FV1A:
+ {
+ m_fv1a = data;
+ break;
+ }
+ case VDU_VCFG:
+ {
+ m_vcfg = data;
+ break;
+ }
+ case VDU_VRST:
+ {
+ m_vrst = data;
+ break;
+ }
+ default:
+ {
+ logerror("%s: VDU WRITE: %x %x %x\n", machine().describe_context(), byte_offs, data, mem_mask);
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// parse_dc_word -
+//-------------------------------------------------
+
+void m2_vdu_device::parse_dc_word(uint32_t cmd)
+{
+ // Determine the control register
+ uint32_t &vdc = cmd & VDL_DC_1 ? m_vdc1 : m_vdc0;
+
+ // Horizontal interpolation
+ uint32_t hint = (cmd & VDL_DC_HINTCTL_MASK) >> VDL_DC_HINTCTL_SHIFT;
+
+ if (hint == VDL_CTL_ENABLE)
+ vdc |= VDU_VDC_HINT;
+ else if (hint == VDL_CTL_DISABLE)
+ vdc &= ~VDU_VDC_HINT;
+
+
+ // Vertical interpolation
+ uint32_t vint = (cmd & VDL_DC_VINTCTL_MASK) >> VDL_DC_VINTCTL_SHIFT;
+
+ if (vint == VDL_CTL_ENABLE)
+ vdc |= VDU_VDC_VINT;
+ else if (vint == VDL_CTL_DISABLE)
+ vdc &= ~VDU_VDC_VINT;
+
+
+ // Dithering
+ uint32_t dith = (cmd & VDL_DC_DITHERCTL_MASK) >> VDL_DC_DITHERCTL_SHIFT;
+
+ if (dith == VDL_CTL_ENABLE)
+ vdc |= VDU_VDC_DITHER;
+ else if (dith == VDL_CTL_DISABLE)
+ vdc &= ~VDU_VDC_DITHER;
+
+
+ // MTXBYP (?)
+ uint32_t mtxbyp = (cmd & VDL_DC_MTXBYPCTL_MASK) >> VDL_DC_MTXBYPCTL_SHIFT;
+
+ if (mtxbyp == VDL_CTL_ENABLE)
+ vdc |= VDU_VDC_MTXBYP;
+ else if (mtxbyp == VDL_CTL_DISABLE)
+ vdc &= ~VDU_VDC_MTXBYP;
+}
+
+
+//-------------------------------------------------
+// parse_av_word -
+//-------------------------------------------------
+
+void m2_vdu_device::parse_av_word(uint32_t cmd)
+{
+ if (cmd & VDL_AV_LD_HSTART)
+ {
+ uint32_t hstart = (cmd & VDL_AV_HSTART_MASK) >> VDL_AV_HSTART_SHIFT;
+ m_avdi &= ~VDU_AVDI_HSTART_MASK;
+ m_avdi |= hstart << VDU_AVDI_HSTART_SHIFT;
+ }
+ if (cmd & VDL_AV_LD_HWIDTH)
+ {
+ uint32_t hwidth = (cmd & VDL_AV_HWIDTH_MASK) >> VDL_AV_HWIDTH_SHIFT;
+ m_avdi &= ~VDU_AVDI_HWIDTH_MASK;
+ m_avdi |= hwidth << VDU_AVDI_HWIDTH_SHIFT;
+ }
+ if (cmd & VDL_AV_LD_HDOUBLE)
+ {
+ if (cmd & VDL_AV_HDOUBLE)
+ m_avdi |= VDU_AVDI_HDOUBLE;
+ else
+ m_avdi &= ~VDU_AVDI_HDOUBLE;
+ }
+ if (cmd & VDL_AV_LD_VDOUBLE)
+ {
+ if (cmd & VDL_AV_VDOUBLE)
+ m_avdi |= VDU_AVDI_VDOUBLE;
+ else
+ m_avdi &= ~VDU_AVDI_VDOUBLE;
+ }
+}
+
+
+//-------------------------------------------------
+// parse_lc_word -
+//-------------------------------------------------
+
+void m2_vdu_device::parse_lc_word(uint32_t cmd)
+{
+ // TODO: This may not be used
+ if (cmd & VDL_LC_LD_BYPASSTYPE)
+ {
+ m_vdli &= ~VDU_VDLI_BYPASSTYPE;
+ m_vdli |= (cmd & VDU_VDLI_BYPASSTYPE) == VDU_VDLI_BYPASSTYPE_MSB ? VDU_VDLI_BYPASSTYPE_MSB : VDU_VDLI_BYPASSTYPE_LSB;
+ }
+ if (cmd & VDL_LC_LD_FBFORMAT)
+ {
+ m_vdli &= ~VDU_VDLI_FBFORMAT;
+ m_vdli |= (cmd & VDL_LC_FBFORMAT) == VDL_LC_FBFORMAT_32 ? VDU_VDLI_FBFORMAT_32 : VDU_VDLI_FBFORMAT_16;
+ }
+
+ // Seems these two are always set by the command word
+ if (cmd & VDL_LC_RANDOMDITHER)
+ m_vdli |= VDU_VDLI_RANDOMDITHER;
+ else
+ m_vdli &= ~VDU_VDLI_RANDOMDITHER;
+
+ if (cmd & VDL_LC_ONEVINTDIS)
+ m_vdli |= VDU_VDLI_ONEVINTDIS;
+ else
+ m_vdli &= ~VDU_VDLI_ONEVINTDIS;
+}
+
+
+//-------------------------------------------------
+// draw_scanline - Draw a scanline
+//-------------------------------------------------
+
+void m2_vdu_device::draw_scanline(uint32_t *dst, uint32_t srclower, uint32_t srcupper)
+{
+ m2_bda_device *m_bda = (m2_bda_device*)owner(); // TEMP
+
+ uint32_t hs = (m_avdi & VDU_AVDI_HSTART_MASK) >> VDU_AVDI_HSTART_SHIFT;
+ uint32_t hw = (m_avdi & VDU_AVDI_HWIDTH_MASK) >> VDU_AVDI_HWIDTH_SHIFT;
+
+ bool is32bpp = m_vdli & VDU_VDLI_FBFORMAT_32 ? true : false;
+// bool bypassmsb = m_vdli & VDU_VDLI_BYPASSTYPE_MSB ? true : false;
+// bool randomdith = m_vdli & VDU_VDLI_RANDOMDITHER ? true : false;
+
+ uint32_t h = 0;
+
+ // Left border
+ while (h < hs)
+ {
+ *dst++ = rgb_t::black();
+ ++h;
+ }
+
+ // Active video area
+ uint32_t vismax = std::min<uint32_t>(h + hw, m_htotal);
+
+ if (is32bpp)
+ {
+ while (h < vismax)
+ {
+ *dst++ = m_bda->read_bus32(srclower);
+ srclower += 4;
+ ++h;
+ }
+ }
+ else
+ {
+ while (h < vismax)
+ {
+ uint16_t srcdata = m_bda->read_bus16(srclower);
+ *dst++ = pal555(srcdata, 10, 5, 0);
+ srclower += 2;
+ ++h;
+ }
+ }
+
+ // Right border
+ while (h < m_htotal)
+ {
+ *dst++ = rgb_t::black();
+ ++h;
+ }
+}
+
+
+//-------------------------------------------------
+// draw_scanline_double - Draw a pixel-doubled scanline
+//-------------------------------------------------
+
+void m2_vdu_device::draw_scanline_double(uint32_t *dst, uint32_t srclower, uint32_t srcupper)
+{
+ m2_bda_device *m_bda = (m2_bda_device*)owner(); // TEMP
+
+ uint32_t hs = (m_avdi & VDU_AVDI_HSTART_MASK) >> VDU_AVDI_HSTART_SHIFT;
+ uint32_t hw = (m_avdi & VDU_AVDI_HWIDTH_MASK) >> VDU_AVDI_HWIDTH_SHIFT;
+
+ bool is32bpp = m_vdli & VDU_VDLI_FBFORMAT_32 ? true : false;
+// bool bypassmsb = m_vdli & VDU_VDLI_BYPASSTYPE_MSB ? true : false;
+// bool randomdith = m_vdli & VDU_VDLI_RANDOMDITHER ? true : false;
+
+ uint32_t h = 0;
+
+ // Left border
+ while (h < hs)
+ {
+ *dst++ = rgb_t::black();
+ ++h;
+ }
+
+ // Active video area
+ uint32_t vismax = std::min<uint32_t>(h + hw, m_htotal);
+
+ if (is32bpp)
+ {
+ while (h < vismax)
+ {
+ uint32_t srcdata = m_bda->read_bus32(srclower);
+
+ srclower += 4;
+ *dst++ = srcdata;
+ *dst++ = srcdata;
+ ++h;
+ }
+ }
+ else
+ {
+ while (h < vismax)
+ {
+ uint32_t srcdata = m_bda->read_bus16(srclower);
+ srcdata = pal555(srcdata, 10, 5, 0);
+
+ srclower += 2;
+ *dst++ = srcdata;
+ *dst++ = srcdata;
+ ++h;
+ }
+ }
+
+ // Right border
+ while (h < m_htotal)
+ {
+ *dst++ = rgb_t::black();
+ ++h;
+ }
+}
+
+
+//-------------------------------------------------
+// core_update_screen -
+//-------------------------------------------------
+
+
+
+//-------------------------------------------------
+// screen_update -
+//-------------------------------------------------
+
+uint32_t m2_vdu_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ m2_bda_device *m_bda = (m2_bda_device*)owner(); // TEMP
+
+ // TODO: Interlace mode
+ uint32_t addr = m_fv0a;//screen.frame_number() & 1 ? m_fv1a : m_fv0a;
+
+ // Fill entire screen with black if disabled
+ if ((m_vrst & (VDU_VRST_VIDRESET | VDU_VRST_DVERESET)) || addr == 0)
+ {
+ bitmap.fill(rgb_t::black());
+ return 0;
+ }
+
+ // Processing begins at VSYNC
+ uint32_t v = 0;
+
+ // Process VDLs until all lines are exhausted
+ while (v < m_vtotal)
+ {
+ // Fetch the 4 header words
+ uint32_t dmactl = m_bda->read_bus32(addr);
+ uint32_t lower = m_bda->read_bus32(addr + 4);
+ uint32_t upper = m_bda->read_bus32(addr + 8);
+ uint32_t next = m_bda->read_bus32(addr + 12);
+
+ addr += 16;
+
+ // Word count includes the header
+ uint32_t words = (dmactl & VDL_DMA_NWORDS_MASK) >> VDL_DMA_NWORDS_SHIFT;
+ words -= 4;
+
+ // Check and adjust the line count
+ uint32_t lines = (dmactl & VDL_DMA_NLINES_MASK) >> VDL_DMA_NLINES_SHIFT;
+
+ if (lines > 0)
+ {
+ uint32_t vend = v + lines;
+
+ if (vend > m_vtotal)
+ lines = vend - m_vtotal;
+ }
+ else
+ {
+ // A zero count denotes all of the remaining screen lines
+ lines = m_vtotal - v;
+ }
+
+ // Parse the command list and update video registers accordingly
+ while (words-- > 0)
+ {
+ uint32_t cmd = m_bda->read_bus32(addr);
+ addr += 4;
+
+ switch (cmd & 0xe0000000)
+ {
+ case VDL_DC:
+ {
+ parse_dc_word(cmd);
+ break;
+ }
+ case VDL_AV:
+ {
+ parse_av_word(cmd);
+ break;
+ }
+ case VDL_LC:
+ {
+ parse_lc_word(cmd);
+ break;
+ }
+ default:
+ {
+ if (cmd != VDL_NOP)
+ fatalerror("VDU: Unknown VDL command word\n");
+ break;
+ }
+ }
+ }
+
+ // DMA from RAM to the display
+ if (dmactl & VDL_DMA_ENABLE)
+ {
+ bool hdouble = m_avdi & VDU_AVDI_HDOUBLE ? true : false;
+ bool vdouble = m_avdi & VDU_AVDI_VDOUBLE ? true : false;
+// bool onevintdis = m_vdli & VDU_VDLI_ONEVINTDIS ? true : false;
+
+ uint32_t srclower = lower;
+ uint32_t srcupper = upper;
+ uint32_t mod = ((dmactl & VDL_DMA_MOD_MASK) >> VDL_DMA_MOD_SHIFT) << 5;
+
+ // Draw these lines
+ while (lines--)
+ {
+ // Line doubling is easily handled
+ for (uint32_t ys = vdouble ? 2 : 1; ys > 0; --ys)
+ {
+ if (hdouble)
+ draw_scanline_double(&bitmap.pix32(v, 0), srclower, srcupper);
+ else
+ draw_scanline(&bitmap.pix32(v, 0), srclower, srcupper);
+
+ ++v;
+ }
+ // Update the source addresses
+ srclower += mod;
+ srcupper += mod;
+ }
+ }
+ else
+ {
+ // Blank this block of lines if DMA is disabled
+ while (lines--)
+ {
+ uint32_t *dst = &bitmap.pix32(v, cliprect.min_x);
+
+ for (uint32_t x = cliprect.min_x; x <= cliprect.max_x; ++x)
+ *dst++ = rgb_t::black();
+
+ ++v;
+ }
+ }
+
+ // Jump to the next VDL
+ addr = next;
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// set_vint_timer -
+//-------------------------------------------------
+
+void m2_vdu_device::set_vint_timer(uint32_t id)
+{
+ uint32_t v;
+ emu_timer *timer = (id == 0) ? m_vint0_timer : m_vint1_timer;
+
+ if (id == 0)
+ v = (m_vint & VDU_VINT_VLINE0_MASK) >> VDU_VINT_VLINE0_SHIFT;
+ else
+ v = (m_vint & VDU_VINT_VLINE1_MASK) >> VDU_VINT_VLINE1_SHIFT;
+
+ if (v == 0)
+ {
+ // Apparently 0 is invalid
+ timer->adjust(attotime::never);
+ }
+ else
+ {
+ // Adjust the count to what the core expects
+ uint32_t vadj = (v - 1 + (m_vtotal - m_vstart)) % m_vtotal;
+ timer->adjust(m_screen->time_until_pos(vadj));
+ }
+}
+
+
+
+//**************************************************************************
+// CONTROL PORTS DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// m2_ctrlport_device - constructor
+//-------------------------------------------------
+
+m2_ctrlport_device::m2_ctrlport_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, M2_CTRLPORT, tag, owner, clock)
+{
+
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_ctrlport_device::device_start()
+{
+
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_ctrlport_device::device_reset()
+{
+
+}
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ32_MEMBER( m2_ctrlport_device::read )
+{
+ //const uint32_t byte_offs = offset << 2;
+ uint32_t data = machine().rand();
+
+ //switch (byte_offs)
+ //{
+ //default:
+ //logerror("%s: CTRLPORT R: [%x] %x\n", machine().describe_context(), byte_offs, data);
+ //}
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_ctrlport_device::write )
+{
+ //uint32_t byte_offs = offset << 2;
+
+ //switch (byte_offs)
+ //{
+ //default:
+ //logerror("%s: CTRLPORT W: [%x] %x\n", machine().describe_context(), byte_offs, data);
+ //}
+}
+
+
+/***************************************************************************
+ PRIVATE FUNCTIONS
+***************************************************************************/
+
+
+
+
+
+//**************************************************************************
+// CDE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// m2_cde_device - constructor
+//-------------------------------------------------
+
+m2_cde_device::m2_cde_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, M2_CDE, tag, owner, clock),
+ m_cpu1(*this, finder_base::DUMMY_TAG),
+ m_int_handler(*this),
+ m_sdbg_out_handler(*this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_cde_device::device_start()
+{
+ // Find our friend the BDA
+ m_bda = downcast<m2_bda_device *>(machine().device("bda"));
+ assert(m_bda != NULL);
+
+ if (m_bda == NULL)
+ throw device_missing_dependencies();
+
+ // Resolve callbacks
+ m_int_handler.resolve_safe();
+ m_sdbg_out_handler.resolve_safe();
+
+ // Init DMA
+ m_dma[0].m_timer = timer_alloc(TIMER_ID_DMA1);
+ m_dma[1].m_timer = timer_alloc(TIMER_ID_DMA2);
+
+ // Register state for saving
+ save_item(NAME(m_sdbg_cntl));
+ save_item(NAME(m_int_status));
+ save_item(NAME(m_int_enable));
+ save_item(NAME(m_bblock_en));
+ save_item(NAME(m_visa_dis));
+
+ for (uint32_t i = 0; i < 8; ++i)
+ {
+ save_item(NAME(m_bio_device[i].m_setup), i);
+ save_item(NAME(m_bio_device[i].m_cycle_time), i);
+ }
+
+ for (uint32_t i = 0; i < 2; ++i)
+ {
+ save_item(NAME(m_dma[i].m_cntl), i);
+ save_item(NAME(m_dma[i].m_cbad), i);
+ save_item(NAME(m_dma[i].m_cpad), i);
+ save_item(NAME(m_dma[i].m_ccnt), i);
+ save_item(NAME(m_dma[i].m_nbad), i);
+ save_item(NAME(m_dma[i].m_npad), i);
+ save_item(NAME(m_dma[i].m_ncnt), i);
+ // timer
+ }
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_cde_device::device_reset()
+{
+ m_sdbg_cntl = 0;
+ m_int_status = 0;
+ m_int_enable = 0;
+
+ // TODO? Boot block is clear on reset
+ m_bblock_en = 1; // ?
+ m_visa_dis = 0;
+
+ reset_dma(0);
+ reset_dma(1);
+}
+
+
+//-------------------------------------------------
+// device_post_load - device-specific post-load
+//-------------------------------------------------
+
+void m2_cde_device::device_post_load()
+{
+
+}
+
+
+//-------------------------------------------------
+// device_timer - a timer
+//-------------------------------------------------
+
+void m2_cde_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_ID_READY:
+ // TODO ?
+ set_interrupt(CDE_ID_READY);
+ break;
+
+ case TIMER_ID_DMA1:
+ next_dma(0);
+ break;
+
+ case TIMER_ID_DMA2:
+ next_dma(1);
+ break;
+
+ default:
+ assert_always(false, "Unknown CDE timer ID");
+ }
+}
+
+
+//-------------------------------------------------
+// set_interrupt -
+//-------------------------------------------------
+
+void m2_cde_device::set_interrupt(uint32_t intmask)
+{
+ m_int_status |= (uint32_t)intmask;
+ update_interrupts();
+}
+
+
+//-------------------------------------------------
+// update_interrupts -
+//-------------------------------------------------
+
+void m2_cde_device::update_interrupts()
+{
+ if (m_int_status & m_int_enable)
+ m_int_handler(ASSERT_LINE);
+ else
+ m_int_handler(CLEAR_LINE);
+}
+
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ32_MEMBER( m2_cde_device::read )
+{
+ const uint32_t byte_offs = offset << 2;
+ uint32_t data = 0;
+
+ switch (byte_offs)
+ {
+ case CDE_DEVICE_ID:
+ {
+ data = 0x00010000;
+ break;
+ }
+ case CDE_VERSION:
+ {
+ data = 0; // TODO
+ break;
+ }
+ case CDE_SDBG_CNTL:
+ {
+ data = m_sdbg_cntl;
+ break;
+ }
+ case CDE_SDBG_RD:
+ {
+ data = m_sdbg_in;
+ break;
+ }
+ case CDE_INT_STS:
+ {
+ data = m_int_status;
+ break;
+ }
+ case CDE_CD_STS_RD:
+ {
+ data = 0x000; // Status ready = 0x100
+ break;
+ }
+ case CDE_INT_ENABLE:
+ {
+ data = m_int_enable;
+ break;
+ }
+ case CDE_DEV_DETECT:
+ {
+ data = 0x0; // ?
+ break;
+ };
+ case CDE_BBLOCK:
+ {
+ // 8, 80
+ data = 0x80; // Needs to be non-zero
+ break;
+ }
+ case CDE_UNIQ_ID_RD:
+ {
+ data = 0xffffffff; // ?
+ break;
+ }
+ case CDE_BBLOCK_EN:
+ {
+ data = m_bblock_en;
+ break;
+ }
+ case CDE_SYSTEM_CONF:
+ {
+ data = m_syscfg;
+ break;
+ }
+ case CDE_MICRO_STATUS:
+ {
+ data = 0x20; // TODO
+ break;
+ }
+ case CDE_MICRO_RWS:
+ {
+ break;
+ }
+ case CDE_VISA_DIS:
+ {
+ data = m_visa_dis;
+ break;
+ }
+ case CDE_DMA1_CNTL:
+ case CDE_DMA2_CNTL:
+ {
+ uint32_t ch = (byte_offs & 0x20) ? 1 : 0;
+ data = m_dma[ch].m_cntl;
+ break;
+ }
+ default:
+ {
+ //logerror("%s: CDE_R UNHANDLED: 0x%.8x 0x%.8x\n", machine().describe_context(), byte_offs, mem_mask));
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_cde_device::write )
+{
+ uint32_t byte_offs = offset << 2;
+ uint32_t dmach = byte_offs & 0x20 ? 1 : 0;
+
+ reg_wmode wm_cw = byte_offs & 0x400 ? REG_CLEAR : REG_WRITE;
+ reg_wmode wm_cs = byte_offs & 0x400 ? REG_CLEAR : REG_SET;
+
+ byte_offs &= ~0x400;
+
+ switch (byte_offs)
+ {
+ case CDE_SDBG_CNTL:
+ {
+ // ........ ........ xxxxxxxx xxxx.... Clock scaler (written with 33MHz/38400 = 868)
+ write_m2_reg(m_sdbg_cntl, data, wm_cw);
+ break;
+ }
+ case CDE_SDBG_WRT:
+ {
+ m_sdbg_out_handler(data);
+ set_interrupt(CDE_SDBG_WRT_DONE);
+ break;
+ }
+ case CDE_INT_STS:
+ {
+ write_m2_reg(m_int_status, data, wm_cw);
+ update_interrupts();
+ break;
+ }
+ case CDE_INT_ENABLE:
+ {
+ write_m2_reg(m_int_enable, data, wm_cs);
+ update_interrupts();
+ break;
+ }
+ case CDE_RESET_CNTL:
+ {
+ if (data & 1)
+ {
+ // TODO: Should we reset both CPUs?
+ downcast<cpu_device *>(&space.device())->pulse_input_line(INPUT_LINE_RESET, attotime::zero);
+
+ // TODO: Is this correct?
+ m_bblock_en = 0;
+ }
+ else if (data & 2)
+ {
+ // TODO: Hard reset
+ }
+
+ break;
+ }
+ case CDE_CD_CMD_WRT:
+ {
+ //set_interrupt(CDE_CD_CMD_WRT_DONE); // ?
+ //set_interrupt(CDE_CD_STS_FL_DONE); // ?
+ break;
+ };
+ case CDE_UNIQ_ID_CMD:
+ {
+ // TODO: What is this?
+ timer_set(attotime::from_usec(250), TIMER_ID_READY);
+ break;
+ }
+ case CDE_BBLOCK:
+ {
+ break;
+ }
+
+ case CDE_DEV0_SETUP:
+ case CDE_DEV1_SETUP:
+ case CDE_DEV2_SETUP:
+ case CDE_DEV3_SETUP:
+ case CDE_DEV4_SETUP:
+ case CDE_DEV5_SETUP:
+ case CDE_DEV6_SETUP:
+ case CDE_DEV7_SETUP:
+ {
+ uint32_t id = (byte_offs - CDE_DEV0_SETUP) >> 3;
+ write_m2_reg(m_bio_device[id].m_setup, data, wm_cw);
+ break;
+ }
+
+ case CDE_DEV0_CYCLE_TIME:
+ case CDE_DEV1_CYCLE_TIME:
+ case CDE_DEV2_CYCLE_TIME:
+ case CDE_DEV3_CYCLE_TIME:
+ case CDE_DEV4_CYCLE_TIME:
+ case CDE_DEV5_CYCLE_TIME:
+ case CDE_DEV6_CYCLE_TIME:
+ case CDE_DEV7_CYCLE_TIME:
+ {
+ uint32_t id = (byte_offs - CDE_DEV0_CYCLE_TIME) >> 3;
+ write_m2_reg(m_bio_device[id].m_cycle_time, data, wm_cw);
+ break;
+ }
+
+// case CDE_SYSTEM_CONF:
+ case CDE_VISA_DIS:
+ {
+ write_m2_reg(m_visa_dis, data, wm_cw);
+ break;
+ }
+ case CDE_MICRO_RWS:
+ case CDE_MICRO_WI:
+ case CDE_MICRO_WOB:
+ case CDE_MICRO_WO:
+ case CDE_MICRO_STATUS:
+ {
+ break;
+ }
+
+ case CDE_DMA1_CNTL:
+ case CDE_DMA2_CNTL:
+ {
+ uint32_t &ctrl = m_dma[dmach].m_cntl;
+ uint32_t old = ctrl;
+
+ write_m2_reg(ctrl, data, wm_cw);
+
+ if (!(old & CDE_DMA_RESET) && (ctrl & CDE_DMA_RESET))
+ reset_dma(dmach);
+
+ if (!(old & CDE_DMA_CURR_VALID) && (ctrl & CDE_DMA_CURR_VALID))
+ start_dma(dmach);
+
+ break;
+ }
+ case CDE_DMA1_CBAD:
+ case CDE_DMA2_CBAD:
+ {
+ write_m2_reg(m_dma[dmach].m_cbad, data, wm_cw);
+ break;
+ }
+ case CDE_DMA1_CPAD:
+ case CDE_DMA2_CPAD:
+ {
+ write_m2_reg(m_dma[dmach].m_cpad, data, wm_cw);
+ break;
+ }
+ case CDE_DMA1_CCNT:
+ case CDE_DMA2_CCNT:
+ {
+ write_m2_reg(m_dma[dmach].m_ccnt, data, wm_cw);
+ break;
+ }
+ default:
+ {
+ //logerror("%s: CDE_W UNHANDLED: 0x%.8x 0x%.8x 0x%.8x\n", machine().describe_context(), byte_offs, data, mem_mask);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// sdbg_in -
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_cde_device::sdbg_in )
+{
+ m_sdbg_in = data;
+ set_interrupt(CDE_SDBG_RD_DONE);
+}
+
+
+
+
+/***************************************************************************
+ PRIVATE FUNCTIONS
+***************************************************************************/
+
+//-------------------------------------------------
+// reset_dma - Reset a DMA channel
+//-------------------------------------------------
+
+void m2_cde_device::reset_dma(uint32_t ch)
+{
+ m_dma[ch].m_cntl = 0;
+ m_dma[ch].m_timer->adjust(attotime::never);
+}
+
+
+//-------------------------------------------------
+// start_dma - DMA between the PowerBus and BioBus
+//-------------------------------------------------
+
+void m2_cde_device::start_dma(uint32_t ch)
+{
+ dma_channel &dma_ch = m_dma[ch];
+ address_space *dma_space = &m_cpu1->space();
+
+ // TODO: DMA timing is probably inaccurate
+ attotime delay = attotime::from_nsec(10);// * dma_ch.m_ccnt;
+
+// attotime delay = clocks_to_attotime(4 * dma_ch.m_ccnt);
+ dma_ch.m_timer->adjust(delay);
+
+ if (dma_ch.m_cntl & CDE_DMA_DIRECTION)
+ {
+ // PowerBus to BioBus
+ assert_always(false, "CDE PowerBus to BioBus DMA currently unsupported");
+ }
+ else
+ {
+ // BioBus to PowerBus
+#if 0
+ logerror("%s: CDE DMA %u: [%.8x] -> [%.8x], 0x%.8x bytes\n", machine().describe_context(), ch, dma_ch.m_cbad, dma_ch.m_cpad, dma_ch.m_ccnt);
+#endif
+ // Determine the BioBus device from the address
+ const uint32_t slot = address_to_biobus_slot(dma_ch.m_cbad);
+
+ // Get the device parameters
+ const uint32_t setup = m_bio_device[slot].m_setup;
+
+ if (setup & CDE_DATAWIDTH_16)
+ {
+ // 16-bit case
+ assert_always((dma_ch.m_ccnt & 1) == 0, "16-bit DMA: Byte count must be even?");
+ assert_always((dma_ch.m_cpad & 1) == 0, "16-bit DMA: DMA destination must be word aligned?");
+
+ const uint32_t srcinc = setup & CDE_READ_SETUP_IO ? 0 : 2;
+
+ while (dma_ch.m_ccnt > 0)
+ {
+ uint16_t data = dma_space->read_word_unaligned(dma_ch.m_cbad); // FIX ME
+ dma_space->write_word(dma_ch.m_cpad, data);
+
+ dma_ch.m_cbad += srcinc;
+ dma_ch.m_cpad += 2;
+ dma_ch.m_ccnt -= 2;
+ }
+ }
+ else
+ {
+ // 8-bit case
+ const uint32_t srcinc = setup & CDE_READ_SETUP_IO ? 0 : 1;
+
+ fatalerror("8-bit DMA untested\n");
+
+ while (dma_ch.m_ccnt > 0)
+ {
+ uint8_t data = dma_space->read_byte(dma_ch.m_cbad);
+ dma_space->write_byte(dma_ch.m_cpad, data);
+
+ dma_ch.m_cbad += srcinc;
+ dma_ch.m_cpad += 1;
+ dma_ch.m_ccnt -= 1;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------
+// next_dma - Start the next DMA if set
+//-------------------------------------------------
+
+void m2_cde_device::next_dma(uint32_t ch)
+{
+ dma_channel &dma_ch = m_dma[ch];
+
+ // TODO: HACK!
+#if 1
+ m_cpu1->set_cache_dirty();
+#endif
+
+ assert_always(dma_ch.m_ccnt == 0, "DMA count non-zero during next DMA");
+
+ if (dma_ch.m_cntl & CDE_DMA_NEXT_VALID)
+ {
+ logerror("NEXT DMA CODE UNTESTED");
+
+ // Update current address and count registers
+ dma_ch.m_cbad = dma_ch.m_nbad;
+ dma_ch.m_cpad = dma_ch.m_npad;
+ dma_ch.m_ccnt = dma_ch.m_ncnt;
+ dma_ch.m_cntl |= CDE_DMA_CURR_VALID;
+
+ // Disable looping
+ if (!(dma_ch.m_cntl & CDE_DMA_GO_FOREVER))
+ dma_ch.m_cntl &= ~CDE_DMA_NEXT_VALID;
+
+ start_dma(ch);
+ }
+ else
+ {
+ // DMA complete
+ dma_ch.m_cntl &= ~CDE_DMA_CURR_VALID;
+ set_interrupt(ch == 0 ? CDE_DMA1_DONE : CDE_DMA2_DONE);
+ }
+}
+
+
+/***************************************************************************
+ MPEG DEVICE
+ ***************************************************************************/
+
+//-------------------------------------------------
+// m2_mpeg_device - constructor
+//-------------------------------------------------
+
+m2_mpeg_device::m2_mpeg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, M2_MPEG, tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_mpeg_device::device_start()
+{
+
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_mpeg_device::device_reset()
+{
+
+}
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+READ32_MEMBER( m2_mpeg_device::read )
+{
+ logerror("%s: MPEG READ: %08X\n", machine().describe_context(), offset);
+ return 0;
+}
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+WRITE32_MEMBER( m2_mpeg_device::write )
+{
+ logerror("%s: MPEG WRITE: %08X %08X\n", machine().describe_context(), offset, data);
+}
diff --git a/src/mame/machine/3dom2.h b/src/mame/machine/3dom2.h
new file mode 100644
index 00000000000..c96d1f6a816
--- /dev/null
+++ b/src/mame/machine/3dom2.h
@@ -0,0 +1,1137 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ 3DO M2
+
+ TODO: Move reg defines out of classes and into source
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef _3DOM2_H_
+#define _3DOM2_H_
+
+#include "emu.h"
+#include "cpu/dspp/dspp.h"
+#include "cpu/powerpc/ppc.h"
+#include "screen.h"
+
+#define M2_BAD_TIMING 0 // HACK
+
+/***************************************************************************
+ ENUMERATIONS
+***************************************************************************/
+
+enum
+{
+ SYSCFG_VIDEO_NTSC = 0x00000000,
+ SYSCFG_VIDEO_PAL = 0x00000001,
+
+ SYSCFG_VIDEO_ENCODER_MEIENC = 0x00000000, // NTSC by default
+ SYSCFG_VIDEO_ENCODER_VP536 = 0x00000004, // NTSC by default
+ SYSCFG_VIDEO_ENCODER_BT9103 = 0x00000008, // PAL by default
+ SYSCFG_VIDEO_ENCODER_DENC = 0x0000000C, // PAL by default
+
+ SYSCFG_REGION_UK = 0x00000800,
+ SYSCFG_REGION_JAPAN = 0x00001000,
+ SYSCFG_REGION_US = 0x00001800,
+
+#if 0 // Console
+ SYSCFG_AUDIO_CS4216 = 0xA0000000,
+ SYSCFG_AUDIO_ASASHI = 0xE0000000,
+#else
+ SYSCFG_AUDIO_CS4216 = 0x20000000,
+ SYSCFG_AUDIO_ASASHI = 0x60000000,
+#endif
+ SYSCFG_BOARD_AC_DEVCARD = 0x00040000,
+ SYSCFG_BOARD_AC_COREBOARD = 0x00058000,
+ SYSCFG_BOARD_DEVCARD = 0x00060000,
+ SYSCFG_BOARD_UPGRADE = 0x00070000,
+ SYSCFG_BOARD_MULTIPLAYER = 0x00078000,
+
+ SYSCONFIG_ARCADE = 0x03600000 | SYSCFG_BOARD_AC_COREBOARD | SYSCFG_AUDIO_ASASHI | SYSCFG_REGION_JAPAN | SYSCFG_VIDEO_ENCODER_MEIENC | SYSCFG_VIDEO_NTSC,
+};
+
+enum bdaint_line
+{
+ BDAINT_EXTD4_LINE = 3,
+ BDAINT_EXTD3_LINE = 4,
+ BDAINT_EXTD2_LINE = 5,
+ BDAINT_EXTD1_LINE = 6,
+ BDAINT_PVIOL_LINE = 7,
+ BDAINT_WVIOL_LINE = 8,
+ BDAINT_TO_LINE = 9,
+
+ BDAINT_CEL_LINE = 21,
+ BDAINT_MYSTERY_LINE = 22,
+ BDAINT_VINT1_LINE = 23,
+ BDAINT_VINT0_LINE = 24,
+ BDAINT_DSP_LINE = 25,
+ BDAINT_MPEG_LINE = 26,
+ BDAINT_TRIGEN_LINE = 27,
+ BDAINT_TRIDFINST_LINE = 28,
+ BDAINT_TRIDMINST_LINE = 29,
+ BDAINT_TRILISTEND_LINE = 30,
+ BDAINT_TRIWINCLIP_LINE = 31,
+};
+
+enum reg_wmode
+{
+ REG_WRITE,
+ REG_INVALID,
+ REG_SET,
+ REG_CLEAR,
+};
+
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+class m2_bda_device;
+class m2_powerbus_device;
+class m2_memctl_device;
+class m2_vdu_device;
+class m2_te_device;
+class m2_ctrlport_device;
+class m2_mpeg_device;
+class m2_cde_device;
+
+
+
+/***************************************************************************
+ BDA ASIC DEVICE
+***************************************************************************/
+
+class m2_bda_device : public device_t
+{
+public:
+ enum rambank_size // TODO: REMOVE ME
+ {
+ RAM_2MB = 2,
+ RAM_4MB = 4,
+ RAM_8MB = 8,
+ RAM_16MB = 16
+ };
+
+ template <typename T, typename U>
+ m2_bda_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu1_tag, U &&cpu2_tag)
+ : m2_bda_device(mconfig, tag, owner, clock)
+ {
+ m_cpu1.set_tag(std::forward<T>(cpu1_tag));
+ m_cpu2.set_tag(std::forward<U>(cpu2_tag));
+ }
+ m2_bda_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto videores_in() { return m_videores_in.bind(); }
+ auto ldac_handler() { return m_dac_l.bind(); }
+ auto rdac_handler() { return m_dac_r.bind(); }
+ void set_ram_size(rambank_size bank1, rambank_size bank2)
+ {
+ m_rambank_size[0] = bank1;
+ m_rambank_size[1] = bank2;
+ }
+
+ // Interface
+ DECLARE_READ32_MEMBER( cpu_id_r );
+ DECLARE_WRITE32_MEMBER( cpu_id_w );
+
+ READ8_MEMBER( read_bus )
+ {
+ return read_bus8(offset);
+ }
+
+ WRITE8_MEMBER( write_bus )
+ {
+ write_bus8(offset, data);
+ }
+
+ uint8_t read_bus8(offs_t offset);
+ uint16_t read_bus16(offs_t offset);
+ uint32_t read_bus32(offs_t offset);
+ void write_bus8(offs_t offset, uint8_t data);
+ void write_bus16(offs_t offset, uint16_t data);
+ void write_bus32(offs_t offset, uint32_t data);
+
+ void * ram_ptr() { return m_ram; }
+ offs_t ram_start() { return RAM_BASE; }
+ offs_t ram_end() { return RAM_BASE + m_ram_mask; }
+ uint32_t get_rambank_size(uint32_t bank) const { return m_rambank_size[bank]; }
+
+ void set_interrupt(uint32_t state);
+
+// screen_device * get_screen() const { return m_screen; }
+
+protected:
+ // Device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_post_load() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+private:
+ enum base_addr
+ {
+ POWERBUS_BASE = 0x00010000,
+ MEMCTL_BASE = 0x00020000,
+ VDU_BASE = 0x00030000,
+ TE_BASE = 0x00040000,
+ DSP_BASE = 0x00060000,
+ CTRLPORT_BASE = 0x00070000,
+ MPEG_BASE = 0x00080000,
+ TE_TRAM_BASE = 0x000c0000,
+ SLOT1_BASE = 0x01000000,
+ SLOT2_BASE = 0x02000000,
+ SLOT3_BASE = 0x03000000,
+ SLOT4_BASE = 0x04000000,
+ SLOT5_BASE = 0x05000000,
+ SLOT6_BASE = 0x06000000,
+ SLOT7_BASE = 0x07000000,
+ SLOT8_BASE = 0x08000000,
+ CPUID_BASE = 0x10000000,
+ RAM_BASE = 0x40000000,
+ };
+
+ enum dev_mask
+ {
+ DEVICE_MASK = 0x0000ffff,
+ SLOT_MASK = 0x00ffffff,
+ TE_TRAM_MASK = 0x00003fff,
+ };
+
+
+ void configure_ppc_address_map(address_space &space);
+
+public: // TODO: THIS SHOULD NOT BE PUBLIC
+ required_device<ppc_device> m_cpu1;
+ required_device<ppc_device> m_cpu2;
+ devcb_read_line m_videores_in;
+
+ // Sub-devices
+ required_device<m2_memctl_device> m_memctl;
+ required_device<m2_powerbus_device> m_powerbus;
+ required_device<m2_vdu_device> m_vdu;
+ required_device<m2_ctrlport_device> m_ctrlport;
+ required_device<dspp_device> m_dspp;
+ required_device<m2_mpeg_device> m_mpeg;
+ required_device<m2_te_device> m_te;
+
+ // System RAM
+ uint32_t *m_ram;
+ uint32_t m_rambank_size[2];
+ uint32_t m_ram_mask;
+
+ devcb_write16 m_dac_l;
+ devcb_write16 m_dac_r;
+
+ emu_timer *m_dac_timer;
+
+ // TODO
+ friend class m2_memctl_device;
+ friend class dspp;
+};
+
+
+
+/***************************************************************************
+ POWERBUS CONTROLLER DEVICE
+***************************************************************************/
+
+class m2_powerbus_device : public device_t
+{
+public:
+ m2_powerbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // Static configuration helpers
+ auto int_handler() { return m_int_handler.bind(); }
+
+ template<uint32_t line> WRITE_LINE_MEMBER( int_line )
+ {
+ if (state)
+ m_int_status |= 1 << line;
+ else
+ m_int_status &= ~(1 << line);
+
+ update_interrupts();
+ }
+
+ DECLARE_WRITE32_MEMBER( write );
+ DECLARE_READ32_MEMBER( read );
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ enum reg_offs
+ {
+ BDAPCTL_DEVID = 0x00,
+ BDAPCTL_PBCONTROL = 0x10,
+ BDAPCTL_PBINTENSET = 0x40,
+ BDAPCTL_PBINTSTAT = 0x50,
+ BDAPCTL_ERRSTAT = 0x60,
+ BDAPCTL_ERRADDR = 0x70,
+ };
+
+ void update_interrupts();
+
+ devcb_write_line m_int_handler;
+
+ // Registers
+ uint32_t m_ctrl;
+ uint32_t m_int_enable;
+ uint32_t m_int_status;
+ uint32_t m_err_status;
+ uint32_t m_err_address;
+};
+
+
+
+/***************************************************************************
+ MEMORY CONTROLLER DEVICE
+***************************************************************************/
+
+class m2_memctl_device : public device_t
+{
+public:
+ m2_memctl_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ template <std::size_t Line> auto gpio_in_handler() { return m_gpio_in[Line].bind(); }
+ template <std::size_t Line> auto gpio_out_handler() { return m_gpio_out[Line].bind(); }
+
+ DECLARE_READ32_MEMBER(read);
+ DECLARE_WRITE32_MEMBER(write);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ enum reg_offs
+ {
+ MCTL_MCONFIG = 0x0,
+ MCTL_MREF = 0x4,
+ MCTL_MCNTL = 0x8,
+ MCTL_MRESET = 0xc,
+ };
+
+ enum mcfg_reg
+ {
+ MCFG_LDIA_MASK = 0x07000000,
+ MCFG_LDIA_SHIFT = 24,
+ MCFG_LDOA_MASK = 0x00c00000,
+ MCFG_LDOA_SHIFT = 22,
+ MCFG_RC_MASK = 0x003c0000,
+ MCFG_RC_SHIFT = 18,
+ MCFG_RCD_MASK = 0x00030000,
+ MCFG_RCD_SHIFT = 16,
+ MCFG_SS1_MASK = 0x0000e000,
+ MCFG_SS1_SHIFT = 13,
+ MCFG_SS0_MASK = 0x00001c00,
+ MCFG_SS0_SHIFT = 10,
+ MCFG_CL_MASK = 0x00000030,
+ MCFG_CL_SHIFT = 4,
+ };
+
+ enum mref_reg
+ {
+ MREF_DEBUGADDR = 0x7F000000, /* Selector if GPIOx_GP == 0 */
+ MREF_GPIO3_GP = 0x00800000, /* General purpose or debug out */
+ MREF_GPIO3_OUT = 0x00400000, /* Output or input */
+ MREF_GPIO3_VALUE = 0x00200000, /* Value if GPIOx_GP == 1 */
+ MREF_GPIO2_GP = 0x00100000, /* General purpose or debug out */
+ MREF_GPIO2_OUT = 0x00080000, /* Output or input */
+ MREF_GPIO2_VALUE = 0x00040000, /* Value if GPIOx_GP == 1 */
+ MREF_GPIO1_GP = 0x00020000, /* General purpose or debug out */
+ MREF_GPIO1_OUT = 0x00010000, /* Output or input */
+ MREF_GPIO1_VALUE = 0x00008000, /* Value if GPIOx_GP == 1 */
+ MREF_GPIO0_GP = 0x00004000, /* General purpose or debug out */
+ MREF_GPIO0_OUT = 0x00002000, /* Output or input */
+ MREF_GPIO0_VALUE = 0x00001000, /* Value if GPIOx_GP == 1 */
+ MREF_REFRESH = 0x00000FFF, /* Memory refresh count */
+ };
+
+
+ uint32_t ramsize_to_mcfg_field(uint32_t size)
+ {
+ // 0:0MB 1:2MB 2:4MB 3:4MB 4:4MB 5:8MB 6:16MB 7:0MB
+ switch (size)
+ {
+ case 0: return 0;
+ case 2: return 1;
+ case 4: return 2;
+ case 8: return 5;
+ case 16: return 6;
+ }
+ return 0;
+ }
+
+
+ // GPIO
+ devcb_read_line m_gpio_in[4];
+ devcb_write_line m_gpio_out[4];
+
+ // Registers
+ uint32_t m_mcfg;
+ uint32_t m_mref;
+ uint32_t m_mcntl;
+ uint32_t m_reset;
+};
+
+
+
+/***************************************************************************
+ VDU DEVICE
+***************************************************************************/
+
+class m2_vdu_device : public device_t
+{
+public:
+ m2_vdu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // Static configuration helpers
+ auto vint0_int_handler() { return m_vint0_int_handler.bind(); }
+ auto vint1_int_handler() { return m_vint1_int_handler.bind(); }
+ template <typename T> void set_screen(T &&screen_tag) { m_screen.set_tag(std::forward<T>(screen_tag)); }
+
+ DECLARE_READ32_MEMBER(read);
+ DECLARE_WRITE32_MEMBER(write);
+
+ uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+private:
+ enum timer_id
+ {
+ TIMER_ID_VBLANK,
+ TIMER_ID_VINT0,
+ TIMER_ID_VINT1,
+ };
+
+ void set_vint_timer(uint32_t id);
+ void parse_dc_word(uint32_t data);
+ void parse_av_word(uint32_t data);
+ void parse_lc_word(uint32_t data);
+ void draw_scanline(uint32_t *dst, uint32_t srclower, uint32_t srcupper);
+ void draw_scanline_double(uint32_t *dst, uint32_t srclower, uint32_t srcupper);
+
+ // Internal stuff
+ required_device<screen_device> m_screen;
+ emu_timer *m_vint0_timer;
+ emu_timer *m_vint1_timer;
+ devcb_write_line m_vint0_int_handler;
+ devcb_write_line m_vint1_int_handler;
+
+ // Registers
+ uint32_t m_vint;
+ uint32_t m_vdc0;
+ uint32_t m_vdc1;
+ uint32_t m_fv0a;
+ uint32_t m_fv1a;
+ uint32_t m_avdi;
+ uint32_t m_vdli;
+ uint32_t m_vcfg;
+ uint32_t m_dmt0;
+ uint32_t m_dmt1;
+ uint32_t m_vrst;
+
+ // Screen parameters
+ uint32_t m_hstart;
+ uint32_t m_htotal;
+ uint32_t m_vstart;
+ uint32_t m_vtotal;
+};
+
+
+
+/***************************************************************************
+ CONTROL PORT DEVICE
+***************************************************************************/
+
+class m2_ctrlport_device : public device_t
+{
+public:
+ m2_ctrlport_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ DECLARE_READ32_MEMBER(read);
+ DECLARE_WRITE32_MEMBER(write);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+
+};
+
+
+
+/***************************************************************************
+ TRIANGLE ENGINE DEVICE
+***************************************************************************/
+
+class m2_te_device : public device_t
+{
+public:
+ m2_te_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // Static configuration helpers
+ auto general_int_handler() { return m_general_int_handler.bind(); }
+ auto dfinstr_int_handler() { return m_dfinstr_int_handler.bind(); }
+ auto iminstr_int_handler() { return m_iminstr_int_handler.bind(); }
+ auto listend_int_handler() { return m_listend_int_handler.bind(); }
+ auto winclip_int_handler() { return m_winclip_int_handler.bind(); }
+
+ DECLARE_READ32_MEMBER(read);
+ DECLARE_WRITE32_MEMBER(write);
+
+ uint32_t *tram_ptr() const { return m_tram; }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_post_load() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+private:
+
+ enum te_state
+ {
+ TE_STOPPED,
+ TE_PAUSED,
+ TE_RUNNING,
+ };
+
+ enum misc
+ {
+ PIP_RAM_WORDS = 256,
+ TEXTURE_RAM_WORDS = 4096,
+ PIP_RAM_BYTEMASK = PIP_RAM_WORDS * 4 - 1,
+ TEXTURE_RAM_BYTEMASK = TEXTURE_RAM_WORDS * 4 - 1,
+ };
+
+ enum inst_type
+ {
+ INST_WRITE_REG = 0x10000000,
+ INST_VTX_SHORT = 0x20000000,
+ INST_VTX_LONG = 0x30000000,
+ INST_VTX_POINT = 0x40000000,
+ INST_MASK = 0xf0000000,
+ };
+
+ enum vtx_flag
+ {
+ VTX_FLAG_SHAD = 0x00010000,
+ VTX_FLAG_TEXT = 0x00020000,
+ VTX_FLAG_PRSP = 0x00040000,
+ VTX_FLAG_NEW = 0x00080000,
+ VTX_FLAG_RM = 0x00100000,
+ };
+
+ struct se_vtx
+ {
+ float x, y;
+ float r, g, b, a;
+ float w;
+ float uw, vw;
+ float iv[8];
+ };
+
+ struct slope_params
+ {
+ float y23;
+ float y31;
+ float y12;
+ float x23;
+ float x31;
+ float x12;
+ float xstep_long;
+ float iAria;
+ };
+
+ struct rgba { uint8_t r, g, b, a; };
+
+ void set_interrupt(uint32_t mask);
+ void update_interrupts();
+
+ void teicntl_w(uint32_t data, reg_wmode wmode);
+ void tedcntl_w(uint32_t data, reg_wmode wmode);
+ void master_mode_w(uint32_t data, reg_wmode wmode);
+
+ void execute();
+ void illegal_inst();
+ uint32_t irp_fetch();
+ float irp_fetch_float();
+
+ void add_vertex(const se_vtx &vtx, uint32_t flags);
+ void log_triangle(uint32_t flags);
+ void setup_triangle(uint32_t flags);
+ void calculate_slope(const slope_params &sp, float q1, float q2, float q3, float &slope_out, float &ddx_out);
+ void walk_edges(uint32_t wrange);
+ void walk_span(uint32_t wrange, bool omit_right, uint32_t y, uint32_t xs, uint32_t xe, int32_t r, int32_t g, int32_t b, int32_t a, uint32_t uw, uint32_t vw, uint32_t w);
+
+ void texcoord_gen(uint32_t wrange, uint32_t uw, uint32_t vw, uint32_t w,
+ uint32_t & uo, uint32_t & vo, uint32_t & wo);
+
+ uint32_t lod_calc(uint32_t u0, uint32_t v0, uint32_t u1, uint32_t v1);
+
+ uint32_t get_tram_bitdepth();
+
+ void addr_calc(uint32_t u, uint32_t v, uint32_t lod,
+ uint32_t & texaddr, uint32_t & texbit, uint32_t & tdepth);
+
+ void get_texture_color(uint32_t u, uint32_t v, uint32_t lod,
+ uint32_t & r, uint32_t & g, uint32_t & b, uint32_t & a, uint32_t & s);
+
+ void get_texel(uint32_t u, uint32_t v, uint32_t lod,
+ uint32_t &r_ti, uint32_t &g_ti, uint32_t &b_ti, uint32_t &a_ti, uint32_t &ssb_ti);
+
+ void texture_fetch(uint32_t texaddr, uint32_t texbit, uint32_t tdepth,
+ uint32_t &r_ti, uint32_t &g_ti, uint32_t &b_ti, uint32_t &a_ti, uint32_t &ssb_ti);
+
+ void select_lerp(uint32_t sel,
+ uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai,
+ uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt,
+ uint32_t & ar, uint32_t & ag, uint32_t & ab );
+
+ void select_mul(uint32_t sel, uint32_t ai, uint32_t at, uint32_t ssbt,
+ uint32_t & a );
+
+ void texture_blend(uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai,
+ uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt,
+ uint32_t &ro, uint32_t &go, uint32_t &bo, uint32_t &ao, uint32_t &ssbo);
+
+ void destination_blend(uint32_t x, uint32_t y, uint32_t w, const rgba & ti_color, uint8_t ssb);
+
+ uint8_t color_blend(uint8_t ct, uint8_t cti, uint8_t cs, uint8_t csrc,
+ uint8_t dm10, uint8_t dm11,
+ uint8_t dm20, uint8_t dm21);
+
+ void select_alpha_dsb();
+ uint8_t get_tex_coef(uint8_t cs, uint8_t dm1const0, uint8_t dm1const1);
+ uint8_t get_src_coef(uint8_t cti, uint8_t dm2const0, uint8_t dm2const1);
+ uint8_t dither(uint8_t in, uint8_t dithval);
+ uint8_t alu_calc(uint16_t a, uint16_t b);
+ void select_src_pixel();
+ void select_tex_pixel();
+ void write_dst_pixel();
+
+ uint8_t read_tram8(offs_t address) const;
+ uint16_t read_tram16(offs_t address) const;
+ uint32_t read_tram32(offs_t address) const;
+ void write_tram8(offs_t address, uint8_t data);
+ void write_tram16(offs_t address, uint16_t data);
+ void write_tram32(offs_t address, uint32_t data);
+
+ uint8_t read_pipram8(offs_t address) const;
+ uint16_t read_pipram16(offs_t address) const;
+ uint32_t read_pipram32(offs_t address) const;
+ void write_pipram32(offs_t address, uint32_t data);
+
+ uint32_t readbits_from_ram(uint32_t & src_addr, uint32_t & bit_offs, uint32_t bits);
+ void load_texture();
+
+ m2_bda_device *m_bda;
+ const address_space_config m_space_config; // TODO: Why is this still here?
+
+ devcb_write_line m_general_int_handler;
+ devcb_write_line m_dfinstr_int_handler;
+ devcb_write_line m_iminstr_int_handler;
+ devcb_write_line m_listend_int_handler;
+ devcb_write_line m_winclip_int_handler;
+
+ // Registers
+ union
+ {
+ struct
+ {
+ uint32_t te_master_mode;
+ uint32_t reserved;
+ uint32_t teicntl_data;
+ uint32_t teicntl;
+ uint32_t tedcntl_data;
+ uint32_t tedcntl;
+ uint32_t iwp;
+ uint32_t irp;
+ uint32_t int_enable;
+ uint32_t int_status;
+ uint32_t vertex_ctrl;
+ };
+ uint32_t m_regs[11];
+ } m_gc;
+
+ union
+ {
+ struct
+ {
+ se_vtx vertices[3];
+ uint32_t reserved[16];
+ uint32_t vertex_state;
+ };
+ uint32_t m_regs[65];
+ } m_se;
+
+ struct
+ {
+ union
+ {
+ struct
+ {
+ uint32_t es_cntl;
+ uint32_t es_capaddr;
+ uint32_t es_capdata;
+ };
+ uint32_t m_regs[3];
+ };
+ union
+ {
+ struct
+ {
+ uint32_t x1;
+ uint32_t y1;
+ uint32_t r1;
+ uint32_t g1;
+ uint32_t b1;
+ uint32_t a1;
+ uint32_t w1;
+ uint32_t uw1;
+ uint32_t vw1;
+ uint32_t x2;
+ uint32_t y2;
+ uint32_t y3;
+ uint32_t xstep_0;
+ uint32_t xstep_1;
+ uint32_t xstep_long;
+ uint32_t xystep_0;
+ uint32_t xystep_1;
+ uint32_t xystep_long;
+ uint32_t dy_0;
+ uint32_t dy_1;
+ uint32_t dy_long;
+ uint32_t ddx_r;
+ uint32_t ddx_g;
+ uint32_t ddx_b;
+ uint32_t ddx_a;
+ uint32_t ddx_w;
+ uint32_t ddx_uw;
+ uint32_t ddx_vw;
+ uint32_t slope_r;
+ uint32_t slope_g;
+ uint32_t slope_b;
+ uint32_t slope_a;
+ uint32_t slope_uw;
+ uint32_t slope_vw;
+ uint32_t slope_w;
+ uint32_t r2l;
+ };
+ uint32_t m_buffer_regs[36];
+ };
+ } m_es;
+
+ union
+ {
+ struct
+ {
+ uint32_t tex_cntl;
+ uint32_t texld_cntl;
+ uint32_t tex_addr_cntl;
+ uint32_t tex_pip_cntl;
+ uint32_t tex_tab_cntl;
+ union
+ {
+ uint32_t tex_lod_base0;
+ uint32_t texld_dstbase;
+ uint32_t tex_mm_dstbase;
+ };
+ uint32_t tex_lod_base1;
+ uint32_t tex_lod_base2;
+ uint32_t tex_lod_base3;
+ union
+ {
+ uint32_t texld_srcbase;
+ uint32_t tex_mm_srcbase;
+ };
+ union
+ {
+ uint32_t tex_bytecnt;
+ uint32_t tex_rowcnt;
+ uint32_t tex_texcnt;
+ };
+ uint32_t uv_max;
+ uint32_t uv_mask;
+ uint32_t tex_srctype01;
+ uint32_t tex_srctype23;
+ uint32_t tex_exptype;
+ union
+ {
+ uint32_t tex_srcconst0;
+ uint32_t tex_clrconst;
+ uint32_t tex_catconst0;
+ };
+ union
+ {
+ uint32_t tex_srcconst1;
+ uint32_t tex_pipconst1;
+ };
+ union
+ {
+ uint32_t tex_srcconst2;
+ uint32_t tex_catiConst0;
+ };
+ union
+ {
+ uint32_t tex_srcconst3;
+ uint32_t tex_caticonst1;
+ };
+ uint32_t tex_srcexp;
+ };
+ uint32_t m_regs[21];
+ } m_tm;
+
+ union
+ {
+ struct
+ {
+ uint32_t snoop;
+ uint32_t supergen_ctrl;
+ uint32_t usergen_ctrl;
+ uint32_t discard_ctrl;
+ uint32_t status;
+ uint32_t int_ctrl;
+ uint32_t fbclip;
+ uint32_t x_winclip;
+ uint32_t y_winclip;
+ uint32_t dst_ctrl;
+ uint32_t dst_baseaddr;
+ uint32_t dst_xstride;
+ uint32_t src_ctrl;
+ uint32_t src_baseaddr;
+ uint32_t src_xstride;
+ uint32_t src_offset;
+ uint32_t z_ctrl;
+ uint32_t z_baseaddr;
+ uint32_t z_offset;
+ uint32_t z_clip;
+ uint32_t ssbdsb_ctrl;
+ uint32_t const_in;
+ uint32_t txt_mult_cntl;
+ uint32_t txt_coef_const0;
+ uint32_t txt_coef_const1;
+ uint32_t src_mult_cntl;
+ uint32_t src_coef_const0;
+ uint32_t src_coef_const1;
+ uint32_t alu_ctrl;
+ uint32_t src_alpha_ctrl;
+ uint32_t dst_alpha_ctrl;
+ uint32_t dst_alpha_const;
+ uint32_t dither_mat_a;
+ uint32_t dither_mat_b;
+ };
+ uint32_t m_regs[34];
+ } m_db;
+
+ // Destination blender state
+ struct
+ {
+ uint32_t x;
+ uint32_t y;
+ uint32_t w;
+
+ rgba ti;
+ uint8_t ssb;
+
+ rgba src;
+ uint8_t dsb;
+
+ rgba srcpath;
+ rgba texpath;
+ rgba blend;
+ rgba dst;
+ } m_dbstate;
+
+ te_state m_state;
+
+ uint32_t *m_pipram;
+ uint32_t *m_tram;
+};
+
+
+
+/***************************************************************************
+ MPEG DEVICE
+***************************************************************************/
+
+class m2_mpeg_device : public device_t
+{
+public:
+ m2_mpeg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ DECLARE_READ32_MEMBER(read);
+ DECLARE_WRITE32_MEMBER(write);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+
+};
+
+
+
+/***************************************************************************
+ CDE ASIC DEVICE
+***************************************************************************/
+
+class m2_cde_device : public device_t
+{
+public:
+ template <typename T>
+ m2_cde_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu1_tag)
+ : m2_cde_device(mconfig, tag, owner, clock)
+ {
+ m_cpu1.set_tag(std::forward<T>(cpu1_tag));
+ }
+ m2_cde_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // Static configuration helpers
+ auto int_handler() { return m_int_handler.bind(); }
+ void set_syscfg(uint32_t syscfg) { m_syscfg = syscfg; }
+ auto sdbg_out() { return m_sdbg_out_handler.bind(); }
+
+ DECLARE_READ32_MEMBER(read);
+ DECLARE_WRITE32_MEMBER(write);
+
+ DECLARE_WRITE32_MEMBER(sdbg_in);
+
+ void set_external_interrupt(uint32_t which, uint32_t state)
+ {
+ set_interrupt(CDE_EXT_INT);
+ }
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_post_load() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+private:
+
+ enum timer_id
+ {
+ TIMER_ID_READY,
+ TIMER_ID_CD_DMA1,
+ TIMER_ID_CD_DMA2,
+ TIMER_ID_DMA1,
+ TIMER_ID_DMA2,
+ };
+
+ enum reg_offs
+ {
+ // Miscellaneous
+ CDE_DEVICE_ID = 0x000,
+ CDE_VERSION = 0x004,
+ CDE_SDBG_CNTL = 0x00C, // Serial debug control register
+ CDE_SDBG_RD = 0x010, // Serial debug read data
+ CDE_SDBG_WRT = 0x014, // Serial debug write data
+ CDE_INT_STS = 0x018, // offset for status reg
+ CDE_INT_ENABLE = 0x01C,
+ CDE_RESET_CNTL = 0x020,
+ CDE_ROM_DISABLE = 0x024,
+ CDE_CD_CMD_WRT = 0x028,
+ CDE_CD_STS_RD = 0x02C,
+ CDE_GPIO1 = 0x030, // GPIO1 control register (UART interrupt)
+ CDE_GPIO2 = 0x034, // GPIO1 control register
+
+ // BIO Bus
+ CDE_DEV_DETECT = 0x200,
+ CDE_BBLOCK = 0x204,
+ CDE_BBLOCK_EN = 0x208, // Blocking enable register
+ CDE_DEV5_CONF = 0x20C,
+ CDE_DEV_STATE = 0x210,
+ CDE_DEV6_CONF = 0x214,
+ CDE_DEV5_VISA_CONF = 0x218,
+ CDE_DEV6_VISA_CONF = 0x21C,
+ CDE_UNIQ_ID_CMD = 0x220,
+ CDE_UNIQ_ID_RD = 0x224,
+ CDE_DEV_ERROR = 0x228,
+ CDE_DEV7_CONF = 0x22C,
+ CDE_DEV7_VISA_CONF = 0x230,
+ CDE_DEV0_SETUP = 0x240,
+ CDE_DEV0_CYCLE_TIME = 0x244,
+ CDE_DEV1_SETUP = 0x248,
+ CDE_DEV1_CYCLE_TIME = 0x24C,
+ CDE_DEV2_SETUP = 0x250,
+ CDE_DEV2_CYCLE_TIME = 0x254,
+ CDE_DEV3_SETUP = 0x258,
+ CDE_DEV3_CYCLE_TIME = 0x25C,
+ CDE_DEV4_SETUP = 0x260,
+ CDE_DEV4_CYCLE_TIME = 0x264,
+ CDE_DEV5_SETUP = 0x268,
+ CDE_DEV5_CYCLE_TIME = 0x26C,
+ CDE_DEV6_SETUP = 0x270,
+ CDE_DEV6_CYCLE_TIME = 0x274,
+ CDE_DEV7_SETUP = 0x278,
+ CDE_DEV7_CYCLE_TIME = 0x27C,
+ CDE_SYSTEM_CONF = 0x280,
+ CDE_VISA_DIS = 0x284,
+ CDE_MICRO_RWS = 0x290,
+ CDE_MICRO_WI = 0x294,
+ CDE_MICRO_WOB = 0x298,
+ CDE_MICRO_WO = 0x29C,
+ CDE_MICRO_STATUS = 0x2A0,
+
+ // CD DMA
+ CDE_CD_DMA1_CNTL = 0x300,
+ CDE_CD_DMA1_CPAD = 0x308,
+ CDE_CD_DMA1_CCNT = 0x30C,
+ CDE_CD_DMA1_NPAD = 0x318,
+ CDE_CD_DMA1_NCNT = 0x31C,
+ CDE_CD_DMA2_CNTL = 0x320,
+ CDE_CD_DMA2_CPAD = 0x328,
+ CDE_CD_DMA2_CCNT = 0x32C,
+ CDE_CD_DMA2_NPAD = 0x338,
+ CDE_CD_DMA2_NCNT = 0x33C,
+
+ // BioBus DMA
+ CDE_DMA1_CNTL = 0x1000,
+ CDE_DMA1_CBAD = 0x1004,
+ CDE_DMA1_CPAD = 0x1008,
+ CDE_DMA1_CCNT = 0x100C,
+ CDE_DMA1_NBAD = 0x1014,
+ CDE_DMA1_NPAD = 0x1018,
+ CDE_DMA1_NCNT = 0x101C,
+ CDE_DMA2_CNTL = 0x1020,
+ CDE_DMA2_CBAD = 0x1024,
+ CDE_DMA2_CPAD = 0x1028,
+ CDE_DMA2_CCNT = 0x102C,
+ CDE_DMA2_NBAD = 0x1034,
+ CDE_DMA2_NPAD = 0x1038,
+ CDE_DMA2_NCNT = 0x103C,
+ };
+
+ enum cde_int
+ {
+ CDE_INT_SENT = 0x80000000,
+ CDE_SDBG_WRT_DONE = 0x10000000,
+ CDE_SDBG_RD_DONE = 0x08000000,
+ CDE_DIPIR = 0x04000000,
+ CDE_ARM_BOUNDS = 0x01000000,
+ CDE_DMA2_BLOCKED = 0x00400000,
+ CDE_DMA1_BLOCKED = 0x00200000,
+ CDE_ID_READY = 0x00100000,
+ CDE_ARM_FENCE = 0x00080000,
+ CDE_EXT_INT = 0x00040000, // PJB: Used for SIO?
+ CDE_3DO_CARD_INT = 0x00020000,
+ CDE_ARM_INT = 0x00010000,
+ CDE_CD_DMA2_OF = 0x00004000,
+ CDE_CD_DMA1_OF = 0x00002000,
+ CDE_ARM_ABORT = 0x00001000,
+ CDE_CD_DMA2_DONE = 0x00000800,
+ CDE_CD_DMA1_DONE = 0x00000400,
+ CDE_DMA2_DONE = 0x00000100,
+ CDE_DMA1_DONE = 0x00000080,
+ CDE_PBUS_ERROR = 0x00000040,
+ CDE_CD_CMD_WRT_DONE = 0x00000020,
+ CDE_CD_STS_RD_DONE = 0x00000010,
+ CDE_CD_STS_FL_DONE = 0x00000008,
+ CDE_GPIO1_INT = 0x00000004,
+ CDE_GPIO2_INT = 0x00000002,
+ CDE_BBUS_ERROR = 0x00000001,
+ };
+
+ enum cde_dma_cntl
+ {
+ CDE_DMA_DIRECTION = 0x00000400, /* PowerBus to BioBus if set */
+ CDE_DMA_RESET = 0x00000200, /* Reset engine if set */
+ CDE_DMA_GLOBAL = 0x00000100, /* snoopable trans if set */
+ CDE_DMA_CURR_VALID = 0x00000080, /* current setup valid if set */
+ CDE_DMA_NEXT_VALID = 0x00000040, /* next setup valid if set */
+ CDE_DMA_GO_FOREVER = 0x00000020, /* copy next to current if set*/
+ CDE_PB_CHANNEL_MASK = 0x0000001F, /* powerbus channel to use */
+ };
+
+ enum cde_dev_setup
+ {
+ CDE_WRITEN_HOLD = 0x00000003,
+ CDE_WRITEN_SETUP = 0x0000001C,
+ CDE_READ_HOLD = 0x00000060,
+ CDE_READ_SETUP = 0x00000380,
+ CDE_PAGEMODE = 0x00000400,
+ CDE_DATAWIDTH = 0x00001800,
+ CDE_DATAWIDTH_8 = 0x00000000,
+ CDE_DATAWIDTH_16 = 0x00000800,
+ CDE_READ_SETUP_IO = 0x0000E000,
+ CDE_MODEA = 0x00010000,
+ CDE_HIDEA = 0x00020000,
+ };
+
+ void write_reg(uint32_t &reg, uint32_t data, bool clear);
+ void set_interrupt(uint32_t intmask);
+ void update_interrupts();
+
+ void reset_dma(uint32_t ch);
+ void start_dma(uint32_t ch);
+ void next_dma(uint32_t ch);
+
+ uint32_t address_to_biobus_slot(uint32_t addr) const
+ {
+ assert_always(addr >= 0x20000000 && addr <= 0x3fffffff, "Address not within BioBus address range");
+ return ((addr >> 24) >> 2) & 7;
+ }
+
+ required_device<ppc_device> m_cpu1;
+ m2_bda_device *m_bda; // todo
+
+ devcb_write_line m_int_handler;
+ devcb_write32 m_sdbg_out_handler;
+
+
+ // Registers
+ uint32_t m_sdbg_in;
+ uint32_t m_sdbg_out;
+ uint32_t m_sdbg_cntl;
+ uint32_t m_int_status;
+ uint32_t m_int_enable;
+ uint32_t m_bblock_en;
+ uint32_t m_syscfg;
+ uint32_t m_visa_dis;
+
+ struct biobus_device
+ {
+ uint32_t m_setup;
+ uint32_t m_cycle_time;
+ } m_bio_device[8];
+
+ struct dma_channel
+ {
+ uint32_t m_cntl;
+ uint32_t m_cbad;
+ uint32_t m_cpad;
+ uint32_t m_ccnt;
+ uint32_t m_nbad;
+ uint32_t m_npad;
+ uint32_t m_ncnt;
+ emu_timer *m_timer;
+ } m_dma[2];
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(M2_BDA, m2_bda_device)
+DECLARE_DEVICE_TYPE(M2_POWERBUS, m2_powerbus_device)
+DECLARE_DEVICE_TYPE(M2_MEMCTL, m2_memctl_device)
+DECLARE_DEVICE_TYPE(M2_VDU, m2_vdu_device)
+DECLARE_DEVICE_TYPE(M2_CTRLPORT, m2_ctrlport_device)
+DECLARE_DEVICE_TYPE(M2_MPEG, m2_mpeg_device)
+DECLARE_DEVICE_TYPE(M2_CDE, m2_cde_device)
+DECLARE_DEVICE_TYPE(M2_TE, m2_te_device)
+
+#endif // _3DOM2_H_
diff --git a/src/mame/machine/3dom2_defs.h b/src/mame/machine/3dom2_defs.h
new file mode 100644
index 00000000000..95731c58136
--- /dev/null
+++ b/src/mame/machine/3dom2_defs.h
@@ -0,0 +1,695 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ 3DO M2
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef MACHINE_3DOM2_DEFS_H
+#define MACHINE_3DOM2_DEFS_H
+
+/***************************************************************************
+ ENUMERATIONS
+***************************************************************************/
+
+#define M2_SYSCFG_VIDEO_NTSC (0x00000000U)
+#define M2_SYSCFG_VIDEO_PAL (0x00000001U)
+
+#define M2_SYSCFG_VIDEO_ENCODER_MEIENC (0x00000000U) // NTSC by default
+#define M2_SYSCFG_VIDEO_ENCODER_VP536 (0x00000004U) // NTSC by default
+#define M2_SYSCFG_VIDEO_ENCODER_BT9103 (0x00000008U) // PAL by default
+#define M2_SYSCFG_VIDEO_ENCODER_DENC (0x0000000CU) // PAL by default
+
+#define M2_SYSCFG_REGION_UK (0x00000800U)
+#define M2_SYSCFG_REGION_JAPAN (0x00001000U)
+#define M2_SYSCFG_REGION_US (0x00001800U)
+
+#if 0 // Console
+#define M2_SYSCFG_AUDIO_CS4216 (0xA0000000U)
+#define M2_SYSCFG_AUDIO_ASASHI (0xE0000000U)
+#else
+#define M2_SYSCFG_AUDIO_CS4216 (0x20000000U)
+#define M2_SYSCFG_AUDIO_ASASHI (0x60000000U)
+#endif
+#define M2_SYSCFG_BOARD_AC_DEVCARD (0x00040000U)
+#define M2_SYSCFG_BOARD_AC_COREBOARD (0x00058000U)
+#define M2_SYSCFG_BOARD_DEVCARD (0x00060000U)
+#define M2_SYSCFG_BOARD_UPGRADE (0x00070000U)
+#define M2_SYSCFG_BOARD_MULTIPLAYER (0x00078000U)
+
+#define M2_SYSCONFIG_ARCADE (0x03600000 | SYSCFG_BOARD_AC_COREBOARD | SYSCFG_AUDIO_ASASHI | SYSCFG_REGION_JAPAN | SYSCFG_VIDEO_ENCODER_MEIENC | SYSCFG_VIDEO_NTSCU)
+
+
+#define M2_MEMBASE_POWERBUS (0x00010000U)
+#define M2_MEMBASE_MEMCTL (0x00020000U)
+#define M2_MEMBASE_VDU (0x00030000U)
+#define M2_MEMBASE_TE (0x00040000U)
+#define M2_MEMBASE_DSP (0x00060000U)
+#define M2_MEMBASE_CTRLPORT (0x00070000U)
+#define M2_MEMBASE_MPEG (0x00080000U)
+#define M2_MEMBASE_TE_TRAM (0x000c0000U)
+#define M2_MEMBASE_SLOT1 (0x01000000U)
+#define M2_MEMBASE_SLOT2 (0x02000000U)
+#define M2_MEMBASE_SLOT3 (0x03000000U)
+#define M2_MEMBASE_SLOT4 (0x04000000U)
+#define M2_MEMBASE_SLOT5 (0x05000000U)
+#define M2_MEMBASE_SLOT6 (0x06000000U)
+#define M2_MEMBASE_SLOT7 (0x07000000U)
+#define M2_MEMBASE_SLOT8 (0x08000000U)
+#define M2_MEMBASE_CPUID (0x10000000U)
+#define M2_MEMBASE_RAM (0x40000000U)
+
+enum dev_mask
+{
+ DEVICE_MASK (0x0000ffffU)
+ SLOT_MASK (0x00ffffffU)
+ TE_TRAM_MASK (0x00003fffU)
+};
+
+ enum reg_offs
+ {
+#define M2_BDAPCTL_DEVID (0x00U)
+#define M2_BDAPCTL_PBCONTROL (0x10U)
+#define M2_BDAPCTL_PBINTENSET (0x40U)
+#define M2_BDAPCTL_PBINTSTAT (0x50U)
+#define M2_BDAPCTL_ERRSTAT (0x60U)
+#define M2_BDAPCTL_ERRADDR (0x70U)
+
+
+ enum reg_offs
+ {
+ MCTL_MCONFIG (0x0U)
+ MCTL_MREF (0x4U)
+ MCTL_MCNTL (0x8U)
+ MCTL_MRESET (0xcU)
+ };
+
+#define M2_MCFG_LDIA_MASK (0x07000000U)
+#define M2_MCFG_LDIA_SHIFT (24U)
+#define M2_MCFG_LDOA_MASK (0x00c00000U)
+#define M2_MCFG_LDOA_SHIFT (22U)
+#define M2_MCFG_RC_MASK (0x003c0000U)
+#define M2_MCFG_RC_SHIFT (18U)
+#define M2_MCFG_RCD_MASK (0x00030000U)
+#define M2_MCFG_RCD_SHIFT (16U)
+#define M2_MCFG_SS1_MASK (0x0000e000U)
+#define M2_MCFG_SS1_SHIFT (13U)
+#define M2_MCFG_SS0_MASK (0x00001c00U)
+#define M2_MCFG_SS0_SHIFT (10U)
+#define M2_MCFG_CL_MASK (0x00000030U)
+#define M2_MCFG_CL_SHIFT (4U)
+
+#define M2_MREF_DEBUGADDR (0x7F000000U) /* Selector if GPIOx_GP =(0 */
+#define M2_MREF_GPIO3_GP (0x00800000U) /* General purpose or debug out */
+#define M2_MREF_GPIO3_OUT (0x00400000U) /* Output or input */
+#define M2_MREF_GPIO3_VALUE (0x00200000U) /* Value if GPIOx_GP =(1 */
+#define M2_MREF_GPIO2_GP (0x00100000U) /* General purpose or debug out */
+#define M2_MREF_GPIO2_OUT (0x00080000U) /* Output or input */
+#define M2_MREF_GPIO2_VALUE (0x00040000U) /* Value if GPIOx_GP =(1 */
+#define M2_MREF_GPIO1_GP (0x00020000U) /* General purpose or debug out */
+#define M2_MREF_GPIO1_OUT (0x00010000U) /* Output or input */
+#define M2_MREF_GPIO1_VALUE (0x00008000U) /* Value if GPIOx_GP =(1 */
+#define M2_MREF_GPIO0_GP (0x00004000U) /* General purpose or debug out */
+#define M2_MREF_GPIO0_OUT (0x00002000U) /* Output or input */
+#define M2_MREF_GPIO0_VALUE (0x00001000U) /* Value if GPIOx_GP =(1 */
+#define M2_MREF_REFRESH (0x00000FFFU) /* Memory refresh count */
+
+
+ enum CDE_REGS
+ // Miscellaneous
+ CDE_DEVICE_ID (0x000U)
+ CDE_VERSION (0x004U)
+ CDE_SDBG_CNTL (0x00C, // Serial debug control register
+ CDE_SDBG_RD (0x010, // Serial debug read data
+ CDE_SDBG_WRT (0x014, // Serial debug write data
+ CDE_INT_STS (0x018, // offset for status reg
+ CDE_INT_ENABLE (0x01CU)
+ CDE_RESET_CNTL (0x020U)
+ CDE_ROM_DISABLE (0x024U)
+ CDE_CD_CMD_WRT (0x028U)
+ CDE_CD_STS_RD (0x02CU)
+ CDE_GPIO1 (0x030, // GPIO1 control register (UART interrupt)
+ CDE_GPIO2 (0x034, // GPIO1 control register
+
+ // BIO Bus
+ CDE_DEV_DETECT (0x200U)
+ CDE_BBLOCK (0x204U)
+ CDE_BBLOCK_EN (0x208, // Blocking enable register
+ CDE_DEV5_CONF (0x20CU)
+ CDE_DEV_STATE (0x210U)
+ CDE_DEV6_CONF (0x214U)
+ CDE_DEV5_VISA_CONF (0x218U)
+ CDE_DEV6_VISA_CONF (0x21CU)
+ CDE_UNIQ_ID_CMD (0x220U)
+ CDE_UNIQ_ID_RD (0x224U)
+ CDE_DEV_ERROR (0x228U)
+ CDE_DEV7_CONF (0x22CU)
+ CDE_DEV7_VISA_CONF (0x230U)
+ CDE_DEV0_SETUP (0x240U)
+ CDE_DEV0_CYCLE_TIME (0x244U)
+ CDE_DEV1_SETUP (0x248U)
+ CDE_DEV1_CYCLE_TIME (0x24CU)
+ CDE_DEV2_SETUP (0x250U)
+ CDE_DEV2_CYCLE_TIME (0x254U)
+ CDE_DEV3_SETUP (0x258U)
+ CDE_DEV3_CYCLE_TIME (0x25CU)
+ CDE_DEV4_SETUP (0x260U)
+ CDE_DEV4_CYCLE_TIME (0x264U)
+ CDE_DEV5_SETUP (0x268U)
+ CDE_DEV5_CYCLE_TIME (0x26CU)
+ CDE_DEV6_SETUP (0x270U)
+ CDE_DEV6_CYCLE_TIME (0x274U)
+ CDE_DEV7_SETUP (0x278U)
+ CDE_DEV7_CYCLE_TIME (0x27CU)
+ CDE_SYSTEM_CONF (0x280U)
+ CDE_VISA_DIS (0x284U)
+ M2_CDE_MICRO_RWS (0x290U)
+ M2_CDE_MICRO_WI (0x294U)
+ M2_CDE_MICRO_WOB (0x298U)
+ M2_CDE_MICRO_WO (0x29CU)
+ M2_CDE_MICRO_STATUS (0x2A0U)
+
+ // CD DMA
+ M2_CDE_CD_DMA1_CNTL (0x300U)
+ M2_CDE_CD_DMA1_CPAD (0x308U)
+ M2_CDE_CD_DMA1_CCNT (0x30CU)
+ M2_CDE_CD_DMA1_NPAD (0x318U)
+ M2_CDE_CD_DMA1_NCNT (0x31CU)
+ M2_CDE_CD_DMA2_CNTL (0x320U)
+ M2_CDE_CD_DMA2_CPAD (0x328U)
+ M2_CDE_CD_DMA2_CCNT (0x32CU)
+ M2_CDE_CD_DMA2_NPAD (0x338U)
+ M2_CDE_CD_DMA2_NCNT (0x33CU)
+
+ // BioBus DMA
+ M2_CDE_DMA1_CNTL (0x1000U)
+ M2_CDE_DMA1_CBAD (0x1004U)
+ M2_CDE_DMA1_CPAD (0x1008U)
+ M2_CDE_DMA1_CCNT (0x100CU)
+ M2_CDE_DMA1_NBAD (0x1014U)
+ M2_CDE_DMA1_NPAD (0x1018U)
+ M2_CDE_DMA1_NCNT (0x101CU)
+ M2_CDE_DMA2_CNTL (0x1020U)
+ M2_CDE_DMA2_CBAD (0x1024U)
+ M2_CDE_DMA2_CPAD (0x1028U)
+ M2_CDE_DMA2_CCNT (0x102CU)
+ M2_CDE_DMA2_NBAD (0x1034U)
+ M2_CDE_DMA2_NPAD (0x1038U)
+ M2_CDE_DMA2_NCNT (0x103CU)
+ };
+
+ enum cde_int
+ {
+ M2_CDE_INT_SENT (0x80000000U)
+ M2_CDE_SDBG_WRT_DONE (0x10000000U)
+ M2_CDE_SDBG_RD_DONE (0x08000000U)
+ M2_CDE_DIPIR (0x04000000U)
+ M2_CDE_ARM_BOUNDS (0x01000000U)
+ M2_CDE_DMA2_BLOCKED (0x00400000U)
+ M2_CDE_DMA1_BLOCKED (0x00200000U)
+ M2_CDE_ID_READY (0x00100000U)
+ M2_CDE_ARM_FENCE (0x00080000U)
+ M2_CDE_EXT_INT (0x00040000, // Added by Phil
+ M2_CDE_3DO_CARD_INT (0x00020000U)
+ M2_CDE_ARM_INT (0x00010000U)
+ M2_CDE_CD_DMA2_OF (0x00004000U)
+ M2_CDE_CD_DMA1_OF (0x00002000U)
+ M2_CDE_ARM_ABORT (0x00001000U)
+ M2_CDE_CD_DMA2_DONE (0x00000800U)
+ M2_CDE_CD_DMA1_DONE (0x00000400U)
+ M2_CDE_DMA2_DONE (0x00000100U)
+ M2_CDE_DMA1_DONE (0x00000080U)
+ M2_CDE_PBUS_ERROR (0x00000040U)
+ M2_CDE_CD_CMD_WRT_DONE (0x00000020U)
+ M2_CDE_CD_STS_RD_DONE (0x00000010U)
+ M2_CDE_CD_STS_FL_DONE (0x00000008U)
+ M2_CDE_GPIO1_INT (0x00000004U)
+ M2_CDE_GPIO2_INT (0x00000002U)
+ M2_CDE_BBUS_ERROR (0x00000001U)
+ };
+
+ enum cde_dma_cntl
+ {
+ M2_CDE_DMA_DIRECTION (0x00000400, /* PowerBus to BioBus if set */
+ M2_CDE_DMA_RESET (0x00000200, /* Reset engine if set */
+ M2_CDE_DMA_GLOBAL (0x00000100, /* snoopable trans if set */
+ M2_CDE_DMA_CURR_VALID (0x00000080, /* current setup valid if set */
+ M2_CDE_DMA_NEXT_VALID (0x00000040, /* next setup valid if set */
+ M2_CDE_DMA_GO_FOREVER (0x00000020, /* copy next to current if set*/
+ M2_CDE_PB_CHANNEL_MASK (0x0000001F, /* powerbus channel to use */
+ };
+
+// CDE
+#define M2_CDE_WRITEN_HOLD (0x00000003U)
+#define M2_CDE_WRITEN_SETUP (0x0000001CU)
+#define M2_CDE_READ_HOLD (0x00000060U)
+#define M2_CDE_READ_SETUP (0x00000380U)
+#define M2_CDE_PAGEMODE (0x00000400U)
+#define M2_CDE_DATAWIDTH (0x00001800U)
+#define M2_CDE_DATAWIDTH_8 (0x00000000U)
+#define M2_CDE_DATAWIDTH_16 (0x00000800U)
+#define M2_CDE_READ_SETUP_IO (0x0000E000U)
+#define M2_CDE_MODEA (0x00010000U)
+#define M2_CDE_HIDEA (0x00020000U)
+
+
+// TE
+
+/***************************************************************************
+ REGISTER DEFINITIONS
+ ***************************************************************************/
+//-------------------------------------------------
+// General Control
+//-------------------------------------------------
+
+// Triangle Engine Master Mode
+#define M2_TE_MASTER_MODE_RESET (0x00000001U)
+#define M2_TE_MASTER_MODE_DTEXT (0x00000002U)
+#define M2_TE_MASTER_MODE_DSHADE (0x00000004U)
+#define M2_TE_MASTER_MODE_DBLEND (0x00000008U)
+#define M2_TE_MASTER_MODE_DZBUF (0x00000010U)
+#define M2_TE_MASTER_MODE_DDITH (0x00000020U)
+
+// Triangle Engine Immediate Control
+#define M2_TE_TEICNTL_INT (0x00000001U)
+#define M2_TE_TEICNTL_STEP (0x00000002U)
+#define M2_TE_TEICNTL_STPL (0x00000004U)
+#define M2_TE_TEICNTL_STPI (0x00000008U)
+#define M2_TE_TEICNTL_RSTRT (0x00000010U)
+#define M2_TE_TEICNTL_STRT (0x00000020U)
+
+#define M2_TE_TEDCNTL_TLD (0x00000001U)
+#define M2_TE_TEDCNTL_JA (0x00000002U)
+#define M2_TE_TEDCNTL_JR (0x00000004U)
+#define M2_TE_TEDCNTL_INT (0x00000008U)
+#define M2_TE_TEDCNTL_PSE (0x00000010U)
+#define M2_TE_TEDCNTL_SYNC (0x00000020U)
+
+#define M2_TE_INTSTAT_DEFERRED_INSTR (0x00000100U)
+#define M2_TE_INTSTAT_IMMEDIATE_INSTR (0x00000200U)
+#define M2_TE_INTSTAT_LIST_END (0x00000400U)
+#define M2_TE_INTSTAT_WINDOW_CLIP (0x00000800U)
+#define M2_TE_INTSTAT_SPECIAL_INSTR (0x00001000U)
+#define M2_TE_INTSTAT_UNIMPLEMENTED_INSTR (0x00002000U)
+#define M2_TE_INTSTAT_SUPERVISOR (0x00004000U)
+#define M2_TE_INTSTAT_ANY_RENDER (0x00008000U)
+#define M2_TE_INTSTAT_Z_FUNC (0x00010000U)
+#define M2_TE_INTSTAT_ALU_STATUS (0x00020000U)
+#define M2_TE_INTSTAT_FB_CLIP (0x00040000U)
+#define M2_TE_INTSTAT_IMMEDIATE (0x00080000U)
+
+// IWP
+// IRP
+// Interrupt Enable
+// Interrupt Status
+// Vertex Control
+
+
+
+//-------------------------------------------------
+// Setup Engine
+//-------------------------------------------------
+
+ // Vertex State
+#define M2_TE_VERTEXSTATE_TSORT_MASK (0x00000007U)
+#define M2_TE_VERTEXSTATE_TSORT_OMN (0x00000001U)
+#define M2_TE_VERTEXSTATE_TSORT_MNO (0x00000002U)
+#define M2_TE_VERTEXSTATE_TSORT_ONM (0x00000003U)
+#define M2_TE_VERTEXSTATE_TSORT_NOM (0x00000004U)
+#define M2_TE_VERTEXSTATE_TSORT_MON (0x00000005U)
+#define M2_TE_VERTEXSTATE_TSORT_NMO (0x00000006U)
+
+#define M2_TE_VERTEXSTATE_VCNT_SHIFT (3U)
+#define M2_TE_VERTEXSTATE_VCNT_MASK (0x00000018U)
+
+
+ //-------------------------------------------------
+ // Edge Walker
+ //-------------------------------------------------
+
+ // Edge and Span Walker Control
+#define ESCNTL_DSPOFF (0x00000001U)
+#define ESCNTL_DUSCAN (0x00000002U)
+#define ESCNTL_PERSPECTIVEOFF (0x00000004U)
+
+
+ //-------------------------------------------------
+ // Texture Mapper
+ //-------------------------------------------------
+
+ // Texture Mapper Master Control (0x00046400)
+#define M2_TE_TXTCNTL_MMDMA_TRAM_ON (0x00000004U)
+#define M2_TE_TXTCNTL_MMDMA_PIP_ON (0x00000008U)
+#define M2_TE_TXTCNTL_SNOOP_ON (0x00000020U)
+
+ // Texture Load Control (0x00046404)
+#define M2_TE_TXTLDCNTL_SRCBITOFFS (0x00000007U)
+#define M2_TE_TXTLDCNTL_LDMODE_MASK (0x00000300U)
+#define M2_TE_TXTLDCNTL_LDMODE_TEXLOAD (0x00000000U)
+#define M2_TE_TXTLDCNTL_LDMODE_MMDMA (0x00000100U)
+#define M2_TE_TXTLDCNTL_LDMODE_PIPLOAD (0x00000200U)
+#define M2_TE_TXTLDCNTL_LDMODE_RESERVED (0x00000300U)
+#define M2_TE_TXTLDCNTL_COMPRESSED (0x00000400U)
+
+ // Address Control (0x00046408)
+#define M2_TE_TXTADDRCNTL_LODMAX_MASK (0x0000000fU)
+#define M2_TE_TXTADDRCNTL_FILTERSEL_MASK (0x00000003U)
+#define M2_TE_TXTADDRCNTL_FILTERSEL_POINT (0x00000000U)
+#define M2_TE_TXTADDRCNTL_FILTERSEL_LINEAR (0x00000001U)
+#define M2_TE_TXTADDRCNTL_FILTERSEL_BILINEAR (0x00000002U)
+#define M2_TE_TXTADDRCNTL_FILTERSEL_QUASITRI (0x00000003U)
+#define M2_TE_TXTADDRCNTL_R12FILTERSEL_SHIFT (4U)
+#define M2_TE_TXTADDRCNTL_R3FILTERSEL_SHIFT (7U)
+#define M2_TE_TXTADDRCNTL_R45FILTERSEL_SHIFT (10U)
+#define M2_TE_TXTADDRCNTL_LOOKUP_EN (0x00002000U)
+
+ // PIP Control (0x0004640C)
+#define M2_TE_TXTPIPCNTL_INDEX_OFFSET (0x000000ffU)
+#define M2_TE_TXTPIPCNTL_COLORSEL_MASK (0x00000700U)
+#define M2_TE_TXTPIPCNTL_COLORSEL_SHIFT (8U)
+#define M2_TE_TXTPIPCNTL_ALPHASEL_MASK (0x00003800U)
+#define M2_TE_TXTPIPCNTL_ALPHASEL_SHIFT (11U)
+#define M2_TE_TXTPIPCNTL_SSBSEL_MASK (0x0001c000U)
+#define M2_TE_TXTPIPCNTL_SSBSEL_SHIFT (14U)
+
+#define M2_TE_TXTPIPCNTL_SEL_CONSTANT 0
+#define M2_TE_TXTPIPCNTL_SEL_TRAM 1
+#define M2_TE_TXTPIPCNTL_SEL_PIP 2
+
+ // Texture Application Control (0x00046410)
+#define M2_TE_TXTTABCNTL_C_ASEL_MASK 0x00000007
+#define M2_TE_TXTTABCNTL_C_ASEL_SHIFT 0
+#define M2_TE_TXTTABCNTL_C_BSEL_MASK 0x00000038
+#define M2_TE_TXTTABCNTL_C_BSEL_SHIFT 3
+#define M2_TE_TXTTABCNTL_C_TSEL_MASK 0x000001c0
+#define M2_TE_TXTTABCNTL_C_TSEL_SHIFT 6
+
+#define M2_TE_TXTTABCNTL_C_ABTSEL_AITER 0
+#define M2_TE_TXTTABCNTL_C_ABTSEL_CITER 1
+#define M2_TE_TXTTABCNTL_C_ABTSEL_AT 2
+#define M2_TE_TXTTABCNTL_C_ABTSEL_CT 3
+#define M2_TE_TXTTABCNTL_C_ABTSEL_ACONST 4
+#define M2_TE_TXTTABCNTL_C_ABTSEL_CCONST 5
+
+#define M2_TE_TXTTABCNTL_C_OSEL_MASK 0x00000600
+#define M2_TE_TXTTABCNTL_C_OSEL_SHIFT 9
+
+#define M2_TE_TXTTABCNTL_CO_SEL_CITER 0
+#define M2_TE_TXTTABCNTL_CO_SEL_CT 1
+#define M2_TE_TXTTABCNTL_CO_SEL_BLEND 2
+#define M2_TE_TXTTABCNTL_CO_SEL_RESERVED 3
+
+#define M2_TE_TXTTABCNTL_A_ASEL_MASK 0x00001800
+#define M2_TE_TXTTABCNTL_A_ASEL_SHIFT 11
+#define M2_TE_TXTTABCNTL_A_BSEL_MASK 0x00006000
+#define M2_TE_TXTTABCNTL_A_BSEL_SHIFT 13
+
+#define M2_TE_TXTTABCNTL_A_ABSEL_AITER 0
+#define M2_TE_TXTTABCNTL_A_ABSEL_AT 1
+#define M2_TE_TXTTABCNTL_A_ABSEL_ACONST 2
+
+#define M2_TE_TXTTABCNTL_A_OSEL_MASK 0x00018000
+#define M2_TE_TXTTABCNTL_A_OSEL_SHIFT 15
+
+#define M2_TE_TXTTABCNTL_AO_SEL_AITER 0
+#define M2_TE_TXTTABCNTL_AO_SEL_AT 1
+#define M2_TE_TXTTABCNTL_AO_SEL_BLEND 2
+#define M2_TE_TXTTABCNTL_AO_SEL_RESERVED 3
+
+#define M2_TE_TXTTABCNTL_BLENDOP_MASK 0x00010000
+#define M2_TE_TXTTABCNTL_BLENDOP_SHIFT 16
+#define M2_TE_TXTTABCNTL_BLENDOP_LERP 0
+#define M2_TE_TXTTABCNTL_BLENDOP_MULT 1
+
+ // TAB Constants
+#define M2_TE_TXTTABCONST_BLUE 0x000000ff
+#define M2_TE_TXTTABCONST_BLUE_SHIFT 0
+#define M2_TE_TXTTABCONST_GREEN 0x0000ff00
+#define M2_TE_TXTTABCONST_GREEN_SHIFT 8
+#define M2_TE_TXTTABCONST_RED 0x00ff0000
+#define M2_TE_TXTTABCONST_RED_SHIFT 16
+#define M2_TE_TXTTABCONST_ALPHA 0x7f000000
+#define M2_TE_TXTTABCONST_ALPHA_SHIFT 24
+#define M2_TE_TXTTABCONST_SSB 0x80000000
+
+ // Texture Loader Destination Base (0x00046414)
+#define M2_TE_TXTLDDSTBASE_ADDR 0x00003ffc
+
+ // Texture Lod Base 0 (0x00046414)
+ // Texture Lod Base 1 (0x00046418)
+ // Texture Lod Base 2 (0x0004641C)
+ // Texture Lod Base 3 (0x00046420)
+#define M2_TE_TXTLODBASE_MASK 0x00003ffc
+
+ // Texture Loader Source Base (0x00046424)
+#define M2_TE_TXTLDSRCBASE_ADDR 0x00003fff
+
+ // Texture Loader Counts (0x00046428)
+#define M2_TE_TXTLDBYTECNT_COUNT 0x0fffffff
+#define M2_TE_TXTLDROWCNT_COUNT 0x0fffffff
+#define M2_TE_TXTLDTEXCNT_COUNT 0x0fffffff
+
+ // Texture Loader Width (0x00046428)
+#define M2_TE_TxTLDWIDTH_SRCROW 0x0000ffff
+#define M2_TE_TxTLDWIDTH_DSTROW_SHIFT 16
+#define M2_TE_TxTLDWIDTH_DSTROW 0xffff0000
+
+ // Texture Size (0x0004642C)
+#define M2_TE_TXTUVMAX_VMAX_MASK 0x000003ff
+#define M2_TE_TXTUVMAX_VMAX_SHIFT 0
+#define M2_TE_TXTUVMAX_UMAX_MASK 0x03ff0000
+#define M2_TE_TXTUVMAX_UMAX_SHIFT 16
+
+ // Texture Mask (0x00046430)
+#define M2_TE_TXTUVMASK_VMASK_MASK 0x000003ff
+#define M2_TE_TXTUVMASK_VMASK_SHIFT 0
+#define M2_TE_TXTUVMASK_UMASK_MASK 0x03ff0000
+#define M2_TE_TXTUVMASK_UMASK_SHIFT 16
+
+ // TRAM Format (0x0004643C)
+ // TODO: Expansion formats
+#define M2_TE_TXTEXPFORM_CDEPTH_MASK 0x0000000f
+#define M2_TE_TXTEXPFORM_CDEPTH_SHIFT 0
+#define M2_TE_TXTEXPFORM_IDEPTH_MASK 0x0000000f
+#define M2_TE_TXTEXPFORM_IDEPTH_SHIFT 0
+#define M2_TE_TXTEXPFORM_ADEPTH_MASK 0x000000f0
+#define M2_TE_TXTEXPFORM_ADEPTH_SHIFT 4
+#define M2_TE_TXTEXPFORM_TRANSPARENT 0x00000100
+#define M2_TE_TXTEXPFORM_SSBON 0x00000200
+#define M2_TE_TXTEXPFORM_COLORON 0x00000400
+#define M2_TE_TXTEXPFORM_INDEXON 0x00000400
+#define M2_TE_TXTEXPFORM_ALPHAON 0x00000800
+#define M2_TE_TXTEXPFORM_LITERAL 0x00001000
+
+
+ // Format Registers
+
+
+ //-------------------------------------------------
+ // Destination Blender
+ //-------------------------------------------------
+
+ // Snoop (0x0048000)
+#define M2_TE_DBSNOOP_DESTWRSNOOP 0x00000001
+#define M2_TE_DBSNOOP_SRCRDSNOOP 0x00000002
+#define M2_TE_DBSNOOP_ZWRSNOOP 0x00000004
+#define M2_TE_DBSNOOP_ZRDSNOOP 0x00000008
+
+ // Supervisor General Control (0x0048004)
+#define M2_TE_DBSUPERGENCTL_DESTOUTEN 0x00000001
+#define M2_TE_DBSUPERGENCTL_DESTWR16BEN 0x00000002
+#define M2_TE_DBSUPERGENCTL_ZWR16BEN 0x00000004
+
+ // User General Control (0x0048008)
+#define M2_TE_DBUSERGENCTL_DESTOUT_MASK 0x0000000f
+#define M2_TE_DBUSERGENCTL_DITHEREN 0x00000010
+#define M2_TE_DBUSERGENCTL_SRCINEN 0x00000020
+#define M2_TE_DBUSERGENCTL_BLENDEN 0x00000040
+#define M2_TE_DBUSERGENCTL_WCLIPOUTEN 0x00000080
+#define M2_TE_DBUSERGENCTL_WCLIPINEN 0x00000100
+#define M2_TE_DBUSERGENCTL_ZOUTEN 0x00000200
+#define M2_TE_DBUSERGENCTL_ZBUFEN 0x00000400
+
+ // Discard Control (0x004800C)
+#define M2_TE_DBDISCARDCTL_ADISEN 0x00000001
+#define M2_TE_DBDISCARDCTL_RGBDISEN 0x00000002
+#define M2_TE_DBDISCARDCTL_SSBDISEN 0x00000004
+#define M2_TE_DBDISCARDCTL_ZCLIPDISEN 0x00000008
+
+ // Status (0x0048010)
+#define M2_TE_DBSTATUS_ANYREND 0x00000001
+#define M2_TE_DBSTATUS_ZFUNC_GT 0x00000002
+#define M2_TE_DBSTATUS_ZFUNC_EQ 0x00000004
+#define M2_TE_DBSTATUS_ZFUNC_LT 0x00000008
+#define DBSTATUS_ALUSTAT_BLUE_GT 0x00000010
+#define DBSTATUS_ALUSTAT_BLUE_EQ 0x00000020
+#define DBSTATUS_ALUSTAT_BLUE_LT 0x00000040
+#define DBSTATUS_ALUSTAT_GREEN_GT 0x00000080
+#define DBSTATUS_ALUSTAT_GREEN_EQ 0x00000100
+#define DBSTATUS_ALUSTAT_GREEN_LT 0x00000200
+#define DBSTATUS_ALUSTAT_RED_GT 0x00000400
+#define DBSTATUS_ALUSTAT_RED_EQ 0x00000800
+#define DBSTATUS_ALUSTAT_RED_LT 0x00001000
+#define M2_TE_DBSTATUS_ZCLIP 0x00002000
+#define M2_TE_DBSTATUS_WINCLIP 0x00004000
+#define M2_TE_DBSTATUS_FBCLIP 0x00008000
+
+ // Interrupt Control (0x00048014)
+#define M2_TE_DBINTCNTL_ZFUNCSTATINTEN_MASK 0x00000003
+#define M2_TE_DBINTCNTL_ZFUNCSTATINTEN_MASK 0x00000003
+
+ // Framebuffer XY Clip Control (0x00048018)
+#define M2_TE_DBFBCLIP_YFBCLIP_MASK 0x000007ff
+#define M2_TE_DBFBCLIP_YFBCLIP_SHIFT 0
+#define M2_TE_DBFBCLIP_XFBCLIP_MASK 0x07ff0000
+#define M2_TE_DBFBCLIP_XFBCLIP_SHIFT 16
+
+ // Window X Clip Control (0x0004801C)
+#define M2_TE_DBFBXWINCLIP_XMAX_MASK 0x000007ff
+#define M2_TE_DBFBXWINCLIP_XMAX_SHIFT 0
+#define M2_TE_DBFBXWINCLIP_XMIN_MASK 0x07ff0000
+#define M2_TE_DBFBXWINCLIP_XMIN_SHIFT 16
+
+ // Window Y Clip Control (0x00048020)
+#define M2_TE_DBFBYWINCLIP_YMAX_MASK 0x000007ff
+#define M2_TE_DBFBYWINCLIP_YMAX_SHIFT 0
+#define M2_TE_DBFBYWINCLIP_YMIN_MASK 0x07ff0000
+#define M2_TE_DBFBYWINCLIP_YMIN_SHIFT 16
+
+ // Destination Write Control (0x0048024)
+#define M2_TE_DBDESTCNTL_32BPP 0x00000001
+
+ // Destination Write Base Address (0x0048028)
+
+ // Destination X Stride (0x004802C)
+#define M2_TE_DBDEST_XSTRIDE 0x000007ff
+
+ // Source Read Control (0x00048030)
+#define M2_TE_DBSRCCNTL_32BPP 0x00000001
+#define M2_TE_DBSRCCNTL_MSBREP 0x00000002
+
+ // Source Read Base Address (0x00048034)
+
+ // Source X Stride (0x00048038)
+#define M2_TE_DBSRCXSTRIDE 0x000007ff
+
+ // Source XY Offset (0x0004803C)
+#define M2_TE_DBSRCOFFS_YOFFS_MASK 0x00000fff
+#define M2_TE_DBSRCOFFS_YOFFS_SHIFT 0
+#define M2_TE_DBSRCOFFS_XOFFS_MASK 0x0fff0000
+#define M2_TE_DBSRCOFFS_XOFFS_SHIFT 16
+
+ // Z Buffer Control (0x00048040)
+#define M2_TE_DBZCNTL_ZFUNCCNTL_MASK 0x0000003f
+#define M2_TE_DBZCNTL_ZPIXOUT_LT 0x00000001
+#define M2_TE_DBZCNTL_ZBUFOUT_LT 0x00000002
+#define M2_TE_DBZCNTL_ZPIXOUT_EQ 0x00000004
+#define M2_TE_DBZCNTL_ZBUFOUT_EQ 0x00000008
+#define M2_TE_DBZCNTL_ZPIXOUT_GT 0x00000010
+#define M2_TE_DBZCNTL_ZBUFOUT_GT 0x00000020
+
+ // Z Buffer Base Address (0x00048044)
+#define M2_TE_DBZBASEADDR_MASK 0x00ffffff
+
+ // Z Buffer XY Offset (0x00048048)
+#define M2_TE_DBZOFFS_YOFFS_MASK 0x00000fff
+#define M2_TE_DBZOFFS_YOFFS_SHIFT 0
+#define M2_TE_DBZOFFS_XOFFS_MASK 0x0fff0000
+#define M2_TE_DBZOFFS_XOFFS_SHIFT 16
+
+ // Z Buffer Clip (0x0004804C)
+#define M2_TE_DBZCLIP_YCLIP_MASK 0x000007ff
+#define M2_TE_DBZCLIP_YCLIP_SHIFT 0
+#define M2_TE_DBZCLIP_XCLIP_MASK 0x07ff0000
+#define M2_TE_DBZCLIP_XCLIP_SHIFT 16
+
+ // SSB/DSB Control (0x00048050)
+#define M2_TE_DBSSBDSBCNTL_DSBSELECT_MASK 0x00000007
+#define M2_TE_DBSSBDSBCNTL_DSBSELECT_SHIFT 0
+#define M2_TE_DBSSBDSBCNTL_DSBSELECT_SSB 0
+#define M2_TE_DBSSBDSBCNTL_DSBSELECT_CONSTANT 1
+#define M2_TE_DBSSBDSBCNTL_DSBSELECT_SRC 2
+
+#define M2_TE_DBSSBDSBCNTL_DSBCONST 0x00000004
+
+ // RGB constants (0x00048054)
+#define M2_TE_DBCONSTIN_B_MASK 0x000000ff
+#define M2_TE_DBCONSTIN_B_SHIFT 0
+#define M2_TE_DBCONSTIN_G_MASK 0x0000ff00
+#define M2_TE_DBCONSTIN_G_SHIFT 8
+#define M2_TE_DBCONSTIN_R_MASK 0x00ff0000
+#define M2_TE_DBCONSTIN_R_SHIFT 16
+
+ // Texture Multiplication Control (0x00048058)
+#define M2_TE_DBTXTMULTCNTL_TXTRJUST 0x00000001
+#define M2_TE_DBTXTMULTCNTL_TXTCOEFCMP 0x00000002
+
+#define M2_TE_DBTXTMULTCNTL_TXTCONSTCNTL_MASK 0x0000000c
+#define M2_TE_DBTXTMULTCNTL_TXTCONSTCNTL_SHIFT 2
+#define M2_TE_DBTXTMULTCNTL_TXTCONSTCNTL_TEXSSB 0
+#define M2_TE_DBTXTMULTCNTL_TXTCONSTCNTL_SRCDSB 1
+
+#define M2_TE_DBTXTMULTCNTL_COEFSEL_MASK 0x00000030
+#define M2_TE_DBTXTMULTCNTL_COEFSEL_SHIFT 4
+#define M2_TE_DBTXTMULTCNTL_COEFSEL_ATI 0
+#define M2_TE_DBTXTMULTCNTL_COEFSEL_ASRC 1
+#define M2_TE_DBTXTMULTCNTL_COEFSEL_CONSTANT 2
+#define M2_TE_DBTXTMULTCNTL_COEFSEL_CSRC 3
+
+#define M2_TE_DBTXTMULTCNTL_INSEL_MASK 0x000000c0
+#define M2_TE_DBTXTMULTCNTL_INSEL_SHIFT 6
+#define M2_TE_DBTXTMULTCNTL_INSEL_CTI 0
+#define M2_TE_DBTXTMULTCNTL_INSEL_CONSTANT 1
+#define M2_TE_DBTXTMULTCNTL_INSEL_COMPSRC 2
+#define M2_TE_DBTXTMULTCNTL_INSEL_ATI 3
+
+ // Source Multiplication Control (0x00048058)
+#define M2_TE_DBSRCMULTCNTL_SRCRJUST 0x00000001
+#define M2_TE_DBSRCMULTCNTL_SRCCOEFCMP 0x00000002
+
+#define M2_TE_DBSRCMULTCNTL_SRCCONSTCNTL_MASK 0x0000000c
+#define M2_TE_DBSRCMULTCNTL_SRCCONSTCNTL_SHIFT 2
+#define M2_TE_DBSRCMULTCNTL_SRCCONSTCNTL_TEXSSB 0
+#define M2_TE_DBSRCMULTCNTL_SRCCONSTCNTL_SRCDSB 1
+
+#define M2_TE_DBSRCMULTCNTL_COEFSEL_MASK 0x00000030
+#define M2_TE_DBSRCMULTCNTL_COEFSEL_SHIFT 4
+#define M2_TE_DBSRCMULTCNTL_COEFSEL_ATI 0
+#define M2_TE_DBSRCMULTCNTL_COEFSEL_ASRC 1
+#define M2_TE_DBSRCMULTCNTL_COEFSEL_CONSTANT 2
+#define M2_TE_DBSRCMULTCNTL_COEFSEL_CTI 3
+
+#define M2_TE_DBSRCMULTCNTL_INSEL_MASK 0x000000c0
+#define M2_TE_DBSRCMULTCNTL_INSEL_SHIFT 6
+#define M2_TE_DBSRCMULTCNTL_INSEL_SRC 0
+#define M2_TE_DBSRCMULTCNTL_INSEL_CONSTANT 1
+#define M2_TE_DBSRCMULTCNTL_INSEL_COMPCTI 2
+#define M2_TE_DBSRCMULTCNTL_INSEL_TEXALPHA 3
+
+// ALU Control (0x00048070)
+#define M2_TE_DBALUCNTL_FINALDIVIDE_MASK 0x00000007
+#define M2_TE_DBALUCNTL_FINALDIVIDE_SHIFT 0
+
+#define M2_TE_DBALUCNTL_ALUOP_MASK 0x000000f8
+#define M2_TE_DBALUCNTL_ALUOP_SHIFT 5
+
+// Source Alpha Control (0x00048074)
+#define M2_TE_DBDSTACNTL_ADESTSEL_MASK 0x00000003
+#define M2_TE_DBDSTACNTL_ADESTSEL_SHIFT 0
+#define M2_TE_DBDSTACNTL_ADESTCONSTCNTL_MASK 0x0000000c
+#define M2_TE_DBDSTACNTL_ADESTCONSTCNTL_SHIFT 2
+
+#define M2_TE_DBDSTALPHACONST_CONST1_MASK 0x000000ff
+#define M2_TE_DBDSTALPHACONST_CONST1_SHIFT 0
+#define M2_TE_DBDSTALPHACONST_CONST0_MASK 0x00ff0000
+#define M2_TE_DBDSTALPHACONST_CONST0_SHIFT 16
+
+#define M2_TE_DBSSBDSBCNTL_DSBSEL_MASK 0x00000003
+#define M2_TE_DBSSBDSBCNTL_DSBSEL_SHIFT 0
+#define M2_TE_DBSSBDSBCNTL_DSBCONST_MASK 0x00000004
+#define M2_TE_DBSSBDSBCNTL_DSBCONST_SHIFT 2
+
+#endif // MACHINE_3DOM2_DEFS_H \ No newline at end of file
diff --git a/src/mame/machine/3dom2_te.cpp b/src/mame/machine/3dom2_te.cpp
new file mode 100644
index 00000000000..55e430b877e
--- /dev/null
+++ b/src/mame/machine/3dom2_te.cpp
@@ -0,0 +1,3959 @@
+// license:BSD-3-Clause
+// copyright-holders:Philip Bennett
+/***************************************************************************
+
+ 3DO M2 BDA Triangle Engine
+
+***************************************************************************/
+
+#include "math.h"
+#include "3dom2.h"
+
+/*
+ TODO:
+
+ VTX_FLAGS do not get passed to the TMAPPER: Should use master control
+ bits to disable shading and texturing.
+
+ - Evil Night attract mode sky is missing. Why?
+ - What is 1/w when 0?
+ - What do we do about RL flat-topped triangles?
+ - Heat of 11 color check has dodgy pixels <- HAS IT?
+ - Polystar blending is incorrect (intro)
+*/
+
+#define TEST_TIMING 1
+
+#if TEST_TIMING
+enum
+{
+ STAT_TRIANGLES_PROCESSED,
+ STAT_TEXEL_LOADS,
+ STAT_TEXEL_READS,
+ STAT_PIXELS_PROCESSED,
+ STAT_PIXEL_LOADS,
+ STAT_PIXEL_STORES,
+ STAT_TEXEL_BYTES,
+ STAT_ZBUFFER_LOADS,
+ STAT_ZBUFFER_STORES,
+};
+static uint32_t g_statistics[16];
+#endif
+
+static bool g_debug = false; // TODO
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+// Device type definition
+DEFINE_DEVICE_TYPE(M2_TE, m2_te_device, "m2te", "BDA Triangle Engine")
+
+
+
+//static const uint32_t fixed_bits = 23;
+
+static const uint32_t xy_bits = 11;
+static const uint32_t color_bits = 8;
+static const uint32_t text_bits[] = { 10, 7, 4, 1 };
+static const int32_t depth_bits[] = { 0, -3, -6, -9 };
+
+// For right-aligning
+static const uint32_t xy_rshift = 12;
+static const uint32_t color_rshift = 4;
+
+
+// 11.0 format
+static const uint32_t xy_one = 1;
+
+
+/***************************************************************************
+ REGISTER DEFINITIONS
+ ***************************************************************************/
+
+// TODO: SUFFIX bits with _BIT?
+// Move to another file?
+
+//-------------------------------------------------
+// General Control
+//-------------------------------------------------
+
+// Triangle Engine Master Mode
+#define TEMASTER_MODE_RESET 0x00000001
+#define TEMASTER_MODE_DTEXT 0x00000002
+#define TEMASTER_MODE_DSHADE 0x00000004
+#define TEMASTER_MODE_DBLEND 0x00000008
+#define TEMASTER_MODE_DZBUF 0x00000010
+#define TEMASTER_MODE_DDITH 0x00000020
+
+// Triangle Engine Immediate Control
+#define TEICNTL_INT 0x00000001
+#define TEICNTL_STEP 0x00000002
+#define TEICNTL_STPL 0x00000004
+#define TEICNTL_STPI 0x00000008
+#define TEICNTL_RSTRT 0x00000010
+#define TEICNTL_STRT 0x00000020
+
+#define TEDCNTL_TLD 0x00000001
+#define TEDCNTL_JA 0x00000002
+#define TEDCNTL_JR 0x00000004
+#define TEDCNTL_INT 0x00000008
+#define TEDCNTL_PSE 0x00000010
+#define TEDCNTL_SYNC 0x00000020
+
+#define INTSTAT_DEFERRED_INSTR 0x00000100
+#define INTSTAT_IMMEDIATE_INSTR 0x00000200
+#define INTSTAT_LIST_END 0x00000400
+#define INTSTAT_WINDOW_CLIP 0x00000800
+#define INTSTAT_SPECIAL_INSTR 0x00001000
+#define INTSTAT_UNIMPLEMENTED_INSTR 0x00002000
+#define INTSTAT_SUPERVISOR 0x00004000
+#define INTSTAT_ANY_RENDER 0x00008000
+#define INTSTAT_Z_FUNC 0x00010000
+#define INTSTAT_ALU_STATUS 0x00020000
+#define INTSTAT_FB_CLIP 0x00040000
+#define INTSTAT_IMMEDIATE 0x00080000
+
+// IWP
+// IRP
+// Interrupt Enable
+// Interrupt Status
+// Vertex Control
+
+
+
+//-------------------------------------------------
+// Setup Engine
+//-------------------------------------------------
+
+// Vertex State
+#define VERTEXSTATE_TSORT_MASK 0x00000007
+#define VERTEXSTATE_TSORT_OMN 0x00000001
+#define VERTEXSTATE_TSORT_MNO 0x00000002
+#define VERTEXSTATE_TSORT_ONM 0x00000003
+#define VERTEXSTATE_TSORT_NOM 0x00000004
+#define VERTEXSTATE_TSORT_MON 0x00000005
+#define VERTEXSTATE_TSORT_NMO 0x00000006
+
+#define VERTEXSTATE_VCNT_SHIFT 3
+#define VERTEXSTATE_VCNT_MASK 0x00000018
+
+
+//-------------------------------------------------
+// Edge Walker
+//-------------------------------------------------
+
+// Edge and Span Walker Control
+#define ESCNTL_DSPOFF 0x00000001
+#define ESCNTL_DUSCAN 0x00000002
+#define ESCNTL_PERSPECTIVEOFF 0x00000004
+
+
+//-------------------------------------------------
+// Texture Mapper
+//-------------------------------------------------
+
+// Texture Mapper Master Control (0x00046400)
+#define TXTCNTL_MMDMA_TRAM_ON 0x00000004
+#define TXTCNTL_MMDMA_PIP_ON 0x00000008
+#define TXTCNTL_SNOOP_ON 0x00000020
+
+// Texture Load Control (0x00046404)
+#define TXTLDCNTL_SRCBITOFFS 0x00000007
+#define TXTLDCNTL_LDMODE_MASK 0x00000300
+#define TXTLDCNTL_LDMODE_TEXLOAD 0x00000000
+#define TXTLDCNTL_LDMODE_MMDMA 0x00000100
+#define TXTLDCNTL_LDMODE_PIPLOAD 0x00000200
+#define TXTLDCNTL_LDMODE_RESERVED 0x00000300
+#define TXTLDCNTL_COMPRESSED 0x00000400
+
+// Address Control (0x00046408)
+#define TXTADDRCNTL_LODMAX_MASK 0x0000000f
+#define TXTADDRCNTL_FILTERSEL_MASK 0x00000003
+#define TXTADDRCNTL_FILTERSEL_POINT 0x00000000
+#define TXTADDRCNTL_FILTERSEL_LINEAR 0x00000001
+#define TXTADDRCNTL_FILTERSEL_BILINEAR 0x00000002
+#define TXTADDRCNTL_FILTERSEL_QUASITRI 0x00000003
+#define TXTADDRCNTL_R12FILTERSEL_SHIFT 4
+#define TXTADDRCNTL_R3FILTERSEL_SHIFT 7
+#define TXTADDRCNTL_R45FILTERSEL_SHIFT 10
+#define TXTADDRCNTL_LOOKUP_EN 0x00002000
+
+// PIP Control (0x0004640C)
+#define TXTPIPCNTL_INDEX_OFFSET 0x000000ff
+#define TXTPIPCNTL_COLORSEL_MASK 0x00000700
+#define TXTPIPCNTL_COLORSEL_SHIFT 8
+#define TXTPIPCNTL_ALPHASEL_MASK 0x00003800
+#define TXTPIPCNTL_ALPHASEL_SHIFT 11
+#define TXTPIPCNTL_SSBSEL_MASK 0x0001c000
+#define TXTPIPCNTL_SSBSEL_SHIFT 14
+
+#define TXTPIPCNTL_SEL_CONSTANT 0
+#define TXTPIPCNTL_SEL_TRAM 1
+#define TXTPIPCNTL_SEL_PIP 2
+
+// Texture Application Control (0x00046410)
+#define TXTTABCNTL_C_ASEL_MASK 0x00000007
+#define TXTTABCNTL_C_ASEL_SHIFT 0
+#define TXTTABCNTL_C_BSEL_MASK 0x00000038
+#define TXTTABCNTL_C_BSEL_SHIFT 3
+#define TXTTABCNTL_C_TSEL_MASK 0x000001c0
+#define TXTTABCNTL_C_TSEL_SHIFT 6
+
+#define TXTTABCNTL_C_ABTSEL_AITER 0
+#define TXTTABCNTL_C_ABTSEL_CITER 1
+#define TXTTABCNTL_C_ABTSEL_AT 2
+#define TXTTABCNTL_C_ABTSEL_CT 3
+#define TXTTABCNTL_C_ABTSEL_ACONST 4
+#define TXTTABCNTL_C_ABTSEL_CCONST 5
+
+#define TXTTABCNTL_C_OSEL_MASK 0x00000600
+#define TXTTABCNTL_C_OSEL_SHIFT 9
+
+#define TXTTABCNTL_CO_SEL_CITER 0
+#define TXTTABCNTL_CO_SEL_CT 1
+#define TXTTABCNTL_CO_SEL_BLEND 2
+#define TXTTABCNTL_CO_SEL_RESERVED 3
+
+#define TXTTABCNTL_A_ASEL_MASK 0x00001800
+#define TXTTABCNTL_A_ASEL_SHIFT 11
+#define TXTTABCNTL_A_BSEL_MASK 0x00006000
+#define TXTTABCNTL_A_BSEL_SHIFT 13
+
+#define TXTTABCNTL_A_ABSEL_AITER 0
+#define TXTTABCNTL_A_ABSEL_AT 1
+#define TXTTABCNTL_A_ABSEL_ACONST 2
+
+#define TXTTABCNTL_A_OSEL_MASK 0x00018000
+#define TXTTABCNTL_A_OSEL_SHIFT 15
+
+#define TXTTABCNTL_AO_SEL_AITER 0
+#define TXTTABCNTL_AO_SEL_AT 1
+#define TXTTABCNTL_AO_SEL_BLEND 2
+#define TXTTABCNTL_AO_SEL_RESERVED 3
+
+#define TXTTABCNTL_BLENDOP_MASK 0x00010000
+#define TXTTABCNTL_BLENDOP_SHIFT 16
+#define TXTTABCNTL_BLENDOP_LERP 0
+#define TXTTABCNTL_BLENDOP_MULT 1
+
+// TAB Constants
+#define TXTTABCONST_BLUE 0x000000ff
+#define TXTTABCONST_BLUE_SHIFT 0
+#define TXTTABCONST_GREEN 0x0000ff00
+#define TXTTABCONST_GREEN_SHIFT 8
+#define TXTTABCONST_RED 0x00ff0000
+#define TXTTABCONST_RED_SHIFT 16
+#define TXTTABCONST_ALPHA 0x7f000000
+#define TXTTABCONST_ALPHA_SHIFT 24
+#define TXTTABCONST_SSB 0x80000000
+
+// Texture Loader Destination Base (0x00046414)
+#define TXTLDDSTBASE_ADDR 0x00003ffc
+
+// Texture Lod Base 0 (0x00046414)
+// Texture Lod Base 1 (0x00046418)
+// Texture Lod Base 2 (0x0004641C)
+// Texture Lod Base 3 (0x00046420)
+#define TXTLODBASE_MASK 0x00003ffc
+
+// Texture Loader Source Base (0x00046424)
+#define TXTLDSRCBASE_ADDR 0x00003fff
+
+// Texture Loader Counts (0x00046428)
+#define TXTLDBYTECNT_COUNT 0x0fffffff
+#define TXTLDROWCNT_COUNT 0x0fffffff
+#define TXTLDTEXCNT_COUNT 0x0fffffff
+
+// Texture Loader Width (0x00046428)
+#define TxTLDWIDTH_SRCROW 0x0000ffff
+#define TxTLDWIDTH_DSTROW_SHIFT 16
+#define TxTLDWIDTH_DSTROW 0xffff0000
+
+// Texture Size (0x0004642C)
+#define TXTUVMAX_VMAX_MASK 0x000003ff
+#define TXTUVMAX_VMAX_SHIFT 0
+#define TXTUVMAX_UMAX_MASK 0x03ff0000
+#define TXTUVMAX_UMAX_SHIFT 16
+
+// Texture Mask (0x00046430)
+#define TXTUVMASK_VMASK_MASK 0x000003ff
+#define TXTUVMASK_VMASK_SHIFT 0
+#define TXTUVMASK_UMASK_MASK 0x03ff0000
+#define TXTUVMASK_UMASK_SHIFT 16
+
+// TRAM Format (0x0004643C)
+// TODO: Expansion formats
+#define TXTEXPFORM_CDEPTH_MASK 0x0000000f
+#define TXTEXPFORM_CDEPTH_SHIFT 0
+#define TXTEXPFORM_IDEPTH_MASK 0x0000000f
+#define TXTEXPFORM_IDEPTH_SHIFT 0
+#define TXTEXPFORM_ADEPTH_MASK 0x000000f0
+#define TXTEXPFORM_ADEPTH_SHIFT 4
+#define TXTEXPFORM_TRANSPARENT 0x00000100
+#define TXTEXPFORM_SSBON 0x00000200
+#define TXTEXPFORM_COLORON 0x00000400
+#define TXTEXPFORM_INDEXON 0x00000400
+#define TXTEXPFORM_ALPHAON 0x00000800
+#define TXTEXPFORM_LITERAL 0x00001000
+
+
+// Format Registers
+
+
+//-------------------------------------------------
+// Destination Blender
+//-------------------------------------------------
+
+// Snoop (0x0048000)
+#define DBSNOOP_DESTWRSNOOP 0x00000001
+#define DBSNOOP_SRCRDSNOOP 0x00000002
+#define DBSNOOP_ZWRSNOOP 0x00000004
+#define DBSNOOP_ZRDSNOOP 0x00000008
+
+// Supervisor General Control (0x0048004)
+#define DBSUPERGENCTL_DESTOUTEN 0x00000001
+#define DBSUPERGENCTL_DESTWR16BEN 0x00000002
+#define DBSUPERGENCTL_ZWR16BEN 0x00000004
+
+// User General Control (0x0048008)
+#define DBUSERGENCTL_DESTOUT_MASK 0x0000000f
+#define DBUSERGENCTL_DITHEREN 0x00000010
+#define DBUSERGENCTL_SRCINEN 0x00000020
+#define DBUSERGENCTL_BLENDEN 0x00000040
+#define DBUSERGENCTL_WCLIPOUTEN 0x00000080
+#define DBUSERGENCTL_WCLIPINEN 0x00000100
+#define DBUSERGENCTL_ZOUTEN 0x00000200
+#define DBUSERGENCTL_ZBUFEN 0x00000400
+
+// Discard Control (0x004800C)
+#define DBDISCARDCTL_ADISEN 0x00000001
+#define DBDISCARDCTL_RGBDISEN 0x00000002
+#define DBDISCARDCTL_SSBDISEN 0x00000004
+#define DBDISCARDCTL_ZCLIPDISEN 0x00000008
+
+// Status (0x0048010)
+#define DBSTATUS_ANYREND 0x00000001
+#define DBSTATUS_ZFUNC_GT 0x00000002
+#define DBSTATUS_ZFUNC_EQ 0x00000004
+#define DBSTATUS_ZFUNC_LT 0x00000008
+#define DBSTATUS_ALUSTAT_BLUE_GT 0x00000010
+#define DBSTATUS_ALUSTAT_BLUE_EQ 0x00000020
+#define DBSTATUS_ALUSTAT_BLUE_LT 0x00000040
+#define DBSTATUS_ALUSTAT_GREEN_GT 0x00000080
+#define DBSTATUS_ALUSTAT_GREEN_EQ 0x00000100
+#define DBSTATUS_ALUSTAT_GREEN_LT 0x00000200
+#define DBSTATUS_ALUSTAT_RED_GT 0x00000400
+#define DBSTATUS_ALUSTAT_RED_EQ 0x00000800
+#define DBSTATUS_ALUSTAT_RED_LT 0x00001000
+#define DBSTATUS_ZCLIP 0x00002000
+#define DBSTATUS_WINCLIP 0x00004000
+#define DBSTATUS_FBCLIP 0x00008000
+
+// Interrupt Control (0x00048014)
+#define DBINTCNTL_ZFUNCSTATINTEN_MASK 0x00000003
+#define DBINTCNTL_ZFUNCSTATINTEN_MASK 0x00000003
+
+// Framebuffer XY Clip Control (0x00048018)
+#define DBFBCLIP_YFBCLIP_MASK 0x000007ff
+#define DBFBCLIP_YFBCLIP_SHIFT 0
+#define DBFBCLIP_XFBCLIP_MASK 0x07ff0000
+#define DBFBCLIP_XFBCLIP_SHIFT 16
+
+// Window X Clip Control (0x0004801C)
+#define DBFBXWINCLIP_XMAX_MASK 0x000007ff
+#define DBFBXWINCLIP_XMAX_SHIFT 0
+#define DBFBXWINCLIP_XMIN_MASK 0x07ff0000
+#define DBFBXWINCLIP_XMIN_SHIFT 16
+
+// Window Y Clip Control (0x00048020)
+#define DBFBYWINCLIP_YMAX_MASK 0x000007ff
+#define DBFBYWINCLIP_YMAX_SHIFT 0
+#define DBFBYWINCLIP_YMIN_MASK 0x07ff0000
+#define DBFBYWINCLIP_YMIN_SHIFT 16
+
+// Destination Write Control (0x0048024)
+#define DBDESTCNTL_32BPP 0x00000001
+
+// Destination Write Base Address (0x0048028)
+
+// Destination X Stride (0x004802C)
+#define DBDEST_XSTRIDE 0x000007ff
+
+// Source Read Control (0x00048030)
+#define DBSRCCNTL_32BPP 0x00000001
+#define DBSRCCNTL_MSBREP 0x00000002
+
+// Source Read Base Address (0x00048034)
+
+// Source X Stride (0x00048038)
+#define DBSRCXSTRIDE 0x000007ff
+
+// Source XY Offset (0x0004803C)
+#define DBSRCOFFS_YOFFS_MASK 0x00000fff
+#define DBSRCOFFS_YOFFS_SHIFT 0
+#define DBSRCOFFS_XOFFS_MASK 0x0fff0000
+#define DBSRCOFFS_XOFFS_SHIFT 16
+
+// Z Buffer Control (0x00048040)
+#define DBZCNTL_ZFUNCCNTL_MASK 0x0000003f
+#define DBZCNTL_ZPIXOUT_LT 0x00000001
+#define DBZCNTL_ZBUFOUT_LT 0x00000002
+#define DBZCNTL_ZPIXOUT_EQ 0x00000004
+#define DBZCNTL_ZBUFOUT_EQ 0x00000008
+#define DBZCNTL_ZPIXOUT_GT 0x00000010
+#define DBZCNTL_ZBUFOUT_GT 0x00000020
+
+// Z Buffer Base Address (0x00048044)
+#define DBZBASEADDR_MASK 0x00ffffff
+
+// Z Buffer XY Offset (0x00048048)
+#define DBZOFFS_YOFFS_MASK 0x00000fff
+#define DBZOFFS_YOFFS_SHIFT 0
+#define DBZOFFS_XOFFS_MASK 0x0fff0000
+#define DBZOFFS_XOFFS_SHIFT 16
+
+// Z Buffer Clip (0x0004804C)
+#define DBZCLIP_YCLIP_MASK 0x000007ff
+#define DBZCLIP_YCLIP_SHIFT 0
+#define DBZCLIP_XCLIP_MASK 0x07ff0000
+#define DBZCLIP_XCLIP_SHIFT 16
+
+// SSB/DSB Control (0x00048050)
+#define DBSSBDSBCNTL_DSBSELECT_MASK 0x00000007
+#define DBSSBDSBCNTL_DSBSELECT_SHIFT 0
+#define DBSSBDSBCNTL_DSBSELECT_SSB 0
+#define DBSSBDSBCNTL_DSBSELECT_CONSTANT 1
+#define DBSSBDSBCNTL_DSBSELECT_SRC 2
+
+#define DBSSBDSBCNTL_DSBCONST 0x00000004
+
+// RGB constants (0x00048054)
+#define DBCONSTIN_B_MASK 0x000000ff
+#define DBCONSTIN_B_SHIFT 0
+#define DBCONSTIN_G_MASK 0x0000ff00
+#define DBCONSTIN_G_SHIFT 8
+#define DBCONSTIN_R_MASK 0x00ff0000
+#define DBCONSTIN_R_SHIFT 16
+
+// Texture Multiplication Control (0x00048058)
+#define DBTXTMULTCNTL_TXTRJUST 0x00000001
+#define DBTXTMULTCNTL_TXTCOEFCMP 0x00000002
+
+#define DBTXTMULTCNTL_TXTCONSTCNTL_MASK 0x0000000c
+#define DBTXTMULTCNTL_TXTCONSTCNTL_SHIFT 2
+#define DBTXTMULTCNTL_TXTCONSTCNTL_TEXSSB 0
+#define DBTXTMULTCNTL_TXTCONSTCNTL_SRCDSB 1
+
+#define DBTXTMULTCNTL_COEFSEL_MASK 0x00000030
+#define DBTXTMULTCNTL_COEFSEL_SHIFT 4
+#define DBTXTMULTCNTL_COEFSEL_ATI 0
+#define DBTXTMULTCNTL_COEFSEL_ASRC 1
+#define DBTXTMULTCNTL_COEFSEL_CONSTANT 2
+#define DBTXTMULTCNTL_COEFSEL_CSRC 3
+
+#define DBTXTMULTCNTL_INSEL_MASK 0x000000c0
+#define DBTXTMULTCNTL_INSEL_SHIFT 6
+#define DBTXTMULTCNTL_INSEL_CTI 0
+#define DBTXTMULTCNTL_INSEL_CONSTANT 1
+#define DBTXTMULTCNTL_INSEL_COMPSRC 2
+#define DBTXTMULTCNTL_INSEL_ATI 3
+
+// Source Multiplication Control (0x00048058)
+#define DBSRCMULTCNTL_SRCRJUST 0x00000001
+#define DBSRCMULTCNTL_SRCCOEFCMP 0x00000002
+
+#define DBSRCMULTCNTL_SRCCONSTCNTL_MASK 0x0000000c
+#define DBSRCMULTCNTL_SRCCONSTCNTL_SHIFT 2
+#define DBSRCMULTCNTL_SRCCONSTCNTL_TEXSSB 0
+#define DBSRCMULTCNTL_SRCCONSTCNTL_SRCDSB 1
+
+#define DBSRCMULTCNTL_COEFSEL_MASK 0x00000030
+#define DBSRCMULTCNTL_COEFSEL_SHIFT 4
+#define DBSRCMULTCNTL_COEFSEL_ATI 0
+#define DBSRCMULTCNTL_COEFSEL_ASRC 1
+#define DBSRCMULTCNTL_COEFSEL_CONSTANT 2
+#define DBSRCMULTCNTL_COEFSEL_CTI 3
+
+#define DBSRCMULTCNTL_INSEL_MASK 0x000000c0
+#define DBSRCMULTCNTL_INSEL_SHIFT 6
+#define DBSRCMULTCNTL_INSEL_SRC 0
+#define DBSRCMULTCNTL_INSEL_CONSTANT 1
+#define DBSRCMULTCNTL_INSEL_COMPCTI 2
+#define DBSRCMULTCNTL_INSEL_TEXALPHA 3
+
+// ALU Control (0x00048070) TODO
+#define DBALUCNTL_FINALDIVIDE_MASK 0x00000007
+#define DBALUCNTL_FINALDIVIDE_SHIFT 0
+
+#define DBALUCNTL_ALUOP_MASK 0x000000f8
+#define DBALUCNTL_ALUOP_SHIFT 5
+
+// Source Alpha Control (0x00048074)
+#define DBDSTACNTL_ADESTSEL_MASK 0x00000003
+#define DBDSTACNTL_ADESTSEL_SHIFT 0
+#define DBDSTACNTL_ADESTCONSTCNTL_MASK 0x0000000c
+#define DBDSTACNTL_ADESTCONSTCNTL_SHIFT 2
+
+#define DBDSTALPHACONST_CONST1_MASK 0x000000ff
+#define DBDSTALPHACONST_CONST1_SHIFT 0
+#define DBDSTALPHACONST_CONST0_MASK 0x00ff0000
+#define DBDSTALPHACONST_CONST0_SHIFT 16
+
+#define DBSSBDSBCNTL_DSBSEL_MASK 0x00000003
+#define DBSSBDSBCNTL_DSBSEL_SHIFT 0
+#define DBSSBDSBCNTL_DSBCONST_MASK 0x00000004
+#define DBSSBDSBCNTL_DSBCONST_SHIFT 2
+
+
+
+//**************************************************************************
+// SUPPORT FUNCTIONS
+//**************************************************************************
+
+static inline float int_trunc(float x)
+{
+ return (float)(int)x;
+}
+
+static inline uint8_t extract_exp(float x)
+{
+ uint32_t u32 = *reinterpret_cast<uint32_t *>(&x);
+ return (u32 >> 23) & 0xff;
+}
+
+// Convert a regular float to sign-magnitude fixed point
+static int32_t ieee754_to_tefix(float f, int32_t bits)
+{
+ float format = powf(2.0f, bits);
+ float tmp1 = format * 2.0f;
+
+ // Check to see if number is within range
+ float tmp2 = fmodf(fabsf(f), tmp1);
+ float tmp3 = (tmp2 >= format) ? tmp2 : tmp2 + format;
+
+ // Extract the result
+ uint32_t res = *reinterpret_cast<uint32_t *>(&tmp3) & 0x007fffff;
+
+ // What is this?
+ if (tmp2 >= format || tmp3 == tmp1)
+ res |= 0x00800000;
+
+ // Negate
+ if (f < 0.0f)
+ res = -res;
+
+ return res;
+}
+
+static void write_te_reg(uint32_t &reg, uint32_t data, reg_wmode mode)
+{
+ switch (mode)
+ {
+ case REG_WRITE:
+ {
+ reg = data;
+ break;
+ }
+ case REG_SET:
+ {
+ reg |= data;
+ break;
+ }
+ case REG_CLEAR:
+ {
+ reg &= ~data;
+ break;
+ }
+ default:
+ assert_always(false, "Bad register write mode");
+ }
+}
+
+#if 0
+static const char *get_reg_name(uint32_t unit, uint32_t reg)
+{
+ static const char *gc_regs[] =
+ {
+ "TEMasterMode",
+ "Reserved",
+ "TEICntlData",
+ "TEICntl",
+ "TEDCntlData",
+ "TEDCntl",
+ "IWP",
+ "IRP",
+ "IntEn",
+ "IntStat",
+ "Vertex Control",
+ };
+
+ static const char *db_regs[] =
+ {
+ "Snoop",
+ "SuperGenControl",
+ "usergen_ctrl",
+ "Discard Control",
+ "Status",
+ "Int Cntl",
+ "FBClip",
+ "XWinClip",
+ "YWinClip",
+ "DestCntl",
+ "DestBaseAddr",
+ "DestXStride",
+ "SrcCntl",
+ "SrcBaseAddr",
+ "SrcXStride",
+ "SrcOffset",
+ "ZCntl",
+ "ZBaseAddr",
+ "ZOffset",
+ "ZClip",
+ "SSBDSBCntl",
+ "ConstIn",
+ "DBTXTMULTCNTL",
+ "TxtCoefConst0",
+ "TxtCoefConst1",
+ "src_mult_cntl",
+ "SrcCoefConst0",
+ "SrcCoefConst1",
+ "src_mult_cntl",
+ "SrcCoefconst0",
+ "SrcCoefconst1",
+ "ALUCntl",
+ "SrcAlphaCntl",
+ "DestAlphaCntl",
+ "DestAlphaConst",
+ "DitherMatA",
+ "DitherMatB",
+ };
+
+ static const char *es_regs[] =
+ {
+ "ESCntl",
+ "ESCapAddr",
+ "ESCapData",
+ };
+
+ static char buffer[128];
+
+ switch (unit)
+ {
+ case 0:
+ {
+ if (reg < sizeof(gc_regs))
+ {
+ sprintf(buffer, "GC:%s", gc_regs[reg]);
+ return buffer;
+ }
+ break;
+ }
+ case 1:
+ {
+ sprintf(buffer, "SE:????");
+ return buffer;
+ }
+ case 2:
+ {
+ if (reg < sizeof(es_regs))
+ {
+ sprintf(buffer, "ES:%s", es_regs[reg]);
+ return buffer;
+ }
+ break;
+ }
+ case 3:
+ {
+// if (reg < sizeof(tm_regs))
+ {
+ sprintf(buffer, "TM:????");
+ return buffer;
+ }
+ break;
+ }
+ case 4:
+ {
+ if (reg < sizeof(db_regs))
+ {
+ sprintf(buffer, "DB:%s", db_regs[reg]);
+ return buffer;
+ }
+ break;
+ }
+ }
+
+ return "????";
+}
+#endif
+//**************************************************************************
+// TRIANGLE ENGINE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// m2_te_device - constructor
+//-------------------------------------------------
+
+m2_te_device::m2_te_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, M2_TE, tag, owner, clock),
+ m_general_int_handler(*this),
+ m_dfinstr_int_handler(*this),
+ m_iminstr_int_handler(*this),
+ m_listend_int_handler(*this),
+ m_winclip_int_handler(*this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void m2_te_device::device_start()
+{
+ // Find our parent
+ m_bda = downcast<m2_bda_device *>(owner());
+
+ // Resolve callbacks
+ m_general_int_handler.resolve_safe();
+ m_dfinstr_int_handler.resolve_safe();
+ m_iminstr_int_handler.resolve_safe();
+ m_listend_int_handler.resolve_safe();
+ m_winclip_int_handler.resolve_safe();
+
+ // Allocate texture RAM
+ m_tram = auto_alloc_array(machine(), uint32_t, TEXTURE_RAM_WORDS);
+
+ // Allocate PIP RAM
+ m_pipram = auto_alloc_array(machine(), uint32_t, PIP_RAM_WORDS);
+
+ // TODO
+ memset(&m_gc, 0, sizeof(m_gc));
+ memset(&m_se, 0, sizeof(m_se));
+ memset(&m_es, 0, sizeof(m_es));
+ memset(&m_tm, 0, sizeof(m_tm));
+ memset(&m_db, 0, sizeof(m_db));
+
+
+ // Register state for saving
+ save_pointer(NAME(m_tram), TEXTURE_RAM_WORDS);
+ save_pointer(NAME(m_pipram), PIP_RAM_WORDS);
+
+ save_item(NAME(m_gc.m_regs));
+ save_item(NAME(m_se.m_regs));
+ save_item(NAME(m_es.m_regs));
+ save_item(NAME(m_tm.m_regs));
+ save_item(NAME(m_db.m_regs));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void m2_te_device::device_reset()
+{
+ m_state = TE_STOPPED;
+
+ // TODO
+}
+
+
+//-------------------------------------------------
+// device_post_load - device-specific post-load
+//-------------------------------------------------
+
+void m2_te_device::device_post_load()
+{
+
+}
+
+
+
+/***************************************************************************
+ PUBLIC FUNCTIONS
+***************************************************************************/
+
+READ32_MEMBER( m2_te_device::read )
+{
+ uint32_t unit = (offset >> 11) & 7;
+ uint32_t reg = offset & 0x1ff;
+
+ logerror("%s: TE R[%x]\n", machine().describe_context(), 0x00040000 + (offset << 2));
+
+ switch (unit)
+ {
+ case 0:
+ {
+ if (reg < sizeof(m_gc) / 4)
+ return m_gc.m_regs[reg];
+
+ break;
+ }
+ case 1:
+ {
+ if (reg < sizeof(m_se) / 4)
+ return m_se.m_regs[reg];
+
+ break;
+ }
+ case 2:
+ {
+ if (reg < sizeof(m_es) / 4)
+ return m_es.m_regs[reg];
+
+ break;
+ }
+ case 3:
+ {
+ if (reg < 0x400/4)
+ {
+ return m_pipram[reg];
+ }
+ else if ((reg - 0x400) < sizeof(m_tm) / 4)
+ {
+ return m_tm.m_regs[reg];
+ }
+
+ break;
+ }
+ case 4:
+ {
+ if (reg < sizeof(m_db) / 4)
+ return m_db.m_regs[reg];
+
+ break;
+ }
+ }
+
+ logerror("%s: Unknown TE register read from %d:[%x]", machine().describe_context(), unit, reg);
+ return 0;
+}
+
+WRITE32_MEMBER( m2_te_device::write )
+{
+ uint32_t unit = (offset >> 11) & 7;
+ uint32_t reg = offset & 0x1ff;
+ reg_wmode wmode = static_cast<reg_wmode>((offset >> 9) & 3);
+
+// logerror("%s: TE W[%.8x] (%s) %.8x\n", machine().describe_context(), 0x00040000 + (offset << 2), get_reg_name(unit, reg), data);
+
+ switch (unit)
+ {
+ case 0:
+ {
+ switch (reg)
+ {
+ case 0:
+ {
+ master_mode_w(data, wmode);
+ return;
+ }
+ case 0x0c/4:
+ {
+ teicntl_w(data, wmode);
+ return;
+ }
+ case 0x14/4:
+ {
+ tedcntl_w(data, wmode);
+ return;
+ }
+ case 0x24/4:
+ {
+ write_te_reg(m_gc.int_status, data, wmode);
+ update_interrupts();
+ return;
+ }
+ default:
+ {
+ if (reg < sizeof(m_gc) / 4)
+ {
+ write_te_reg(m_gc.m_regs[reg], data, wmode);
+ return;
+ }
+ }
+ }
+ break;
+ }
+ case 1:
+ {
+ if (reg < sizeof(m_se) / 4)
+ {
+ write_te_reg(m_se.m_regs[reg], data, wmode);
+ return;
+ }
+ break;
+ }
+ case 2:
+ {
+ if (reg < sizeof(m_es) / 4)
+ {
+ write_te_reg(m_es.m_regs[reg], data, wmode);
+ return;
+ }
+ break;
+ }
+ case 3:
+ {
+ if (reg < 0x400 / 4)
+ {
+ m_pipram[reg] = data;
+ return;
+ }
+ else if ((reg - 0x400 / 4) < sizeof(m_tm) / 4)
+ {
+ write_te_reg(m_tm.m_regs[reg - 0x400 / 4], data, wmode);
+ return;
+ }
+ break;
+ }
+ case 4:
+ {
+ if (reg < sizeof(m_db) / 4)
+ {
+ write_te_reg(m_db.m_regs[reg], data, wmode);
+ return;
+ }
+ break;
+ }
+ }
+
+ logerror("%s: Unknown TE register write to %d:[%x] with %x\n", machine().describe_context(), unit, reg, data);
+}
+
+
+
+/***************************************************************************
+ PRIVATE FUNCTIONS
+***************************************************************************/
+
+/***************************************************************************
+ INTERRUPTS
+***************************************************************************/
+
+//-------------------------------------------------
+// set_interrupt -
+//-------------------------------------------------
+
+void m2_te_device::set_interrupt(uint32_t mask)
+{
+ m_gc.int_status |= mask;
+ update_interrupts();
+}
+
+
+//-------------------------------------------------
+// update_interrupts -
+//-------------------------------------------------
+
+void m2_te_device::update_interrupts()
+{
+ bool gen_int = ((m_gc.int_status & m_gc.int_enable) & 0x0000ff00) != 0;
+
+ // TODO: ALU status and FB clip are controlled by dest blender
+ m_general_int_handler(gen_int);
+
+ // From DBL (Page 265)
+ // FBClip
+ // WinClip
+ // ZClip
+ // ALUStat
+ // ZFuncStat
+
+ // Page 43
+
+ // PAGE 26
+ m_dfinstr_int_handler((m_gc.int_status >> 8) & 1);
+ m_iminstr_int_handler((m_gc.int_status >> 9) & 1);
+ m_listend_int_handler((m_gc.int_status >> 10) & 1);
+ m_winclip_int_handler((m_gc.int_status >> 11) & 1);
+}
+
+
+
+/***************************************************************************
+ SPECIAL REGISTER WRITES
+***************************************************************************/
+
+//-------------------------------------------------
+// master_mode_w -
+//-------------------------------------------------
+
+void m2_te_device::master_mode_w(uint32_t data, reg_wmode wmode)
+{
+ write_te_reg(m_gc.te_master_mode, data, wmode);
+
+ if (m_gc.te_master_mode & TEMASTER_MODE_RESET)
+ device_reset();
+}
+
+
+//-------------------------------------------------
+// teicntl_w -
+//-------------------------------------------------
+
+void m2_te_device::teicntl_w(uint32_t data, reg_wmode wmode)
+{
+ uint32_t newreg = 0;
+
+ write_te_reg(newreg, data, wmode);
+ write_te_reg(m_gc.te_master_mode, data, wmode);
+
+ if (newreg & TEICNTL_STRT)
+ {
+ m_gc.irp = m_gc.teicntl_data;
+ m_state = TE_RUNNING;
+ execute();
+ }
+ else if (newreg & TEICNTL_RSTRT)
+ {
+ m_state = TE_RUNNING;
+ execute();
+ }
+}
+
+
+//-------------------------------------------------
+// tedcntl_w -
+//-------------------------------------------------
+
+void m2_te_device::tedcntl_w(uint32_t data, reg_wmode wmode)
+{
+ write_te_reg(m_gc.tedcntl, data, wmode);
+
+ if (m_gc.tedcntl & TEDCNTL_SYNC)
+ {
+ // TODO
+ }
+ else if (m_gc.tedcntl & TEDCNTL_PSE)
+ {
+ m_state = TE_PAUSED;
+ }
+ else if (m_gc.tedcntl & TEDCNTL_INT)
+ {
+ set_interrupt(INTSTAT_IMMEDIATE);
+ }
+ else if (m_gc.tedcntl & TEDCNTL_JR)
+ {
+ m_gc.irp += m_gc.tedcntl_data;
+ }
+ else if (m_gc.tedcntl & TEDCNTL_JA)
+ {
+ m_gc.irp = m_gc.tedcntl_data;
+ }
+ else if (m_gc.tedcntl & TEDCNTL_TLD)
+ {
+ load_texture();
+ }
+}
+
+
+
+/***************************************************************************
+ VERTEX PROCESSING
+***************************************************************************/
+
+//-------------------------------------------------
+// add_vertex -
+//-------------------------------------------------
+
+void m2_te_device::add_vertex(const se_vtx &vtx, uint32_t flags)
+{
+ uint32_t tsort;
+ uint32_t vcnt;
+
+ if (flags & VTX_FLAG_NEW)
+ {
+ // Reset state for a new triangle
+ tsort = 0;
+ vcnt = 0;
+ }
+ else
+ {
+ // Continue current triangle
+ tsort = m_se.vertex_state & VERTEXSTATE_TSORT_MASK;
+ vcnt = (m_se.vertex_state & VERTEXSTATE_VCNT_MASK) >> VERTEXSTATE_VCNT_SHIFT;
+ }
+
+ if (vcnt < 3)
+ {
+ // Add vertex to incomplete triangle
+ m_se.vertices[vcnt++] = vtx;
+
+ // Are we now complete?
+ if (vcnt == 3)
+ tsort = VERTEXSTATE_TSORT_OMN;
+ }
+ else
+ {
+ // Replace an existing vertex
+ if (flags & VTX_FLAG_RM)
+ {
+ // Triangle fan mode
+ switch (tsort)
+ {
+ case VERTEXSTATE_TSORT_OMN: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_ONM; break;
+ case VERTEXSTATE_TSORT_MNO: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NMO; break;
+ case VERTEXSTATE_TSORT_ONM: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_OMN; break;
+ case VERTEXSTATE_TSORT_NOM: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_MON; break;
+ case VERTEXSTATE_TSORT_MON: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NOM; break;
+ case VERTEXSTATE_TSORT_NMO: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_MNO; break;
+ }
+ }
+ else
+ {
+ // Triangle strip mode
+ switch (tsort)
+ {
+ case VERTEXSTATE_TSORT_OMN: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NOM; break;
+ case VERTEXSTATE_TSORT_MNO: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_OMN; break;
+ case VERTEXSTATE_TSORT_ONM: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NMO; break;
+ case VERTEXSTATE_TSORT_NOM: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_MNO; break;
+ case VERTEXSTATE_TSORT_MON: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_ONM; break;
+ case VERTEXSTATE_TSORT_NMO: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_MON; break;
+ }
+ }
+
+ }
+
+ // Update fields
+ m_se.vertex_state = (vcnt << VERTEXSTATE_VCNT_SHIFT) | tsort;
+
+ // Do we have three valid vertices?
+ if (vcnt == 3)
+ {
+ // Send the triangle to the setup engine
+ setup_triangle(flags);
+ }
+}
+
+
+//-------------------------------------------------
+// calculate_slope -
+//-------------------------------------------------
+
+void m2_te_device::calculate_slope(const slope_params &sp, float q1, float q2, float q3, float &slope_out, float &ddx_out)
+{
+ float detx = q1 * sp.y23 + q2 * sp.y31 + q3 * sp.y12;
+ float dety = q1 * sp.x23 + q2 * sp.x31 + q3 * sp.x12;
+ float detxy = sp.xstep_long * detx - dety;
+
+ slope_out = detxy * sp.iAria;
+ ddx_out = detx * sp.iAria;
+}
+
+
+//-------------------------------------------------
+// log_triangle -
+//-------------------------------------------------
+
+void m2_te_device::log_triangle(uint32_t flags)
+{
+ logerror("[Triangle]\n");
+
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ char s[64];
+ char t[64];
+ char p[64];
+
+ s[0] = '\0';
+ t[0] = '\0';
+ p[0] = '\0';
+
+ const se_vtx &vtx = m_se.vertices[i];
+
+ if (flags & VTX_FLAG_SHAD)
+ sprintf(s, "COLR[R:%.6f G:%.6f B:%.6f A:%.6f]", vtx.r, vtx.g, vtx.b, vtx.a);
+
+ if (flags & VTX_FLAG_TEXT)
+ sprintf(t, "TEXT[UW:%.6f VW:%.6f]", vtx.uw, vtx.vw);
+
+ if (flags & VTX_FLAG_PRSP)
+ sprintf(p, "PRSP[W:%.6f]", vtx.w);
+
+ logerror("V%d: X:%.6f Y:%.6f %s %s %s\n", i, vtx.x, vtx.y, s, t, p);
+ }
+}
+
+
+//-------------------------------------------------
+// setup_triangle -
+//-------------------------------------------------
+
+void m2_te_device::setup_triangle(uint32_t flags)
+{
+// log_triangle(flags);
+
+ se_vtx va = m_se.vertices[0];
+ se_vtx vb = m_se.vertices[1];
+ se_vtx vc = m_se.vertices[2];
+
+ // Truncate XY coordinates to integers
+ va.x = int_trunc(va.x);
+ vb.x = int_trunc(vb.x);
+ vc.x = int_trunc(vc.x);
+
+ va.y = int_trunc(va.y);
+ vb.y = int_trunc(vb.y);
+ vc.y = int_trunc(vc.y);
+
+
+ // Scale and truncate colors
+ if (flags & VTX_FLAG_SHAD)
+ {
+ va.r = int_trunc(va.r * 255.0f);
+ va.g = int_trunc(va.g * 255.0f);
+ va.b = int_trunc(va.b * 255.0f);
+ va.a = int_trunc(va.a * 255.0f);
+
+ vb.r = int_trunc(vb.r * 255.0f);
+ vb.g = int_trunc(vb.g * 255.0f);
+ vb.b = int_trunc(vb.b * 255.0f);
+ vb.a = int_trunc(vb.a * 255.0f);
+
+ vc.r = int_trunc(vc.r * 255.0f);
+ vc.g = int_trunc(vc.g * 255.0f);
+ vc.b = int_trunc(vc.b * 255.0f);
+ vc.a = int_trunc(vc.a * 255.0f);
+ }
+
+ // Sort the vertices into top, middle and bottom
+ uint32_t a = 0;
+
+ if ((va.y - vb.y) < 0.0f) a |= 4;
+ if ((vb.y - vc.y) < 0.0f) a |= 2;
+ if ((vc.y - va.y) < 0.0f) a |= 1;
+
+ const se_vtx *v1 = NULL;
+ const se_vtx *v2 = NULL;
+ const se_vtx *v3 = NULL;
+
+ switch (a)
+ {
+ case 1: v1 = &vc; v2 = &vb; v3 = &va; break;
+ case 2: v1 = &vb; v2 = &va; v3 = &vc; break;
+ case 3: v1 = &vb; v2 = &vc; v3 = &va; break;
+ case 4: v1 = &va; v2 = &vc; v3 = &vb; break;
+ case 5: v1 = &vc; v2 = &va; v3 = &vb; break;
+ case 6: v1 = &va; v2 = &vb; v3 = &vc; break;
+ default:
+ return; // Reject degenerates
+ }
+
+
+ // Determine the W range for depth and texture values
+ uint32_t wrange = 0;
+
+ if (flags & VTX_FLAG_PRSP)
+ {
+ const uint8_t exp_zero = 0x7f;
+ const uint8_t wexp0 = exp_zero - 3;
+ const uint8_t wexp1 = exp_zero - 6;
+ const uint8_t wexp2 = exp_zero - 9;
+
+ uint8_t w1exp = extract_exp(v1->w);
+ uint8_t w2exp = extract_exp(v2->w);
+ uint8_t w3exp = extract_exp(v3->w);
+
+ if (w1exp >= wexp0 || w2exp >= wexp0 || w3exp >= wexp0)
+ wrange = 0;
+ else if (w1exp >= wexp1 || w2exp >= wexp1 || w3exp >= wexp1)
+ wrange = 1;
+ else if (w1exp >= wexp2 || w2exp >= wexp2 || w3exp >= wexp2)
+ wrange = 2;
+ else
+ wrange = 3;
+ }
+
+ // Calculate the coordinate deltas
+ float x12 = v1->x - v2->x;
+ float x23 = v2->x - v3->x;
+ float x31 = v3->x - v1->x;
+ float y12 = v1->y - v2->y;
+ float y23 = v2->y - v3->y;
+ float y31 = v3->y - v1->y;
+
+ // Calculate the triangle area
+ float aria = v1->x * y23 + v2->x * y31 + v3->x * y12;
+
+ // Reject degenerates
+ if (aria == 0.0f)
+ return;
+
+ float iaria = 1.0f / aria;
+
+ // Determine scan direction
+ bool scan_lr = aria > 0.0f;
+
+ // Calculate vertex slopes
+ float abs_y12 = fabs(y12);
+ float abs_y23 = fabs(y23);
+ float abs_y31 = fabs(y31);
+
+
+ // Avoid division by zero
+ float xslope_0 = (abs_y12 > 0.0f) ? (-x12 / abs_y12) : 0.0f;
+ float xslope_1 = (abs_y23 > 0.0f) ? (-x23 / abs_y23) : 0.0f;
+ float xslope_long = (abs_y31 > 0.0f) ? (x31 / abs_y31) : 0.0f;
+
+
+ // Calculate x steps
+ float xstep_long;
+ float xstep_0;
+ float xstep_1;
+
+ if (scan_lr)
+ {
+ xstep_long = floor(xslope_long);
+ xstep_0 = ceil(xslope_0);
+ xstep_1 = ceil(xslope_1);
+ }
+ else
+ {
+ xstep_long = ceil(xslope_long);
+ xstep_0 = floor(xslope_0);
+ xstep_1 = floor(xslope_1);
+ }
+
+ float xystep_0 = x12 - xstep_0 * y12;
+ float xystep_1 = x23 - xstep_1 * y23;
+ float xystep_long = x31 - xstep_long * y31;
+
+ float dy_0 = -y12;
+ float dy_1 = -y23;
+ float dy_long = -y31;
+
+
+ // Calculate color and texture slopes
+ slope_params sparams = { y23, y31, y12, x23, x31, x12, xstep_long, iaria };
+
+ float r_slope = 0.0f, r_ddx = 0.0f;
+ float g_slope = 0.0f, g_ddx = 0.0f;
+ float b_slope = 0.0f, b_ddx = 0.0f;
+ float a_slope = 0.0f, a_ddx = 0.0f;
+ float w_slope = 0.0f, w_ddx = 0.0f;
+ float uw_slope = 0.0f, uw_ddx = 0.0f;
+ float vw_slope = 0.0f, vw_ddx = 0.0f;
+
+ if (flags & VTX_FLAG_SHAD)
+ {
+ calculate_slope(sparams, v1->r, v2->r, v3->r, r_slope, r_ddx);
+ calculate_slope(sparams, v1->g, v2->g, v3->g, g_slope, g_ddx);
+ calculate_slope(sparams, v1->b, v2->b, v3->b, b_slope, b_ddx);
+ calculate_slope(sparams, v1->a, v2->a, v3->a, a_slope, a_ddx);
+ }
+
+ if (flags & VTX_FLAG_TEXT)
+ {
+ calculate_slope(sparams, v1->uw, v2->uw, v3->uw, uw_slope, uw_ddx);
+ calculate_slope(sparams, v1->vw, v2->vw, v3->vw, vw_slope, vw_ddx);
+ }
+
+ if (flags & VTX_FLAG_PRSP)
+ {
+ calculate_slope(sparams, v1->w, v2->w, v3->w, w_slope, w_ddx);
+ }
+
+ const uint32_t textbits = text_bits[wrange];
+ const uint32_t depthbits = depth_bits[wrange];
+
+ // Convert everything to fixed point and pass to the edge walker
+
+ /*
+ NOT SURE THESE ARE RIGHT. See P209
+
+ XY 12.0
+ SL s12.0
+ RGBA 9.0
+ RGBA SLOPES = s9.11
+ TEX: 11.13
+ DEPTH: 1.23
+ TEX SLOPES: s11.13
+ DEPTH SLOPES: s1.23
+ AREA : s23.0
+
+ Numbers output to the edge walker are 24 bits
+
+ IEE: 1.8.23
+ BDA: 1.7.24 (includes hidden bit)
+
+ However, we're using 23 bits.
+ */
+
+
+ // XY: 0000 0000 0iii iiii iiii 0000 0000 0000
+ // Colors: 0000 0000 0iii iiii ifff ffff ffff 0000
+ // UV:
+ // W: 0000 0000 0iii iiii iiii iiii iiii iiii
+
+
+ // Converted numbers are left-aligned into the mantissa
+ // However, we want them right-aligned for convenience
+ // TODO: Is there a better way to do this?
+ m_es.x1 = ieee754_to_tefix(v1->x, xy_bits) >> xy_rshift;
+ m_es.y1 = ieee754_to_tefix(v1->y, xy_bits) >> xy_rshift;
+ m_es.x2 = ieee754_to_tefix(v2->x, xy_bits) >> xy_rshift;
+ m_es.y2 = ieee754_to_tefix(v2->y, xy_bits) >> xy_rshift;
+ m_es.y3 = ieee754_to_tefix(v3->y, xy_bits) >> xy_rshift;
+
+ m_es.xstep_0 = ieee754_to_tefix(xstep_0, xy_bits) >> xy_rshift;
+ m_es.xstep_1 = ieee754_to_tefix(xstep_1, xy_bits) >> xy_rshift;
+ m_es.xstep_long = ieee754_to_tefix(xstep_long, xy_bits) >> xy_rshift;
+ m_es.xystep_0 = ieee754_to_tefix(xystep_0, xy_bits) >> xy_rshift;
+ m_es.xystep_1 = ieee754_to_tefix(xystep_1, xy_bits) >> xy_rshift;
+ m_es.xystep_long = ieee754_to_tefix(xystep_long, xy_bits) >> xy_rshift;
+ m_es.dy_0 = ieee754_to_tefix(dy_0, xy_bits) >> xy_rshift;
+ m_es.dy_1 = ieee754_to_tefix(dy_1, xy_bits) >> xy_rshift;
+ m_es.dy_long = ieee754_to_tefix(dy_long, xy_bits) >> xy_rshift;
+
+ m_es.r1 = ieee754_to_tefix(v1->r, color_bits) >> color_rshift;
+ m_es.g1 = ieee754_to_tefix(v1->g, color_bits) >> color_rshift;
+ m_es.b1 = ieee754_to_tefix(v1->b, color_bits) >> color_rshift;
+ m_es.a1 = ieee754_to_tefix(v1->a, color_bits) >> color_rshift;
+ m_es.ddx_r = ieee754_to_tefix(r_ddx, color_bits) >> color_rshift;
+ m_es.ddx_g = ieee754_to_tefix(g_ddx, color_bits) >> color_rshift;
+ m_es.ddx_b = ieee754_to_tefix(b_ddx, color_bits) >> color_rshift;
+ m_es.ddx_a = ieee754_to_tefix(a_ddx, color_bits) >> color_rshift;
+ m_es.slope_r = ieee754_to_tefix(r_slope, color_bits) >> color_rshift;
+ m_es.slope_g = ieee754_to_tefix(g_slope, color_bits) >> color_rshift;
+ m_es.slope_b = ieee754_to_tefix(b_slope, color_bits) >> color_rshift;
+ m_es.slope_a = ieee754_to_tefix(a_slope, color_bits) >> color_rshift;
+
+ // No need to shift these
+ m_es.uw1 = ieee754_to_tefix(v1->uw, textbits);
+ m_es.vw1 = ieee754_to_tefix(v1->vw, textbits);
+ m_es.w1 = ieee754_to_tefix(v1->w, depthbits);
+ m_es.ddx_uw = ieee754_to_tefix(uw_ddx, textbits);
+ m_es.ddx_vw = ieee754_to_tefix(vw_ddx, textbits);
+ m_es.ddx_w = ieee754_to_tefix(w_ddx, depthbits);
+ m_es.slope_uw = ieee754_to_tefix(uw_slope, textbits);
+ m_es.slope_vw = ieee754_to_tefix(vw_slope, textbits);
+ m_es.slope_w = ieee754_to_tefix(w_slope, depthbits);
+
+ m_es.r2l = !scan_lr;
+
+#if TEST_TIMING
+ g_statistics[STAT_TRIANGLES_PROCESSED]++;
+#endif
+
+ // Proceed to walk the edges
+ walk_edges(wrange);
+}
+
+static inline bool ins(bool lr, int32_t v)
+{
+ return lr ? v <= 0 : v >= 0;
+}
+
+static inline bool ein(bool lr, int32_t v)
+{
+ return lr ? v < 0 : v > 0;
+}
+
+static const uint8_t m_nr_rom[128] =
+{
+ 127, 125, 123, 121, 119, 118,
+ 116, 114, 112, 110, 109, 107,
+ 105, 104, 102, 100, 99, 97,
+ 96, 94, 93, 91, 90, 88,
+ 87, 86, 84, 83, 81, 80,
+ 79, 78, 76, 75, 74, 73,
+ 71, 70, 69, 68, 67, 65,
+ 64, 63, 62, 61, 60, 59,
+ 58, 57, 56, 55, 54, 53,
+ 52, 51, 50, 49, 48, 47,
+ 46, 45, 44, 43, 42, 41,
+ 40, 40, 39, 38, 37, 36,
+ 35, 35, 34, 33, 32, 31,
+ 31, 30, 29, 28, 28, 27,
+ 26, 25, 25, 24, 23, 23,
+ 22, 21, 21,20, 19, 19,
+ 18, 17, 17, 16, 15, 15,
+ 14, 13, 13, 12, 12, 11,
+ 11, 10, 9, 9, 8, 8,
+ 7, 7, 6, 5, 5, 4,
+ 4, 3, 3, 2, 2, 1,
+ 1, 0
+};
+
+
+//-------------------------------------------------
+// nr_invert - Newton Rhapson reciprocal
+//-------------------------------------------------
+
+uint32_t nr_invert(uint32_t num, uint32_t & shift_amount)
+{
+ uint32_t original;
+ uint32_t first_guess;
+ uint32_t m;
+ uint32_t shfnum;
+
+ // TODO: Unconfirmed but seems sensible
+ if (num == 0)
+ {
+ shift_amount = 0;
+ return 0;
+ }
+
+ shift_amount = -1;
+ while ((num << ++shift_amount) < 0x800000);
+
+ shfnum = num << shift_amount;
+ original = shfnum >> 8;
+ first_guess = m_nr_rom[(shfnum >> 16) & ((1 << 7) - 1)];
+ first_guess = first_guess + 128;
+ m = first_guess * original;
+ m = (1 << 24) - m;
+ m = m >> 3;
+ m = first_guess * m;
+ m = m >> 8;
+
+ return m;
+}
+
+
+//-------------------------------------------------
+// clamp -
+//-------------------------------------------------
+
+uint32_t clamp(int32_t v, int32_t min, int32_t max)
+{
+ if (v < min)
+ return min;
+ else if (v > max)
+ return max;
+
+ return v;
+}
+
+
+//-------------------------------------------------
+// walk_edges -
+//-------------------------------------------------
+
+void m2_te_device::walk_edges(uint32_t wrange)
+{
+ bool dsp_off = m_es.es_cntl & ESCNTL_DSPOFF;
+ bool du_scan = m_es.es_cntl & ESCNTL_DUSCAN;
+ bool omit_right = true;
+ bool scan_lr = m_es.r2l == false;
+
+ uint32_t cf_long = 0;
+ uint32_t cf_short = 0;
+ uint32_t xystep;
+ uint32_t xstep;
+ uint32_t dy;
+ uint32_t xs;
+ uint32_t xe;
+
+ int32_t r, g, b, a;
+ int32_t uw, vw;
+ int32_t w;
+
+ // Determine starting values
+ uint32_t y = m_es.y1;
+
+ // Flat-top triangles are a special case
+ if (m_es.y1 == m_es.y2)
+ {
+ xystep = m_es.xystep_1;
+ xstep = m_es.xstep_1;
+ dy = m_es.dy_1;
+
+ if (scan_lr ^ (m_es.x1 < m_es.x2))
+ {
+ // TODO: Is this possible?
+ assert_always(false, "SPECIAL CASE: WHAT DO?");
+ r = m_es.r1; // Where do the colors come from?
+ g = m_es.g1;
+ b = m_es.b1;
+ a = m_es.a1;
+ uw = m_es.uw1;
+ vw = m_es.vw1;
+ w = m_es.w1;
+
+ xs = m_es.x2;
+ xe = m_es.x1;
+ }
+ else
+ {
+ r = m_es.r1;
+ g = m_es.g1;
+ b = m_es.b1;
+ a = m_es.a1;
+ uw = m_es.uw1;
+ vw = m_es.vw1;
+ w = m_es.w1;
+
+ xs = m_es.x1;
+ xe = m_es.x2;
+ }
+ }
+ else
+ {
+ // Regular triangles
+ xystep = m_es.xystep_0;
+ xstep = m_es.xstep_0;
+ dy = m_es.dy_0;
+ r = m_es.r1;
+ g = m_es.g1;
+ b = m_es.b1;
+ a = m_es.a1;
+ uw = m_es.uw1;
+ vw = m_es.vw1;
+ w = m_es.w1;
+
+ xs = m_es.x1;
+ xe = xs;
+ }
+
+ do
+ {
+ // Render the pixels from this span
+ walk_span(wrange, omit_right, y, xs, xe, r, g, b, a, uw, vw, w);
+
+ // Now update the values
+ omit_right = false;
+ cf_short += xystep;
+ cf_long += m_es.xystep_long;
+
+ bool step_back = false;
+
+ if (scan_lr)
+ {
+ xs += m_es.xstep_long;
+ xe += xstep;
+
+ if (!ins(scan_lr, cf_long))
+ {
+ step_back = true;
+ cf_long += m_es.dy_long;
+ xs += xy_one;
+ }
+
+ if (dsp_off ? !ins(scan_lr, cf_short) : !ein(scan_lr, cf_short))
+ {
+ cf_short -= dy;
+ xe -= xy_one;
+ }
+ }
+ else
+ {
+ xe += xstep;
+ xs += m_es.xstep_long;
+
+ if (!ins(scan_lr, cf_short))
+ {
+ cf_short += dy;
+ xe += xy_one;
+ }
+
+ if (dsp_off ? !ins(scan_lr, cf_long) : !ein(scan_lr, cf_long))
+ {
+ step_back = true;
+ cf_long -= m_es.dy_long;
+ xs -= xy_one;
+ }
+ }
+
+ // Update the color values
+ if (!(m_gc.te_master_mode & TEMASTER_MODE_DSHADE))
+ {
+ if (scan_lr)
+ {
+ r += step_back ? m_es.slope_r + m_es.ddx_r : m_es.slope_r;
+ g += step_back ? m_es.slope_g + m_es.ddx_g : m_es.slope_g;
+ b += step_back ? m_es.slope_b + m_es.ddx_b : m_es.slope_b;
+ a += step_back ? m_es.slope_a + m_es.ddx_a : m_es.slope_a;
+ }
+ else
+ {
+ r += step_back ? m_es.slope_r - m_es.ddx_r : m_es.slope_r;
+ g += step_back ? m_es.slope_g - m_es.ddx_g : m_es.slope_g;
+ b += step_back ? m_es.slope_b - m_es.ddx_b : m_es.slope_b;
+ a += step_back ? m_es.slope_a - m_es.ddx_a : m_es.slope_a;
+ }
+
+ // Clamp to 8.11
+ r = clamp(r, 0, 0x0007ffff);
+ g = clamp(g, 0, 0x0007ffff);
+ b = clamp(b, 0, 0x0007ffff);
+ a = clamp(a, 0, 0x0007ffff);
+ }
+
+ if (!(m_es.es_cntl & TEMASTER_MODE_DTEXT))
+ {
+ if (scan_lr)
+ {
+ uw += step_back ? m_es.slope_uw + m_es.ddx_uw : m_es.slope_uw;
+ vw += step_back ? m_es.slope_vw + m_es.ddx_vw : m_es.slope_vw;
+ }
+ else
+ {
+ uw += step_back ? m_es.slope_uw - m_es.ddx_uw : m_es.slope_uw;
+ vw += step_back ? m_es.slope_vw - m_es.ddx_vw : m_es.slope_vw;
+ }
+
+ // Clamp to 10.13
+ uw = clamp(uw, 0, 0x007fffff);
+ vw = clamp(vw, 0, 0x007fffff);
+ }
+
+ if (!(m_es.es_cntl & ESCNTL_PERSPECTIVEOFF))
+ {
+ if (scan_lr)
+ w += step_back ? m_es.slope_w + m_es.ddx_w : m_es.slope_w;
+ else
+ w += step_back ? m_es.slope_w - m_es.ddx_w : m_es.slope_w;
+
+ // Clamp to 0.23
+ w = clamp(w, 0, 0x007fffff);
+ }
+
+ // Update Y
+ uint32_t next_y = y + (du_scan ? -xy_one : xy_one);
+
+ if (next_y == m_es.y2)
+ {
+ cf_short = 0;
+ xystep = m_es.xystep_1;
+ xstep = m_es.xstep_1;
+ dy = m_es.dy_1;
+ xe = m_es.x2;
+
+ if (scan_lr)
+ omit_right = true;
+ }
+
+ y = next_y;
+
+ } while (y != m_es.y3);
+}
+
+
+
+//-------------------------------------------------
+// texcoord_gen -
+//-------------------------------------------------
+
+void m2_te_device::texcoord_gen(uint32_t wrange, uint32_t uw, uint32_t vw, uint32_t w,
+ uint32_t & uo, uint32_t & vo, uint32_t & wo)
+{
+
+ // Perspective correction
+ if (!(m_es.es_cntl & ESCNTL_PERSPECTIVEOFF))
+ {
+ uint32_t wshift;
+
+ // Calculate the inverse of 1/w. Output is 0.20
+ uint32_t winv = nr_invert(w, wshift);
+
+ // 10.13 normalize then reduce to 10.6
+ // Normalization occurs by detecting leading zeroes and
+ // left-shifting until 1 in MSB
+
+ uint32_t uwshift = 0;
+ uint32_t vwshift = 0;
+
+ while ((uw < 0x00400000) && uwshift < 7)
+ {
+ uw <<= 1;
+ ++uwshift;
+ }
+
+ while ((vw < 0x00400000) && vwshift < 7)
+ {
+ vw <<= 1;
+ ++vwshift;
+ }
+
+ uint32_t normalized_uw = uw >> 7;
+ uint32_t normalized_vw = vw >> 7;
+
+ // 10.6 * 0.20 = 10.26
+ uint64_t ur = (uint64_t)normalized_uw * winv;
+ uint64_t vr = (uint64_t)normalized_vw * winv;
+
+ // De-normalize
+ if (uwshift > wshift)
+ ur >>= (uwshift - wshift);
+ else
+ ur <<= (wshift - uwshift);
+
+ if (vwshift > wshift)
+ vr >>= (vwshift - wshift);
+ else
+ vr <<= (wshift - vwshift);
+
+ // Reduce from 10.26 to 10.6
+ uo = ur >> 20;
+ vo = vr >> 20;
+ }
+ else
+ {
+ // Reduce from 10.13 to 10.6
+ // TODO: Is this actually correct?
+ uo = uw >> (7 + (10 - text_bits[wrange]));
+ vo = vw >> (7 + (10 - text_bits[wrange]));
+ }
+
+ // Output to texture mapper is 10.4
+ uo = uo >> 2;
+ vo = vo >> 2;
+}
+
+
+//-------------------------------------------------
+// lod_calc -
+//-------------------------------------------------
+
+uint32_t m2_te_device::lod_calc(uint32_t u0, uint32_t v0, uint32_t u1, uint32_t v1)
+{
+ return 0;
+}
+
+
+//-------------------------------------------------
+// get_tram_bitdepth
+//-------------------------------------------------
+
+uint32_t m2_te_device::get_tram_bitdepth()
+{
+ // TODO: Could cache this
+ const uint32_t tex_type = m_tm.tex_exptype;
+
+ uint32_t bitdepth = 0;
+
+ if (tex_type & TXTEXPFORM_COLORON)
+ bitdepth += (tex_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT;
+ if (tex_type & TXTEXPFORM_ALPHAON)
+ bitdepth += (tex_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT;
+ if (tex_type & TXTEXPFORM_SSBON)
+ ++bitdepth;
+
+ return bitdepth;
+}
+
+
+//-------------------------------------------------
+// get_texture_color -
+//-------------------------------------------------
+void m2_te_device::get_texture_color(uint32_t u, uint32_t v, uint32_t lod,
+ uint32_t & r, uint32_t & g, uint32_t & b, uint32_t & a, uint32_t & s)
+{
+ uint32_t texaddr;
+ uint32_t texbit;
+ uint32_t texdepth = get_tram_bitdepth();
+
+ // TODO: Multiple LODs
+ uint32_t filter = (m_tm.tex_addr_cntl >> TXTADDRCNTL_R12FILTERSEL_SHIFT) & TXTADDRCNTL_FILTERSEL_MASK;
+
+ switch (filter)
+ {
+ case TXTADDRCNTL_FILTERSEL_POINT:
+ case TXTADDRCNTL_FILTERSEL_LINEAR: // TODO
+ {
+ addr_calc(u, v, lod, texaddr, texbit, texdepth);
+ get_texel(texaddr, texbit, texdepth, r, g, b, a, s);
+ break;
+ }
+
+ case TXTADDRCNTL_FILTERSEL_BILINEAR:
+ case TXTADDRCNTL_FILTERSEL_QUASITRI: // TODO
+ {
+ // See p170 for implemenation
+ uint32_t r0, g0, b0, a0, s0;
+ uint32_t r1, g1, b1, a1, s1;
+ uint32_t r2, g2, b2, a2, s2;
+ uint32_t r3, g3, b3, a3, s3;
+
+ addr_calc(u, v, lod, texaddr, texbit, texdepth);
+ get_texel(texaddr, texbit, texdepth, r0, g0, b0, a0, s0);
+ addr_calc(u + 0x10, v, lod, texaddr, texbit, texdepth);
+ get_texel(texaddr, texbit, texdepth, r1, g1, b1, a1, s1);
+ addr_calc(u, v + 0x10, lod, texaddr, texbit, texdepth);
+ get_texel(texaddr, texbit, texdepth, r2, g2, b2, a2, s2);
+ addr_calc(u + 0x10, v + 0x10, lod, texaddr, texbit, texdepth);
+ get_texel(texaddr, texbit, texdepth, r3, g3, b3, a3, s3);
+
+ // LERP
+ uint32_t ufrac = u & 0xf;
+ uint32_t vfrac = v & 0xf;
+ uint32_t om_ufrac = 0x10 - ufrac;
+ uint32_t om_vfrac = 0x10 - vfrac;
+
+ // This is probably wrong
+ s0 = s0 * 0xff;
+ s1 = s1 * 0xff;
+ s2 = s2 * 0xff;
+ s3 = s3 * 0xff;
+
+ // 8.0 * 1.4 + 8.0 * 1.4 = 9.4
+ uint32_t rl = r0 * (om_ufrac) + r1 * ufrac;
+ uint32_t gl = g0 * (om_ufrac) + g1 * ufrac;
+ uint32_t bl = b0 * (om_ufrac) + b1 * ufrac;
+ uint32_t al = a0 * (om_ufrac) + a1 * ufrac;
+ uint32_t sl = s0 * (om_ufrac) + s1 * ufrac;
+
+ uint32_t ru = r2 * (om_ufrac) + r3 * ufrac;
+ uint32_t gu = g2 * (om_ufrac) + g3 * ufrac;
+ uint32_t bu = b2 * (om_ufrac) + b3 * ufrac;
+ uint32_t au = a2 * (om_ufrac) + a3 * ufrac;
+ uint32_t su = s2 * (om_ufrac) + s3 * ufrac;
+
+ // 9.4 * 0.4 + 9.4 * 0.4 = 10.8?
+ r = (rl * om_vfrac + ru * vfrac) >> 8;
+ g = (gl * om_vfrac + gu * vfrac) >> 8;
+ b = (bl * om_vfrac + bu * vfrac) >> 8;
+ a = (al * om_vfrac + au * vfrac) >> 8;
+
+ s = ((sl * om_vfrac + su * vfrac) >> 10) ? 1 : 0;
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// addr_calc -
+//-------------------------------------------------
+void m2_te_device::addr_calc(uint32_t u, uint32_t v, uint32_t lod,
+ uint32_t & texaddr, uint32_t & texbit, uint32_t & tdepth)
+{
+ uint32_t u_mask = (m_tm.uv_mask & TXTUVMASK_UMASK_MASK) >> TXTUVMASK_UMASK_SHIFT;
+ uint32_t v_mask = (m_tm.uv_mask & TXTUVMASK_VMASK_MASK) >> TXTUVMASK_VMASK_SHIFT;
+ uint32_t u_max = (m_tm.uv_max & TXTUVMAX_UMAX_MASK) >> TXTUVMAX_UMAX_SHIFT;
+ uint32_t v_max = (m_tm.uv_max & TXTUVMAX_VMAX_MASK) >> TXTUVMAX_VMAX_SHIFT;
+
+ // Remove fractional parts (10.0)
+ uint32_t u0 = u >> 4;
+ uint32_t v0 = v >> 4;
+
+ u0 = u0 & u_mask;
+ v0 = v0 & v_mask;
+
+ u_max &= u_mask;
+ v_max &= v_mask;
+
+ u0 = clamp(u0, 0, u_max);
+ v0 = clamp(v0, 0, v_max);
+
+ // LOD
+ uint32_t lodmax = m_tm.tex_addr_cntl & TXTADDRCNTL_LODMAX_MASK;
+ uint32_t lod_shift = (lodmax - lod) & 3;
+
+ // 20.0
+ uint32_t voffset = (v0 * (u_max + 1)) << lod_shift;
+ uint32_t offset = (voffset + u0) >> lod_shift;
+
+ offset = offset * tdepth;
+
+ uint32_t base_addr = 0;
+
+ switch (lod)
+ {
+ case 0: base_addr = m_tm.tex_lod_base0; break;
+ case 1: base_addr = m_tm.tex_lod_base1; break;
+ case 2: base_addr = m_tm.tex_lod_base2; break;
+ case 3: base_addr = m_tm.tex_lod_base3; break;
+ }
+
+ uint32_t adsum = (base_addr << 3) + offset;
+
+ texaddr = adsum / 32;
+ texbit = adsum & 31;
+}
+
+
+void m2_te_device::get_texel(uint32_t tex_addr, uint32_t tex_bit, uint32_t tdepth,
+ uint32_t & r, uint32_t & g, uint32_t & b, uint32_t & a, uint32_t & ssb)
+{
+ const uint32_t tex_type = m_tm.tex_exptype;
+
+ uint8_t rtex, gtex, btex, atex;
+ uint8_t ssbtex;
+
+ uint8_t rpip, gpip, bpip, apip;
+ uint8_t ssbpip;
+
+ // Page 127
+ // See M2_2_7_part3_clt_ocrc.pdf page 95 for better expl.
+
+ uint32_t tram_data = m_tram[tex_addr];
+
+#if TEST_TIMING
+ g_statistics[STAT_TEXEL_READS]++;
+#endif
+
+
+ // Align the texel
+ uint32_t texel = tram_data >> (tex_bit & ~7);
+
+ // Align within byte (TODO: Fix for 32-bits!)
+ texel >>= (tex_bit ^ (8 - tdepth)) & 7;
+
+ uint32_t c_depth = (tex_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT;
+ uint32_t a_depth = (tex_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT;
+ uint32_t i_depth = c_depth;
+
+ // Color is either sourced from tram or PIP
+ if (tex_type & TXTEXPFORM_LITERAL)
+ {
+ if (tex_type & TXTEXPFORM_COLORON)
+ {
+ // Literal can only be 32-bit or 16bpp
+ uint32_t mask = (1 << c_depth) - 1;
+
+ btex = texel & mask;
+ texel >>= c_depth;
+ gtex = texel & mask;
+ texel >>= c_depth;
+ rtex = texel & mask;
+ texel >>= c_depth;
+ }
+ else
+ {
+ rtex = gtex = btex = 0;
+ }
+ }
+ else
+ {
+ rtex = gtex = btex = 0;
+ }
+
+ if (tex_type & TXTEXPFORM_INDEXON)
+ {
+ uint32_t pipidx = texel & ((1 << i_depth) - 1);
+ uint32_t pipaddr = (m_tm.tex_pip_cntl & TXTPIPCNTL_INDEX_OFFSET) + pipidx;
+
+ uint32_t pipval = m_pipram[pipaddr & 0xff];
+
+ // Color, alpha and SSB always present in PIP
+ bpip = pipval & 0xff;
+ gpip = (pipval >> 8) & 0xff;
+ rpip = (pipval >> 16) & 0xff;
+ apip = (pipval >> 24) & 0x7f;
+ ssbpip = pipval >> 31;
+
+ texel >>= i_depth;
+ }
+ else
+ {
+ // Nothing coming from the PIP
+ rpip = gpip = bpip = 0;
+ apip = ssbpip = 0;
+ }
+
+ // Alpha and SSB could be present
+ if (tex_type & TXTEXPFORM_ALPHAON)
+ {
+ uint32_t mask = (1 << a_depth) - 1;
+
+ atex = texel & mask;
+
+ // Need to expand alpha if 4-bits
+ if (a_depth == 4)
+ atex = (atex << 3) | (atex >> 1);
+
+ texel >>= a_depth;
+ }
+ else
+ {
+ atex = 0;
+ }
+
+ if (tex_type & TXTEXPFORM_SSBON)
+ ssbtex = texel & 1;
+ else
+ ssbtex = 0;
+
+ // Select the SSB
+ switch ((m_tm.tex_pip_cntl & TXTPIPCNTL_SSBSEL_MASK) >> TXTPIPCNTL_SSBSEL_SHIFT)
+ {
+ case TXTPIPCNTL_SEL_CONSTANT:
+ {
+ uint32_t cnst = ssbtex ? m_tm.tex_srcconst1 : m_tm.tex_srcconst0;
+ ssb = cnst >> 31;
+ break;
+ }
+ case TXTPIPCNTL_SEL_TRAM:
+ {
+ ssb = ssbtex;
+ break;
+ }
+ case TXTPIPCNTL_SEL_PIP:
+ {
+ ssb = ssbpip;
+ break;
+ }
+ }
+
+ // PIP color control
+ switch ((m_tm.tex_pip_cntl & TXTPIPCNTL_COLORSEL_MASK) >> TXTPIPCNTL_COLORSEL_SHIFT)
+ {
+ case TXTPIPCNTL_SEL_CONSTANT:
+ {
+ uint32_t cnst = ssb ? m_tm.tex_srcconst1 : m_tm.tex_srcconst0;
+ r = (cnst >> 16) & 0xff;
+ g = (cnst >> 8) & 0xff;
+ b = (cnst >> 0) & 0xff;
+ break;
+ }
+ case TXTPIPCNTL_SEL_TRAM:
+ {
+ r = rtex;
+ g = gtex;
+ b = btex;
+ break;
+ }
+ case TXTPIPCNTL_SEL_PIP:
+ {
+ r = rpip;
+ g = gpip;
+ b = bpip;
+ break;
+ }
+ }
+
+ // Alpha control
+ switch ((m_tm.tex_pip_cntl & TXTPIPCNTL_ALPHASEL_MASK) >> TXTPIPCNTL_ALPHASEL_SHIFT)
+ {
+ case TXTPIPCNTL_SEL_CONSTANT:
+ {
+ uint32_t cnst = ssb ? m_tm.tex_srcconst1 : m_tm.tex_srcconst0;
+ a = (cnst >> 24) & 0x7f;
+ break;
+ }
+ case TXTPIPCNTL_SEL_TRAM:
+ {
+ a = atex;
+ break;
+ }
+ case TXTPIPCNTL_SEL_PIP:
+ {
+ a = apip;
+ break;
+ }
+ }
+
+ // Expand alpha to 8-bits
+ a = (a << 1) | (a >> 6);
+}
+
+
+//-------------------------------------------------
+// lerp
+//-------------------------------------------------
+
+static inline uint8_t lerp(uint8_t a, uint8_t b, uint8_t t)
+{
+ if (t == 255)
+ return b;
+ if (t == 0)
+ return a;
+
+ return (((255 - t) * a) >> 8) + ((t * b) >> 8);
+}
+
+
+//-------------------------------------------------
+// multiply
+//-------------------------------------------------
+
+static inline uint8_t multiply(uint8_t a, uint8_t b)
+{
+ if (b == 255)
+ return a;
+ if (a == 255)
+ return b;
+ else
+ return (a * b) >> 8;
+}
+
+
+//-------------------------------------------------
+// texture_blend -
+//-------------------------------------------------
+
+void m2_te_device::texture_blend(
+ uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai,
+ uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt,
+ uint32_t &ro, uint32_t &go, uint32_t &bo, uint32_t &ao, uint32_t &ssbo)
+{
+ uint32_t rbl = 0, gbl = 0, bbl = 0, abl = 0;
+
+ {
+ uint32_t ar, ab, ag, aa;
+ uint32_t br, bb, bg, ba;
+ uint32_t tr, tb, tg;
+
+ select_lerp( (m_tm.tex_tab_cntl & TXTTABCNTL_C_ASEL_MASK) >> TXTTABCNTL_C_ASEL_SHIFT,
+ ri, gi, bi, ai,
+ rt, gt, bt, at, ssbt,
+ ar, ag, ab );
+
+ select_lerp( (m_tm.tex_tab_cntl & TXTTABCNTL_C_BSEL_MASK) >> TXTTABCNTL_C_BSEL_SHIFT,
+ ri, gi, bi, ai,
+ rt, gt, bt, at, ssbt,
+ br, bg, bb );
+
+ select_lerp( (m_tm.tex_tab_cntl & TXTTABCNTL_C_TSEL_MASK) >> TXTTABCNTL_C_TSEL_SHIFT,
+ ri, gi, bi, ai,
+ rt, gt, bt, at, ssbt,
+ tr, tg, tb );
+
+ if (((m_tm.tex_tab_cntl & TXTTABCNTL_BLENDOP_MASK) >> TXTTABCNTL_BLENDOP_SHIFT) == TXTTABCNTL_BLENDOP_LERP)
+ {
+ rbl = lerp(ar, br, tr);
+ gbl = lerp(ag, bg, tg);
+ bbl = lerp(ab, bb, tb);
+ }
+ else
+ {
+ // TODO: CHECK ME
+ // Alpha is multiply only
+ select_mul( (m_tm.tex_tab_cntl & TXTTABCNTL_A_ASEL_MASK) >> TXTTABCNTL_A_ASEL_SHIFT,
+ ai, at, ssbt,
+ aa);
+
+ select_mul( (m_tm.tex_tab_cntl & TXTTABCNTL_A_BSEL_MASK) >> TXTTABCNTL_A_BSEL_SHIFT,
+ ai, at, ssbt,
+ ba);
+
+ rbl = multiply(ar, br);
+ gbl = multiply(ag, bg);
+ bbl = multiply(ab, bb);
+ abl = multiply(aa, ba);
+ }
+ }
+
+ // Now select the output
+ switch ((m_tm.tex_tab_cntl & TXTTABCNTL_C_OSEL_MASK) >> TXTTABCNTL_C_OSEL_SHIFT)
+ {
+ case TXTTABCNTL_CO_SEL_CITER:
+ {
+ ro = ri;
+ go = gi;
+ bo = bi;
+ break;
+ }
+ case TXTTABCNTL_CO_SEL_CT:
+ {
+ ro = rt;
+ go = gt;
+ bo = bt;
+ break;
+ }
+ case TXTTABCNTL_CO_SEL_BLEND:
+ {
+ ro = rbl;
+ go = gbl;
+ bo = bbl;
+ break;
+ }
+ case TXTTABCNTL_CO_SEL_RESERVED:
+ {
+ ro = go = bo = 0;
+ break;
+ }
+ }
+
+ // Select alpha output
+ switch ((m_tm.tex_tab_cntl & TXTTABCNTL_A_OSEL_MASK) >> TXTTABCNTL_A_OSEL_SHIFT)
+ {
+ case TXTTABCNTL_AO_SEL_AITER:
+ {
+ ao = ai;
+ break;
+ }
+ case TXTTABCNTL_AO_SEL_AT:
+ {
+ ao = at;
+ break;
+ }
+ case TXTTABCNTL_AO_SEL_BLEND:
+ {
+ ao = abl;
+ break;
+ }
+ case TXTTABCNTL_AO_SEL_RESERVED:
+ {
+ ao = 0;
+ break;
+ }
+ }
+}
+
+void m2_te_device::select_lerp( uint32_t sel,
+ uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai,
+ uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt,
+ uint32_t & ar, uint32_t & ag, uint32_t & ab )
+{
+ switch (sel)
+ {
+ case TXTTABCNTL_C_ABTSEL_AITER:
+ {
+ ar = ai;
+ ag = ai;
+ ab = ai;
+ break;
+ }
+ case TXTTABCNTL_C_ABTSEL_CITER:
+ {
+ ar = ri;
+ ag = gi;
+ ab = bi;
+ break;
+ }
+ case TXTTABCNTL_C_ABTSEL_AT:
+ {
+ ar = at;
+ ag = at;
+ ab = at;
+ break;
+ }
+ case TXTTABCNTL_C_ABTSEL_CT:
+ {
+ ar = rt;
+ ag = gt;
+ ab = bt;
+ break;
+ }
+ case TXTTABCNTL_C_ABTSEL_ACONST:
+ {
+ uint32_t cnst = ssbt ? m_tm.tex_srcconst3 : m_tm.tex_srcconst2;
+ uint8_t aval = (cnst >> 24) & 0x7f;
+
+ // Expand to 8-bit
+ aval = (aval << 1) | (aval >> 6);
+
+ ar = aval;
+ ag = aval;
+ ab = aval;
+ break;
+ }
+ case TXTTABCNTL_C_ABTSEL_CCONST:
+ {
+ uint32_t cnst = ssbt ? m_tm.tex_srcconst3 : m_tm.tex_srcconst2;
+
+ ar = (cnst >> 24) & 0xff;
+ ag = (cnst >> 16) & 0xff;
+ ab = (cnst >> 0) & 0xff;
+ break;
+ }
+ default:
+ {
+ ar = 0;
+ ag = 0;
+ ab = 0;
+ break;
+ }
+ }
+}
+
+
+void m2_te_device::select_mul(uint32_t sel, uint32_t ai, uint32_t at, uint32_t ssbt,
+ uint32_t & a )
+{
+ switch (sel)
+ {
+ case TXTTABCNTL_A_ABSEL_AITER:
+ {
+ a = ai;
+ break;
+ }
+ case TXTTABCNTL_A_ABSEL_AT:
+ {
+ a = at;
+ break;
+ }
+ case TXTTABCNTL_A_ABSEL_ACONST:
+ {
+ uint32_t cnst = ssbt ? m_tm.tex_srcconst3 : m_tm.tex_srcconst2;
+ uint8_t aval = (cnst >> 24) & 0x7f;
+
+ // Expand to 8-bit
+ a = (aval << 1) | (aval >> 6);
+ break;
+ }
+ default:
+ {
+ a = 0;
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// write_dst_pixel - Write pixel to framebuffer
+//-------------------------------------------------
+
+void m2_te_device::write_dst_pixel()
+{
+ uint32_t mask = m_db.usergen_ctrl & DBUSERGENCTL_DESTOUT_MASK;
+
+ if (m_db.dst_ctrl & DBDESTCNTL_32BPP)
+ {
+ uint32_t dstaddr = m_db.dst_baseaddr + (m_dbstate.y * m_db.dst_xstride + m_dbstate.x) * sizeof(uint32_t);
+
+ uint32_t old = m_bda->read_bus32(dstaddr);
+ uint32_t out = 0;
+
+ uint8_t sdsb_a = (old >> 24) & 0xff;
+ uint8_t sr = (old >> 16) & 0xff;
+ uint8_t sg = (old >> 8) & 0xff;
+ uint8_t sb = old & 0xff;
+
+ out |= (mask & 8 ? (m_dbstate.dsb << 7) | (m_dbstate.dst.a >> 1) : sdsb_a) << 24;
+ out |= (mask & 4 ? m_dbstate.dst.r : sr) << 16;
+ out |= (mask & 2 ? m_dbstate.dst.g : sg) << 8;
+ out |= mask & 1 ? m_dbstate.dst.b : sb;
+
+ m_bda->write_bus32(dstaddr, out);
+ }
+ else
+ {
+ uint32_t dstaddr = m_db.dst_baseaddr + (m_dbstate.y * m_db.dst_xstride + m_dbstate.x) * sizeof(uint16_t);
+
+ uint16_t old = m_bda->read_bus16(dstaddr);
+ uint16_t out = 0;
+
+ uint8_t sdsb_a = (old >> 15) & 0x1;
+ uint8_t sr = (old >> 10) & 0x1f;
+ uint8_t sg = (old >> 5) & 0x1f;
+ uint8_t sb = old & 0x1f;
+
+ out |= (mask & 8 ? m_dbstate.dsb : sdsb_a) << 15;
+ out |= (mask & 4 ? m_dbstate.dst.r >> 3 : sr) << 10;
+ out |= (mask & 2 ? m_dbstate.dst.g >> 3 : sg) << 5;
+ out |= mask & 1 ? m_dbstate.dst.b >> 3 : sb;
+
+ m_bda->write_bus16(dstaddr, out);
+ }
+
+#if TEST_TIMING
+ g_statistics[STAT_PIXEL_STORES]++;
+#endif
+}
+
+
+//-------------------------------------------------
+// destination_blend -
+//-------------------------------------------------
+
+void m2_te_device::destination_blend(uint32_t x, uint32_t y, uint32_t w, const rgba & ti_color, uint8_t ssb)
+{
+ m_dbstate.x = x;
+ m_dbstate.y = y;
+ m_dbstate.w = w;
+ m_dbstate.ti = ti_color;
+ m_dbstate.ssb = ssb;
+
+ bool dis = false;
+ bool zpixout = true;
+ bool zbufout = true;
+ bool zclip = false;
+ bool zclipdis = false;
+ bool fbclipdis = false;
+ bool winclipdis = false;
+
+ // Z Status
+ uint32_t zgel = 0;
+
+ uint32_t zaddr;
+
+ // FBCLIP
+ {
+ uint32_t xclip = (m_db.fbclip & DBFBCLIP_XFBCLIP_MASK) >> DBFBCLIP_XFBCLIP_SHIFT;
+ uint32_t yclip = (m_db.fbclip & DBFBCLIP_YFBCLIP_MASK) >> DBFBCLIP_YFBCLIP_SHIFT;
+
+ fbclipdis = (x >= xclip) || (y >= yclip);
+
+ if (fbclipdis)
+ m_db.status |= DBSTATUS_FBCLIP;
+ }
+
+ // WINCLIP
+ {
+ uint32_t xmin = (m_db.x_winclip & DBFBXWINCLIP_XMIN_MASK) >> DBFBXWINCLIP_XMIN_SHIFT;
+ uint32_t xmax = (m_db.x_winclip & DBFBXWINCLIP_XMAX_MASK) >> DBFBXWINCLIP_XMAX_SHIFT;
+ uint32_t ymin = (m_db.y_winclip & DBFBYWINCLIP_YMIN_MASK) >> DBFBYWINCLIP_YMIN_SHIFT;
+ uint32_t ymax = (m_db.y_winclip & DBFBYWINCLIP_YMAX_MASK) >> DBFBYWINCLIP_YMAX_SHIFT;
+
+ bool inside = (x >= xmin) && (x < xmax) && (y >= ymin) && (y < ymax);
+
+ winclipdis = ((m_db.usergen_ctrl & DBUSERGENCTL_WCLIPINEN) && inside) ||
+ ((m_db.usergen_ctrl & DBUSERGENCTL_WCLIPOUTEN) && !inside);
+
+ if (winclipdis)
+ m_db.status |= DBSTATUS_WINCLIP;
+ }
+
+ select_src_pixel();
+
+ select_tex_pixel();
+
+ select_alpha_dsb();
+
+
+ {
+ uint8_t dm10, dm11, dm20, dm21;
+ uint32_t txtcnst0 = m_db.txt_coef_const0;
+ uint32_t txtcnst1 = m_db.txt_coef_const1;
+ uint32_t srccnst0 = m_db.src_coef_const0;
+ uint32_t srccnst1 = m_db.src_coef_const1;
+
+ if ((m_db.usergen_ctrl & DBUSERGENCTL_BLENDEN) && !(m_gc.te_master_mode & TEMASTER_MODE_DBLEND))
+ {
+ // Blue
+ dm10 = txtcnst0 & 0xff; txtcnst0 >>= 8;
+ dm11 = txtcnst1 & 0xff; txtcnst1 >>= 8;
+ dm20 = srccnst0 & 0xff; srccnst0 >>= 8;
+ dm21 = srccnst1 & 0xff; srccnst1 >>= 8;
+ m_dbstate.blend.b = color_blend(m_dbstate.texpath.b, m_dbstate.ti.b, m_dbstate.srcpath.b, m_dbstate.src.b, dm10, dm11, dm20, dm21);
+
+ // TODO: ALURGEL for each
+
+ // Green
+ dm10 = txtcnst0 & 0xff; txtcnst0 >>= 8;
+ dm11 = txtcnst1 & 0xff; txtcnst1 >>= 8;
+ dm20 = srccnst0 & 0xff; srccnst0 >>= 8;
+ dm21 = srccnst1 & 0xff; srccnst1 >>= 8;
+ m_dbstate.blend.g = color_blend(m_dbstate.texpath.g, m_dbstate.ti.g, m_dbstate.srcpath.g, m_dbstate.src.g, dm10, dm11, dm20, dm21);
+
+ // Red
+ dm10 = txtcnst0 & 0xff;
+ dm11 = txtcnst1 & 0xff;
+ dm20 = srccnst0 & 0xff;
+ dm21 = srccnst1 & 0xff;
+ m_dbstate.blend.r = color_blend(m_dbstate.texpath.r, m_dbstate.ti.r, m_dbstate.srcpath.r, m_dbstate.src.r, dm10, dm11, dm20, dm21);
+ }
+ else
+ {
+ m_dbstate.blend.r = m_dbstate.ti.r;
+ m_dbstate.blend.g = m_dbstate.ti.g;
+ m_dbstate.blend.b = m_dbstate.ti.b;
+ }
+
+ // Dithering
+ if (m_db.usergen_ctrl & DBUSERGENCTL_DITHEREN)
+ {
+ uint32_t dith_x = x & 3;
+ uint32_t dith_y = y & 3;
+
+ uint32_t dith_mtx = dith_y & 2 ? m_db.dither_mat_b : m_db.dither_mat_a;
+ uint32_t idx = 7 ^ (((dith_y & 1) << 2) | dith_x);
+ uint8_t val = (dith_mtx >> (idx * 4)) & 0xf;
+
+ m_dbstate.dst.r = dither(m_dbstate.blend.r, val);
+ m_dbstate.dst.g = dither(m_dbstate.blend.g, val);
+ m_dbstate.dst.b = dither(m_dbstate.blend.b, val);
+ }
+ else
+ {
+ m_dbstate.dst.r = m_dbstate.blend.r;
+ m_dbstate.dst.g = m_dbstate.blend.g;
+ m_dbstate.dst.b = m_dbstate.blend.b;
+ }
+ }
+
+
+ if (!(m_gc.te_master_mode & TEMASTER_MODE_DZBUF) &&
+ (m_db.usergen_ctrl & DBUSERGENCTL_ZBUFEN))
+ {
+ int32_t x_offs = (m_db.z_offset & DBZOFFS_XOFFS_MASK) >> DBZOFFS_XOFFS_SHIFT;
+ int32_t y_offs = (m_db.z_offset & DBZOFFS_YOFFS_MASK) >> DBZOFFS_YOFFS_SHIFT;
+
+ // Sign extend
+ x_offs = (x_offs << 20) >> 20;
+ y_offs = (x_offs << 20) >> 20;
+
+ x_offs += m_dbstate.x;
+ y_offs += m_dbstate.y;
+
+ uint32_t x_clip = (m_db.z_clip & DBZCLIP_XCLIP_MASK) >> DBZCLIP_XCLIP_SHIFT;
+ uint32_t y_clip = (m_db.z_clip & DBZCLIP_YCLIP_MASK) >> DBZCLIP_YCLIP_SHIFT;
+
+ zclip = (x_offs < 0) || (y_offs < 0) || (x_offs >= x_clip) || (y_offs >= y_clip);
+
+ zaddr = m_db.z_baseaddr + (x_offs + y_offs * m_db.dst_xstride) * 2;
+ }
+ else
+ {
+ zaddr = 0;
+ zclip = false;
+ }
+
+ zclipdis = zclip && (m_db.discard_ctrl & DBDISCARDCTL_ZCLIPDISEN);
+
+ if (zclipdis)
+ m_db.status |= DBSTATUS_ZCLIP;
+
+ // Z-path
+ if (!(m_gc.te_master_mode & TEMASTER_MODE_DZBUF) &&
+ (m_db.usergen_ctrl & DBUSERGENCTL_ZBUFEN) &&
+ !zclip)
+ {
+#if TEST_TIMING
+ g_statistics[STAT_ZBUFFER_LOADS]++;
+#endif
+
+#if 1 // TODO: Why are we using this?
+ int32_t zdiff = w - m_bda->read_bus16(zaddr);
+#else
+ // Shift W back to 0.23
+ uint16_t oldw = m_bda->read_bus16(zaddr);
+ uint32_t exp = (oldw & 0xc000) >> 14;
+ uint32_t man = (oldw & 0x3fff) << 17;
+
+ uint32_t oldz = man >> (exp * 3);
+
+ exp = (w & 0xc000) >> 14;
+ man = (w & 0x3fff) << 17;
+ uint32_t curz = man >> (exp * 3);
+
+ int32_t zdiff = curz - oldz;
+#endif
+
+ // TODO: Why isn't this working?
+ // W vs Z?
+ if (zdiff > 0)
+ {
+ zpixout = m_db.z_ctrl & 1;//DBZCNTL_ZPIXOUT_GT;
+ zbufout = m_db.z_ctrl & 2;//DBZCNTL_ZBUFOUT_GT;
+ zgel |= 4;
+ m_db.status |= DBSTATUS_ZFUNC_GT;
+ }
+ else if (zdiff == 0)
+ {
+ zpixout = m_db.z_ctrl & DBZCNTL_ZPIXOUT_EQ;
+ zbufout = m_db.z_ctrl & DBZCNTL_ZBUFOUT_EQ;
+ zgel |= 2;
+ m_db.status |= DBSTATUS_ZFUNC_EQ;
+ }
+ else
+ {
+ zpixout = m_db.z_ctrl & 0x10;//DBZCNTL_ZPIXOUT_LT;
+ zbufout = m_db.z_ctrl & 0x20;//DBZCNTL_ZBUFOUT_LT;
+ zgel |= 1;
+ m_db.status |= DBSTATUS_ZFUNC_LT;
+ }
+ }
+ else
+ {
+ zpixout = true;
+ zbufout = false;
+ }
+
+ // Discard logic
+ {
+ bool ssbdis = (m_db.discard_ctrl & DBDISCARDCTL_SSBDISEN) && (m_dbstate.ssb == 0);
+
+ bool adis = (m_db.discard_ctrl & DBDISCARDCTL_ADISEN) && (m_dbstate.dst.a == 0);
+
+ bool rgbdis = (m_db.discard_ctrl & DBDISCARDCTL_RGBDISEN) &&
+ (m_dbstate.dst.r == 0) && (m_dbstate.dst.g == 0) && (m_dbstate.dst.b == 0);
+
+ dis = fbclipdis || winclipdis || zclipdis || ssbdis || adis || rgbdis;
+ }
+
+ // Write output depth and color
+ if (!dis)
+ {
+ // Z-buffer
+ if (zbufout && (m_db.usergen_ctrl & DBUSERGENCTL_ZOUTEN))
+ {
+#if TEST_TIMING
+ g_statistics[STAT_ZBUFFER_STORES]++;
+#endif
+ m_bda->write_bus16(zaddr, w & 0xffff);
+ }
+
+ // Color
+ if (zpixout && (m_db.supergen_ctrl & DBSUPERGENCTL_DESTOUTEN))
+ {
+ write_dst_pixel();
+ }
+ }
+
+ // TODO: Status
+/*
+ {
+ fbClipStat = fbClipDis
+ winClipStat = winClipDis
+ zClipStat = zClipDis
+ alurstat
+ alugstat
+ alubstat
+ zFuncStat
+ anyRender
+ set_interrupt
+ }
+*/
+}
+
+// Select between texture unit and source pixel
+void m2_te_device::select_tex_pixel()
+{
+ uint32_t cntl;
+
+ // TODO: REGBITS
+ if (m_dbstate.ti.a == 0)
+ cntl = (m_db.src_alpha_ctrl >> 4) & 3;
+ else if (m_dbstate.ti.a == 255)
+ cntl = m_db.src_alpha_ctrl & 3;
+ else
+ cntl = (m_db.src_alpha_ctrl >> 2) & 3;
+
+ switch (cntl)
+ {
+ case 0: m_dbstate.texpath.a = m_dbstate.ti.a; break;
+ case 1: m_dbstate.texpath.a = 255; break;
+ case 2: m_dbstate.texpath.a = 0; break;
+ }
+
+ switch ((m_db.txt_mult_cntl & DBTXTMULTCNTL_INSEL_MASK) >> DBTXTMULTCNTL_INSEL_SHIFT)
+ {
+ case DBTXTMULTCNTL_INSEL_CTI:
+ {
+ m_dbstate.texpath.r = m_dbstate.ti.r;
+ m_dbstate.texpath.g = m_dbstate.ti.g;
+ m_dbstate.texpath.b = m_dbstate.ti.b;
+ break;
+ }
+ case DBTXTMULTCNTL_INSEL_CONSTANT:
+ {
+ uint32_t cnst = m_db.const_in;
+ m_dbstate.texpath.r = (cnst >> 16) & 0xff;
+ m_dbstate.texpath.g = (cnst >> 8) & 0xff;
+ m_dbstate.texpath.b = cnst & 0xff;
+ break;
+ }
+ case DBTXTMULTCNTL_INSEL_COMPSRC:
+ {
+ m_dbstate.texpath.r = ~m_dbstate.src.r;
+ m_dbstate.texpath.g = ~m_dbstate.src.g;
+ m_dbstate.texpath.b = ~m_dbstate.src.b;
+ break;
+ }
+ case DBTXTMULTCNTL_INSEL_ATI:
+ {
+ m_dbstate.texpath.r = m_dbstate.ti.a;
+ m_dbstate.texpath.g = m_dbstate.ti.a;
+ m_dbstate.texpath.b = m_dbstate.ti.a;
+ break;
+ }
+ }
+
+ if (m_db.txt_mult_cntl & DBTXTMULTCNTL_TXTRJUST)
+ {
+ m_dbstate.texpath.r >>= 3;
+ m_dbstate.texpath.g >>= 3;
+ m_dbstate.texpath.b >>= 3;
+ }
+}
+
+void m2_te_device::select_src_pixel()
+{
+ if ((m_db.usergen_ctrl & DBUSERGENCTL_SRCINEN)
+ && (m_db.usergen_ctrl & DBUSERGENCTL_BLENDEN)
+ && !(m_gc.te_master_mode & TEMASTER_MODE_DBLEND))
+ {
+ int32_t x_offs = (m_db.src_offset & DBSRCOFFS_XOFFS_MASK) >> DBSRCOFFS_YOFFS_SHIFT;
+ int32_t y_offs = (m_db.src_offset & DBSRCOFFS_YOFFS_MASK) >> DBSRCOFFS_YOFFS_SHIFT;
+
+ // Sign extend
+ x_offs = (x_offs << 20) >> 20;
+ y_offs = (y_offs << 20) >> 20;
+
+ x_offs += m_dbstate.x;
+ y_offs += m_dbstate.y;
+
+ uint32_t addr = y_offs * m_db.src_xstride + x_offs;
+
+ if (m_db.src_ctrl & DBSRCCNTL_32BPP)
+ {
+ uint32_t srcaddr = m_db.src_baseaddr + addr * sizeof(uint32_t);
+ uint32_t srcval = m_bda->read_bus32(srcaddr);
+
+ m_dbstate.src.a = ((srcval >> 24) & 0x7f) << 1;
+ m_dbstate.src.r = (srcval >> 16) & 0xff;
+ m_dbstate.src.g = (srcval >> 8) & 0xff;
+ m_dbstate.src.b = (srcval >> 0) & 0xff;
+
+ if (m_db.src_ctrl & DBSRCCNTL_MSBREP)
+ m_dbstate.src.a |= (m_dbstate.src.a >> 6) & 1;
+
+ m_dbstate.dsb = (srcval >> 31) & 1;
+ }
+ else
+ {
+ uint32_t srcaddr = m_db.src_baseaddr + addr * sizeof(uint16_t);
+ uint32_t srcval = m_bda->read_bus16(srcaddr);
+
+ m_dbstate.src.r = (srcval >> 10) & 0x1f;
+ m_dbstate.src.g = (srcval >> 5) & 0x1f;
+ m_dbstate.src.b = srcval & 0x1f;
+ m_dbstate.src.a = 0;
+
+ m_dbstate.dsb = srcval & 0x8000;
+ m_dbstate.src.r <<= 3;
+ m_dbstate.src.g <<= 3;
+ m_dbstate.src.b <<= 3;
+
+ if (m_db.src_ctrl & DBSRCCNTL_MSBREP)
+ {
+ m_dbstate.src.r |= (m_dbstate.src.r >> 5);
+ m_dbstate.src.g |= (m_dbstate.src.g >> 5);
+ m_dbstate.src.b |= (m_dbstate.src.b >> 5);
+ }
+ }
+#if TEST_TIMING
+ g_statistics[STAT_PIXEL_LOADS]++;
+#endif
+ }
+ else
+ {
+ // Source input disabled
+ m_dbstate.dsb = 0;
+ m_dbstate.src.r = 0;
+ m_dbstate.src.g = 0;
+ m_dbstate.src.b = 0;
+ m_dbstate.src.a = 0;
+ }
+
+ // Now
+ switch ((m_db.src_mult_cntl & DBSRCMULTCNTL_INSEL_MASK) >> DBSRCMULTCNTL_INSEL_SHIFT)
+ {
+ case DBSRCMULTCNTL_INSEL_SRC:
+ {
+ m_dbstate.srcpath.r = m_dbstate.src.r;
+ m_dbstate.srcpath.g = m_dbstate.src.g;
+ m_dbstate.srcpath.b = m_dbstate.src.b;
+ break;
+ }
+ case DBSRCMULTCNTL_INSEL_CONSTANT:
+ {
+ uint32_t cnst = m_db.const_in;
+ m_dbstate.srcpath.r = (cnst >> 16) & 0xff;
+ m_dbstate.srcpath.g = (cnst >> 8) & 0xff;
+ m_dbstate.srcpath.b = (cnst >> 0) & 0xff;
+ break;
+ }
+ case DBSRCMULTCNTL_INSEL_COMPCTI:
+ {
+ m_dbstate.srcpath.r = ~m_dbstate.ti.r;
+ m_dbstate.srcpath.g = ~m_dbstate.ti.g;
+ m_dbstate.srcpath.b = ~m_dbstate.ti.b;
+ break;
+ }
+ case DBSRCMULTCNTL_INSEL_TEXALPHA:
+ {
+ m_dbstate.srcpath.r = m_dbstate.src.a;
+ m_dbstate.srcpath.g = m_dbstate.src.a;
+ m_dbstate.srcpath.b = m_dbstate.src.a;
+ break;
+ }
+ }
+
+ if (m_db.src_mult_cntl & DBSRCMULTCNTL_SRCRJUST)
+ {
+ m_dbstate.srcpath.r >>= 3;
+ m_dbstate.srcpath.g >>= 3;
+ m_dbstate.srcpath.b >>= 3;
+ }
+
+ m_dbstate.srcpath.a = m_dbstate.src.a;
+}
+
+uint8_t m2_te_device::dither(uint8_t in, uint8_t dithval)
+{
+ int32_t res;
+ int32_t sgn_val;
+
+ if (dithval & 8)
+ sgn_val = -8 + (dithval & 7);
+ else
+ sgn_val = dithval;
+
+ res = (int32_t)in + sgn_val;
+
+ if (res > 255)
+ res = 255;
+ else if (res < 0)
+ res = 0;
+
+ return (uint8_t)res;
+}
+
+uint8_t m2_te_device::get_src_coef(uint8_t cti, uint8_t dm2const0, uint8_t dm2const1)
+{
+ uint32_t sel=0;
+ uint8_t cnst, coef=0;
+
+ switch ((m_db.src_mult_cntl & DBSRCMULTCNTL_SRCCONSTCNTL_MASK) >> DBSRCMULTCNTL_SRCCONSTCNTL_SHIFT)
+ {
+ case DBSRCMULTCNTL_SRCCONSTCNTL_TEXSSB: sel = m_dbstate.ssb; break;
+ case DBSRCMULTCNTL_SRCCONSTCNTL_SRCDSB: sel = m_dbstate.dsb; break;
+ }
+
+ cnst = sel ? dm2const1 : dm2const0;
+
+ switch ((m_db.src_mult_cntl & DBSRCMULTCNTL_COEFSEL_MASK) >> DBSRCMULTCNTL_COEFSEL_SHIFT)
+ {
+ case DBSRCMULTCNTL_COEFSEL_ATI: coef = m_dbstate.texpath.a; break;
+ case DBSRCMULTCNTL_COEFSEL_ASRC: coef = m_dbstate.srcpath.a; break;
+ case DBSRCMULTCNTL_COEFSEL_CONSTANT: coef = cnst; break;
+ case DBSRCMULTCNTL_COEFSEL_CTI: coef = cti; break;
+ }
+
+ if (m_db.src_mult_cntl & DBSRCMULTCNTL_SRCCOEFCMP)
+ return ~coef;
+ else
+ return coef;
+}
+
+uint8_t m2_te_device::get_tex_coef(uint8_t cs, uint8_t dm1const0, uint8_t dm1const1)
+{
+ uint32_t sel=0;
+ uint8_t cnst, coef=0;
+
+ // TODO: Make like src coefficient
+ uint32_t cntl = ((m_db.txt_mult_cntl & DBTXTMULTCNTL_TXTCONSTCNTL_MASK) >> DBTXTMULTCNTL_TXTCONSTCNTL_SHIFT);
+
+ if (cntl == DBTXTMULTCNTL_TXTCONSTCNTL_TEXSSB)
+ sel = m_dbstate.ssb;
+ else if (cntl == DBTXTMULTCNTL_TXTCONSTCNTL_SRCDSB)
+ sel = m_dbstate.dsb;
+
+ cnst = sel ? dm1const1 : dm1const0;
+
+ switch ((m_db.txt_mult_cntl & DBTXTMULTCNTL_COEFSEL_MASK) >> DBTXTMULTCNTL_COEFSEL_SHIFT)
+ {
+ case DBTXTMULTCNTL_COEFSEL_ATI: coef = m_dbstate.texpath.a; break;
+ case DBTXTMULTCNTL_COEFSEL_ASRC: coef = m_dbstate.srcpath.a; break;
+ case DBTXTMULTCNTL_COEFSEL_CONSTANT: coef = cnst; break;
+ case DBTXTMULTCNTL_COEFSEL_CSRC: coef = cs; break;
+ }
+
+ if (m_db.txt_mult_cntl & DBTXTMULTCNTL_TXTCOEFCMP)
+ return ~coef;
+ else
+ return coef;
+}
+
+void m2_te_device::select_alpha_dsb()
+{
+ if ((m_db.usergen_ctrl & DBUSERGENCTL_BLENDEN) && !(m_gc.te_master_mode & TEMASTER_MODE_DBLEND))
+ {
+ uint32_t sel = 0;
+ uint8_t aconst;
+
+ switch ((m_db.dst_alpha_ctrl & DBDSTACNTL_ADESTCONSTCNTL_MASK) >> DBDSTACNTL_ADESTCONSTCNTL_SHIFT)
+ {
+ case 0: sel = m_dbstate.ssb; break;
+ case 1: sel = m_dbstate.dsb; break;
+ }
+
+ if (sel)
+ aconst = (m_db.dst_alpha_const & DBDSTALPHACONST_CONST1_MASK) >> DBDSTALPHACONST_CONST1_SHIFT;
+ else
+ aconst = (m_db.dst_alpha_const & DBDSTALPHACONST_CONST0_MASK) >> DBDSTALPHACONST_CONST0_SHIFT;
+
+ switch ((m_db.dst_alpha_ctrl & DBDSTACNTL_ADESTSEL_MASK) >> DBDSTACNTL_ADESTSEL_SHIFT)
+ {
+ case 0: m_dbstate.dst.a = m_dbstate.texpath.a; break;
+ case 1: m_dbstate.dst.a = aconst; break;
+ case 2: m_dbstate.dst.a = m_dbstate.srcpath.a; break;
+ case 3: m_dbstate.dst.a = m_dbstate.blend.r; break;
+ }
+
+ switch ((m_db.ssbdsb_ctrl & DBSSBDSBCNTL_DSBSEL_MASK) >> DBSSBDSBCNTL_DSBSEL_SHIFT)
+ {
+ case 0: m_dbstate.dsb = m_dbstate.ssb; break;
+ case 1: m_dbstate.dsb = (m_db.ssbdsb_ctrl & DBSSBDSBCNTL_DSBCONST_MASK) >> DBSSBDSBCNTL_DSBCONST_SHIFT; break;
+ case 2: m_dbstate.dsb = m_dbstate.dsb; break;
+ }
+ }
+ else
+ {
+ m_dbstate.dst.a = m_dbstate.texpath.a;
+ m_dbstate.dsb = m_dbstate.ssb;
+ }
+}
+
+
+uint8_t m2_te_device::color_blend(uint8_t ct, uint8_t cti, uint8_t cs, uint8_t csrc,
+ uint8_t dm10, uint8_t dm11,
+ uint8_t dm20, uint8_t dm21)
+{
+ uint8_t tcoef, scoef;
+ uint16_t tm, sm;
+
+ tcoef = get_tex_coef(csrc, dm10, dm11);
+ scoef = get_src_coef(cti, dm20, dm21);
+
+ tm = (tcoef == 255) ? ct : ((ct == 255) ? tcoef : ((tcoef * ct) >> 8));
+ sm = (scoef == 255) ? cs : ((cs == 255) ? scoef : ((scoef * cs) >> 8));
+
+ return alu_calc(tm, sm);
+}
+
+#if 1
+
+uint8_t m2_te_device::alu_calc(uint16_t a, uint16_t b)
+{
+ uint16_t cinv;
+ uint16_t c = 0;
+ uint32_t blendout;
+ uint32_t result;
+ uint32_t carry = 0;
+ uint32_t borrow = 0;
+ uint32_t cntl = (m_db.alu_ctrl & DBALUCNTL_ALUOP_MASK) >> DBALUCNTL_ALUOP_SHIFT;
+
+ // p271
+
+ /* ALU */
+ if ((cntl & 8) == 0)
+ {
+ if (!(cntl & 4))
+ {
+ result = a + b;
+ }
+ else if (cntl & 2)
+ {
+ result = b - a;
+ if (result < 0)
+ borrow = 1;
+ }
+ else
+ {
+ result = a - b;
+ if (result < 0)
+ borrow = 1;
+ }
+ }
+ /* Boolean */
+ else
+ {
+ cinv = 0;
+ int i, j;
+
+ for (i = 0; i < 8; ++i)
+ {
+ j = (a & 1) *2 + (b & 1);
+
+ switch (j)
+ {
+ case 0: cinv |= (cntl & 1); break;
+ case 1: cinv |= (cntl & 2) && 1; break;
+ case 2: cinv |= (cntl & 4) && 1; break;
+ case 3: cinv |= (cntl & 8) && 1; break;
+ }
+
+ cinv <<= 1;
+ a >>= 1;
+ b >>= 1;
+ }
+ cinv >>= 1;
+
+ for (i = 0; i < 8; ++i)
+ {
+ c |= cinv & 1;
+ c <<= 1;
+ cinv >>= 1;
+ }
+
+ c >>= 1;
+ result = (int)c;
+ }
+
+ result &= 0x1ff;
+
+ switch ((m_db.alu_ctrl & DBALUCNTL_FINALDIVIDE_MASK) >> DBALUCNTL_FINALDIVIDE_SHIFT)
+ {
+ case 1: blendout = result << 1; break;
+ case 2: blendout = result << 2; break;
+ case 3: blendout = result << 3; break;
+ case 7: blendout = result >> 1; break;
+ case 6: blendout = result >> 2; break;
+ case 5: blendout = result >> 3; break;
+ default: blendout = result; break;
+ }
+
+ if (blendout > 255)
+ carry = 1;
+
+#if 0
+ int alugel;
+ // TODO: FIX ALUGEL - Needs to be propagated to ALU status
+ if (borrow == 1)
+ alugel = 1;
+ else if (blendout == 0)
+ alugel = 2;
+ else
+ alugel = 4;
+#endif
+
+ if ((cntl & 8) == 0)
+ {
+ /* Clamp? */
+ if (!(cntl & 1))
+ {
+ blendout = carry ? 255 : blendout;
+ blendout = borrow ? 0 : blendout;
+ }
+ else
+ {
+ if (cntl & 2)
+ {
+ blendout = carry ? 255 : blendout;
+ blendout = borrow ? 0 : blendout;
+ }
+ }
+ }
+
+ return blendout & 0xff;
+}
+
+
+
+#endif
+
+//-------------------------------------------------
+// walk_span -
+//-------------------------------------------------
+
+void m2_te_device::walk_span(uint32_t wrange, bool omit_right,
+ uint32_t y, uint32_t xs, uint32_t xe,
+ int32_t r, int32_t g, int32_t b, int32_t a,
+ uint32_t uw, uint32_t vw,
+ uint32_t w)
+{
+ bool scan_lr = !m_es.r2l;
+
+ // TODO: Is this correct?
+ xe = scan_lr ? xe + 1 : xe - 1;
+
+ /*
+ Edge to Span walker
+ X/Y 11.0
+ RGBA 8.11
+ U/W, V/W 10.13
+ 1/W 0.23
+ RGBA DDX s8.11
+ UV DDX s10.13
+ 1/W DDX s0.23
+
+ To destination blender:
+ X/Y 11.0
+ W 0.16
+
+ To texture mapper:
+ RGBA 8.0
+ UV 10.4
+ */
+
+ if (omit_right)
+ {
+ if (scan_lr)
+ {
+ xe -= 1;
+ }
+ else
+ {
+ xs -= 1;
+ r -= m_es.ddx_r;
+ g -= m_es.ddx_g;
+ b -= m_es.ddx_b;
+ a -= m_es.ddx_a;
+ uw -= m_es.ddx_uw;
+ vw -= m_es.ddx_vw;
+ w -= m_es.ddx_w;
+ }
+ }
+
+ if (g_debug)
+ {
+ g_debug = true;
+ }
+
+ while (xs != xe)
+ {
+ uint32_t sx = xs;
+ uint32_t sy = y;
+
+#if 1 // DEBUG
+ if (sx == 320/2 && sy == 200)
+ {
+ ;
+ }
+#endif
+
+ // Fetch RGB and A
+ uint32_t rt, gt, bt, at, ssbt;
+
+ uint32_t w16 = 0;
+
+ // W
+ {
+ // Undo shifting that took place during setup and reduce 0.23 to 0.16
+ uint32_t normalized_w = w >> -depth_bits[wrange];
+ w16 = (normalized_w >> 7) & 0xffff;
+ }
+
+ if (!(m_gc.te_master_mode & TEMASTER_MODE_DTEXT) && (m_tm.tex_addr_cntl & TXTADDRCNTL_LOOKUP_EN))
+ {
+ uint32_t u, v;
+
+ // UV and W
+ texcoord_gen(wrange, uw, vw, w, u, v, w16);
+
+ // TODO: FIXME
+ uint32_t lod = lod_calc(u, v, u, v);
+
+ get_texture_color(u, v, lod, rt, gt, bt, at, ssbt);
+ }
+ else
+ {
+ rt = gt = bt = at = ssbt = 0;
+ }
+
+ uint32_t ri, gi, bi, ai;
+
+ if (!(m_gc.te_master_mode & TEMASTER_MODE_DSHADE))
+ {
+ // Remove the fractional parts of iterated ARGB
+ ri = r >> 11;
+ gi = g >> 11;
+ bi = b >> 11;
+ ai = a >> 11;
+ }
+ else
+ {
+ ri = 0xff;
+ gi = 0xff;
+ bi = 0xff;
+ ai = 0xff;
+ }
+
+ uint32_t ro, go, bo, ao;
+
+ // Note: SSB may be overriden
+ uint32_t ssbo = ssbt;
+
+ // Blend iterated RGB with texel
+ texture_blend(ri, gi, bi, ai,
+ rt, gt, bt, at, ssbt,
+ ro, go, bo, ao, ssbo);
+
+ // Destination blend and write-out
+ // Interface:
+ // Span length
+ // Left 2 Right
+ // W0, W1
+
+ rgba texout;
+ texout.r = ro;
+ texout.g = go;
+ texout.b = bo;
+ texout.a = ao;
+
+ destination_blend(sx, sy, w16, texout, ssbo);
+
+ // Update interpolated paramters
+ if (scan_lr)
+ {
+ xs += 1;
+ r += m_es.ddx_r;
+ g += m_es.ddx_g;
+ b += m_es.ddx_b;
+ a += m_es.ddx_a;
+ uw += m_es.ddx_uw;
+ vw += m_es.ddx_vw;
+ w += m_es.ddx_w;
+ }
+ else
+ {
+ xs -= 1;
+ r -= m_es.ddx_r;
+ g -= m_es.ddx_g;
+ b -= m_es.ddx_b;
+ a -= m_es.ddx_a;
+ uw -= m_es.ddx_uw;
+ vw -= m_es.ddx_vw;
+ w -= m_es.ddx_w;
+ }
+
+ // Clamp to 11.8
+ r = clamp(r, 0, 0x0007ffff);
+ g = clamp(g, 0, 0x0007ffff);
+ b = clamp(b, 0, 0x0007ffff);
+ a = clamp(a, 0, 0x0007ffff);
+
+ // Clamp to 10.13
+ uw = clamp(uw, 0, 0x007fffff);
+ vw = clamp(vw, 0, 0x007fffff);
+
+ // Clamp to 0.23
+ w = clamp(w, 0, 0x007fffff);
+
+#if TEST_TIMING
+ g_statistics[STAT_PIXELS_PROCESSED]++;
+#endif
+ }
+}
+
+
+
+/***************************************************************************
+ INSTRUCTION PROCESSING
+***************************************************************************/
+
+//-------------------------------------------------
+// irp_fetch -
+//-------------------------------------------------
+
+uint32_t m2_te_device::irp_fetch()
+{
+ uint32_t data = m_bda->read_bus32(m_gc.irp);
+ m_gc.irp += 4;
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// irp_fetch_float -
+//-------------------------------------------------
+
+float m2_te_device::irp_fetch_float()
+{
+ uint32_t data = m_bda->read_bus32(m_gc.irp);
+ m_gc.irp += 4;
+
+ return *reinterpret_cast<float*>(&data);
+}
+
+
+//-------------------------------------------------
+// illegal_inst -
+//-------------------------------------------------
+
+void m2_te_device::illegal_inst()
+{
+ set_interrupt(INTSTAT_UNIMPLEMENTED_INSTR);
+ m_state = TE_STOPPED;
+}
+
+
+//-------------------------------------------------
+// execute -
+//-------------------------------------------------
+
+void m2_te_device::execute()
+{
+ address_space &space = machine().driver_data()->generic_space();
+
+#if TEST_TIMING
+ memset(g_statistics, 0, sizeof(g_statistics));
+#endif
+
+ while (m_state == TE_RUNNING)
+ {
+ uint32_t inst = irp_fetch();
+
+ switch (inst & INST_MASK)
+ {
+ case INST_WRITE_REG:
+ {
+ uint32_t offs = inst & 0xffff;
+ int32_t cnt = (inst >> 16) & 0xff;
+
+ while (cnt-- >= 0)
+ {
+ write(space, offs >> 2, irp_fetch(), 0xffffffff);
+ offs += 4;
+
+ if (m_state != TE_RUNNING)
+ break;
+ }
+ break;
+ }
+
+ case INST_VTX_SHORT:
+ {
+ int32_t cnt = inst & 0xffff;
+ uint32_t flags = inst & 0x001f0000;
+ uint32_t ver = (inst >> 24) & 0xf;
+
+ if (ver != 0)
+ {
+ illegal_inst();
+ break;
+ }
+
+ while (cnt-- >= 0)
+ {
+ se_vtx vtx = { 0 };
+
+ vtx.x = irp_fetch_float();
+ vtx.y = irp_fetch_float();
+
+ if (flags & VTX_FLAG_SHAD)
+ {
+ vtx.r = irp_fetch_float();
+ vtx.g = irp_fetch_float();
+ vtx.b = irp_fetch_float();
+ vtx.a = irp_fetch_float();
+ }
+ if (flags & VTX_FLAG_PRSP)
+ {
+ vtx.w = irp_fetch_float();
+ }
+ if (flags & VTX_FLAG_TEXT)
+ {
+ vtx.uw = irp_fetch_float();
+ vtx.vw = irp_fetch_float();
+ }
+
+ // Send this vertex for processing
+ add_vertex(vtx, flags);
+
+ // Clear the new triangle flag if set
+ flags &= ~VTX_FLAG_NEW;
+ }
+
+ break;
+ }
+ case INST_VTX_LONG:
+ {
+ const uint32_t ver = (inst >> 24) & 0xf;
+
+ if (ver != 0)
+ {
+ illegal_inst();
+ break;
+ }
+
+ fatalerror("Long format unimplemented");
+
+ break;
+ }
+ case INST_VTX_POINT:
+ {
+ const uint32_t ver = (inst >> 24) & 0xf;
+
+ if (ver != 0)
+ {
+ illegal_inst();
+ break;
+ }
+
+ fatalerror("Point format unimplemented");
+
+ break;
+ }
+ default:
+ {
+ illegal_inst();
+ break;
+ }
+ }
+
+ // Stop or pause execution?
+ if (m_gc.irp == m_gc.iwp)
+ {
+ m_state = m_gc.te_master_mode & TEICNTL_STPL ? TE_STOPPED : TE_PAUSED;
+ set_interrupt(INTSTAT_LIST_END);
+ }
+ else if (m_gc.te_master_mode & (TEICNTL_STPI | TEICNTL_STEP))
+ {
+ m_state = TE_STOPPED;
+ }
+ };
+
+#if TEST_TIMING
+/*
+ TESetup Engine: 600-700 triangles/sec (?)
+
+ Pixel Rates:
+ Point - 132Mpix/s
+ Linear - 66Mpix/s
+ Bilin - 33Mpix
+ QTril - 22M
+
+ No blend, no Z - 120MPix
+ Zbuffer - 66-120M pix
+ Bend - 66 M pix
+*/
+
+ uint32_t total_cycles = (g_statistics[STAT_TRIANGLES_PROCESSED] * 100) +
+ (g_statistics[STAT_TEXEL_READS]) +
+// (g_statistics[STAT_PIXELS_PROCESSED]) +
+ (g_statistics[STAT_PIXEL_LOADS]) +
+ (g_statistics[STAT_PIXEL_STORES]) +
+ (g_statistics[STAT_TEXEL_BYTES]/4) +
+ (g_statistics[STAT_ZBUFFER_LOADS]) +
+ (g_statistics[STAT_ZBUFFER_STORES]);
+#if 0
+ logerror(">>> END OF LIST <<<\n");
+ logerror("Triangles: %u\n", g_statistics[STAT_TRIANGLES_PROCESSED]);
+ logerror("Texture samples: %u\n", g_statistics[STAT_TEXEL_READS]);
+ logerror("Texture bytes loaded: %u\n", g_statistics[STAT_TEXEL_BYTES]);
+ logerror("Pixels rasterized: %u\n", g_statistics[STAT_PIXELS_PROCESSED]);
+ logerror("Pixel reads: %u\n", g_statistics[STAT_PIXEL_LOADS]);
+ logerror("Pixel writes: %u\n", g_statistics[STAT_PIXEL_STORES]);
+ logerror("Z reads: %u\n", g_statistics[STAT_ZBUFFER_LOADS]);
+ logerror("Z writes: %u\n", g_statistics[STAT_ZBUFFER_STORES]);
+ logerror("Total: %u cycles (%fusec)\n", total_cycles, clocks_to_attotime(total_cycles).as_double()*1.0e6);
+#endif
+ timer_set(clocks_to_attotime(total_cycles), 0);
+#else
+ // Interrupt after stopping?
+ if (m_gc.te_master_mode & TEICNTL_INT)
+ {
+ set_interrupt(INTSTAT_IMMEDIATE_INSTR);
+ }
+#endif
+}
+
+
+
+/***************************************************************************
+ TEXTURE RAM ACCESSORS
+***************************************************************************/
+
+uint8_t m2_te_device::read_tram8(offs_t address) const
+{
+ address &= TEXTURE_RAM_BYTEMASK;
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_tram[0]) + BYTE4_XOR_BE(address);
+ return *ptr;
+}
+
+uint16_t m2_te_device::read_tram16(offs_t address) const
+{
+ address &= TEXTURE_RAM_BYTEMASK;
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_tram[0]) + address;//WORD_XOR_BE(address);
+ return *reinterpret_cast<uint16_t *>(ptr);
+}
+
+uint32_t m2_te_device::read_tram32(offs_t address) const
+{
+ address &= TEXTURE_RAM_BYTEMASK;
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_tram[0]) + address;//DWORD_XOR_BE(address);
+ return *reinterpret_cast<uint32_t *>(ptr);
+}
+
+void m2_te_device::write_tram8(offs_t address, uint8_t data)
+{
+ assert(address <= TEXTURE_RAM_WORDS * 4);
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_tram[0]) + address;//BYTE8_XOR_BE(address);
+ *ptr = data;
+}
+
+void m2_te_device::write_tram16(offs_t address, uint16_t data)
+{
+ assert(address < TEXTURE_RAM_WORDS * 4);
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_tram[0]) + WORD2_XOR_BE(address);
+ *reinterpret_cast<uint16_t *>(ptr) = data;
+}
+
+void m2_te_device::write_tram32(offs_t address, uint32_t data)
+{
+ address &= TEXTURE_RAM_BYTEMASK;
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_tram[0]) + address;//DWORD_XOR_BE(address);
+ *reinterpret_cast<uint32_t *>(ptr) = data;
+}
+
+
+
+/***************************************************************************
+ PIP RAM ACCESSORS
+***************************************************************************/
+
+uint8_t m2_te_device::read_pipram8(offs_t address) const
+{
+ address &= PIP_RAM_BYTEMASK;
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_pipram[0]) + address;//BYTE4_XOR_BE(address);
+ return *ptr;
+}
+
+uint16_t m2_te_device::read_pipram16(offs_t address) const
+{
+ address &= PIP_RAM_BYTEMASK;
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_pipram[0]) + address;//WORD_XOR_BE(address);
+ return *reinterpret_cast<uint16_t *>(ptr);
+}
+
+uint32_t m2_te_device::read_pipram32(offs_t address) const
+{
+ address &= PIP_RAM_BYTEMASK;
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_pipram[0]) + address;//DWORD_XOR_BE(address);
+ return *reinterpret_cast<uint32_t *>(ptr);
+}
+
+void m2_te_device::write_pipram32(offs_t address, uint32_t data)
+{
+ address &= PIP_RAM_BYTEMASK;
+
+ uint8_t *ptr = reinterpret_cast<uint8_t *>(&m_pipram[0]) + address;//DWORD_XOR_BE(address);
+ *reinterpret_cast<uint32_t *>(ptr) = data;
+}
+
+
+// For extracting bit fields from RAM
+uint32_t m2_te_device::readbits_from_ram(uint32_t & src_addr, uint32_t & bit_offs, uint32_t bits)
+{
+ uint32_t src_val = m_bda->read_bus32(src_addr);
+
+ if (((bit_offs & 31) + bits) > 32)
+ {
+ uint32_t src_val2 = m_bda->read_bus32(src_addr + 4);
+
+ uint32_t r_bits = ((bit_offs & 31) + bits) - 32;
+ uint32_t l_bits = bits - r_bits;
+
+ src_val &= (1 << l_bits) - 1;
+ src_val <<= r_bits;
+
+ // Position the right hand side
+ src_val2 >>= (32 - r_bits);
+ src_val2 &= (1 << r_bits) - 1;
+
+ src_val |= src_val2;
+ }
+ else
+ {
+ src_val = src_val >> (32 - (bits + (bit_offs & 31)));
+ }
+
+ return src_val &= (1 << bits) - 1;
+}
+
+void m2_te_device::load_texture()
+{
+ switch (m_tm.texld_cntl & TXTLDCNTL_LDMODE_MASK)
+ {
+ case TXTLDCNTL_LDMODE_TEXLOAD:
+ {
+ if (m_tm.texld_cntl & TXTLDCNTL_COMPRESSED)
+ {
+ // Source address is byte aligned
+ uint32_t src_addr = m_tm.texld_srcbase;
+ uint32_t bit_offs = m_tm.texld_cntl & TXTLDCNTL_SRCBITOFFS;
+
+ // Destination address is dword-aligned
+ uint32_t dst_addr = m_tm.texld_dstbase << 3;
+ int32_t texels = m_tm.tex_bytecnt;
+
+ uint32_t dst_type = m_tm.tex_exptype;
+ uint32_t dst_cdepth = (dst_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT;
+ uint32_t dst_adepth = (dst_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT;
+ uint32_t dst_bits = 0;
+
+ if (dst_type & TXTEXPFORM_COLORON)
+ {
+ if (dst_type & TXTEXPFORM_LITERAL)
+ dst_bits += dst_cdepth * 3;
+ else
+ dst_bits += dst_cdepth;
+ }
+
+ if (dst_type & TXTEXPFORM_SSBON)
+ ++dst_bits;
+
+ if (dst_bits & TXTEXPFORM_ALPHAON)
+ dst_bits += dst_adepth;
+
+ while (texels > 0)
+ {
+ uint8_t cntl = readbits_from_ram(src_addr, bit_offs, 8);
+
+ uint32_t type = (cntl >> 6) & 3;
+ uint32_t cnst;
+
+ // Select constant register
+ if (type == 0)
+ cnst = m_tm.tex_srcconst0;
+ else if (type == 1)
+ cnst = m_tm.tex_srcconst1;
+ else if (type == 2)
+ cnst = m_tm.tex_srcconst2;
+ else
+ cnst = m_tm.tex_srcconst3;
+
+ // Select pixel type register
+ uint32_t src_type = type & 2 ? m_tm.tex_srctype23 : m_tm.tex_srctype01;
+
+ if (type & 1)
+ src_type = src_type >> 16;
+
+ const bool has_color = src_type & TXTEXPFORM_COLORON;
+ const bool has_alpha = src_type & TXTEXPFORM_ALPHAON;
+ const bool has_ssb = src_type & TXTEXPFORM_SSBON;
+ const bool is_transparent = src_type & TXTEXPFORM_TRANSPARENT;
+ const bool is_literal = src_type & TXTEXPFORM_LITERAL;
+
+ uint32_t cnt = (cntl & (is_transparent ? 0x3f : 0x1f)) + 1;
+
+ uint32_t src_cdepth = (src_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT;
+ uint32_t src_adepth = (src_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT;
+ uint32_t src_bits = 0;
+
+ if (is_literal)
+ src_cdepth *= 3;
+
+ uint32_t src_val = 0;
+
+ if (is_transparent)
+ {
+ src_val = cnst;
+ }
+ else
+ {
+ src_bits += src_cdepth;
+
+ if (has_ssb)
+ ++src_bits;
+
+ if (has_alpha)
+ src_bits += src_adepth;
+ }
+
+ // String
+ if (!is_transparent && (cntl & 0x20))
+ {
+ for (uint32_t i = 0; i < cnt; ++i)
+ {
+ uint32_t dst_val = 0;
+ uint32_t src_ssb = 0;
+ uint32_t src_color = 0;
+ uint32_t src_alpha = 0;
+ uint32_t src_val = readbits_from_ram(src_addr, bit_offs, src_bits);
+
+#if TEST_TIMING // FIXME
+ g_statistics[STAT_TEXEL_BYTES] += 4;
+#endif
+
+ if (has_color)
+ {
+ src_color = src_val & ((1 << src_cdepth) - 1);
+ src_val >>= src_cdepth;
+
+ // Indexed format - add an offset
+ if (!(src_type & TXTEXPFORM_INDEXON))
+ src_color += cnst & 0xff;
+ }
+
+ if (has_alpha)
+ {
+ if (is_transparent)
+ {
+ src_alpha = (cnst >> 24) & ((1 << src_adepth) - 1);
+ }
+ else
+ {
+ src_alpha = src_val & ((1 << src_adepth) - 1);
+ src_val >>= src_adepth;
+ }
+ }
+
+ if (has_ssb)
+ {
+ if (is_transparent)
+ src_ssb = (cnst >> 31) & 1;
+ else
+ src_ssb = src_val & 1;
+ }
+
+ // Now create the destination value
+ dst_val = src_color
+ | (src_alpha << src_cdepth)
+ | (src_ssb << (src_cdepth + src_adepth));
+
+ uint32_t oldval = m_tram[(dst_addr >> 3) >> 2];
+
+ // Clear out the old value
+ uint32_t shift = (32 - (dst_bits + (dst_addr & 31)));
+ oldval &= ~(((1 << dst_bits) - 1) << shift);
+ oldval |= dst_val << shift;
+
+ m_tram[(dst_addr >> 3) >> 2] = oldval;
+
+ //src_addr += src_bits;
+ dst_addr += dst_bits;
+ }
+ }
+ else
+ {
+ uint32_t dst_val;
+
+ if (!is_transparent)
+ {
+ // Read one texel
+ src_val = readbits_from_ram(src_addr, bit_offs, src_bits);
+
+#if TEST_TIMING // FIXME
+ g_statistics[STAT_TEXEL_BYTES] += 4;
+#endif
+
+ // Indexed format - add an offset
+ if (!is_literal)
+ src_val += cnst & 0xff;
+ }
+
+ // HACK: Bits don't match?
+ dst_val = src_val;
+
+ for (uint32_t i = 0; i < cnt; ++i)
+ {
+ uint32_t oldval = m_tram[(dst_addr >> 3) & ~3];
+
+ // Clear out the old value
+ uint32_t shift = (32 - (dst_bits + (dst_addr & 31)));
+ oldval &= ~(((1 << dst_bits) - 1) << shift);
+ oldval |= dst_val << shift;
+
+ m_tram[(dst_addr >> 3) >> 2] = oldval;
+
+ dst_addr += dst_bits;
+ }
+
+ // Copy
+ //src_addr += src_bits;
+ }
+
+ texels -= cnt;
+ // assert if negative?
+ }
+ }
+ else
+ {
+ // Regular
+ fatalerror("REGULAR TEXTURE NOT SUPPORTED\n");
+ }
+
+ break;
+ }
+
+ case TXTLDCNTL_LDMODE_MMDMA:
+ {
+ uint32_t srcaddr = m_tm.tex_mm_srcbase;
+ uint32_t dstaddr = m_tm.tex_mm_dstbase;
+ uint32_t bytes = m_tm.tex_bytecnt;
+
+ // TODO: Do TRAM and PIPRAM only allow 32-bit accesses?
+ assert((bytes & 3) == 0);
+
+ if (m_tm.tex_cntl & TXTCNTL_MMDMA_TRAM_ON)
+ {
+ // TRAM destination must be 32-bit aligned
+ assert((dstaddr & 3) == 0);
+
+ while (bytes > 0)
+ {
+#if 0
+ uint32_t data = m_bda->read_bus32(srcaddr);
+ write_tram32(dstaddr, data);
+ dstaddr += 4;
+ srcaddr += 4;
+ bytes -= 4;
+#else
+ uint32_t data = m_bda->read_bus8(srcaddr);
+ write_tram8(dstaddr, data);
+ dstaddr ++;
+ srcaddr ++;
+ bytes--;
+
+#if TEST_TIMING
+ g_statistics[STAT_TEXEL_BYTES]++;
+#endif
+
+#endif
+ }
+ }
+ else if (m_tm.tex_cntl & TXTCNTL_MMDMA_PIP_ON)
+ {
+ // TODO: Should PIP destination be 32-bit aligned?
+ assert((dstaddr & 3) == 0);
+
+ while (bytes > 0)
+ {
+ uint32_t data = m_bda->read_bus32(srcaddr);
+ write_pipram32(dstaddr, data);
+ dstaddr += 4;
+ srcaddr += 4;
+ bytes -= 4;
+
+#if TEST_TIMING
+ g_statistics[STAT_TEXEL_BYTES] += 4;
+#endif
+ }
+ }
+
+ break;
+ }
+
+ case TXTLDCNTL_LDMODE_PIPLOAD:
+ {
+ // TODO: What is the difference between this and the MMDMA?
+ uint32_t srcaddr = m_tm.texld_srcbase;
+ uint32_t dstaddr = m_tm.texld_dstbase;
+ uint32_t bytes = m_tm.tex_bytecnt;
+
+ // Assuming byte count must be aligned?
+ assert((m_tm.tex_bytecnt & 3) == 0);
+
+ while (bytes > 0)
+ {
+ uint32_t data = m_bda->read_bus32(srcaddr);
+ write_pipram32(dstaddr, data);
+ dstaddr += 4;
+ srcaddr += 4;
+ bytes -= 4;
+#if TEST_TIMING
+ g_statistics[STAT_TEXEL_BYTES] += 4;
+#endif
+ }
+
+ break;
+ }
+
+ default:
+ {
+ logerror("UNHANDLED TEXTURE LOAD!\n");
+ break;
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ TIMERS
+***************************************************************************/
+
+void m2_te_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case 0:
+ if (m_gc.te_master_mode & TEICNTL_INT)
+ set_interrupt(INTSTAT_IMMEDIATE_INSTR);
+ break;
+ }
+
+}
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 39208932d13..c2e0f4da982 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -17780,7 +17780,6 @@ winspike // 1997.?? GX705 (Europe)
winspikej // 1997.07 GX705 (Japan)
@source:konamim2.cpp
-3do_m2 //
btltryst // GX636 (c) 1998
evilngt // GX810 (c) 1998
evilngte // GX810 (c) 1998
@@ -38521,10 +38520,6 @@ vigilanto // (c) 1988 (US)
@source:vii.cpp
batmantv // The Batman, 2004
vii // KenSingTon / Jungle Soft / Siatronics Vii
-vsmile //
-vsmileb //
-vsmilef //
-vsmileg //
walle //
wrlshunt // Wireless: Hunting Video Game System
wirels60 // Wireless 60
@@ -38536,6 +38531,12 @@ rad_skatp //
rad_sktv //
rad_crik //
+@source:vsmile.cpp
+vsmile //
+vsmileb //
+vsmilef //
+vsmileg //
+
@source:vsmilepro.cpp
vsmilpro
diff --git a/src/mame/mess.flt b/src/mame/mess.flt
index 15343435a83..537c9960a4b 100644
--- a/src/mame/mess.flt
+++ b/src/mame/mess.flt
@@ -825,6 +825,7 @@ votrpss.cpp
votrtnt.cpp
vp415.cpp
vp60.cpp
+vsmile.cpp
vsmilepro.cpp
vt100.cpp
vt220.cpp
@@ -890,7 +891,6 @@ zx.cpp
+jaguar
+jaguarcd
//konamim2.cpp
-+3do_m2
//neogeo.cpp
+aes
//vectrex.cpp