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