1 /* Mednafen - Multi-system Emulator
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "pce.h"
19 #include "mcgenjin.h"
20
21 using namespace MDFN_IEN_PCE;
22
MCGenjin_CS_Device()23 MCGenjin_CS_Device::MCGenjin_CS_Device()
24 {
25
26 }
27
~MCGenjin_CS_Device()28 MCGenjin_CS_Device::~MCGenjin_CS_Device()
29 {
30
31 }
32
Power(void)33 void MCGenjin_CS_Device::Power(void)
34 {
35
36 }
37
Update(int32 timestamp)38 void MCGenjin_CS_Device::Update(int32 timestamp)
39 {
40
41 }
42
ResetTS(int32 ts_base)43 void MCGenjin_CS_Device::ResetTS(int32 ts_base)
44 {
45
46 }
47
StateAction(StateMem * sm,int load,int data_only,const char * sname)48 int MCGenjin_CS_Device::StateAction(StateMem *sm, int load, int data_only, const char *sname)
49 {
50 return 1;
51 }
52
53
Read(int32 timestamp,uint32 A)54 uint8 MCGenjin_CS_Device::Read(int32 timestamp, uint32 A)
55 {
56 return 0xFF;
57 }
58
Write(int32 timestamp,uint32 A,uint8 V)59 void MCGenjin_CS_Device::Write(int32 timestamp, uint32 A, uint8 V)
60 {
61
62 }
63
GetNVSize(void) const64 uint32 MCGenjin_CS_Device::GetNVSize(void) const
65 {
66 return 0;
67 }
68
ReadNV(void) const69 const uint8* MCGenjin_CS_Device::ReadNV(void) const
70 {
71 return NULL;
72 }
73
WriteNV(const uint8 * buffer,uint32 offset,uint32 count)74 void MCGenjin_CS_Device::WriteNV(const uint8 *buffer, uint32 offset, uint32 count)
75 {
76
77 }
78
79 class MCGenjin_CS_Device_RAM : public MCGenjin_CS_Device
80 {
81 public:
82
MCGenjin_CS_Device_RAM(uint32 size,bool nv)83 MCGenjin_CS_Device_RAM(uint32 size, bool nv)
84 {
85 assert(round_up_pow2(size) == size);
86
87 ram.resize(size);
88 nonvolatile = nv;
89 }
90
~MCGenjin_CS_Device_RAM()91 virtual ~MCGenjin_CS_Device_RAM() override
92 {
93
94 }
95
Power(void)96 virtual void Power(void) override
97 {
98 if(!nonvolatile)
99 ram.assign(ram.size(), 0xFF);
100
101 bank_select = 0;
102 }
103
StateAction(StateMem * sm,int load,int data_only,const char * sname)104 virtual int StateAction(StateMem *sm, int load, int data_only, const char *sname) override
105 {
106 SFORMAT StateRegs[] =
107 {
108 SFPTR8(&ram[0], ram.size()),
109 SFVAR(bank_select),
110 SFEND
111 };
112 int ret = 1;
113
114 ret &= MDFNSS_StateAction(sm, load, data_only, StateRegs, sname);
115
116 return ret;
117 }
118
119
Read(int32 timestamp,uint32 A)120 virtual uint8 Read(int32 timestamp, uint32 A) override
121 {
122 return ram[(A | (bank_select << 18)) & (ram.size() - 1)];
123 }
124
Write(int32 timestamp,uint32 A,uint8 V)125 virtual void Write(int32 timestamp, uint32 A, uint8 V) override
126 {
127 if(!A)
128 bank_select = V;
129
130 ram[(A | (bank_select << 18)) & (ram.size() - 1)] = V;
131 }
132
GetNVSize(void) const133 virtual uint32 GetNVSize(void) const override
134 {
135 return nonvolatile ? ram.size() : 0;
136 }
137
ReadNV(void) const138 virtual const uint8* ReadNV(void) const override
139 {
140 return &ram[0];
141 }
142
WriteNV(const uint8 * buffer,uint32 offset,uint32 count)143 virtual void WriteNV(const uint8 *buffer, uint32 offset, uint32 count) override
144 {
145 while(count)
146 {
147 ram[offset % ram.size()] = *buffer;
148 buffer++;
149 offset++;
150 count--;
151 }
152 }
153
154 private:
155 std::vector<uint8> ram;
156 bool nonvolatile;
157 uint8 bank_select;
158 };
159
Power(void)160 void MCGenjin::Power(void)
161 {
162 bank_select = 0;
163 dlr = 0;
164
165 stmode_control = 0x00;
166
167 for(unsigned i = 0; i < 2; i++)
168 cs[i]->Power();
169 }
170
Update(int32 timestamp)171 void MCGenjin::Update(int32 timestamp)
172 {
173 for(unsigned i = 0; i < 2; i++)
174 cs[i]->Update(timestamp);
175 }
176
ResetTS(int32 ts_base)177 void MCGenjin::ResetTS(int32 ts_base)
178 {
179 for(unsigned i = 0; i < 2; i++)
180 cs[i]->ResetTS(ts_base);
181 }
182
GetNVSize(const unsigned di) const183 uint32 MCGenjin::GetNVSize(const unsigned di) const
184 {
185 return cs[di]->GetNVSize();
186 }
187
ReadNV(const unsigned di) const188 const uint8* MCGenjin::ReadNV(const unsigned di) const
189 {
190 return cs[di]->ReadNV();
191 }
192
WriteNV(const unsigned di,const uint8 * buffer,uint32 offset,uint32 count)193 void MCGenjin::WriteNV(const unsigned di, const uint8 *buffer, uint32 offset, uint32 count)
194 {
195 cs[di]->WriteNV(buffer, offset, count);
196 }
197
MCGenjin(Stream * fp)198 MCGenjin::MCGenjin(Stream* fp)
199 {
200 const uint64 rr_size = fp->size();
201 uint8 revision, num256_pages, region, cs_di[2];
202
203 if(rr_size > 1024 * 1024 * 128)
204 throw MDFN_Error(0, _("MCGenjin ROM size is too large!"));
205
206 if(rr_size < 8192)
207 throw MDFN_Error(0, _("MCGenjin ROM size is too small!"));
208
209 rom.resize(round_up_pow2(rr_size));
210 fp->read(&rom[0], rr_size);
211
212 if(memcmp(&rom[0x1FD0], "MCGENJIN", 8))
213 throw MDFN_Error(0, _("MC Genjin header magic missing!"));
214
215 revision = rom[0x1FD8];
216 num256_pages = rom[0x1FD9];
217 region = rom[0x1FDA];
218 cs_di[0] = rom[0x1FDB];
219 cs_di[1] = rom[0x1FDC];
220
221 MDFN_printf(_("MCGenjin Header:\n"));
222 MDFN_indent(1);
223 MDFN_printf(_("Revision: 0x%02x\n"), revision);
224 MDFN_printf(_("ROM Size: %u\n"), num256_pages * 262144);
225 MDFN_printf(_("Region: 0x%02x\n"), region);
226 MDFN_printf(_("CS0 Type: 0x%02x\n"), cs_di[0]);
227 MDFN_printf(_("CS1 Type: 0x%02x\n"), cs_di[1]);
228 MDFN_indent(-1);
229
230 // Don't set addr_write_mask to larger than 0xF unless code in mcgenjin.h is adjusted as well.
231 if(revision >= 0x80)
232 addr_write_mask = 0xF;
233 else
234 addr_write_mask = 0x3;
235
236 for(unsigned i = 0; i < 2; i++)
237 {
238 if((cs_di[i] >= 0x10 && cs_di[i] <= 0x18) || (cs_di[i] >= 0x20 && cs_di[i] <= 0x28))
239 {
240 MDFN_printf(_("CS%d: %uKiB %sRAM\n"), i, 8 << (cs_di[i] & 0xF), (cs_di[i] & 0x20) ? "Nonvolatile " : "");
241 cs[i].reset(new MCGenjin_CS_Device_RAM(8192 << (cs_di[i] & 0xF), (bool)(cs_di[i] & 0x20)));
242 }
243 else switch(cs_di[i])
244 {
245 default:
246 throw MDFN_Error(0, _("Unsupported MCGENJIN device on CS%d: 0x%02x"), i, cs_di[i]);
247 break;
248
249 case 0x00:
250 MDFN_printf(_("CS%d: Unused\n"), i);
251 cs[i].reset(new MCGenjin_CS_Device());
252 break;
253 }
254 }
255 }
256
~MCGenjin()257 MCGenjin::~MCGenjin()
258 {
259
260 }
261
StateAction(StateMem * sm,int load,int data_only)262 int MCGenjin::StateAction(StateMem *sm, int load, int data_only)
263 {
264 SFORMAT StateRegs[] =
265 {
266 SFVAR(bank_select),
267 SFVAR(dlr),
268 SFEND
269 };
270 int ret = 1;
271
272 ret &= MDFNSS_StateAction(sm, load, data_only, StateRegs, "MCGENJIN");
273
274 for(unsigned i = 0; i < 2; i++)
275 ret &= MDFNSS_StateAction(sm, load, data_only, StateRegs, i ? "MCGENJIN_CS1" : "MCGENJIN_CS0");
276
277 return ret;
278 }
279
280