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