diff options
author | 2018-12-22 17:06:23 +0100 | |
---|---|---|
committer | 2018-12-22 17:06:47 +0100 | |
commit | dc8834b8dca7f63288f3f512d7e8600356485808 (patch) | |
tree | cb81425c648108f02542ae493e91ec96ad3d2ac4 | |
parent | 1fd2f33b314b18237e80d8c6a9f70b580854802a (diff) |
Last round of macro removals before the freeze. (nw)
-sound/discrete, okim6295: Removed MCFG macros. [Ryan Holtz]
-norautp, osi, audio/mario: Removed MACHINE_CONFIG macros. [Ryan Holtz]
-vsmile: Split into its own driver from vii.cpp. [Ryan Holtz]
-vii: Fixed broken controller inputs. [Ryan Holtz]
-konamim2: Massive update. Most games work, but are still marked non-working due to rare MAME crashes in the PPC DRC. [Phil Bennett, Ryan Holtz]
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 ¶ms) +{ +#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 ¶ms) 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> ¶ms); + void debug_commands(int ref, const std::vector<std::string> ¶ms); - 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> ¶ms); +}; - 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(¤t_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> ¶ms) +{ + 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> ¶ms) +{ + 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> ¶ms) +{ + 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 ®, 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 ®, 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 ®, 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 |