1 // license:BSD-3-Clause
2 // copyright-holders:Fabio Priuli, MetalliC
3 /***************************************************************************
4
5
6 MegaDrive / Genesis Cart + STM95 EEPROM device
7
8
9 TO DO: split STM95 to a separate device...
10
11 ***************************************************************************/
12
13
14 #include "burnint.h"
15 #include "bitswap.h"
16 #include "m68000_intf.h"
17 #include "driver.h"
18
19 #define M95320_SIZE 0x1000
20
21 enum STMSTATE
22 {
23 IDLE = 0,
24 CMD_WRSR,
25 CMD_RDSR,
26 M95320_CMD_READ,
27 CMD_WRITE,
28 READING,
29 WRITING
30 };
31
32 static UINT8 eeprom_data[M95320_SIZE];
33 static INT32 latch;
34 static INT32 reset_line;
35 static INT32 sck_line;
36 static INT32 WEL;
37 static INT32 stm_state;
38 static INT32 stream_pos;
39 static INT32 stream_data;
40 static INT32 eeprom_addr;
41
42 static UINT8 m_bank[3];
43 static INT32 m_rdcnt;
44
45 static UINT16 *m_rom;
46
set_cs_line(INT32 state)47 static void set_cs_line(INT32 state)
48 {
49 reset_line = state;
50 if (reset_line != CLEAR_LINE)
51 {
52 stream_pos = 0;
53 stm_state = IDLE;
54 }
55 }
56
set_si_line(INT32 state)57 static void set_si_line(INT32 state)
58 {
59 latch = state;
60 }
61
get_so_line(void)62 static INT32 get_so_line(void)
63 {
64 if (stm_state == READING || stm_state == CMD_RDSR)
65 return (stream_data >> 8) & 1;
66 else
67 return 0;
68 }
69
set_sck_line(INT32 state)70 static void set_sck_line(INT32 state)
71 {
72 if (reset_line == CLEAR_LINE)
73 {
74 if (state == ASSERT_LINE && sck_line == CLEAR_LINE)
75 {
76 switch (stm_state)
77 {
78 case IDLE:
79 stream_data = (stream_data << 1) | (latch ? 1 : 0);
80 stream_pos++;
81 if (stream_pos == 8)
82 {
83 stream_pos = 0;
84 //printf("STM95 EEPROM: got cmd %02X\n", stream_data&0xff);
85 switch(stream_data & 0xff)
86 {
87 case 0x01: // write status register
88 if (WEL != 0)
89 stm_state = CMD_WRSR;
90 WEL = 0;
91 break;
92 case 0x02: // write
93 if (WEL != 0)
94 stm_state = CMD_WRITE;
95 stream_data = 0;
96 WEL = 0;
97 break;
98 case 0x03: // read
99 stm_state = M95320_CMD_READ;
100 stream_data = 0;
101 break;
102 case 0x04: // write disable
103 WEL = 0;
104 break;
105 case 0x05: // read status register
106 stm_state = CMD_RDSR;
107 stream_data = WEL<<1;
108 break;
109 case 0x06: // write enable
110 WEL = 1;
111 break;
112 }
113 }
114 break;
115 case CMD_WRSR:
116 stream_pos++; // just skip, don't care block protection
117 if (stream_pos == 8)
118 {
119 stm_state = IDLE;
120 stream_pos = 0;
121 }
122 break;
123 case CMD_RDSR:
124 stream_data = stream_data<<1;
125 stream_pos++;
126 if (stream_pos == 8)
127 {
128 stm_state = IDLE;
129 stream_pos = 0;
130 }
131 break;
132 case M95320_CMD_READ:
133 stream_data = (stream_data << 1) | (latch ? 1 : 0);
134 stream_pos++;
135 if (stream_pos == 16)
136 {
137 eeprom_addr = stream_data & (M95320_SIZE - 1);
138 stream_data = eeprom_data[eeprom_addr];
139 stm_state = READING;
140 stream_pos = 0;
141 }
142 break;
143 case READING:
144 stream_data = stream_data<<1;
145 stream_pos++;
146 if (stream_pos == 8)
147 {
148 if (++eeprom_addr == M95320_SIZE)
149 eeprom_addr = 0;
150 stream_data |= eeprom_data[eeprom_addr];
151 stream_pos = 0;
152 }
153 break;
154 case CMD_WRITE:
155 stream_data = (stream_data << 1) | (latch ? 1 : 0);
156 stream_pos++;
157 if (stream_pos == 16)
158 {
159 eeprom_addr = stream_data & (M95320_SIZE - 1);
160 stm_state = WRITING;
161 stream_pos = 0;
162 }
163 break;
164 case WRITING:
165 stream_data = (stream_data << 1) | (latch ? 1 : 0);
166 stream_pos++;
167 if (stream_pos == 8)
168 {
169 eeprom_data[eeprom_addr] = stream_data;
170 if (++eeprom_addr == M95320_SIZE)
171 eeprom_addr = 0;
172 stream_pos = 0;
173 }
174 break;
175 }
176 }
177 }
178 sck_line = state;
179 }
180
md_eeprom_stm95_reset()181 void md_eeprom_stm95_reset()
182 {
183 stream_pos = 0;
184 stm_state = IDLE;
185
186 m_rdcnt = 0;
187 m_bank[0] = 0;
188 m_bank[1] = 0;
189 m_bank[2] = 0;
190 }
191
192 /*-------------------------------------------------
193 mapper specific handlers
194 -------------------------------------------------*/
195
read_word(UINT32 offset)196 static UINT16 __fastcall read_word(UINT32 offset)
197 {
198 offset /= 2;
199
200 if (offset == 0x0015e6/2 || offset == 0x0015e8/2)
201 {
202 // ugly hack until we don't know much about game protection
203 // first 3 reads from 15e6 return 0x00000010, then normal 0x00018010 value for crc check
204 UINT16 res;
205 offset -= 0x0015e6/2;
206
207 if (m_rdcnt < 6)
208 {
209 m_rdcnt++;
210 res = offset ? 0x10 : 0;
211 }
212 else
213 res = offset ? 0x8010 : 0x0001;
214 return res;
215 }
216 if (offset < 0x280000/2)
217 return m_rom[offset];
218 else // last 0x180000 are bankswitched
219 {
220 UINT8 bank = (offset - 0x280000/2) >> 18;
221 return m_rom[(offset & 0x7ffff/2) + (m_bank[bank] * 0x80000)/2];
222 }
223 }
224
md_psolar_rw(UINT32 offset)225 UINT16 md_psolar_rw(UINT32 offset) // dmatransaktionizationimmizer
226 {
227 return read_word(offset);
228 }
229
read_byte(UINT32 offset)230 static UINT8 __fastcall read_byte(UINT32 offset)
231 {
232 if (offset & 1)
233 return read_word(offset);
234
235 return read_word(offset) >> 8;
236 }
237
read_a13_word(UINT32 offset)238 static UINT16 __fastcall read_a13_word(UINT32 offset)
239 {
240 offset = (offset/2) & 0x7f;
241
242 if (offset == 0x0a/2)
243 {
244 return get_so_line() & 1;
245 }
246 return 0xffff;
247 }
248
read_a13_byte(UINT32 offset)249 static UINT8 __fastcall read_a13_byte(UINT32 offset)
250 {
251 return read_a13_word(offset);
252 }
253
write_a13_word(UINT32 offset,UINT16 data)254 static void __fastcall write_a13_word(UINT32 offset, UINT16 data)
255 {
256 offset = (offset/2) & 0x7f;
257
258 if (offset < 0x08/2)
259 {
260 m_bank[offset - 1] = data & 0x0f;
261 }
262 else if (offset < 0x0a/2)
263 {
264 set_si_line(BIT(data, 0));
265 set_sck_line(BIT(data, 1));
266 // set_halt_line(BIT(data, 2));
267 set_cs_line(BIT(data, 3));
268 }
269 }
270
write_a13_byte(UINT32 offset,UINT8 data)271 static void __fastcall write_a13_byte(UINT32 offset, UINT8 data)
272 {
273 write_a13_word(offset,data);
274 }
275
276
md_eeprom_stm95_init(UINT8 * rom)277 void md_eeprom_stm95_init(UINT8 *rom)
278 {
279 m_rom = (UINT16*)rom;
280
281 SekOpen(0);
282
283 // unmap everything except vectors
284 for (INT32 i = 0x000; i < 0xa00000; i+= 0x400) {
285 SekMapMemory(NULL, i, i+0x3ff, MAP_RAM);
286 }
287
288 SekMapHandler(5, 0x000000, 0x9fffff, MAP_ROM);
289 SekSetReadByteHandler (5, read_byte);
290 SekSetReadWordHandler (5, read_word);
291
292 SekMapHandler(6, 0xa13000, 0xa130ff, MAP_RAM);
293 SekSetReadByteHandler (6, read_a13_byte);
294 SekSetReadWordHandler (6, read_a13_word);
295 SekSetWriteByteHandler(6, write_a13_byte);
296 SekSetWriteWordHandler(6, write_a13_word);
297
298 SekClose();
299 }
300
md_eeprom_stm95_scan(INT32 nAction)301 void md_eeprom_stm95_scan(INT32 nAction)
302 {
303 struct BurnArea ba;
304
305 if (nAction & ACB_NVRAM) {
306 ba.Data = eeprom_data;
307 ba.nLen = M95320_SIZE;
308 ba.nAddress = 0xa13000;
309 ba.szName = "NV RAM";
310 BurnAcb(&ba);
311 }
312
313 if (nAction & ACB_DRIVER_DATA) {
314
315 SCAN_VAR(latch);
316 SCAN_VAR(reset_line);
317 SCAN_VAR(sck_line);
318 SCAN_VAR(WEL);
319 SCAN_VAR(stm_state);
320 SCAN_VAR(stream_pos);
321 SCAN_VAR(stream_data);
322 SCAN_VAR(eeprom_addr);
323
324 SCAN_VAR(m_bank[0]);
325 SCAN_VAR(m_bank[1]);
326 SCAN_VAR(m_bank[2]);
327 SCAN_VAR(m_rdcnt);
328 }
329 }
330