OSDN Git Service

[VM][FM7][PC88][PC60][PC98][X1] DATAREC/SEEK; has sound files, will abandon WAV_SOUND...
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc6001 / pc6001.cpp
1 /*
2         NEC PC-6001 Emulator 'yaPC-6001'
3         NEC PC-6001mkII Emulator 'yaPC-6201'
4         NEC PC-6001mkIISR Emulator 'yaPC-6401'
5         NEC PC-6601 Emulator 'yaPC-6601'
6         NEC PC-6601SR Emulator 'yaPC-6801'
7
8         Author : tanam
9         Date   : 2013.07.15-
10
11         [ virtual machine ]
12 */
13
14 #include "pc6001.h"
15 #include "../../emu.h"
16 #include "../device.h"
17 #include "../event.h"
18
19 #include "../disk.h"
20 #include "../i8255.h"
21 #include "../io.h"
22 #ifdef _PC6001
23 #include "../mc6847.h"
24 #include "display.h"
25 #else
26 #include "../upd7752.h"
27 #endif
28 #include "../pc6031.h"
29 #include "../pc80s31k.h"
30 #include "../prnfile.h"
31 #include "../upd765a.h"
32 #include "../ym2203.h"
33 #include "../z80.h"
34
35 #include "../datarec.h"
36 #include "../mcs48.h"
37
38 #ifdef USE_DEBUGGER
39 #include "../debugger.h"
40 #endif
41
42 #if defined(_PC6601) || defined(_PC6601SR)
43 #include "floppy.h"
44 #endif
45 #include "joystick.h"
46 #include "memory.h"
47 #include "psub.h"
48 #include "sub.h"
49 #include "timer.h"
50
51 // ----------------------------------------------------------------------------
52 // initialize
53 // ----------------------------------------------------------------------------
54
55 VM::VM(EMU* parent_emu) : emu(parent_emu)
56 {
57         support_pc80s31k = FILEIO::IsFileExisting(create_local_path(_T("DISK.ROM")));
58 #ifdef _PC6601SR
59         support_sub_cpu = false;
60 #else
61         support_sub_cpu = FILEIO::IsFileExisting(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
62 #endif
63         
64         // create devices
65         first_device = last_device = NULL;
66         dummy = new DEVICE(this, emu);  // must be 1st device
67         event = new EVENT(this, emu);   // must be 2nd device
68 #if defined(_USE_QT)
69         dummy->set_device_name(_T("1st Dummy"));
70 #endif  
71         d_pc80s31k_seek = d_pc6031_seek = d_floppy_seek = NULL; 
72         pio_sub = new I8255(this, emu);
73         io = new IO(this, emu);
74         psg = new YM2203(this, emu);
75         cpu = new Z80(this, emu);
76 #if defined(_USE_QT)
77 #ifdef _PC6001
78         pio_sub->set_device_name(_T("i8255 PIO(PRINTER/SOUND/SUB/VDP)"));
79 #else
80         pio_sub->set_device_name(_T("i8255 PIO(PRINTER/SOUND/SUB)"));
81 #endif
82 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
83         psg->set_device_name(_T("YM2203 OPN"));
84 #else
85         psg->set_device_name(_T("AY-3-8910 PSG"));
86 #endif
87         cpu->set_device_name(_T("CPU(Z80)"));
88 #endif  
89         
90         if(config.printer_device_type == 0) {
91                 printer = new PRNFILE(this, emu);
92         } else {
93                 printer = dummy;
94         }
95         
96 #if defined(_PC6601) || defined(_PC6601SR)
97         floppy = new FLOPPY(this, emu);
98 #if defined(_USE_QT)
99         floppy->set_device_name(_T("FLOPPY I/F"));
100 #endif
101 #endif
102         joystick = new JOYSTICK(this, emu);
103         memory = new MEMORY(this, emu);
104         timer = new TIMER(this, emu);
105 #if defined(_USE_QT)
106         joystick->set_device_name(_T("JOYSTICK I/F"));
107         memory->set_device_name(_T("MEMORY"));
108         timer->set_device_name(_T("TIMER"));
109 #endif
110         
111         // set contexts
112         event->set_context_cpu(cpu);
113         event->set_context_sound(psg);
114         
115         pio_sub->set_context_port_b(printer, SIG_PRINTER_DATA, 0xff, 0);
116         pio_sub->set_context_port_c(printer, SIG_PRINTER_STROBE, 0x01, 0);
117         pio_sub->set_context_port_c(memory, SIG_MEMORY_PIO_PORT_C, 0x06, 0);    // CRTKILL,CGSWN
118         
119 #ifdef _PC6001
120         display = new DISPLAY(this, emu);
121         vdp = new MC6847(this, emu);
122         display->set_context_vdp(vdp);
123         display->set_vram_ptr(memory->get_vram());
124         display->set_context_timer(timer);
125         vdp->load_font_image(create_local_path(_T("CGROM60.60")));
126         vdp->set_context_cpu(cpu);
127         pio_sub->set_context_port_c(vdp, SIG_MC6847_ENABLE, 0x02, 0);   // CRTKILL
128 #if defined(_USE_QT)
129         display->set_device_name(_T("DISPLAY I/F"));
130 #endif
131 #else
132         voice = new UPD7752(this, emu);
133         event->set_context_sound(voice);
134         memory->set_context_timer(timer);
135 #endif
136         memory->set_context_cpu(cpu);
137         joystick->set_context_psg(psg);
138         
139         timer->set_context_cpu(cpu);
140 #ifndef _PC6001
141         timer->set_context_memory(memory);
142 #endif
143         if(support_sub_cpu) {
144                 cpu_sub = new MCS48(this, emu);
145                 sub = new SUB(this, emu);
146                 drec = new DATAREC(this, emu);
147                 event->set_context_cpu(cpu_sub, 8000000);
148                 event->set_context_sound(drec);
149 #if defined(USE_SOUND_FILES)
150                 drec->load_sound_data(DATAREC_SNDFILE_RELAY_ON, _T("RELAY_ON.WAV"));
151                 drec->load_sound_data(DATAREC_SNDFILE_RELAY_OFF, _T("RELAY_OFF.WAV"));
152 #endif          
153                 cpu_sub->set_context_mem(new MCS48MEM(this, emu));
154                 cpu_sub->set_context_io(sub);
155 #ifdef USE_DEBUGGER
156                 cpu_sub->set_context_debugger(new DEBUGGER(this, emu));
157 #endif
158                 sub->set_context_pio(pio_sub);
159                 sub->set_context_drec(drec);
160                 sub->set_context_timer(timer);
161                 pio_sub->set_context_port_c(cpu_sub, SIG_CPU_IRQ, 0x80, 0);
162                 drec->set_context_ear(sub, SIG_SUB_DATAREC, 1);
163                 timer->set_context_sub(sub);
164         } else {
165                 psub = new PSUB(this, emu);
166 #if defined(_USE_QT)
167                 psub->set_device_name(_T("PSEUDO SUB SYSTEM"));
168 #endif
169                 psub->set_context_pio(pio_sub);
170                 psub->set_context_timer(timer);
171                 timer->set_context_sub(psub);
172                 cpu_sub = NULL;
173         }
174         if(support_pc80s31k) {
175                 pio_fdd = new I8255(this, emu);
176                 pio_pc80s31k = new I8255(this, emu);
177                 pc80s31k = new PC80S31K(this, emu);
178                 fdc_pc80s31k = new UPD765A(this, emu);
179                 cpu_pc80s31k = new Z80(this, emu);
180 #if defined(_USE_QT)
181                 pio_fdd->set_device_name(_T("i8255 PIO(FDD)"));
182                 pio_pc80s31k->set_device_name(_T("i8255 PIO(PC-80S31K)"));
183                 pc80s31k->set_device_name(_T("PC-80S31K FDD"));
184                 fdc_pc80s31k->set_device_name(_T("uPD765A FDC(PC-80S31K)"));
185                 cpu_pc80s31k->set_device_name(_T("Z80 CPU(PC-80S31K)"));
186 #endif
187 #if defined(USE_SOUND_FILES)
188                 if(fdc_pc80s31k->load_sound_data(UPD765A_SND_TYPE_SEEK, _T("FDDSEEK.WAV"))) {
189                         event->set_context_sound(fdc_pc80s31k);
190                 }
191 #endif          
192                 event->set_context_cpu(cpu_pc80s31k, 4000000);
193                 pc80s31k->set_context_cpu(cpu_pc80s31k);
194                 pc80s31k->set_context_fdc(fdc_pc80s31k);
195                 pc80s31k->set_context_pio(pio_pc80s31k);
196                 pio_fdd->set_context_port_a(pio_pc80s31k, SIG_I8255_PORT_B, 0xff, 0);
197                 pio_fdd->set_context_port_b(pio_pc80s31k, SIG_I8255_PORT_A, 0xff, 0);
198                 pio_fdd->set_context_port_c(pio_pc80s31k, SIG_I8255_PORT_C, 0x0f, 4);
199                 pio_fdd->set_context_port_c(pio_pc80s31k, SIG_I8255_PORT_C, 0xf0, -4);
200                 pio_fdd->clear_ports_by_cmdreg = true;
201                 pio_pc80s31k->set_context_port_a(pio_fdd, SIG_I8255_PORT_B, 0xff, 0);
202                 pio_pc80s31k->set_context_port_b(pio_fdd, SIG_I8255_PORT_A, 0xff, 0);
203                 pio_pc80s31k->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0x0f, 4);
204                 pio_pc80s31k->set_context_port_c(pio_fdd, SIG_I8255_PORT_C, 0xf0, -4);
205                 pio_pc80s31k->clear_ports_by_cmdreg = true;
206                 fdc_pc80s31k->set_context_irq(cpu_pc80s31k, SIG_CPU_IRQ, 1);
207                 cpu_pc80s31k->set_context_mem(pc80s31k);
208                 cpu_pc80s31k->set_context_io(pc80s31k);
209                 cpu_pc80s31k->set_context_intr(pc80s31k);
210 #ifdef USE_DEBUGGER
211                 cpu_pc80s31k->set_context_debugger(new DEBUGGER(this, emu));
212 #endif
213 #if defined(_PC6601) || defined(_PC6601SR)
214                 floppy->set_context_ext(pio_fdd);
215 #endif
216         } else {
217                 pc6031 = new PC6031(this, emu);
218 #if defined(_PC6601) || defined(_PC6601SR)
219                 floppy->set_context_ext(pc6031);
220 #endif
221 #if defined(USE_SOUND_FILES)
222                 if(pc6031->load_sound_data(PC6031_SND_TYPE_SEEK, _T("FDDSEEK.WAV"))) {
223                         event->set_context_sound(pc6031);
224                 }
225                 if(floppy->load_sound_data(FLOPPY_SND_TYPE_SEEK, _T("FDDSEEK.WAV"))) {
226                         event->set_context_sound(floppy);
227                 }
228 #endif          
229                 cpu_pc80s31k = NULL;
230         }
231         
232         // cpu bus
233         cpu->set_context_mem(memory);
234         cpu->set_context_io(io);
235         cpu->set_context_intr(timer);
236 #ifdef USE_DEBUGGER
237         cpu->set_context_debugger(new DEBUGGER(this, emu));
238 #endif
239         
240         // i/o bus
241         if(support_sub_cpu) {
242                 io->set_iomap_range_rw(0x90, 0x93, sub);
243         } else {
244                 io->set_iomap_range_rw(0x90, 0x93, psub);
245         }
246         io->set_iomap_alias_w(0xa0, psg, 0);                    // PSG ch
247         io->set_iomap_alias_w(0xa1, psg, 1);                    // PSG data
248         io->set_iomap_alias_r(0xa2, psg, 1);                    // PSG data
249 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
250         io->set_iomap_alias_r(0xa3, psg, 0);                    // FM status
251         io->set_iomap_range_rw(0x40, 0x6f, memory);             // VRAM addr
252 #endif
253 #ifdef _PC6001
254         io->set_iomap_single_w(0xb0, display);                  // VRAM addr
255         io->set_iomap_single_w(0x00, memory);                   // MEMORY MAP
256 #else
257         io->set_iomap_single_w(0xb0, memory);                   // VRAM addr
258         io->set_iomap_range_rw(0xc0, 0xcf, memory);             // VRAM addr
259         io->set_iomap_range_rw(0xe0, 0xe3, voice);              // VOICE
260 #if defined(_PC6601) || defined(_PC6601SR)
261         io->set_iomap_range_rw(0xb8, 0xbf, timer);              // IRQ
262         io->set_iomap_range_rw(0xfa, 0xfb, timer);              // IRQ
263 #endif
264         io->set_iomap_range_rw(0xf3, 0xf7, timer);              // IRQ/Timer
265 #endif
266         
267 #if defined(_PC6601) || defined(_PC6601SR)
268         io->set_iomap_range_rw(0xb1, 0xb3, floppy);             // DISK DRIVE
269         io->set_iomap_range_rw(0xb5, 0xb7, floppy);             // DISK DRIVE (Mirror)
270         io->set_iomap_range_rw(0xd0, 0xde, floppy);             // DISK DRIVE
271 #else
272         io->set_iovalue_single_r(0xb1, 0x01);
273 #if defined(_PC6601SR)
274         io->set_iovalue_single_r(0xb2, 0x02);
275 #elif defined(_PC6001MK2SR)
276         io->set_iovalue_single_r(0xb2, 0x00);
277 #endif
278         
279         if(support_pc80s31k) {
280                 io->set_iomap_range_rw(0xd0, 0xd2, pio_fdd);
281                 io->set_iomap_single_w(0xd3, pio_fdd);
282         } else {
283                 io->set_iomap_range_rw(0xd0, 0xd3, pc6031);
284         }
285 #endif
286         io->set_iomap_range_rw(0xf0, 0xf2, memory);             // MEMORY MAP
287         
288         // initialize all devices
289         for(DEVICE* device = first_device; device; device = device->next_device) {
290                 device->initialize();
291         }
292         if(support_sub_cpu) {
293                 // load rom images after cpustate is allocated
294 #ifdef _PC6601SR
295 #else
296                 cpu_sub->load_rom_image(create_local_path(_T(SUB_CPU_ROM_FILE_NAME)));
297 #endif
298         }
299         int drive_num = 0;
300 #if defined(_PC6601) || defined(_PC6601SR)
301         floppy->get_disk_handler(0)->drive_num = drive_num++;
302         floppy->get_disk_handler(1)->drive_num = drive_num++;
303 #endif
304         if(support_pc80s31k) {
305                 fdc_pc80s31k->get_disk_handler(0)->drive_num = drive_num++;
306                 fdc_pc80s31k->get_disk_handler(1)->drive_num = drive_num++;
307         } else {
308                 pc6031->get_disk_handler(0)->drive_num = drive_num++;
309                 pc6031->get_disk_handler(1)->drive_num = drive_num++;
310         }
311 }
312
313 VM::~VM()
314 {
315         // delete all devices
316         for(DEVICE* device = first_device; device;) {
317                 DEVICE *next_device = device->next_device;
318                 device->release();
319                 delete device;
320                 device = next_device;
321         }
322 }
323
324 DEVICE* VM::get_device(int id)
325 {
326         for(DEVICE* device = first_device; device; device = device->next_device) {
327                 if(device->this_device_id == id) {
328                         return device;
329                 }
330         }
331         return NULL;
332 }
333
334 // ----------------------------------------------------------------------------
335 // drive virtual machine
336 // ----------------------------------------------------------------------------
337 void VM::reset()
338 {
339         // reset all devices
340         for(DEVICE* device = first_device; device; device = device->next_device) {
341                 device->reset();
342         }
343         if(support_pc80s31k) {
344                 pio_fdd->write_signal(SIG_I8255_PORT_C, 0, 0xff);
345                 pio_pc80s31k->write_signal(SIG_I8255_PORT_C, 0, 0xff);
346         }
347 }
348
349 void VM::run()
350 {
351         event->drive();
352 }
353
354 // ----------------------------------------------------------------------------
355 // debugger
356 // ----------------------------------------------------------------------------
357
358 #ifdef USE_DEBUGGER
359 DEVICE *VM::get_cpu(int index)
360 {
361         if(index == 0) {
362                 return cpu;
363         } else if(index == 1) {
364                 return cpu_sub;
365         } else if(index == 2) {
366                 return cpu_pc80s31k;
367         }
368         return NULL;
369 }
370 #endif
371
372 // ----------------------------------------------------------------------------
373 // draw screen
374 // ----------------------------------------------------------------------------
375
376 void VM::draw_screen()
377 {
378 #ifdef _PC6001
379         display->draw_screen();
380 #else
381         memory->draw_screen();
382 #endif
383 }
384 // ----------------------------------------------------------------------------
385 // soud manager
386 // ----------------------------------------------------------------------------
387
388 void VM::initialize_sound(int rate, int samples)
389 {
390         // init sound manager
391         event->initialize_sound(rate, samples);
392         
393         // init sound gen
394         psg->initialize_sound(rate, 4000000, samples, 0, 0);
395 #ifndef _PC6001
396         voice->initialize_sound(rate);
397 #endif
398 }
399
400 uint16_t* VM::create_sound(int* extra_frames)
401 {
402         return event->create_sound(extra_frames);
403 }
404
405 int VM::get_sound_buffer_ptr()
406 {
407         return event->get_sound_buffer_ptr();
408 }
409
410 #ifdef USE_SOUND_VOLUME
411 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
412 {
413         if(ch-- == 0) {
414                 psg->set_volume(1, decibel_l, decibel_r);
415 #if !defined(_PC6001)
416         } else if(ch-- == 0) {
417                 voice->set_volume(0, decibel_l, decibel_r);
418 #endif
419         } else if(ch-- == 0) {
420                 if(support_sub_cpu) {
421                         drec->set_volume(0, decibel_l, decibel_r);
422                 }
423         }
424 #if defined(USE_SOUND_FILES)
425          else if(ch-- == 0) {
426                  if(support_pc80s31k) {
427                          if(fdc_pc80s31k != NULL) fdc_pc80s31k->set_volume(0, decibel_l, decibel_r);
428                  } else {
429                          if(pc6031 != NULL) pc6031->set_volume(0, decibel_l, decibel_r);
430                          if(floppy != NULL) floppy->set_volume(0, decibel_l, decibel_r);
431                  }
432         }
433 #endif
434 }
435 #endif
436
437 // ----------------------------------------------------------------------------
438 // notify key
439 // ----------------------------------------------------------------------------
440
441 void VM::key_down(int code, bool repeat)
442 {
443         if(!support_sub_cpu) {
444                 psub->key_down(code);
445         }
446 }
447
448 void VM::key_up(int code)
449 {
450         if(!support_sub_cpu) {
451                 psub->key_up(code);
452         }
453 }
454
455 // ----------------------------------------------------------------------------
456 // user interface
457 // ----------------------------------------------------------------------------
458
459 void VM::open_cart(int drv, const _TCHAR* file_path)
460 {
461         if(drv == 0) {
462                 memory->open_cart(file_path);
463                 reset();
464         }
465 }
466
467 void VM::close_cart(int drv)
468 {
469         if(drv == 0) {
470                 memory->close_cart();
471                 reset();
472         }
473 }
474
475 bool VM::is_cart_inserted(int drv)
476 {
477         if(drv == 0) {
478                 return memory->is_cart_inserted();
479         } else {
480                 return false;
481         }
482 }
483
484 uint32_t VM::get_access_lamp_status()
485 {
486         uint32_t status = 0; /// fdc->read_signal(0);
487 #if defined(_PC6601) || defined(_PC6601SR)
488         status = floppy->read_signal(0);
489 #endif
490         if(support_pc80s31k) {
491                 status |= fdc_pc80s31k->read_signal(0);
492         } else {
493                 status |= pc6031->read_signal(0);
494         }
495         return status;
496 }
497
498 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
499 {
500 #if defined(_PC6601) || defined(_PC6601SR)
501         if(drv < 2) {
502                 floppy->open_disk(drv, file_path, bank);
503                 return;
504         } else {
505                 drv -= 2;
506         }
507 #endif
508         if(support_pc80s31k) {
509                 fdc_pc80s31k->open_disk(drv, file_path, bank);
510         } else {
511                 pc6031->open_disk(drv, file_path, bank);
512         }
513 }
514
515 void VM::close_floppy_disk(int drv)
516 {
517 #if defined(_PC6601) || defined(_PC6601SR)
518         if(drv < 2) {
519                 floppy->close_disk(drv);
520                 return;
521         } else {
522                 drv -= 2;
523         }
524 #endif
525         if(support_pc80s31k) {
526                 fdc_pc80s31k->close_disk(drv);
527         } else {
528                 pc6031->close_disk(drv);
529         }
530 }
531
532 bool VM::is_floppy_disk_inserted(int drv)
533 {
534 #if defined(_PC6601) || defined(_PC6601SR)
535         if(drv < 2) {
536                 return floppy->is_disk_inserted(drv);
537         } else {
538                 drv -= 2;
539         }
540 #endif
541         if(support_pc80s31k) {
542                 return fdc_pc80s31k->is_disk_inserted(drv);
543         } else {
544                 return pc6031->is_disk_inserted(drv);
545         }
546 }
547
548 void VM::is_floppy_disk_protected(int drv, bool value)
549 {
550 #if defined(_PC6601) || defined(_PC6601SR)
551         if(drv < 2) {
552                 floppy->is_disk_protected(drv, value);
553                 return;
554         } else {
555                 drv -= 2;
556         }
557 #endif
558         if(support_pc80s31k) {
559                 fdc_pc80s31k->is_disk_protected(drv, value);
560         } else {
561                 pc6031->is_disk_protected(drv, value);
562         }
563 }
564
565 bool VM::is_floppy_disk_protected(int drv)
566 {
567 #if defined(_PC6601) || defined(_PC6601SR)
568         if(drv < 2) {
569                 return floppy->is_disk_protected(drv);
570         } else {
571                 drv -= 2;
572         }
573 #endif
574         if(support_pc80s31k) {
575                 return fdc_pc80s31k->is_disk_protected(drv);
576         } else {
577                 return pc6031->is_disk_protected(drv);
578         }
579 }
580
581 void VM::play_tape(const _TCHAR* file_path)
582 {
583         if(support_sub_cpu) {
584                 // support both p6/p6t and wav
585                 drec->play_tape(file_path);
586         } else {
587                 // support only p6/p6t
588                 psub->play_tape(file_path);
589         }
590 }
591
592 void VM::rec_tape(const _TCHAR* file_path)
593 {
594         if(support_sub_cpu) {
595                 // support both p6/p6t and wav
596                 sub->rec_tape(file_path);       // temporary
597 //              drec->rec_tape(file_path);
598         } else {
599                 // support both p6/p6t and wav
600                 psub->rec_tape(file_path);
601         }
602 }
603
604 void VM::close_tape()
605 {
606         if(support_sub_cpu) {
607                 if(sub->is_tape_inserted()) {
608                         sub->close_tape();      // temporary
609                 } else {
610                         drec->close_tape();
611                 }
612         } else {
613                 psub->close_tape();
614         }
615 }
616
617 bool VM::is_tape_inserted()
618 {
619         if(support_sub_cpu) {
620                 return drec->is_tape_inserted() || sub->is_tape_inserted();
621         } else {
622                 return psub->is_tape_inserted();
623         }
624 }
625
626 bool VM::is_tape_playing()
627 {
628         if(support_sub_cpu) {
629                 return drec->is_tape_playing();
630         } else {
631                 return false;
632         }
633 }
634
635 bool VM::is_tape_recording()
636 {
637         if(support_sub_cpu) {
638                 return drec->is_tape_recording();
639         } else {
640                 return false;
641         }
642 }
643
644 int VM::get_tape_position()
645 {
646         if(support_sub_cpu) {
647                 return drec->get_tape_position();
648         } else {
649                 return 0;
650         }
651 }
652
653 bool VM::is_frame_skippable()
654 {
655         return event->is_frame_skippable();
656 }
657
658 void VM::update_config()
659 {
660         for(DEVICE* device = first_device; device; device = device->next_device) {
661                 device->update_config();
662         }
663 }
664
665 #define STATE_VERSION   3
666
667 void VM::save_state(FILEIO* state_fio)
668 {
669         state_fio->FputUint32(STATE_VERSION);
670         
671         for(DEVICE* device = first_device; device; device = device->next_device) {
672                 device->save_state(state_fio);
673         }
674         state_fio->FputInt32(sr_mode);
675 }
676
677 bool VM::load_state(FILEIO* state_fio)
678 {
679         if(state_fio->FgetUint32() != STATE_VERSION) {
680                 return false;
681         }
682         for(DEVICE* device = first_device; device; device = device->next_device) {
683                 if(!device->load_state(state_fio)) {
684                         return false;
685                 }
686         }
687         sr_mode = state_fio->FgetInt32();
688         return true;
689 }
690