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