OSDN Git Service

[VM] TRY:Use namespace {VMNAME} to separate around VMs. This feature still apply...
[csp-qt/common_source_project-fm7.git] / source / src / vm / fm7 / fm_bubblecasette.cpp
1 /*
2  * BUBBLE CASETTE for FM-8/7? [bubblecasette.h]
3  *
4  * Author: K.Ohta <whatisthis.sowhat _at_ gmail.com>
5  * License: GPLv2
6  * History:
7  *   Mar 22, 2016 : Initial
8  *
9  */
10 #include "../vm.h"
11 #include "../device.h"
12 #include "./bubblecasette.h"
13
14 namespace FM7 {
15
16 BUBBLECASETTE::BUBBLECASETTE(VM_TEMPLATE* parent_vm, EMU *parent_emu) : DEVICE(parent_vm, parent_emu)
17 {
18         fio = NULL;
19         memset(image_path, 0x00, _MAX_PATH * sizeof(_TCHAR));
20         bubble_type = -1;
21         memset(&bbl_header, 0x00, sizeof(bbl_header_t));
22         memset(bubble_data, 0x00, 0x20000);
23         bubble_inserted = false;
24         read_access = write_access = false;
25         set_device_name(_T("FM Bubble Casette"));
26
27 }
28
29 BUBBLECASETTE::~BUBBLECASETTE()
30 {
31 }
32
33 void BUBBLECASETTE::initialize()
34 {
35         is_wrote = false;
36         header_changed = false;
37         is_b77 = false;
38         write_protect = false;
39         not_ready = true;
40         stat_error = false;
41         cmd_error = true;
42         cmd_reg = 0;
43         media_offset = 0;
44         media_offset_new = 0;
45         media_size = 0;
46         file_length = 0;
47 }
48
49 void BUBBLECASETTE::reset()
50 {
51         data_reg = 0;
52         offset_reg = 0;
53         if(is_wrote) {
54                 write_one_page();
55                 if(is_b77) {
56                         if(header_changed) write_header();
57                         header_changed = false;
58                 }
59                 is_wrote = false;
60         }
61         cmd_reg = 0;
62         page_address.d = 0;
63         page_count.d = 0;
64         write_access = read_access = false;
65         
66         stat_busy = false;
67         stat_tdra = false;
68         stat_rda = false;
69         cmd_error = false;
70         stat_error = false;
71         
72         eject_error = false;
73         povr_error = false;
74         crc_error = false;
75         transfer_error = false;
76         bad_loop_over_error = false;
77         no_marker_error = false;
78         undefined_cmd_error = false;
79 }
80
81 uint32_t BUBBLECASETTE::read_data8(uint32_t address)
82 {
83         uint32_t val = 0xff;
84         uint32_t offset;
85         uint16_t mask;
86         uint16_t page_size_tmp;
87         uint32_t media_size_tmp;
88         if(bubble_type == BUBBLE_TYPE_32KB) {
89                 page_size_tmp = 0x20;
90                 mask = 0x3ff;
91                 media_size_tmp = 0x8000;
92         } else if(bubble_type == BUBBLE_TYPE_128KB) {
93                 page_size_tmp = 0x40;
94                 mask = 0x7ff;
95                 media_size_tmp = 0x20000;
96         } else {
97                 //return val; // Not inserted.
98                 mask = 0;
99         }
100         switch(address & 7) {
101         case 0: // Data Resistor
102                 val = (uint32_t)data_reg;
103                 offset = (page_address.w.l & mask) * page_size_tmp + offset_reg;
104                 if(stat_rda) {
105                         if(offset >= media_size_tmp) {
106                                 povr_error = true;
107                                 stat_error = true;
108                                 cmd_error = true;
109                                 read_access = false;
110                                 return val;
111                         }
112                         write_access = false;
113                         read_access = true;
114                         offset_reg++;
115                         if(offset_reg == page_size_tmp) {
116                                 stat_busy = false;
117                                 stat_rda = false;
118                                 cmd_error = true;
119                                 offset_reg = 0;
120                                 //if(!read_one_page()) {
121                                 //      stat_error = true;
122                                 //      cmd_error = true;
123                                 //      transfer_error = true; // Okay?
124                                 //      // Error handling: End?
125                                 //      page_count.w.l = 0;
126                                 //}
127                                 if(page_count.w.l > 0) page_count.w.l--;
128                                 if((page_count.w.l > 0) && (offset < media_size_tmp)) {
129                                         // Multi read
130                                         stat_busy = true;
131                                         cmd_error = false;
132                                         page_address.w.l = (page_address.w.l + 1) & mask;
133                                         data_reg = bubble_data[page_address.w.l * page_size_tmp];
134                                         //stat_rda = true;
135                                 } else { // End multi read
136                                         offset_reg = 0;
137                                         read_access = false;
138                                         //page_count.w.l = 0; // ??
139                                 }
140                         } else {
141                                 // Normal read
142                                 data_reg = bubble_data[(page_address.w.l & mask) * page_size_tmp + offset_reg];
143                                 //stat_rda = true;
144                                 cmd_error = false;
145                                 stat_busy = true;
146                         }
147                 }
148                 break;
149         case 2: // Read status register
150                 val = 0x00;
151                 if(!bubble_inserted) {
152                         cmd_error = true;
153                         not_ready = true;
154                         stat_error = true;
155                         eject_error = true;
156                 }
157                 val |= (cmd_error)  ? 0x80 : 0;
158                 val |= (stat_tdra)  ? 0x40 : 0;
159                 val |= (stat_rda)   ? 0x20 : 0;
160                 val |= (not_ready)  ? 0x10 : 0;
161                 val |= (write_protect) ? 0x04 : 0;
162                 val |= (stat_error) ? 0x02 : 0;
163                 val |= (stat_busy)  ? 0x01 : 0;
164                 if(!(bubble_inserted) && (stat_busy)) {
165                         stat_busy = false;
166                 }
167                 if((cmd_reg == 1) && (bubble_inserted) && (read_access)){
168                         if(!stat_rda) stat_rda = true;
169                 } else  if((cmd_reg == 2) && (bubble_inserted) && (write_access)){
170                         if(!stat_tdra) stat_tdra = true;
171                 }
172                 break;
173         case 3: // Read Error register
174                 val = 0x00;
175                 val |= (eject_error)         ? 0x80 : 0;
176                 val |= (povr_error)          ? 0x20 : 0;
177                 val |= (crc_error)           ? 0x10 : 0;
178                 val |= (transfer_error)      ? 0x08 : 0;
179                 val |= (bad_loop_over_error) ? 0x04 : 0;
180                 val |= (no_marker_error)     ? 0x02 : 0;
181                 val |= (undefined_cmd_error) ? 0x01 : 0;
182                 break;
183         // 4-7 : Write Only.
184         }
185         return val;
186 }
187
188 void BUBBLECASETTE::bubble_command(uint8_t cmd)
189 {
190         uint16_t mask = 0;
191         uint16_t page_size_tmp;
192         uint32_t media_size_tmp;
193         if(bubble_type == BUBBLE_TYPE_32KB) {
194                 page_size_tmp = 0x20;
195                 mask = 0x3ff;
196                 media_size_tmp = 0x8000;
197         } else if(bubble_type == BUBBLE_TYPE_128KB) {
198                 page_size_tmp = 0x40;
199                 mask = 0x7ff;
200                 media_size_tmp = 0x20000;
201         }
202         switch(cmd) {
203         case 1: // Read
204                 offset_reg = 0;
205                 read_access = false;
206                 write_access = false;
207                 if(!bubble_inserted) {
208                         stat_error = true;
209                         cmd_error = true;
210                         no_marker_error = true;
211                         eject_error = true;
212                 } else {
213                         data_reg = bubble_data[(page_address.w.l & mask) * page_size_tmp];
214                         stat_rda = true;
215                         read_access = true;
216                 }
217                 break;
218         case 2: // Write :: Will not check insert?
219                 stat_busy = true;
220                 write_access = false;
221                 read_access = false;
222                 if(!bubble_inserted) {
223                         stat_error = true;
224                         cmd_error = true;
225                         no_marker_error = true;
226                         eject_error = true;
227                 } else {
228                         if(write_protect) {
229                                 stat_busy = false;
230                                 cmd_error = true;
231                                 stat_tdra = false;
232                         } else {
233                                 offset_reg = 0;
234                                 write_access = true;
235                                 stat_tdra = true;
236                                 cmd_error = false;
237                         }
238                 }
239                 break;
240         case 4:
241         case 15: // Reset
242                 data_reg = 0;
243                 if(is_wrote) {
244                         write_one_page();
245                         is_wrote = false;
246                 }
247                 page_address.d = 0;
248                 page_count.d = 0;
249                 write_access = read_access = false;
250                 break;
251         default:
252                 stat_error = true;
253                 cmd_error = true;
254                 undefined_cmd_error = true;
255                 break;
256         }
257 }
258 void BUBBLECASETTE::write_data8(uint32_t address, uint32_t data)
259 {
260         uint8_t val;
261         uint32_t offset;
262         uint16_t mask = 0;
263         uint16_t page_size_tmp;
264         uint32_t media_size_tmp;
265         if(bubble_type == BUBBLE_TYPE_32KB) {
266                 page_size_tmp = 0x20;
267                 mask = 0x3ff;
268                 media_size_tmp = 0x8000;
269         } else if(bubble_type == BUBBLE_TYPE_128KB) {
270                 page_size_tmp = 0x40;
271                 mask = 0x7ff;
272                 media_size_tmp = 0x20000;
273         } else {
274                 //return; // Not inserted.
275         }
276         val = (uint8_t)data;
277
278         switch(address & 7) {
279         case 0: // Write Data
280                 data_reg = val;
281                 if(stat_tdra) {
282                         if(offset >= media_size_tmp) {
283                                 povr_error = true;
284                                 stat_error = true;
285                                 cmd_error = true;
286                                 return;
287                         }
288                         is_wrote = true;
289                         offset = page_address.w.l * page_size_tmp + offset_reg;
290                         bubble_data[(page_address.w.l & mask) * page_size_tmp + offset_reg] = data_reg;
291                         write_access = true;
292                         read_access = false;
293                         offset_reg++;
294                         if(offset_reg == page_size_tmp) {
295                                 stat_busy = false;
296                                 stat_tdra = false;
297                                 cmd_error = true;
298                                 stat_error = false;
299                                 if(!write_one_page()) {
300                                         stat_error = true;
301                                         cmd_error = true;
302                                         transfer_error = true; // Okay?
303                                         // Error handling: End?
304                                         page_count.w.l = 0;
305                                         return;
306                                 }
307                                 offset_reg = 0;
308                                 if(page_count.w.l > 0) {
309                                         page_count.w.l--;
310                                         //page_address.w.l = (page_address.w.l + 1) & mask;
311                                 }
312                                 if((page_count.w.l > 0) && (offset < media_size_tmp)) {
313                                         stat_busy = true;
314                                         cmd_error = false;
315                                         page_address.w.l = (page_address.w.l + 1) & mask;
316                                 } else {
317                                         // Completed
318                                         write_access = false;
319                                 }
320                         } else {
321                                 //stat_busy = true;
322                                 //stat_tdra = false; // Move to event_callback()?
323                         }
324                 }
325                 break;
326         case 1: // CMD register
327                 stat_busy = false;
328                 stat_tdra = false;
329                 stat_rda = false;
330                 cmd_error = false;
331                 stat_error = false;
332
333                 eject_error = false;
334                 povr_error = false;
335                 crc_error = false;
336                 transfer_error = false;
337                 bad_loop_over_error = false;
338                 no_marker_error = false;
339                 undefined_cmd_error = false;
340                 cmd_reg = val;
341                 bubble_command(val);
342                 
343                 break;
344         case 2: // Read only
345         case 3: // Read only
346                 break;
347         case 4:
348                 page_address.b.h = val;
349                 break;
350         case 5:
351                 page_address.b.l = val;
352                 break;
353         case 6:
354                 page_count.b.h = val;
355                 break;
356         case 7:
357                 page_count.b.l = val;
358                 break;
359         }
360 }
361
362 uint32_t BUBBLECASETTE::read_signal(int address)
363 {
364 }
365
366 void BUBBLECASETTE::write_signal(int id, uint32_t data, uint32_t mask)
367 {
368 }
369
370 bool BUBBLECASETTE::open(_TCHAR* file_path, int bank)
371 {
372         int i;
373         int contain_medias = 0;
374         is_wrote = false;
375         header_changed = false;
376         is_b77 = false;
377         fio = NULL;
378         
379         media_offset = 0;
380         media_offset_new = 0;
381         file_length = 0;
382         bubble_inserted = false;
383         not_ready = true;
384         cmd_error = true;
385         stat_tdra = false;
386         stat_rda = false;
387         stat_error = false; // OK?
388         stat_busy = false;
389         
390         memset(bubble_data, 0, 0x20000);
391         memset(&bbl_header, 0, sizeof(bbl_header_t));
392         bubble_type = -1;
393
394         if(fio != NULL) {
395                 close();
396         }
397         fio = new FILEIO;
398         if(fio == NULL) return false;
399         memset(image_path, 0x00, _MAX_PATH * sizeof(_TCHAR));
400         _tcsncpy(image_path, file_path, _MAX_PATH);
401
402         if(fio->IsFileExisting(file_path)) {
403                 fio->Fopen(file_path, FILEIO_READ_WRITE_BINARY);
404                 file_length = fio->FileLength();
405                 if(file_length == 0) return false;
406                 //printf("Size=%d\n", file_length);
407                 if(file_length == 0x8000) { // 32KB
408                         bubble_type = BUBBLE_TYPE_32KB;
409                         media_size = 0x8000;
410                 } else if(file_length == 0x20000) {
411                         bubble_type = BUBBLE_TYPE_128KB;
412                         media_size = 0x20000;
413                 } else {
414                         bubble_type = BUBBLE_TYPE_B77;
415                 }
416                 
417                 if(bubble_type != BUBBLE_TYPE_B77) {
418                         if(bubble_type < 0) return false;
419                         write_protect = false;
420                         not_ready = false;
421                         switch(bubble_type) {
422                         case BUBBLE_TYPE_32KB:
423                                 if(fio->Fread(bubble_data, 0x8000, 1) != 1) return false;
424                                 break;
425                         case BUBBLE_TYPE_128KB:
426                                 if(fio->Fread(bubble_data, 0x20000, 1) != 1) return false;
427                                 break;
428                         }
429                         media_num = 0;
430                         bubble_inserted = true;
431                         return true;
432                 } else { // b77
433                         int remain;
434                         do {
435                                 write_protect = false;
436                                 not_ready = false;
437                                 if(!this->read_header()) break;
438                                 if(contain_medias != bank) {
439                                         fio->Fseek(media_offset_new , FILEIO_SEEK_SET); // Skip
440                                         if(fio->Ftell() >= file_length) return false; // Error
441                                         contain_medias++;
442                                 } else { // Image found
443                                         if(bubble_type == BUBBLE_TYPE_32KB) {
444                                                 if(bbl_header.offset.d > 0x20) fio->Fseek(media_offset, FILEIO_SEEK_SET);
445                                                 remain = file_length - bbl_header.offset.d;
446                                                 media_size = 0x8000;
447                                                 if(remain >= 0x8000) {
448                                                         remain = 0x8000;
449                                                 }
450                                                 fio->Fread(bubble_data, remain, 1);
451                                                 is_b77 = true;
452                                         } else if(bubble_type == BUBBLE_TYPE_128KB) {
453                                                 if(bbl_header.offset.d > 0x20) fio->Fseek(media_offset, FILEIO_SEEK_SET);
454                                                 remain = file_length - bbl_header.offset.d;
455                                                 media_size = 0x20000;
456                                                 
457                                                 if(remain >= 0x20000) {
458                                                         remain = 0x20000;
459                                                 }
460                                                 fio->Fread(bubble_data, remain, 1);
461                                                 is_b77 = true;
462                                         }
463                                         bubble_inserted = true;
464                                         media_num = (uint32_t)bank;
465                                         contain_medias++;
466                                 }
467                                 //contain_medias++;
468                         } while(contain_medias <= 16);
469                         if(contain_medias > 0) return true;
470                         return false;
471                 }
472         } else {
473                 not_ready = true;
474                 return false;
475         }
476         return false;
477 }
478
479 bool BUBBLECASETTE::read_header()
480 {
481         uint32_t f_pos;
482         uint8_t tmpval[16];
483         if(fio == NULL) return false;
484         if(fio->Ftell() >= file_length) return false;
485         // You need convert to [UTF8|Local8Bit] when using UI.
486         fio->Fread(bbl_header.filename, 0x10, 1);
487         if(fio->Fread(&tmpval, 0x10, 1) != 0x10) return false;
488         // Offset(little endian)
489         bbl_header.offset.b.l  = tmpval[4];
490         bbl_header.offset.b.h  = tmpval[5];
491         bbl_header.offset.b.h2 = tmpval[6];
492         bbl_header.offset.b.h3 = tmpval[7];
493         // Casette size(little endian)
494         bbl_header.size.b.l  = tmpval[12];
495         bbl_header.size.b.h  = tmpval[13];
496         bbl_header.size.b.h2 = tmpval[14];
497         bbl_header.size.b.h3 = tmpval[15];
498         // Misc
499         bbl_header.misc[0] = tmpval[0];
500         bbl_header.misc[1] = tmpval[1];
501         bbl_header.misc[2] = tmpval[2];
502         bbl_header.misc[3] = tmpval[3];
503         
504         bbl_header.misc[4] = tmpval[8];
505         bbl_header.misc[5] = tmpval[9];
506         bbl_header.misc[6] = tmpval[10];
507         bbl_header.misc[7] = tmpval[11];
508
509         if((tmpval[10] & 0x10) != 0) {
510                 write_protect = true; // ToDo : Relate to permission of image file.
511         } else {
512                 write_protect = false; // ToDo : Relate to permission of image file.
513         }
514         switch(tmpval[11]) {
515         case 0x80:
516                 bubble_type = BUBBLE_TYPE_32KB;
517                 break;
518         case 0x90:
519                 bubble_type = BUBBLE_TYPE_128KB;
520                 break;
521         default:
522                 return false;
523                 break;
524         }
525         media_size = bbl_header.size.d;
526         media_offset = media_offset_new + bbl_header.offset.d;
527         media_offset_new = media_offset_new + media_size;
528         return true;
529 }       
530
531 void BUBBLECASETTE::write_header()
532 {
533         uint32_t f_pos;
534         uint8_t tmpval[16];
535         if(fio == NULL) return;
536         if(fio->Ftell() >= file_length) return;
537         // You need convert to [UTF8|Local8Bit] when using UI.
538         // Offset(little endian)
539         tmpval[4]  = bbl_header.offset.b.l;
540         tmpval[5]  = bbl_header.offset.b.h;
541         tmpval[6]  = bbl_header.offset.b.h2;
542         tmpval[7]  = bbl_header.offset.b.h3;
543         // Casette size(little endian)
544         tmpval[12] = bbl_header.size.b.l;
545         tmpval[13] = bbl_header.size.b.h;
546         tmpval[14] = bbl_header.size.b.h2;
547         tmpval[15] = bbl_header.size.b.h3;
548         // Misc
549         tmpval[0]  = bbl_header.misc[0];
550         tmpval[1]  = bbl_header.misc[1];
551         tmpval[2]  = bbl_header.misc[2];
552         tmpval[3]  = bbl_header.misc[3];
553         
554         tmpval[8]  = bbl_header.misc[4];
555         tmpval[9]  = bbl_header.misc[5];
556         tmpval[10] = bbl_header.misc[6];
557         tmpval[11] = bbl_header.misc[7];
558         
559         if(write_protect) {
560                 tmpval[10] |= 0x10;
561         } else {
562                 tmpval[10] &= (uint8_t)(~0x10);
563         }
564         switch(bubble_type) {
565         case BUBBLE_TYPE_32KB:
566                 tmpval[11] = 0x80;
567                 break;
568         case BUBBLE_TYPE_128KB:
569                 tmpval[11] = 0x90;
570                 break;
571         default:
572                 return;
573                 break;
574         }
575         fio->Fwrite(bbl_header.filename, 0x10, 1);
576         fio->Fwrite(&tmpval, 0x10, 1);
577         return;
578 }
579
580 bool BUBBLECASETTE::read_one_page()
581 {
582         uint32_t f_pos;
583         if(fio == NULL) return false;
584         if(!fio->IsOpened()) return false;
585         if(!bubble_inserted) {
586                 // Error Handling
587                 return false;
588         }
589         f_pos = media_offset;
590         {
591                 uint32_t offset = 0;
592                 uint32_t page_size = 0;
593                 int remain = (int)media_size - (int)bbl_header.offset.d;
594                 if(remain <= 0) return false;
595                 switch(bubble_type) {
596                 case BUBBLE_TYPE_32KB:
597                         offset = (page_address.w.l & 0x03ff) * 0x20;
598                         page_size = 0x20;
599                         break;
600                 case BUBBLE_TYPE_128KB:
601                         offset = bbl_header.offset.d + (page_address.w.l & 0x07ff) * 0x40;
602                         page_size = 0x40;
603                         break;
604                 default:
605                         return false;
606                         break;
607                 }
608                 if(remain < (int)(offset + page_size)) return false;
609                 fio->Fseek(f_pos + offset, FILEIO_SEEK_SET);
610                 fio->Fread(&bubble_data[offset], page_size, 1);
611         }
612         return true;
613 }
614
615 bool BUBBLECASETTE::write_one_page()
616 {
617         uint32_t f_pos;
618         if(fio == NULL) return false;
619         if(!fio->IsOpened()) return false;
620         if(!bubble_inserted) {
621                 // Error Handling
622                 return false;
623         }
624         f_pos = media_offset;
625         if(is_wrote) {
626                 uint32_t offset = 0;
627                 uint32_t page_size = 0;
628                 int remain = (int)media_size - (int)bbl_header.offset.d;
629                 if(remain <= 0) return false;
630                 switch(bubble_type) {
631                 case BUBBLE_TYPE_32KB:
632                         offset = (page_address.w.l & 0x03ff) * 0x20;
633                         page_size = 0x20;
634                         break;
635                 case BUBBLE_TYPE_128KB:
636                         offset = bbl_header.offset.d + (page_address.w.l & 0x07ff) * 0x40;
637                         page_size = 0x40;
638                         break;
639                 default:
640                         return false;
641                         break;
642                 }
643                 //printf("Write One Page: PAGE=%04x COUNT=%04x:\n ",page_address.w.l, page_count.w.l);
644                 if(remain < (int)(offset + page_size)) return false;
645                 fio->Fseek(f_pos + offset, FILEIO_SEEK_SET);
646                 fio->Fwrite(&bubble_data[offset], page_size, 1);
647                 is_wrote = false;
648         }
649         return true;
650 }
651
652 void BUBBLECASETTE::close()
653 {
654         int i;
655         if(fio != NULL) {
656                 if(fio->IsOpened()) {
657                         if(is_wrote) write_one_page();
658                         if(is_b77) {
659                                 if(header_changed) write_header();
660                                 header_changed = false;
661                                 is_b77 = false;
662                         }
663                         fio->Fclose();
664                 }
665                 delete fio;
666         }
667         fio = NULL;
668         memset(image_path, 0x00, _MAX_PATH * sizeof(_TCHAR));
669         bubble_type = -1;
670         memset(&bbl_header, 0x00, sizeof(bbl_header_t));
671         memset(bubble_data, 0x00, 0x20000);
672         media_offset = 0;
673         media_offset_new = 0;
674         is_wrote = false;
675         is_b77 = false;
676         header_changed = false;
677         bubble_inserted = false;
678         read_access = write_access = false;
679 }
680
681 void BUBBLECASETTE::event_callback(int event_id, int err)
682 {
683 }
684
685
686 #define STATE_VERSION 5
687
688 bool BUBBLECASETTE::process_state(FILEIO *state_fio, bool loading)
689 {
690         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
691                 return false;
692         }
693         if(!state_fio->StateCheckInt32(this_device_id)) {
694                 return false;
695         }
696         
697         state_fio->StateBool(is_wrote);
698         state_fio->StateBool(is_b77);
699         state_fio->StateBool(header_changed);
700         state_fio->StateBool(read_access);
701         state_fio->StateBool(write_access);
702
703         state_fio->StateUint8(offset_reg);
704         state_fio->StateUint8(data_reg);
705         state_fio->StateUint8(cmd_reg);
706
707         state_fio->StateBool(cmd_error);  
708         state_fio->StateBool(stat_tdra);  
709         state_fio->StateBool(stat_rda);   
710         state_fio->StateBool(not_ready);  
711         state_fio->StateBool(write_protect); 
712         state_fio->StateBool(stat_error); 
713         state_fio->StateBool(stat_busy);  
714
715         state_fio->StateBool(eject_error);         
716         state_fio->StateBool(povr_error);          
717         state_fio->StateBool(crc_error);           
718         state_fio->StateBool(transfer_error);      
719         state_fio->StateBool(bad_loop_over_error); 
720         state_fio->StateBool(no_marker_error);     
721         state_fio->StateBool(undefined_cmd_error); 
722         
723         state_fio->StateUint32(page_address.d);
724         state_fio->StateUint32(page_count.d);
725         state_fio->StateBool(bubble_inserted);
726         state_fio->StateInt32(bubble_type);
727         state_fio->StateInt32(media_num);
728         // Header
729         state_fio->StateBuffer(image_path, sizeof(image_path), 1);
730         state_fio->StateBuffer((bbl_header.filename), sizeof(bbl_header.filename), 1);
731         state_fio->StateUint32((bbl_header.size.d));
732         state_fio->StateUint32((bbl_header.offset.d));
733         state_fio->StateBuffer((bbl_header.misc), sizeof(bbl_header.misc), 1);
734
735
736         state_fio->StateUint32(media_offset);
737         state_fio->StateUint32(media_offset_new);
738         state_fio->StateUint32(media_size);
739         state_fio->StateUint32(file_length);
740         state_fio->StateBuffer(bubble_data, sizeof(bubble_data), 1);
741  
742 #if 0
743         if(loading) {
744                 is_wrote = false;
745                 header_changed = false;
746                 if(_tcslen(image_path) > 0) {
747                         bool is_wrote_bak = is_wrote;
748                         bool header_changed_bak = header_changed;
749                         bool is_b77_bak = is_b77;
750                         uint32_t media_offset_bak = media_offset;
751                         uint32_t media_offset_new_bak = media_offset_new;
752                         uint32_t file_length_bak = file_length;
753                         bool bubble_inserted_bak = bubble_inserted;
754                         bool not_ready_bak = not_ready;
755                         bool cmd_error_bak = cmd_error;
756                         bool stat_tdra_bak = stat_tdra;
757                         bool stat_rda_bak = stat_rda;
758                         bool stat_error_bak = stat_error; // OK?
759                         bool stat_busy_bak = stat_busy;
760                         int bubble_type_bak = bubble_type;
761                         uint32_t media_size_bak = media_size;
762                         bool write_protect_bak = write_protect;
763                         bool not_ready_bak = not_ready;
764                         uint32_t media_num_bak = media_num;
765                         
766                         bbl_header_t bbl_header_bak;
767                         uint8_t bubble_data_bak[0x20000];
768                         _TCHAR image_path_bak[_MAX_PATH];
769                         memcpy(&bbl_header_bak, &bbl_header, sizeof(bbl_header_t));
770                         memcpy(bubble_data_bak, bubble_data, 0x20000);
771                         memcpy(image_path_bak, image_path, _MAXPATH * sizeof(_TCHAR));
772                         if(!open(image_path, (int)media_num)) {
773                                 // Revert loaded status
774                                 is_wrote = is_wrote_bak;
775                                 header_changed = header_changed_bak;
776                                 is_b77 = is_b77_bak;
777                                 media_offset = media_offset_bak;
778                                 media_offset_new = media_offset_new_bak;
779                                 file_length = file_length_bak;
780                                 bubble_inserted = bubble_inserted_bak;
781                                 not_ready = not_ready_bak;
782                                 cmd_error = cmd_error_bak;
783                                 stat_tdra = stat_tdra_bak;
784                                 stat_rda = stat_rda_bak;
785                                 stat_error = stat_error_bak; // OK?
786                                 stat_busy = stat_busy_bak;
787                                 bubble_type = bubble_type_bak;
788                                 media_size = media_size_bak;
789                                 write_protect = write_protect_bak;
790                                 not_ready = not_ready_bak;
791                                 media_num = media_num_bak;
792                                 memcpy(&bbl_header, &bbl_header_bak, sizeof(bbl_header_t));
793                                 memcpy(bubble_data, bubble_data_bak, 0x20000);
794                                 memcpy(image_path, image_path_bak, _MAXPATH * sizeof(_TCHAR));
795                                 return true;
796                         }
797                 }
798         } else {
799                 if(state_fio != NULL) {
800                         if(state_fio->IsOpened()) {
801                                 if(is_wrote) write_one_page();
802                                 if(is_b77) {
803                                         if(header_changed) {
804                                                 write_header();
805                                                 header_changed = false;
806                                         }
807                                 }
808                         }
809                 }
810         }
811 #endif
812         return true;
813 }
814
815 }