// license:BSD-3-Clause // copyright-holders:Philip Bennett /*************************************************************************** 3DO M2 TODO: Move reg defines out of classes and into source ***************************************************************************/ #ifndef MAME_MACHINE_3DOM2_H #define MAME_MACHINE_3DOM2_H #pragma once #include "video/3dom2_te.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 m2_reg_wmode { REG_WRITE, REG_INVALID, REG_SET, REG_CLEAR, }; /*************************************************************************** FORWARD DECLARATIONS ***************************************************************************/ class m2_bda_device; class m2_powerbus_device; class m2_memctl_device; class m2_vdu_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 m2_bda_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu1_tag, U &&cpu2_tag, V &&cde_tag) : m2_bda_device(mconfig, tag, owner, clock) { m_cpu1.set_tag(std::forward(cpu1_tag)); m_cpu2.set_tag(std::forward(cpu2_tag)); m_cde.set_tag(std::forward(cde_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 uint32_t cpu_id_r(address_space &space); void cpu_id_w(address_space &space, uint32_t 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 m_cpu1; required_device m_cpu2; required_device m_cde; devcb_read_line m_videores_in; // Sub-devices required_device m_memctl; required_device m_powerbus; required_device m_vdu; required_device m_ctrlport; required_device m_dspp; required_device m_mpeg; required_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 WRITE_LINE_MEMBER( int_line ) { if (state) m_int_status |= 1 << line; else m_int_status &= ~(1 << line); update_interrupts(); } void write(offs_t offset, uint32_t data); uint32_t read(offs_t offset); 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 auto gpio_in_handler() { return m_gpio_in[Line].bind(); } template auto gpio_out_handler() { return m_gpio_out[Line].bind(); } uint32_t read(offs_t offset, uint32_t mem_mask = ~0); void write(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); 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::array<4> m_gpio_in; devcb_write_line::array<4> m_gpio_out; // 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 void set_screen(T &&screen_tag) { m_screen.set_tag(std::forward(screen_tag)); } uint32_t read(offs_t offset, uint32_t mem_mask = ~0); void write(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); 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 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); uint32_t read(offs_t offset); void write(offs_t offset, uint32_t data); protected: virtual void device_start() override; virtual void device_reset() override; private: }; /*************************************************************************** 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); uint32_t read(offs_t offset); void write(offs_t offset, uint32_t data); protected: virtual void device_start() override; virtual void device_reset() override; private: }; /*************************************************************************** CDE ASIC DEVICE ***************************************************************************/ class m2_cde_device : public device_t { public: template m2_cde_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu1_tag, U &&bda_tag) : m2_cde_device(mconfig, tag, owner, clock) { m_cpu1.set_tag(std::forward(cpu1_tag)); m_bda.set_tag(std::forward(bda_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(); } uint32_t read(address_space &space, offs_t offset, uint32_t mem_mask = ~0); void write(address_space &space, offs_t offset, uint32_t data, uint32_t mem_mask = ~0); void sdbg_in(uint32_t data); 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); static uint32_t address_to_biobus_slot(uint32_t addr) { if ((addr < 0x20000000) || (addr > 0x3fffffff)) throw emu_fatalerror("m2_cde_device::address_to_biobus_slot: Address not within BioBus address range"); return ((addr >> 24) >> 2) & 7; } required_device m_cpu1; required_device m_bda; 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) #endif // MAME_MACHINE_3DOM2_H