OSDN Git Service

[VM][General] Merge upstream 2016-02-13. Still don't implement OSD/Gui part of joysti...
[csp-qt/common_source_project-fm7.git] / source / src / vm / familybasic / familybasic.cpp
1 /*
2         Nintendo Family BASIC Emulator 'eFamilyBASIC'
3
4         Origin : nester
5         Author : Takeda.Toshiya
6         Date   : 2010.08.11-
7
8         [ virtual machine ]
9 */
10
11 #include "familybasic.h"
12 #include "../../emu.h"
13 #include "../device.h"
14 #include "../event.h"
15
16 #include "../datarec.h"
17 #include "../m6502.h"
18
19 #include "memory.h"
20 #include "apu.h"
21 #include "ppu.h"
22
23 // ----------------------------------------------------------------------------
24 // initialize
25 // ----------------------------------------------------------------------------
26
27 VM::VM(EMU* parent_emu) : emu(parent_emu)
28 {
29         // check configs
30 //      boot_mode = config.boot_mode;
31         boot_mode = -1;
32         
33         // create devices
34         first_device = last_device = NULL;
35         dummy = new DEVICE(this, emu);  // must be 1st device
36         event = new EVENT(this, emu);   // must be 2nd device
37         
38         drec = new DATAREC(this, emu);
39         cpu = new M6502(this, emu);
40         
41         memory = new MEMORY(this, emu);
42         apu = new APU(this, emu);
43         ppu = new PPU(this, emu);
44         
45         // set contexts
46         event->set_context_cpu(cpu);
47         event->set_context_sound(apu);
48         event->set_context_sound(drec);
49         
50         memory->set_context_cpu(cpu);
51         memory->set_context_apu(apu);
52         memory->set_context_ppu(ppu);
53         memory->set_context_drec(drec);
54         memory->set_spr_ram_ptr(ppu->get_spr_ram());
55         apu->set_context_cpu(cpu);
56         apu->set_context_memory(memory);
57         ppu->set_context_cpu(cpu);
58         
59         // cpu bus
60         cpu->set_context_mem(memory);
61         cpu->set_context_intr(dummy);
62         
63         // initialize all devices
64         for(DEVICE* device = first_device; device; device = device->next_device) {
65                 device->initialize();
66         }
67 }
68
69 VM::~VM()
70 {
71         // delete all devices
72         for(DEVICE* device = first_device; device;) {
73                 DEVICE *next_device = device->next_device;
74                 device->release();
75                 delete device;
76                 device = next_device;
77         }
78 }
79
80 DEVICE* VM::get_device(int id)
81 {
82         for(DEVICE* device = first_device; device; device = device->next_device) {
83                 if(device->this_device_id == id) {
84                         return device;
85                 }
86         }
87         return NULL;
88 }
89
90 // ----------------------------------------------------------------------------
91 // drive virtual machine
92 // ----------------------------------------------------------------------------
93
94 void VM::reset()
95 {
96         // load basic rom
97         if(boot_mode != config.boot_mode) {
98                 if(boot_mode != -1) {
99                         memory->save_backup();
100                 }
101                 if(config.boot_mode == 0) {
102                         memory->load_rom_image(_T("BASIC_V2.NES"));
103                         ppu->load_rom_image(_T("BASIC_V2.NES"));
104                 } else if(config.boot_mode == 1) {
105                         memory->load_rom_image(_T("BASIC_V3.NES"));
106                         ppu->load_rom_image(_T("BASIC_V3.NES"));
107                 } else {
108                         memory->load_rom_image(_T("PLAYBOX_BASIC.NES"));
109                         ppu->load_rom_image(_T("PLAYBOX_BASIC.NES"));
110                 }
111                 boot_mode = config.boot_mode;
112         }
113         
114         // reset all devices
115         for(DEVICE* device = first_device; device; device = device->next_device) {
116                 device->reset();
117         }
118 }
119
120 void VM::run()
121 {
122         event->drive();
123 }
124
125 // ----------------------------------------------------------------------------
126 // draw screen
127 // ----------------------------------------------------------------------------
128
129 void VM::draw_screen()
130 {
131         ppu->draw_screen();
132 }
133
134 // ----------------------------------------------------------------------------
135 // soud manager
136 // ----------------------------------------------------------------------------
137
138 void VM::initialize_sound(int rate, int samples)
139 {
140         // init sound manager
141         event->initialize_sound(rate, samples);
142         
143         // init sound gen
144         apu->initialize_sound(rate, samples);
145 }
146
147 uint16* VM::create_sound(int* extra_frames)
148 {
149         return event->create_sound(extra_frames);
150 }
151
152 int VM::sound_buffer_ptr()
153 {
154         return event->sound_buffer_ptr();
155 }
156
157 #ifdef USE_SOUND_VOLUME
158 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
159 {
160         if(ch == 0) {
161                 apu->set_volume(0, decibel_l, decibel_r);
162         } else if(ch == 1) {
163                 drec->set_volume(0, decibel_l, decibel_r);
164         }
165 }
166 #endif
167
168 // ----------------------------------------------------------------------------
169 // user interface
170 // ----------------------------------------------------------------------------
171
172 void VM::play_tape(const _TCHAR* file_path)
173 {
174         drec->play_tape(file_path);
175         drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);
176 }
177
178 void VM::rec_tape(const _TCHAR* file_path)
179 {
180         drec->rec_tape(file_path);
181         drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);
182 }
183
184 void VM::close_tape()
185 {
186         drec->close_tape();
187         drec->write_signal(SIG_DATAREC_REMOTE, 0, 1);
188 }
189
190 bool VM::tape_inserted()
191 {
192         return drec->tape_inserted();
193 }
194
195 bool VM::tape_playing()
196 {
197         return drec->tape_playing();
198 }
199
200 bool VM::tape_recording()
201 {
202         return drec->tape_recording();
203 }
204
205 int VM::tape_position()
206 {
207         return drec->tape_position();
208 }
209
210 bool VM::now_skip()
211 {
212         return event->now_skip();
213 }
214
215 void VM::update_config()
216 {
217         if(boot_mode != config.boot_mode) {
218                 // boot mode is changed !!!
219 //              boot_mode = config.boot_mode;
220                 reset();
221         } else {
222                 for(DEVICE* device = first_device; device; device = device->next_device) {
223                         device->update_config();
224                 }
225         }
226 }
227
228 #define STATE_VERSION   1
229
230 void VM::save_state(FILEIO* state_fio)
231 {
232         state_fio->FputUint32(STATE_VERSION);
233         
234         for(DEVICE* device = first_device; device; device = device->next_device) {
235                 device->save_state(state_fio);
236         }
237         state_fio->FputInt32(boot_mode);
238 }
239
240 bool VM::load_state(FILEIO* state_fio)
241 {
242         if(state_fio->FgetUint32() != STATE_VERSION) {
243                 return false;
244         }
245         for(DEVICE* device = first_device; device; device = device->next_device) {
246                 if(!device->load_state(state_fio)) {
247                         return false;
248                 }
249         }
250         boot_mode = state_fio->FgetInt32();
251         return true;
252 }
253