Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/genplus-gx32/core/cart_hw/eeprom_spi.c
2 views
1
/****************************************************************************
2
* Genesis Plus
3
* SPI Serial EEPROM (25xxx/95xxx) support
4
*
5
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
6
*
7
* Redistribution and use of this code or any derivative works are permitted
8
* provided that the following conditions are met:
9
*
10
* - Redistributions may not be sold, nor may they be used in a commercial
11
* product or activity.
12
*
13
* - Redistributions that are modified from the original source must include the
14
* complete source code, including the source code for all components used by a
15
* binary built from the modified sources. However, as a special exception, the
16
* source code distributed need not include anything that is normally distributed
17
* (in either source or binary form) with the major components (compiler, kernel,
18
* and so on) of the operating system on which the executable runs, unless that
19
* component itself accompanies the executable.
20
*
21
* - Redistributions must reproduce the above copyright notice, this list of
22
* conditions and the following disclaimer in the documentation and/or other
23
* materials provided with the distribution.
24
*
25
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
* POSSIBILITY OF SUCH DAMAGE.
36
*
37
****************************************************************************************/
38
39
#include "shared.h"
40
#include "eeprom_spi.h"
41
42
/* max supported size 64KB (25x512/95x512) */
43
#define SIZE_MASK 0xffff
44
#define PAGE_MASK 0x7f
45
46
/* hard-coded board implementation (!WP pin not used) */
47
#define BIT_DATA (0)
48
#define BIT_CLK (1)
49
#define BIT_HOLD (2)
50
#define BIT_CS (3)
51
52
T_EEPROM_SPI spi_eeprom;
53
54
void eeprom_spi_init()
55
{
56
/* reset eeprom state */
57
memset(&spi_eeprom, 0, sizeof(T_EEPROM_SPI));
58
spi_eeprom.out = 1;
59
spi_eeprom.state = GET_OPCODE;
60
61
/* enable backup RAM */
62
sram.custom = 2;
63
sram.on = 1;
64
}
65
66
void eeprom_spi_write(unsigned char data)
67
{
68
/* Make sure !HOLD is high */
69
if (data & (1 << BIT_HOLD))
70
{
71
/* Check !CS state */
72
if (data & (1 << BIT_CS))
73
{
74
/* !CS high -> end of current operation */
75
spi_eeprom.cycles = 0;
76
spi_eeprom.out = 1;
77
spi_eeprom.opcode = 0;
78
spi_eeprom.state = GET_OPCODE;
79
}
80
else
81
{
82
/* !CS low -> process current operation */
83
switch (spi_eeprom.state)
84
{
85
case GET_OPCODE:
86
{
87
/* latch data on CLK positive edge */
88
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
89
{
90
/* 8-bit opcode buffer */
91
spi_eeprom.opcode |= ((data >> BIT_DATA) & 1);
92
spi_eeprom.cycles++;
93
94
/* last bit ? */
95
if (spi_eeprom.cycles == 8)
96
{
97
/* reset cycles count */
98
spi_eeprom.cycles = 0;
99
100
/* Decode instruction */
101
switch (spi_eeprom.opcode)
102
{
103
case 0x01:
104
{
105
/* WRITE STATUS */
106
spi_eeprom.buffer = 0;
107
spi_eeprom.state = WRITE_BYTE;
108
break;
109
}
110
111
case 0x02:
112
{
113
/* WRITE BYTE */
114
spi_eeprom.addr = 0;
115
spi_eeprom.state = GET_ADDRESS;
116
break;
117
}
118
119
case 0x03:
120
{
121
/* READ BYTE */
122
spi_eeprom.addr = 0;
123
spi_eeprom.state = GET_ADDRESS;
124
break;
125
}
126
127
case 0x04:
128
{
129
/* WRITE DISABLE */
130
spi_eeprom.status &= ~0x02;
131
spi_eeprom.state = STANDBY;
132
break;
133
}
134
135
case 0x05:
136
{
137
/* READ STATUS */
138
spi_eeprom.buffer = spi_eeprom.status;
139
spi_eeprom.state = READ_BYTE;
140
break;
141
}
142
143
case 0x06:
144
{
145
/* WRITE ENABLE */
146
spi_eeprom.status |= 0x02;
147
spi_eeprom.state = STANDBY;
148
break;
149
}
150
151
default:
152
{
153
/* specific instructions (not supported) */
154
spi_eeprom.state = STANDBY;
155
break;
156
}
157
}
158
}
159
else
160
{
161
/* shift opcode value */
162
spi_eeprom.opcode = spi_eeprom.opcode << 1;
163
}
164
}
165
break;
166
}
167
168
case GET_ADDRESS:
169
{
170
/* latch data on CLK positive edge */
171
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
172
{
173
/* 16-bit address */
174
spi_eeprom.addr |= ((data >> BIT_DATA) & 1);
175
spi_eeprom.cycles++;
176
177
/* last bit ? */
178
if (spi_eeprom.cycles == 16)
179
{
180
/* reset cycles count */
181
spi_eeprom.cycles = 0;
182
183
/* mask unused address bits */
184
spi_eeprom.addr &= SIZE_MASK;
185
186
/* operation type */
187
if (spi_eeprom.opcode & 0x01)
188
{
189
/* READ operation */
190
spi_eeprom.buffer = sram.sram[spi_eeprom.addr];
191
spi_eeprom.state = READ_BYTE;
192
}
193
else
194
{
195
/* WRITE operation */
196
spi_eeprom.buffer = 0;
197
spi_eeprom.state = WRITE_BYTE;
198
}
199
}
200
else
201
{
202
/* shift address value */
203
spi_eeprom.addr = spi_eeprom.addr << 1;
204
}
205
}
206
break;
207
}
208
209
case WRITE_BYTE:
210
{
211
/* latch data on CLK positive edge */
212
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
213
{
214
/* 8-bit data buffer */
215
spi_eeprom.buffer |= ((data >> BIT_DATA) & 1);
216
spi_eeprom.cycles++;
217
218
/* last bit ? */
219
if (spi_eeprom.cycles == 8)
220
{
221
/* reset cycles count */
222
spi_eeprom.cycles = 0;
223
224
/* write data to destination */
225
if (spi_eeprom.opcode & 0x01)
226
{
227
/* update status register */
228
spi_eeprom.status = (spi_eeprom.status & 0x02) | (spi_eeprom.buffer & 0x0c);
229
230
/* wait for operation end */
231
spi_eeprom.state = STANDBY;
232
}
233
else
234
{
235
/* Memory Array (write-protected) */
236
if (spi_eeprom.status & 2)
237
{
238
/* check array protection bits (BP0, BP1) */
239
switch ((spi_eeprom.status >> 2) & 0x03)
240
{
241
case 0x01:
242
{
243
/* $C000-$FFFF (sector #3) is protected */
244
if (spi_eeprom.addr < 0xC000)
245
{
246
sram.sram[spi_eeprom.addr] = spi_eeprom.buffer;
247
}
248
break;
249
}
250
251
case 0x02:
252
{
253
/* $8000-$FFFF (sectors #2 and #3) is protected */
254
if (spi_eeprom.addr < 0x8000)
255
{
256
sram.sram[spi_eeprom.addr] = spi_eeprom.buffer;
257
}
258
break;
259
}
260
261
case 0x03:
262
{
263
/* $0000-$FFFF (all sectors) is protected */
264
break;
265
}
266
267
default:
268
{
269
/* no sectors protected */
270
sram.sram[spi_eeprom.addr] = spi_eeprom.buffer;
271
break;
272
}
273
}
274
}
275
276
/* reset data buffer */
277
spi_eeprom.buffer = 0;
278
279
/* increase array address (sequential writes are limited within the same page) */
280
spi_eeprom.addr = (spi_eeprom.addr & ~PAGE_MASK) | ((spi_eeprom.addr + 1) & PAGE_MASK);
281
}
282
}
283
else
284
{
285
/* shift data buffer value */
286
spi_eeprom.buffer = spi_eeprom.buffer << 1;
287
}
288
}
289
break;
290
}
291
292
case READ_BYTE:
293
{
294
/* output data on CLK positive edge */
295
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
296
{
297
/* read out bits */
298
spi_eeprom.out = (spi_eeprom.buffer >> (7 - spi_eeprom.cycles)) & 1;
299
spi_eeprom.cycles++;
300
301
/* last bit ? */
302
if (spi_eeprom.cycles == 8)
303
{
304
/* reset cycles count */
305
spi_eeprom.cycles = 0;
306
307
/* read from memory array ? */
308
if (spi_eeprom.opcode == 0x03)
309
{
310
/* read next array byte */
311
spi_eeprom.addr = (spi_eeprom.addr + 1) & SIZE_MASK;
312
spi_eeprom.buffer = sram.sram[spi_eeprom.addr];
313
}
314
}
315
}
316
break;
317
}
318
319
default:
320
{
321
/* wait for !CS low->high transition */
322
break;
323
}
324
}
325
}
326
}
327
328
/* update input lines */
329
spi_eeprom.cs = (data >> BIT_CS) & 1;
330
spi_eeprom.clk = (data >> BIT_CLK) & 1;
331
}
332
333
unsigned int eeprom_spi_read(unsigned int address)
334
{
335
return (spi_eeprom.out << BIT_DATA);
336
}
337
338
339