1 /*****************************************************************************
2 ** $Source: /cygdrive/d/Private/_SVNROOT/bluemsx/blueMSX/Src/IoDevice/Microwire93Cx6.c,v $
3 **
4 ** $Revision: 1.4 $
5 **
6 ** $Date: 2008-03-30 18:38:40 $
7 **
8 ** More info: http://www.bluemsx.com
9 **
10 ** Copyright (C) 2003-2006 Daniel Vik
11 **
12 ** This program is free software; you can redistribute it and/or modify
13 ** it under the terms of the GNU General Public License as published by
14 ** the Free Software Foundation; either version 2 of the License, or
15 ** (at your option) any later version.
16 **
17 ** This program is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ** GNU General Public License for more details.
21 **
22 ** You should have received a copy of the GNU General Public License
23 ** along with this program; if not, write to the Free Software
24 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 **
26 ******************************************************************************
27 */
28 #include "Microwire93Cx6.h"
29 #include "Board.h"
30 #include "SaveState.h"
31 #include "sramLoader.h"
32 #include <stdlib.h>
33 #include <string.h>
34
35 // Emulates the Microchip Technology Inc. 93C76/86 eeprom chips
36
37 typedef struct Microwire93Cx6
38 {
39 UInt8* romData;
40 int romMask;
41 int modeX8;
42
43 int phase;
44 UInt32 command;
45 UInt32 commandIdx;
46 UInt32 value;
47 UInt32 valueIdx;
48 int programEnable;
49
50 int Di;
51 int Do;
52 int Cs;
53 int Clk;
54
55 BoardTimer* timer;
56
57 char sramFilename[512];
58 };
59
60 #define PHASE_IDLE 0
61 #define PHASE_COMMAND 1
62 #define PHASE_DATATRANSFER_WRITE 2
63 #define PHASE_DATATRANSFER_READ 3
64 #define PHASE_PROGRAMMING 4
65 #define PHASE_COMMAND_DONE 5
66
67
68 static void test(Microwire93Cx6* rm);
69
70
romWrite(Microwire93Cx6 * rm,UInt32 address,UInt32 value)71 static void romWrite(Microwire93Cx6* rm, UInt32 address, UInt32 value)
72 {
73 if (rm->modeX8) {
74 ((UInt8*)(rm->romData))[address & rm->romMask] = (UInt8)value;
75 }
76 else {
77 ((UInt16*)(rm->romData))[address & (rm->romMask / 2)] = (UInt16)value;
78 }
79 }
80
romRead(Microwire93Cx6 * rm,UInt32 address)81 static UInt32 romRead(Microwire93Cx6* rm, UInt32 address)
82 {
83 if (rm->modeX8) {
84 return ((UInt8*)(rm->romData))[address & rm->romMask];
85 }
86 else {
87 return ((UInt16*)(rm->romData))[address & (rm->romMask / 2)];
88 }
89 }
90
onTimer(Microwire93Cx6 * rm,UInt32 time)91 static void onTimer(Microwire93Cx6* rm, UInt32 time)
92 {
93 if (rm->Do == 1) {
94 rm->phase = PHASE_IDLE;
95 }
96 else {
97 rm->phase = PHASE_COMMAND_DONE;
98 }
99 }
100
microwire93Cx6Create(int size,int mode,void * imgData,int imgSize,const char * sramFilename)101 Microwire93Cx6* microwire93Cx6Create(int size, int mode, void* imgData, int imgSize, const char* sramFilename)
102 {
103 Microwire93Cx6* rm = calloc(1, sizeof(Microwire93Cx6));
104
105 if (sramFilename != NULL) {
106 strcpy(rm->sramFilename, sramFilename);
107 }
108
109 // Allocate memory
110 rm->romMask = (size - 1) & 0x01ff;
111 rm->romData = malloc(size);
112 memset(rm->romData, 0xff, size);
113
114 // Load rom data if present
115 if (imgData != NULL) {
116 if (imgSize > size) {
117 imgSize = size;
118 }
119 memcpy(rm->romData, imgData, imgSize);
120 }
121
122 // Set mode (8/16 bit)
123 rm->modeX8 = mode == 16 ? 0 : 1;
124
125 rm->timer = boardTimerCreate(onTimer, rm);
126
127 microwire93Cx6Reset(rm);
128
129 return rm;
130 }
131
microwire93Cx6Destroy(Microwire93Cx6 * rm)132 void microwire93Cx6Destroy(Microwire93Cx6* rm)
133 {
134 if (rm->sramFilename[0]) {
135 sramSave(rm->sramFilename, rm->romData, rm->romMask + 1, NULL, 0);
136 }
137
138 boardTimerDestroy(rm->timer);
139
140 free(rm->romData);
141 free(rm);
142 }
143
microwire93Cx6Reset(Microwire93Cx6 * rm)144 void microwire93Cx6Reset(Microwire93Cx6* rm)
145 {
146 rm->Cs = 0;
147 rm->Do = 1;
148 rm->Di = 0;
149
150 rm->phase = PHASE_IDLE;
151 rm->programEnable = 0;
152 }
153
microwire93Cx6SaveState(Microwire93Cx6 * rm)154 void microwire93Cx6SaveState(Microwire93Cx6* rm)
155 {
156 SaveState* state = saveStateOpenForWrite("Microwire93Cx6");
157
158 saveStateSet(state, "phase", rm->phase);
159 saveStateSet(state, "command", rm->command);
160 saveStateSet(state, "commandIdx", rm->commandIdx);
161 saveStateSet(state, "value", rm->value);
162 saveStateSet(state, "valueIdx", rm->valueIdx);
163 saveStateSet(state, "programEnable",rm->programEnable);
164 saveStateSet(state, "Di", rm->Di);
165 saveStateSet(state, "Do", rm->Do);
166 saveStateSet(state, "Cs", rm->Cs);
167 saveStateSet(state, "Clk", rm->Clk);
168
169 saveStateClose(state);
170 }
171
microwire93Cx6LoadState(Microwire93Cx6 * rm)172 void microwire93Cx6LoadState(Microwire93Cx6* rm)
173 {
174 SaveState* state = saveStateOpenForRead("Microwire93Cx6");
175
176 rm->phase = saveStateGet(state, "phase", PHASE_IDLE);
177 rm->command = saveStateGet(state, "command", 0);
178 rm->commandIdx = saveStateGet(state, "commandIdx", 0);
179 rm->value = saveStateGet(state, "value", 0);
180 rm->valueIdx = saveStateGet(state, "valueIdx", 0);
181 rm->programEnable = saveStateGet(state, "programEnable",0);
182 rm->Di = saveStateGet(state, "Di", 0);
183 rm->Do = saveStateGet(state, "Do", 1);
184 rm->Cs = saveStateGet(state, "Cs", 0);
185 rm->Clk = saveStateGet(state, "Clk", 0);
186
187 if (rm->phase == PHASE_PROGRAMMING) {
188 onTimer(rm, 0);
189 }
190
191 saveStateClose(state);
192 }
193
microwire93Cx6SetCs(Microwire93Cx6 * rm,int value)194 void microwire93Cx6SetCs(Microwire93Cx6* rm, int value)
195 {
196 rm->Cs = value ? 1 : 0;
197
198 if (rm->Cs == 0) {
199 rm->Do = 1;
200 if (rm->phase == PHASE_COMMAND_DONE || rm->phase == PHASE_DATATRANSFER_READ) {
201 rm->phase = PHASE_IDLE;
202 }
203 }
204 }
205
microwire93Cx6SetDi(Microwire93Cx6 * rm,int value)206 void microwire93Cx6SetDi(Microwire93Cx6* rm, int value)
207 {
208 rm->Di = value ? 1 : 0;
209 }
210
microwire93Cx6GetDo(Microwire93Cx6 * rm)211 int microwire93Cx6GetDo(Microwire93Cx6* rm)
212 {
213 return rm->Do;
214 }
215
microwire93Cx6SetClk(Microwire93Cx6 * rm,int value)216 void microwire93Cx6SetClk(Microwire93Cx6* rm, int value)
217 {
218 value = value ? 1 : 0;
219
220 if (rm->Clk == value) {
221 // No edge
222 return;
223 }
224
225 rm->Clk = value;
226
227 if (rm->Cs == 0 || rm->Clk == 0) {
228 // Falling edge or chip not selected
229 return;
230 }
231
232 switch (rm->phase) {
233 case PHASE_IDLE:
234 if (rm->Cs && rm->Di) {
235 rm->phase = PHASE_COMMAND;
236 rm->command = 0;
237 rm->commandIdx = 12 + rm->modeX8;
238 }
239 break;
240
241 case PHASE_COMMAND:
242 rm->command |= rm->Di << --rm->commandIdx;
243 if (rm->commandIdx != 0) {
244 break;
245 }
246
247 switch ((rm->command >> (10 + rm->modeX8)) & 0x03) {
248 case 0:
249 switch ((rm->command >> (8 + rm->modeX8)) & 0x03) {
250 case 0:
251 // EWDS command
252 rm->programEnable = 0;
253 rm->phase = PHASE_COMMAND_DONE;
254 break;
255 case 1:
256 // WRAL command
257 rm->value = 0;
258 rm->valueIdx = rm->modeX8 ? 8 : 16;
259 rm->phase = PHASE_DATATRANSFER_WRITE;
260 break;
261 case 2:
262 // ERAL command
263 if (rm->programEnable) {
264 memset(rm->romData, 0xff, rm->romMask + 1);
265 rm->Do = 0;
266 boardTimerAdd(rm->timer, boardSystemTime() + boardFrequency() * 8 / 1000);
267 rm->phase = PHASE_PROGRAMMING;
268 }
269 else {
270 rm->Do = 1;
271 rm->phase = PHASE_COMMAND_DONE;
272 }
273 break;
274 case 3:
275 // EWEN command
276 rm->programEnable = 1;
277 rm->phase = PHASE_COMMAND_DONE;
278 break;
279 }
280 break;
281 case 1:
282 // WRITE command
283 rm->value = 0;
284 rm->valueIdx = rm->modeX8 ? 8 : 16;
285 rm->phase = PHASE_DATATRANSFER_WRITE;
286 break;
287 case 2:
288 // READ command
289 rm->value = romRead(rm, rm->command);
290 rm->valueIdx = rm->modeX8 ? 8 : 16;
291 rm->phase = PHASE_DATATRANSFER_READ;
292 break;
293 case 3:
294 // ERASE command
295 if (rm->programEnable) {
296 romWrite(rm, rm->command, 0xffff);
297 rm->Do = 0;
298 boardTimerAdd(rm->timer, boardSystemTime() + boardFrequency() * 3 / 1000);
299 rm->phase = PHASE_PROGRAMMING;
300 }
301 else {
302 rm->Do = 1;
303 rm->phase = PHASE_COMMAND_DONE;
304 }
305 break;
306 }
307 break;
308
309 case PHASE_DATATRANSFER_READ:
310 case PHASE_DATATRANSFER_WRITE:
311 switch ((rm->command >> (10 + rm->modeX8)) & 0x03) {
312 case 0:
313 if (((rm->command >> (8 + rm->modeX8)) & 0x03) == 1) {
314 // WRAL command
315 rm->value |= rm->Di << --rm->valueIdx;
316
317 if (rm->valueIdx == 0) {
318 if (rm->programEnable) {
319 int i;
320 for (i = 0; i <= rm->romMask; i++) {
321 romWrite(rm, i, rm->value);
322 }
323 rm->Do = 0;
324 boardTimerAdd(rm->timer, boardSystemTime() + boardFrequency() * 16 / 1000);
325 rm->phase = PHASE_PROGRAMMING;
326 }
327 else {
328 rm->Do = 1;
329 rm->phase = PHASE_COMMAND_DONE;
330 }
331 }
332 }
333 break;
334 case 1:
335 // WRITE command
336 rm->value |= rm->Di << --rm->valueIdx;
337
338 if (rm->valueIdx == 0) {
339 if (rm->programEnable) {
340 romWrite(rm, rm->command, rm->value);
341 rm->Do = 0;
342 boardTimerAdd(rm->timer, boardSystemTime() + boardFrequency() * 3 / 1000);
343 rm->phase = PHASE_PROGRAMMING;
344 }
345 else {
346 rm->Do = 1;
347 rm->phase = PHASE_COMMAND_DONE;
348 }
349 }
350 break;
351 case 2:
352 // READ command
353 rm->Do = (rm->value >> --rm->valueIdx) & 1;
354
355 if (rm->valueIdx == 0) {
356 rm->command = (rm->command & 0xfe00) | ((rm->command + 1) & 0x01ff);
357
358 rm->value = romRead(rm, rm->command);
359 rm->valueIdx = rm->modeX8 ? 8 : 16;
360 }
361 break;
362 }
363 break;
364 }
365 }
366
367
368
369
370
371
372
373
374 #if 0
375
376 /////////////////////////////////////////////////////////
377 //
378 // Test code
379 //
380 /////////////////////////////////////////////////////////
381
382
383
384
385 static void testEWEN(Microwire93Cx6* rm)
386 {
387 UInt16 cmd = (0x03 << 9);
388 UInt16 m;
389
390 // Start Command Engine
391 microwire93Cx6SetCs(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
392 microwire93Cx6SetDi(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
393
394 // Write command
395 for (m = 1 << 12; m > 0; m /= 2) {
396 microwire93Cx6SetDi(rm, cmd & m); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
397 }
398
399 microwire93Cx6SetCs(rm, 0); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
400 }
401
402 static void testEWDS(Microwire93Cx6* rm)
403 {
404 UInt16 cmd = (0x00 << 9);
405 UInt16 m;
406
407 // Start Command Engine
408 microwire93Cx6SetCs(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
409 microwire93Cx6SetDi(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
410
411 // Write command
412 for (m = 1 << 12; m > 0; m /= 2) {
413 microwire93Cx6SetDi(rm, cmd & m); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
414 }
415
416 microwire93Cx6SetCs(rm, 0); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
417 }
418
419 static void testWRITE(Microwire93Cx6* rm)
420 {
421 UInt16 cmd = (0x04 << 9) | 0x0010; // Write at address 10;
422 UInt16 val = 0xa5;
423 UInt16 m;
424
425 // Set write mode
426 testEWEN(rm);
427
428 // Start Command Engine
429 microwire93Cx6SetCs(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
430 microwire93Cx6SetDi(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
431
432 // Write command
433 for (m = 1 << 12; m > 0; m /= 2) {
434 microwire93Cx6SetDi(rm, cmd & m); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
435 }
436
437 // Write data
438 for (m = 1 << 7; m > 0; m /= 2) {
439 microwire93Cx6SetDi(rm, val & m); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
440 }
441 }
442
443 static void testWRAL(Microwire93Cx6* rm)
444 {
445 UInt16 cmd = (0x01 << 9);
446 UInt16 val = 0x39;
447 UInt16 m;
448
449 // Set write mode
450 testEWEN(rm);
451
452 // Start Command Engine
453 microwire93Cx6SetCs(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
454 microwire93Cx6SetDi(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
455
456 // Write command
457 for (m = 1 << 12; m > 0; m /= 2) {
458 microwire93Cx6SetDi(rm, cmd & m); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
459 }
460
461 // Write data
462 for (m = 1 << 7; m > 0; m /= 2) {
463 microwire93Cx6SetDi(rm, val & m); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
464 }
465 }
466
467 static void testERASE(Microwire93Cx6* rm)
468 {
469 UInt16 cmd = (0x0c << 9) | 0x0010; // Write at address 10;
470 UInt16 m;
471
472 // Set write mode
473 testEWEN(rm);
474
475 // Start Command Engine
476 microwire93Cx6SetCs(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
477 microwire93Cx6SetDi(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
478
479 rm->romData[0x10] = 44;
480
481 // Write command
482 for (m = 1 << 12; m > 0; m /= 2) {
483 microwire93Cx6SetDi(rm, cmd & m); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
484 }
485
486 printf("Erase %.2x\n", rm->romData[0x10]);
487 }
488
489 static void testERAL(Microwire93Cx6* rm)
490 {
491 UInt16 cmd = (0x02 << 9);
492 UInt16 m;
493
494 // Set write mode
495 testEWEN(rm);
496
497 // Start Command Engine
498 microwire93Cx6SetCs(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
499 microwire93Cx6SetDi(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
500
501 memset(rm->romData, 0, 0x100);
502
503 // Write command
504 for (m = 1 << 12; m > 0; m /= 2) {
505 microwire93Cx6SetDi(rm, cmd & m); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
506 }
507 printf("%.2x %.2x %.2x %.2x\n", rm->romData[0], rm->romData[1], rm->romData[2], rm->romData[3]);
508 }
509
510 static void testREAD(Microwire93Cx6* rm)
511 {
512 UInt16 cmd = (0x08 << 9) | 0x0010; // Write at address 10;
513 UInt16 val;
514 UInt16 m;
515
516 // Set read mode
517 testEWDS(rm);
518
519 // Start Command Engine
520 microwire93Cx6SetCs(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
521 microwire93Cx6SetDi(rm, 1); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
522
523 // Write command
524 for (m = 1 << 12; m > 0; m /= 2) {
525 microwire93Cx6SetDi(rm, cmd & m); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
526 }
527
528 rm->romData[0x10] = 0x5a;
529 rm->romData[0x11] = 0x4b;
530 rm->romData[0x12] = 0x3c;
531
532 // Read data
533 val = 0;
534 for (m = 1 << 7; m > 0; m /= 2) {
535 val |= m * microwire93Cx6GetDo(rm); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
536 }
537 printf("Read 0x%.2x, Expected 0x%.2x\n", val, rm->romData[0x10]);
538
539 val = 0;
540 for (m = 1 << 7; m > 0; m /= 2) {
541 val |= m * microwire93Cx6GetDo(rm); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
542 }
543 printf("Read 0x%.2x, Expected 0x%.2x\n", val, rm->romData[0x11]);
544
545 val = 0;
546 for (m = 1 << 7; m > 0; m /= 2) {
547 val |= m * microwire93Cx6GetDo(rm); microwire93Cx6SetClk(rm, 1); microwire93Cx6SetClk(rm, 0);
548 }
549 printf("Read 0x%.2x, Expected 0x%.2x\n", val, rm->romData[0x12]);
550 }
551
552 static void test(Microwire93Cx6* rm)
553 {
554 testERASE(rm);
555 }
556
557 #endif
558