// license:BSD-3-Clause // copyright-holders:Angelo Salese, R. Belmont, Anthony Kruize, Fabio Priuli, Ryan Holtz #ifndef MAME_INCLUDES_SNES_H #define MAME_INCLUDES_SNES_H #include "cpu/spc700/spc700.h" #include "cpu/g65816/g65816.h" #include "audio/snes_snd.h" #include "video/snes_ppu.h" #include "screen.h" /* SNES timing theory: the master clock drives the CPU and PPU 4 MC ticks = 1 PPU dot 6 MC ticks = 1 65816 cycle for 3.58 MHz (3.579545) 8 MC ticks = 1 65816 cycle for 2.68 MHz (2.684659) 12 MC ticks = 1 65816 cycle for 1.78 MHz (1.789772) Each scanline has 341 readable positions and 342 actual dots. This is because 2 dots are "long" dots that last 6 MC ticks, resulting in 1 extra dot per line. */ // Useful definitions #define SNES_DMA_BASE 0x4300 /* Base DMA register address */ #define SNES_MODE_20 0x01 /* Lo-ROM cart */ #define SNES_MODE_21 0x02 /* Hi-ROM cart */ #define SNES_MODE_22 0x04 /* Extended Lo-ROM cart - SDD-1 */ #define SNES_MODE_25 0x08 /* Extended Hi-ROM cart */ #define SNES_MODE_BSX 0x10 #define SNES_MODE_BSLO 0x20 #define SNES_MODE_BSHI 0x40 #define SNES_MODE_ST 0x80 #define SNES_EXROM_START 0x1000000 // some PPU registers we still use in machine/snes.c #define INIDISP 0x2100 #define OAMADDL 0x2102 #define OAMADDH 0x2103 #define SETINI 0x2133 #define MPYL 0x2134 #define MPYM 0x2135 #define MPYH 0x2136 #define APU00 0x2140 #define APU01 0x2141 #define APU02 0x2142 #define APU03 0x2143 #define WMDATA 0x2180 #define WMADDL 0x2181 #define WMADDM 0x2182 #define WMADDH 0x2183 // Definitions for CPU Memory-Mapped registers #define OLDJOY1 0x4016 #define OLDJOY2 0x4017 #define NMITIMEN 0x4200 #define WRIO 0x4201 //#define WRMPYA 0x4202 //#define WRMPYB 0x4203 //#define WRDIVL 0x4204 //#define WRDIVH 0x4205 //#define WRDVDD 0x4206 #define HTIMEL 0x4207 #define HTIMEH 0x4208 #define VTIMEL 0x4209 #define VTIMEH 0x420A #define MDMAEN 0x420B #define HDMAEN 0x420C //#define MEMSEL 0x420D #define RDNMI 0x4210 #define TIMEUP 0x4211 #define HVBJOY 0x4212 #define RDIO 0x4213 //#define RDDIVL 0x4214 //#define RDDIVH 0x4215 //#define RDMPYL 0x4216 //#define RDMPYH 0x4217 #define JOY1L 0x4218 #define JOY1H 0x4219 #define JOY2L 0x421A #define JOY2H 0x421B #define JOY3L 0x421C #define JOY3H 0x421D #define JOY4L 0x421E #define JOY4H 0x421F /* DMA */ #define DMAP0 0x4300 #define BBAD0 0x4301 #define A1T0L 0x4302 #define A1T0H 0x4303 #define A1B0 0x4304 #define DAS0L 0x4305 #define DAS0H 0x4306 #define DSAB0 0x4307 #define A2A0L 0x4308 #define A2A0H 0x4309 #define NTRL0 0x430A #define DMAP1 0x4310 #define BBAD1 0x4311 #define A1T1L 0x4312 #define A1T1H 0x4313 #define A1B1 0x4314 #define DAS1L 0x4315 #define DAS1H 0x4316 #define DSAB1 0x4317 #define A2A1L 0x4318 #define A2A1H 0x4319 #define NTRL1 0x431A #define DMAP2 0x4320 #define BBAD2 0x4321 #define A1T2L 0x4322 #define A1T2H 0x4323 #define A1B2 0x4324 #define DAS2L 0x4325 #define DAS2H 0x4326 #define DSAB2 0x4327 #define A2A2L 0x4328 #define A2A2H 0x4329 #define NTRL2 0x432A #define DMAP3 0x4330 #define BBAD3 0x4331 #define A1T3L 0x4332 #define A1T3H 0x4333 #define A1B3 0x4334 #define DAS3L 0x4335 #define DAS3H 0x4336 #define DSAB3 0x4337 #define A2A3L 0x4338 #define A2A3H 0x4339 #define NTRL3 0x433A #define DMAP4 0x4340 #define BBAD4 0x4341 #define A1T4L 0x4342 #define A1T4H 0x4343 #define A1B4 0x4344 #define DAS4L 0x4345 #define DAS4H 0x4346 #define DSAB4 0x4347 #define A2A4L 0x4348 #define A2A4H 0x4349 #define NTRL4 0x434A #define DMAP5 0x4350 #define BBAD5 0x4351 #define A1T5L 0x4352 #define A1T5H 0x4353 #define A1B5 0x4354 #define DAS5L 0x4355 #define DAS5H 0x4356 #define DSAB5 0x4357 #define A2A5L 0x4358 #define A2A5H 0x4359 #define NTRL5 0x435A #define DMAP6 0x4360 #define BBAD6 0x4361 #define A1T6L 0x4362 #define A1T6H 0x4363 #define A1B6 0x4364 #define DAS6L 0x4365 #define DAS6H 0x4366 #define DSAB6 0x4367 #define A2A6L 0x4368 #define A2A6H 0x4369 #define NTRL6 0x436A #define DMAP7 0x4370 #define BBAD7 0x4371 #define A1T7L 0x4372 #define A1T7H 0x4373 #define A1B7 0x4374 #define DAS7L 0x4375 #define DAS7H 0x4376 #define DSAB7 0x4377 #define A2A7L 0x4378 #define A2A7H 0x4379 #define NTRL7 0x437A /* Definitions for sound DSP */ #define DSP_V0_VOLL 0x00 #define DSP_V0_VOLR 0x01 #define DSP_V0_PITCHL 0x02 #define DSP_V0_PITCHH 0x03 #define DSP_V0_SRCN 0x04 #define DSP_V0_ADSR1 0x05 /* gdddaaaa = g:gain enable | d:decay | a:attack */ #define DSP_V0_ADSR2 0x06 /* llllrrrr = l:sustain left | r:sustain right */ #define DSP_V0_GAIN 0x07 #define DSP_V0_ENVX 0x08 #define DSP_V0_OUTX 0x09 #define DSP_V1_VOLL 0x10 #define DSP_V1_VOLR 0x11 #define DSP_V1_PITCHL 0x12 #define DSP_V1_PITCHH 0x13 #define DSP_V1_SRCN 0x14 #define DSP_V1_ADSR1 0x15 #define DSP_V1_ADSR2 0x16 #define DSP_V1_GAIN 0x17 #define DSP_V1_ENVX 0x18 #define DSP_V1_OUTX 0x19 #define DSP_V2_VOLL 0x20 #define DSP_V2_VOLR 0x21 #define DSP_V2_PITCHL 0x22 #define DSP_V2_PITCHH 0x23 #define DSP_V2_SRCN 0x24 #define DSP_V2_ADSR1 0x25 #define DSP_V2_ADSR2 0x26 #define DSP_V2_GAIN 0x27 #define DSP_V2_ENVX 0x28 #define DSP_V2_OUTX 0x29 #define DSP_V3_VOLL 0x30 #define DSP_V3_VOLR 0x31 #define DSP_V3_PITCHL 0x32 #define DSP_V3_PITCHH 0x33 #define DSP_V3_SRCN 0x34 #define DSP_V3_ADSR1 0x35 #define DSP_V3_ADSR2 0x36 #define DSP_V3_GAIN 0x37 #define DSP_V3_ENVX 0x38 #define DSP_V3_OUTX 0x39 #define DSP_V4_VOLL 0x40 #define DSP_V4_VOLR 0x41 #define DSP_V4_PITCHL 0x42 #define DSP_V4_PITCHH 0x43 #define DSP_V4_SRCN 0x44 #define DSP_V4_ADSR1 0x45 #define DSP_V4_ADSR2 0x46 #define DSP_V4_GAIN 0x47 #define DSP_V4_ENVX 0x48 #define DSP_V4_OUTX 0x49 #define DSP_V5_VOLL 0x50 #define DSP_V5_VOLR 0x51 #define DSP_V5_PITCHL 0x52 #define DSP_V5_PITCHH 0x53 #define DSP_V5_SRCN 0x54 #define DSP_V5_ADSR1 0x55 #define DSP_V5_ADSR2 0x56 #define DSP_V5_GAIN 0x57 #define DSP_V5_ENVX 0x58 #define DSP_V5_OUTX 0x59 #define DSP_V6_VOLL 0x60 #define DSP_V6_VOLR 0x61 #define DSP_V6_PITCHL 0x62 #define DSP_V6_PITCHH 0x63 #define DSP_V6_SRCN 0x64 #define DSP_V6_ADSR1 0x65 #define DSP_V6_ADSR2 0x66 #define DSP_V6_GAIN 0x67 #define DSP_V6_ENVX 0x68 #define DSP_V6_OUTX 0x69 #define DSP_V7_VOLL 0x70 #define DSP_V7_VOLR 0x71 #define DSP_V7_PITCHL 0x72 #define DSP_V7_PITCHH 0x73 #define DSP_V7_SRCN 0x74 #define DSP_V7_ADSR1 0x75 #define DSP_V7_ADSR2 0x76 #define DSP_V7_GAIN 0x77 #define DSP_V7_ENVX 0x78 #define DSP_V7_OUTX 0x79 #define DSP_MVOLL 0x0C #define DSP_MVOLR 0x1C #define DSP_EVOLL 0x2C #define DSP_EVOLR 0x3C #define DSP_KON 0x4C /* 01234567 = Key on for voices 0-7 */ #define DSP_KOF 0x5C /* 01234567 = Key off for voices 0-7 */ #define DSP_FLG 0x6C /* rme--n-- = r:Soft reset | m:Mute | e:External memory through echo | n:Clock of noise generator */ #define DSP_ENDX 0x7C #define DSP_EFB 0x0D /* sfffffff = s: sign bit | f: feedback */ #define DSP_PMOD 0x2D #define DSP_NON 0x3D #define DSP_EON 0x4D #define DSP_DIR 0x5D #define DSP_ESA 0x6D #define DSP_EDL 0x7D /* ----dddd = d: echo delay */ #define DSP_FIR_C0 0x0F #define DSP_FIR_C1 0x1F #define DSP_FIR_C2 0x2F #define DSP_FIR_C3 0x3F #define DSP_FIR_C4 0x4F #define DSP_FIR_C5 0x5F #define DSP_FIR_C6 0x6F #define DSP_FIR_C7 0x7F #define SNES_CPU_REG(a) m_cpu_regs[a - 0x4200] // regs 0x4200-0x421f struct snes_cart_info { uint8_t *m_rom; uint32_t m_rom_size; std::unique_ptr m_nvram; uint32_t m_nvram_size; uint8_t mode; /* ROM memory mode */ uint32_t sram_max; /* Maximum amount sram in cart (based on ROM mode) */ int slot_in_use; /* this is needed by Sufami Turbo slots (to check if SRAM has to be saved) */ uint8_t rom_bank_map[0x100]; }; class snes_state : public driver_device { public: enum { TIMER_NMI_TICK, TIMER_HIRQ_TICK, TIMER_RESET_OAM_ADDRESS, TIMER_RESET_HDMA, TIMER_UPDATE_IO, TIMER_SCANLINE_TICK, TIMER_HBLANK_TICK, TIMER_SNES_LAST }; snes_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), m_soundcpu(*this, "soundcpu"), m_spc700(*this, "spc700"), m_ppu(*this, "ppu"), m_screen(*this, "screen") { } /* misc */ uint16_t m_hblank_offset; uint32_t m_wram_address; uint16_t m_htime; uint16_t m_vtime; bool m_is_pal; /* non-SNES HW-specific flags / variables */ uint8_t m_is_nss; uint8_t m_input_disabled; uint8_t m_game_over_flag; uint8_t m_joy_flag; uint8_t m_is_sfcbox; /* timers */ emu_timer *m_scanline_timer; emu_timer *m_hblank_timer; emu_timer *m_nmi_timer; emu_timer *m_hirq_timer; // emu_timer *m_div_timer; // emu_timer *m_mult_timer; emu_timer *m_io_timer; /* DMA/HDMA-related */ struct { uint8_t dmap; uint8_t dest_addr; uint16_t src_addr; uint16_t trans_size; uint8_t bank; uint8_t ibank; uint16_t hdma_addr; uint16_t hdma_iaddr; uint8_t hdma_line_counter; uint8_t unk; int do_transfer; int dma_disabled; // used to stop DMA if HDMA is enabled (currently not implemented, see machine/snes.c) } m_dma_channel[8]; uint8_t m_hdmaen; /* channels enabled for HDMA */ uint8_t m_dma_regs[0x80]; uint8_t m_cpu_regs[0x20]; uint8_t m_oldjoy1_latch; /* input-related */ uint16_t m_data1[4]; // JOY1/JOY2 + 3rd & 4th only used by multitap (hacky support) uint16_t m_data2[4]; // JOY3/JOY4 + 3rd & 4th only used by multitap (hacky support) uint8_t m_read_idx[4]; // 3rd & 4th only used by multitap (hacky support) /* cart related */ snes_cart_info m_cart; // used by NSS/SFCBox only! to be moved in a derived class! void rom_map_setup(uint32_t size); uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); /* devices */ required_device<_5a22_device> m_maincpu; required_device m_soundcpu; required_device m_spc700; required_device m_ppu; required_device m_screen; void init_snes(); void init_snes_hirom(); void init_snes_mess(); void init_snesst(); inline int dma_abus_valid(uint32_t address); inline uint8_t abus_read(address_space &space, uint32_t abus); inline void dma_transfer(address_space &space, uint8_t dma, uint32_t abus, uint16_t bbus); inline int is_last_active_channel(int dma); inline uint32_t get_hdma_addr(int dma); inline uint32_t get_hdma_iaddr(int dma); void dma(address_space &space, uint8_t channels); void hdma(address_space &space); void hdma_init(address_space &space); void hdma_update(address_space &space, int dma); void hirq_tick(); virtual void write_joy_latch(uint8_t data); virtual void wrio_write(uint8_t data); inline uint8_t snes_rom_access(uint32_t offset); void snes_init_ram(); // input related virtual DECLARE_WRITE8_MEMBER(io_read); virtual uint8_t oldjoy1_read(int latched); virtual uint8_t oldjoy2_read(int latched); DECLARE_READ8_MEMBER(snes_r_io); DECLARE_WRITE8_MEMBER(snes_w_io); DECLARE_READ8_MEMBER(snes_io_dma_r); DECLARE_WRITE8_MEMBER(snes_io_dma_w); DECLARE_READ8_MEMBER(snes_r_bank1); DECLARE_READ8_MEMBER(snes_r_bank2); DECLARE_WRITE8_MEMBER(snes_w_bank1); DECLARE_WRITE8_MEMBER(snes_w_bank2); uint8_t snes_open_bus_r(); DECLARE_READ8_MEMBER(snes_open_bus_r); TIMER_CALLBACK_MEMBER(snes_nmi_tick); TIMER_CALLBACK_MEMBER(snes_hirq_tick_callback); TIMER_CALLBACK_MEMBER(snes_reset_oam_address); TIMER_CALLBACK_MEMBER(snes_reset_hdma); TIMER_CALLBACK_MEMBER(snes_update_io); TIMER_CALLBACK_MEMBER(snes_scanline_tick); TIMER_CALLBACK_MEMBER(snes_hblank_tick); DECLARE_WRITE_LINE_MEMBER(snes_extern_irq_w); DECLARE_DEVICE_IMAGE_LOAD_MEMBER(snes_cart); DECLARE_DEVICE_IMAGE_LOAD_MEMBER(sufami_cart); void snes_init_timers(); virtual void machine_start() override; virtual void machine_reset() override; protected: virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; }; /* Special chips, checked at init and used in memory handlers */ enum { HAS_NONE = 0, HAS_DSP1, HAS_DSP2, HAS_DSP3, HAS_DSP4, HAS_SUPERFX, HAS_SA1, HAS_SDD1, HAS_OBC1, HAS_RTC, HAS_Z80GB, HAS_CX4, HAS_ST010, HAS_ST011, HAS_ST018, HAS_SPC7110, HAS_SPC7110_RTC, HAS_UNK }; #endif // MAME_INCLUDES_SNES_H