OSDN Git Service

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