1 /******************************************************************************/
2 /* Mednafen Sega Saturn Emulation Module */
3 /******************************************************************************/
4 /* cart.cpp - Expansion cart emulation
5 ** Copyright (C) 2016-2017 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include "ss.h"
23 #include <streams/file_stream.h>
24 #include "../general.h"
25 #include "../mednafen-endian.h"
26 #include "../settings.h"
27
28 #include "cart.h"
29 #include "cart/backup.h"
30 #include "cart/cs1ram.h"
31 #include "cart/debug.h"
32 #include "cart/extram.h"
33 //#include "cart/nlmodem.h"
34 #include "cart/rom.h"
35 #include "cart/ar4mp.h"
36
37
38 CartInfo Cart;
39
DummyRead(uint32 A,uint16 * DB)40 static MDFN_HOT void DummyRead(uint32 A, uint16* DB)
41 {
42 // Don't set *DB here.
43 SS_DBG(SS_DBG_WARNING, "[CART] Unknown %zu-byte read from 0x%08x\n", sizeof(uint16), A);
44 }
45
DummyWrite_uint8(uint32 A,uint16 * DB)46 static MDFN_HOT void DummyWrite_uint8(uint32 A, uint16* DB)
47 {
48 SS_DBG(SS_DBG_WARNING, "[CART] Unknown %zu-byte write to 0x%08x(DB=0x%04x)\n", sizeof(uint8), A, *DB);
49 }
50
DummyWrite_uint16(uint32 A,uint16 * DB)51 static MDFN_HOT void DummyWrite_uint16(uint32 A, uint16* DB)
52 {
53 SS_DBG(SS_DBG_WARNING, "[CART] Unknown %zu-byte write to 0x%08x(DB=0x%04x)\n", sizeof(uint16), A, *DB);
54 }
55
DummyUpdate(sscpu_timestamp_t timestamp)56 static sscpu_timestamp_t DummyUpdate(sscpu_timestamp_t timestamp)
57 {
58 return SS_EVENT_DISABLED_TS;
59 }
60
DummyAdjustTS(const int32 delta)61 static void DummyAdjustTS(const int32 delta)
62 {
63
64 }
65
DummySetCPUClock(const int32 master_clock,const int32 divider)66 static void DummySetCPUClock(const int32 master_clock, const int32 divider)
67 {
68
69 }
70
DummyReset(bool powering_up)71 static MDFN_COLD void DummyReset(bool powering_up)
72 {
73
74 }
75
DummyStateAction(StateMem * sm,const unsigned load,const bool data_only)76 static MDFN_COLD void DummyStateAction(StateMem* sm, const unsigned load, const bool data_only)
77 {
78
79 }
80
DummyGetClearNVDirty(void)81 static MDFN_COLD bool DummyGetClearNVDirty(void)
82 {
83 return false;
84 }
85
DummyGetNVInfo(const char ** ext,void ** nv_ptr,bool * nv16,uint64 * nv_size)86 static MDFN_COLD void DummyGetNVInfo(const char** ext, void** nv_ptr, bool* nv16, uint64* nv_size)
87 {
88 *ext = nullptr;
89 *nv_ptr = nullptr;
90 *nv16 = false;
91 *nv_size = 0;
92 }
93
DummyKill(void)94 static MDFN_COLD void DummyKill(void)
95 {
96
97 }
98
CS01_SetRW8W16(uint32 Astart,uint32 Aend,void (* r16)(uint32 A,uint16 * DB),void (* w8)(uint32 A,uint16 * DB),void (* w16)(uint32 A,uint16 * DB))99 void CartInfo::CS01_SetRW8W16(uint32 Astart, uint32 Aend, void (*r16)(uint32 A, uint16* DB), void (*w8)(uint32 A, uint16* DB), void (*w16)(uint32 A, uint16* DB))
100 {
101 assert(Astart >= 0x02000000 && Aend <= 0x04FFFFFF);
102
103 assert(!(Astart & ((1U << 20) - 1)));
104 assert(!((Aend + 1) & ((1U << 20) - 1)));
105
106 for(unsigned i = (Astart - 0x02000000) >> 20; i <= (Aend - 0x02000000) >> 20; i++)
107 {
108 auto& rw = Cart.CS01_RW[i];
109
110 if(r16) rw.Read16 = r16;
111 if(w8) rw.Write8 = w8;
112 if(w16) rw.Write16 = w16;
113 }
114 }
115
CS2M_SetRW8W16(uint8 Ostart,uint8 Oend,void (* r16)(uint32 A,uint16 * DB),void (* w8)(uint32 A,uint16 * DB),void (* w16)(uint32 A,uint16 * DB))116 void CartInfo::CS2M_SetRW8W16(uint8 Ostart, uint8 Oend, void (*r16)(uint32 A, uint16* DB), void (*w8)(uint32 A, uint16* DB), void (*w16)(uint32 A, uint16* DB))
117 {
118 assert(!(Ostart & 0x1));
119 assert(Oend & 0x1);
120 assert(Ostart < 0x40);
121 assert(Oend < 0x40);
122
123 for(int i = Ostart >> 1; i <= Oend >> 1; i++)
124 {
125 auto& rw = Cart.CS2M_RW[i];
126
127 if(r16) rw.Read16 = r16;
128 if(w8) rw.Write8 = w8;
129 if(w16) rw.Write16 = w16;
130 }
131 }
132
133
CART_Init(const int cart_type)134 void CART_Init(const int cart_type)
135 {
136 Cart.CS01_SetRW8W16(0x02000000, 0x04FFFFFF, DummyRead, DummyWrite_uint8, DummyWrite_uint16);
137 Cart.CS2M_SetRW8W16(0x00, 0x3F, DummyRead, DummyWrite_uint8, DummyWrite_uint16);
138
139 Cart.Reset = DummyReset;
140 Cart.Kill = DummyKill;
141 Cart.GetNVInfo = DummyGetNVInfo;
142 Cart.GetClearNVDirty = DummyGetClearNVDirty;
143 Cart.StateAction = DummyStateAction;
144 Cart.EventHandler = DummyUpdate;
145 Cart.AdjustTS = DummyAdjustTS;
146 Cart.SetCPUClock = DummySetCPUClock;
147
148 switch(cart_type)
149 {
150 default:
151 case CART_NONE:
152 break;
153
154 case CART_BACKUP_MEM:
155 CART_Backup_Init(&Cart);
156 break;
157
158 case CART_EXTRAM_1M:
159 case CART_EXTRAM_4M:
160 CART_ExtRAM_Init(&Cart, cart_type == CART_EXTRAM_4M);
161 break;
162
163 case CART_KOF95:
164 case CART_ULTRAMAN:
165 {
166 const std::string path_cxx = MDFN_GetSettingS((cart_type == CART_KOF95) ? "ss.cart.kof95_path" : "ss.cart.ultraman_path");
167 const char *path = MDFN_MakeFName(MDFNMKF_FIRMWARE, 0, path_cxx.c_str());
168 RFILE *fp = filestream_open(path,
169 RETRO_VFS_FILE_ACCESS_READ,
170 RETRO_VFS_FILE_ACCESS_HINT_NONE);
171
172 if (fp)
173 {
174 CART_ROM_Init(&Cart, fp);
175 filestream_close(fp);
176 }
177 }
178 break;
179
180 case CART_AR4MP:
181 {
182 const std::string path_cxx = MDFN_GetSettingS("ss.cart.satar4mp_path");
183 const char *path = MDFN_MakeFName(MDFNMKF_FIRMWARE, 0, path_cxx.c_str());
184 RFILE *fp = filestream_open(path,
185 RETRO_VFS_FILE_ACCESS_READ,
186 RETRO_VFS_FILE_ACCESS_HINT_NONE);
187
188 if (fp)
189 {
190 CART_AR4MP_Init(&Cart, fp);
191 filestream_close(fp);
192 }
193 }
194 break;
195
196 case CART_CS1RAM_16M:
197 CART_CS1RAM_Init(&Cart);
198 break;
199
200 case CART_MDFN_DEBUG:
201 CART_Debug_Init(&Cart);
202 break;
203
204 // case CART_NLMODEM:
205 // CART_NLModem_Init(&Cart);
206 // break;
207 }
208
209 for(auto& m : Cart.CS01_RW)
210 assert(m.Read16 != nullptr && m.Write8 != nullptr && m.Write16 != nullptr);
211
212 for(auto& m : Cart.CS2M_RW)
213 assert(m.Read16 != nullptr && m.Write8 != nullptr && m.Write16 != nullptr);
214 }
215
216