1 // license:BSD-3-Clause
2 // copyright-holders:Fabio Priuli
3 #ifndef MAME_BUS_MEGADRIVE_MD_SLOT_H
4 #define MAME_BUS_MEGADRIVE_MD_SLOT_H
5 
6 #pragma once
7 
8 #include "softlist_dev.h"
9 
10 /***************************************************************************
11  TYPE DEFINITIONS
12  ***************************************************************************/
13 
14 #define MD_ADDR(a)  (rom_bank_map[((a << 1) / 0x10000) & 0x3f] * 0x10000 + ((a << 1) & 0xffff))/2
15 
16 /* PCB */
17 enum
18 {
19 	SEGA_STD = 0,
20 
21 	// Cart + Slot Expansion
22 	SEGA_SK,                     /* Sonic & Knuckles pass-through cart */
23 
24 	// Cart + SVP
25 	SEGA_SVP,                    /* Virtua Racing */
26 
27 	// Cart + NVRAM
28 	SEGA_SRAM, SEGA_FRAM,
29 	HARDBALL95,                  /* Hardball 95 uses different sram start address */
30 	XINQIG,                   /* Xin Qigai Wangzi uses different sram start address and has no valid header */
31 	BEGGARP,                     /* Beggar Prince uses different sram start address + bankswitch tricks */
32 	WUKONG,                      /* Legend of Wukong uses different sram start address + bankswitch trick for last 128K of ROM */
33 	STARODYS,                    /* Star Odyssey */
34 
35 	// EEPROM
36 	SEGA_EEPROM,                 /* Wonder Boy V / Evander Holyfield's Boxing / Greatest Heavyweights of the Ring / Sports Talk Baseball / Megaman */
37 	NBA_JAM,                     /* NBA Jam */
38 	NBA_JAM_ALT,                     /* NBA Jam */
39 	NBA_JAM_TE,                  /* NBA Jam TE / NFL Quarterback Club */
40 	NFL_QB_96,                   /* NFL Quarterback Club '96 */
41 	C_SLAM,                      /* College Slam / Frank Thomas Big Hurt Baseball */
42 	EA_NHLPA,                    /* NHLPA Hockey 93 / Rings of Power */
43 	BRIAN_LARA,                  /* Brian Lara Cricket 96 */
44 	PSOLAR,                      /* Pier Solar (STM95 EEPROM) */
45 
46 	// J-Cart
47 	CM_JCART,                    /* Pete Sampras Tennis */
48 	CODE_MASTERS,                /* Micro Machines 2 / Military (J-Cart + SEPROM)  */
49 	CM_MM96,                     /* Micro Machines 96 (J-Cart + SEPROM, diff I2C model)  */
50 
51 	// Various
52 	SSF2,                        /* Super Street Fighter 2 */
53 	CM_2IN1,                     /* CodeMasters 2in1 : Psycho Pinball + Micro Machines */
54 	GAME_KANDUME,                /* Game no Kandume Otokuyou */
55 	RADICA,                      /* Radica TV games.. these probably should be a separate driver since they are a separate 'console' */
56 
57 	TILESMJ2,                    /* 16 Mahjong Tiles II */
58 	BUGSLIFE,                    /* A Bug's Life */
59 	CHINFIGHT3,                  /* Chinese Fighters 3 */
60 	ELFWOR,                      /* Linghuan Daoshi Super Magician */
61 	KAIJU,                       /* Pokemon Stadium */
62 	KOF98,                       /* King of Fighters '98 */
63 	KOF99,                       /* King of Fighters '99 */
64 	LIONK2,                      /* Lion King 2 */
65 	LIONK3,                      /* Lion King 3, Super Donkey Kong 99, Super King Kong 99 */
66 	MC_PIRATE,                   /* Super 19 in 1, Super 15 in 1, 12 in 1 and a few more multicarts */
67 	MJLOVER,                     /* Mahjong Lover */
68 	CJMJCLUB,                    /* Super Mahjong Club */
69 	POKEMONA,                    /* Pocket Monster Alt Protection */
70 	REALTEC,                     /* Whac a Critter/Mallet legend, Defend the Earth, Funnyworld/Ballonboy */
71 	REDCLIFF,                    /* Romance of the Three Kingdoms - Battle of Red Cliffs, already decoded from .mdx format */
72 	REDCL_EN,                    /* The encoded version... */
73 	ROCKMANX3,                   /* Rockman X3 */
74 	SBUBBOB,                     /* Super Bubble Bobble */
75 	SMB,                         /* Super Mario Bros. */
76 	SMB2,                        /* Super Mario Bros. 2 */
77 	SMW64,                       /* Super Mario World 64 */
78 	SMOUSE,                      /* Smart Mouse */
79 	SOULBLAD,                    /* Soul Blade */
80 	SQUIRRELK,                   /* Squirrel King */
81 	TEKKENSP,                    /* Tekken Special */
82 	TOPFIGHTER,                  /* Top Fighter 2000 MK VIII */
83 
84 	// when loading from fullpath, we need to treat SRAM in custom way
85 	SEGA_SRAM_FULLPATH,
86 	SEGA_SRAM_FALLBACK
87 };
88 
89 
90 // ======================> device_md_cart_interface
91 
92 class device_md_cart_interface : public device_interface
93 {
94 	friend class base_md_cart_slot_device;
95 public:
96 	// construction/destruction
97 	virtual ~device_md_cart_interface();
98 
99 	// reading and writing
read(offs_t offset)100 	virtual uint16_t read(offs_t offset) { return 0xffff; }
101 	virtual void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) {}
read_a13(offs_t offset)102 	virtual uint16_t read_a13(offs_t offset) { return 0xffff; }
write_a13(offs_t offset,uint16_t data)103 	virtual void write_a13(offs_t offset, uint16_t data) {}
read_a15(offs_t offset)104 	virtual uint16_t read_a15(offs_t offset) { return 0xffff; }
write_a15(offs_t offset,uint16_t data)105 	virtual void write_a15(offs_t offset, uint16_t data) {}
106 
read_test()107 	virtual int read_test() { return 0; }   // used by Virtua Racing test
108 
109 	// this probably should do more, like make Genesis V2 'die' if the SEGA string is not written promptly
write_tmss_bank(offs_t offset,uint16_t data)110 	virtual void write_tmss_bank(offs_t offset, uint16_t data) { device().logerror("Write to TMSS bank: offset %x data %x\n", 0xa14000 + (offset << 1), data); };
111 
112 	virtual void rom_alloc(size_t size, const char *tag);
113 	virtual void nvram_alloc(size_t size);
get_rom_base()114 	virtual uint16_t* get_rom_base() { return m_rom; };
get_nvram_base()115 	virtual uint16_t* get_nvram_base() { return &m_nvram[0]; };
get_rom_size()116 	virtual uint32_t get_rom_size() { return m_rom_size; };
get_nvram_size()117 	virtual uint32_t get_nvram_size() { return m_nvram.size()*sizeof(uint16_t); };
set_bank_to_rom(const char * banktag,uint32_t offset)118 	virtual void set_bank_to_rom(const char *banktag, uint32_t offset) {};
119 
save_nvram()120 	void save_nvram() { device().save_item(NAME(m_nvram)); }
121 
122 	void rom_map_setup(uint32_t size);
123 	uint32_t get_padded_size(uint32_t size);
124 
125 protected:
126 	device_md_cart_interface(const machine_config &mconfig, device_t &device);
127 
128 	int m_nvram_start, m_nvram_end;
129 	int m_nvram_active, m_nvram_readonly;
130 
131 	// when loading from fullpath, we create NVRAM even if not set in the header
132 	// however in this case we access it only if the game turn it on
133 	// the variable below is basically needed to track this...
134 	int m_nvram_handlers_installed;
135 
136 	// internal state
137 public: // FIXME: this needs to be public because the S&K "lock-on" cart is implemented in a really dodgy way
138 	uint16_t  *m_rom;
139 protected:
140 	uint32_t  m_rom_size;
141 	std::vector<uint16_t> m_nvram;
142 
143 	uint8_t rom_bank_map[128];    // 64K chunks of rom
144 };
145 
146 
147 // ======================> base_md_cart_slot_device
148 
149 class base_md_cart_slot_device : public device_t,
150 								public device_image_interface,
151 								public device_single_card_slot_interface<device_md_cart_interface>
152 {
153 public:
154 	// construction/destruction
155 	virtual ~base_md_cart_slot_device();
156 
157 	// image-level overrides
158 	virtual image_init_result call_load() override;
159 	virtual void call_unload() override;
160 
image_type()161 	virtual iodevice_t image_type() const noexcept override { return IO_CARTSLOT; }
is_readable()162 	virtual bool is_readable()  const noexcept override { return true; }
is_writeable()163 	virtual bool is_writeable() const noexcept override { return false; }
is_creatable()164 	virtual bool is_creatable() const noexcept override { return false; }
must_be_loaded()165 	virtual bool must_be_loaded() const noexcept override { return m_must_be_loaded; }
is_reset_on_load()166 	virtual bool is_reset_on_load() const noexcept override { return true; }
167 
168 	// slot interface overrides
169 	virtual std::string get_default_card_software(get_default_card_software_hook &hook) const override;
170 
get_type()171 	int get_type() { return m_type; }
172 
173 	image_init_result load_list();
174 	image_init_result load_nonlist();
175 	static int get_cart_type(const uint8_t *ROM, uint32_t len);
176 
177 	void setup_custom_mappers();
178 	void setup_nvram();
set_must_be_loaded(bool _must_be_loaded)179 	void set_must_be_loaded(bool _must_be_loaded) { m_must_be_loaded = _must_be_loaded; }
180 	void file_logging(uint8_t *ROM, uint32_t rom_len, uint32_t nvram_len);
181 
save_nvram()182 	void save_nvram() { if (m_cart && m_cart->get_nvram_size()) m_cart->save_nvram(); }
183 
184 	// reading and writing
185 	virtual uint16_t read(offs_t offset);
186 	virtual void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
187 	virtual uint16_t read_a13(offs_t offset);
188 	virtual void write_a13(offs_t offset, uint16_t data);
189 	virtual uint16_t read_a15(offs_t offset);
190 	virtual void write_a15(offs_t offset, uint16_t data);
write_tmss_bank(offs_t offset,uint16_t data)191 	virtual void write_tmss_bank(offs_t offset, uint16_t data) { if (m_cart) m_cart->write_tmss_bank(offset, data); };
192 
read_test()193 	virtual int read_test() { if (m_cart) return m_cart->read_test(); else return 0; }  // used by Virtua Racing test
194 
195 // TODO: this only needs to be public because megasvp copies rom into memory region, so we need to rework that code...
196 //private:
197 
198 	int m_type;
199 	device_md_cart_interface*       m_cart;
200 	bool                            m_must_be_loaded;
201 
202 protected:
203 	base_md_cart_slot_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
204 
205 	// device-level overrides
206 	virtual void device_start() override;
207 
208 	// device_image_interface implementation
get_software_list_loader()209 	virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); }
210 
211 };
212 
213 // ======================> md_cart_slot_device
214 
215 class md_cart_slot_device :  public base_md_cart_slot_device
216 {
217 public:
218 	// construction/destruction
219 	template <typename T>
md_cart_slot_device(machine_config const & mconfig,char const * tag,device_t * owner,T && opts,char const * dflt)220 	md_cart_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt)
221 		: md_cart_slot_device(mconfig, tag, owner, (uint32_t)0)
222 	{
223 		option_reset();
224 		opts(*this);
225 		set_default_option(dflt);
226 		set_fixed(false);
227 	}
228 
229 	md_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
image_interface()230 	virtual const char *image_interface() const noexcept override { return "megadriv_cart"; }
file_extensions()231 	virtual const char *file_extensions() const noexcept override { return "smd,bin,md,gen"; }
232 };
233 
234 // ======================> pico_cart_slot_device
235 
236 class pico_cart_slot_device :  public base_md_cart_slot_device
237 {
238 public:
239 	// construction/destruction
240 	template <typename T>
pico_cart_slot_device(machine_config const & mconfig,char const * tag,device_t * owner,T && opts,char const * dflt)241 	pico_cart_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt)
242 		: pico_cart_slot_device(mconfig, tag, owner, (uint32_t)0)
243 	{
244 		option_reset();
245 		opts(*this);
246 		set_default_option(dflt);
247 		set_fixed(false);
248 	}
249 	pico_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
image_interface()250 	virtual const char *image_interface() const noexcept override { return "pico_cart"; }
file_extensions()251 	virtual const char *file_extensions() const noexcept override { return "bin,md"; }
252 };
253 
254 // ======================> copera_cart_slot_device
255 
256 class copera_cart_slot_device :  public base_md_cart_slot_device
257 {
258 public:
259 	// construction/destruction
260 	template <typename T>
copera_cart_slot_device(machine_config const & mconfig,char const * tag,device_t * owner,T && opts,char const * dflt)261 	copera_cart_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt)
262 		: copera_cart_slot_device(mconfig, tag, owner, (uint32_t)0)
263 	{
264 		option_reset();
265 		opts(*this);
266 		set_default_option(dflt);
267 		set_fixed(false);
268 	}
269 	copera_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
image_interface()270 	virtual const char *image_interface() const noexcept override { return "copera_cart"; }
file_extensions()271 	virtual const char *file_extensions() const noexcept override { return "bin,md"; }
272 };
273 
274 
275 // device type definition
276 DECLARE_DEVICE_TYPE(MD_CART_SLOT,     md_cart_slot_device)
277 DECLARE_DEVICE_TYPE(PICO_CART_SLOT,   pico_cart_slot_device)
278 DECLARE_DEVICE_TYPE(COPERA_CART_SLOT, copera_cart_slot_device)
279 
280 
281 /***************************************************************************
282  DEVICE CONFIGURATION MACROS
283  ***************************************************************************/
284 
285 #define MDSLOT_ROM_REGION_TAG ":cart:rom"
286 
287 #endif // MAME_BUS_MEGADRIVE_MD_SLOT_H
288