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