OSDN Git Service

[VM][FMTOWNS][MEMORY] Fix setup around memory banks by I/O 0404h and 0480h.
[csp-qt/common_source_project-fm7.git] / source / src / vm / hc20 / hc20.cpp
1 /*
2         EPSON HC-20 Emulator 'eHC-20'
3
4         Author : Takeda.Toshiya
5         Date   : 2011.05.23-
6
7         [ virtual machine ]
8 */
9
10 #include "hc20.h"
11 #include "../../emu.h"
12 #include "../device.h"
13 #include "../event.h"
14
15 #include "../beep.h"
16 #include "../disk.h"
17 #include "../hd146818p.h"
18 #include "../i8255.h"
19 //#include "../mc6800.h"
20 #include "../hd6301.h"
21 #include "../noise.h"
22 #include "../tf20.h"
23 #include "../upd765a.h"
24 #include "../z80.h"
25 #include "../z80sio.h"
26
27 #ifdef USE_DEBUGGER
28 #include "../debugger.h"
29 #endif
30
31 #include "memory.h"
32
33 using HC20::MEMORY;
34
35 // ----------------------------------------------------------------------------
36 // initialize
37 // ----------------------------------------------------------------------------
38
39 VM::VM(EMU_TEMPLATE* parent_emu) : VM_TEMPLATE(parent_emu)
40 {
41         // create devices
42         first_device = last_device = NULL;
43         dummy = new DEVICE(this, emu);  // must be 1st device
44         event = new EVENT(this, emu);   // must be 2nd device
45         dummy->set_device_name(_T("1st Dummy"));
46         
47         beep = new BEEP(this, emu);
48         rtc = new HD146818P(this, emu);
49         //cpu = new MC6800(this, emu);
50         cpu = new HD6301(this, emu);
51         tf20 = new TF20(this, emu);
52         pio_tf20 = new I8255(this, emu);
53         fdc_tf20 = new UPD765A(this, emu);
54         fdc_tf20->set_context_noise_seek(new NOISE(this, emu));
55         fdc_tf20->set_context_noise_head_down(new NOISE(this, emu));
56         fdc_tf20->set_context_noise_head_up(new NOISE(this, emu));
57         cpu_tf20 = new Z80(this, emu);
58         sio_tf20 = new Z80SIO(this, emu);
59         pio_tf20->set_device_name(_T("TF20 PIO(i8255)"));
60         cpu_tf20->set_device_name(_T("TF20 CPU(Z80)"));
61         sio_tf20->set_device_name(_T("TF20 SIO(Z80 SIO)"));
62         fdc_tf20->set_device_name(_T("TF20 FDC(uPD765A)"));
63         memory = new MEMORY(this, emu);
64         // set contexts
65         event->set_context_cpu(cpu);
66         event->set_context_cpu(cpu_tf20, 4000000);
67         event->set_context_sound(beep);
68         event->set_context_sound(fdc_tf20->get_context_noise_seek());
69         event->set_context_sound(fdc_tf20->get_context_noise_head_down());
70         event->set_context_sound(fdc_tf20->get_context_noise_head_up());
71         
72 /*
73         memory:
74                 0002    in      ---     port1 (cpu)
75                 0003    in/out  ---     port2 (cpu)
76                 0006            ---     port3 (cpu)
77                 0007            ---     port4 (cpu)
78                 0020    out     bit0-7  key scan line
79                 0022    in      bit0-7  key scan result (lo)
80                 0026    out     bit0-2  selection of lcd driver (0,1-6)
81                                 bit3    output selection for lcd driver (0=data 1=command)
82                                 bit4    key input interrupt mask (0=Mask)
83                                 bit5    pout (serial control line)
84                                 bit6    shift/load select for rom cartridge (0=load 1=shift)
85                                 bit7    clock for rom cartridge
86                 0028    in      bit0-1  key scan result (hi)
87                                 bit6    power switch interrupt flag (0=active)
88                                 bit7    busy signal of lcd controller (0=busy)
89                 002a    out     bit0-7  output data to lcd controller
90                         in      ---     serial clock to lcd controller
91                 002b    in      ---     serial clock to lcd controller
92                 002c    in/out  ---     used for interrupt mask setting in sleep mode
93                 0030    in/out  ---     select expansion unit rom (bank1)
94                 0032    in/out  ---     select internal rom (bank0)
95                 0033    in/out  ---     select internal rom (bank0)
96                 003c    in      ---     XXX: unknown
97
98         port1:
99                 p10     in      dsr (RS-232C)
100                 p11     in      cts (RS-232C)
101                 p12     in      error status of slave mcu (P34)
102                 p13     in      external interrupt flag(0=active)
103                 p14     in      battery voltage interrupt flag (0=active)
104                 p15     in      key input inerrupt flag (0=active)
105                 p16     in      pin (serial control line)
106                 p17     in      counter status of microcassete / rom data / plug-in option
107
108         port 2:
109                 p20     in      barcode input signal (1=mark 0=space)
110                 p21     out     txd (RS-232C)
111                 p22     out     selection for CPU serial communication (0=slave 1=serial)
112 */      
113         cpu->set_context_port2(memory, SIG_MEMORY_PORT_2, 0xff, 0);
114         cpu->set_context_port3(memory, SIG_MEMORY_PORT_3, 0xff, 0);
115         cpu->set_context_port4(memory, SIG_MEMORY_PORT_4, 0xff, 0);
116         cpu->set_context_sio(memory, SIG_MEMORY_SIO_MAIN);
117         rtc->set_context_intr_line(memory, SIG_MEMORY_RTC_IRQ, 1);
118         
119         memory->set_context_beep(beep);
120         memory->set_context_cpu(cpu);
121         memory->set_context_rtc(rtc);
122         memory->set_context_sio_tf20(sio_tf20);
123         
124         // cpu bus
125         cpu->set_context_mem(memory);
126 #ifdef USE_DEBUGGER
127         cpu->set_context_debugger(new DEBUGGER(this, emu));
128 #endif
129         
130         // tf-20
131         tf20->set_context_cpu(cpu_tf20);
132         tf20->set_context_fdc(fdc_tf20);
133         tf20->set_context_pio(pio_tf20);
134         tf20->set_context_sio(sio_tf20);
135         cpu_tf20->set_context_mem(tf20);
136         cpu_tf20->set_context_io(tf20);
137         cpu_tf20->set_context_intr(tf20);
138 #ifdef USE_DEBUGGER
139         cpu_tf20->set_context_debugger(new DEBUGGER(this, emu));
140 //      beep->set_context_debugger(new DEBUGGER(this, emu));
141 //      fdc_tf20->set_context_debugger(new DEBUGGER(this, emu));
142 #endif
143         
144         fdc_tf20->set_context_irq(cpu_tf20, SIG_CPU_IRQ, 1);
145         sio_tf20->set_context_send(0, memory, SIG_MEMORY_SIO_TF20);
146         sio_tf20->set_tx_clock(0, 4915200 / 8); // 4.9152MHz / 8 (38.4kbps)
147         sio_tf20->set_rx_clock(0, 4915200 / 8); // baud-rate can be changed by jumper pin
148         sio_tf20->set_tx_clock(1, 4915200 / 8);
149         sio_tf20->set_rx_clock(1, 4915200 / 8);
150         
151         // initialize all devices
152 #if defined(__GIT_REPO_VERSION)
153         set_git_repo_version(__GIT_REPO_VERSION);
154 #endif
155         initialize_devices();
156         
157         for(int i = 0; i < MAX_DRIVE; i++) {
158                 fdc_tf20->set_drive_type(i, DRIVE_TYPE_2D);
159         }
160 }
161
162 VM::~VM()
163 {
164         // delete all devices
165         for(DEVICE* device = first_device; device;) {
166                 DEVICE *next_device = device->next_device;
167                 device->release();
168                 delete device;
169                 device = next_device;
170         }
171 }
172
173
174 // ----------------------------------------------------------------------------
175 // drive virtual machine
176 // ----------------------------------------------------------------------------
177
178 void VM::reset()
179 {
180         // reset all devices
181         VM_TEMPLATE::reset();
182         cpu->write_signal(SIG_MC6801_PORT_1, 0x78, 0xff);
183         cpu->write_signal(SIG_MC6801_PORT_2, 0x9e, 0xff);
184 }
185
186 void VM::notify_power_off()
187 {
188 //      this->out_debug_log(T("--- POWER OFF ---\n"));
189         memory->notify_power_off();
190 }
191
192 void VM::run()
193 {
194         event->drive();
195 }
196
197 // ----------------------------------------------------------------------------
198 // debugger
199 // ----------------------------------------------------------------------------
200
201 #ifdef USE_DEBUGGER
202 DEVICE *VM::get_cpu(int index)
203 {
204         if(index == 0) {
205                 return cpu;
206         } else if(index == 1) {
207                 return cpu_tf20;
208         }
209         return NULL;
210 }
211 #endif
212
213 // ----------------------------------------------------------------------------
214 // draw screen
215 // ----------------------------------------------------------------------------
216
217 void VM::draw_screen()
218 {
219         memory->draw_screen();
220 }
221
222 // ----------------------------------------------------------------------------
223 // soud manager
224 // ----------------------------------------------------------------------------
225
226 void VM::initialize_sound(int rate, int samples)
227 {
228         // init sound manager
229         event->initialize_sound(rate, samples);
230         
231         // init sound gen
232         beep->initialize_sound(rate, 1000, 8000);
233 }
234
235 uint16_t* VM::create_sound(int* extra_frames)
236 {
237         return event->create_sound(extra_frames);
238 }
239
240 int VM::get_sound_buffer_ptr()
241 {
242         return event->get_sound_buffer_ptr();
243 }
244
245 #ifdef USE_SOUND_VOLUME
246 void VM::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
247 {
248         if(ch == 0) {
249                 beep->set_volume(0, decibel_l, decibel_r);
250         } else if(ch == 1) {
251                 fdc_tf20->get_context_noise_seek()->set_volume(0, decibel_l, decibel_r);
252                 fdc_tf20->get_context_noise_head_down()->set_volume(0, decibel_l, decibel_r);
253                 fdc_tf20->get_context_noise_head_up()->set_volume(0, decibel_l, decibel_r);
254         }
255 }
256 #endif
257
258 // ----------------------------------------------------------------------------
259 // notify key
260 // ----------------------------------------------------------------------------
261
262 void VM::key_down(int code, bool repeat)
263 {
264         memory->key_down(code);
265 }
266
267 void VM::key_up(int code)
268 {
269         memory->key_up(code);
270 }
271
272 // ----------------------------------------------------------------------------
273 // user interface
274 // ----------------------------------------------------------------------------
275
276 void VM::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
277 {
278         fdc_tf20->open_disk(drv, file_path, bank);
279 }
280
281 void VM::close_floppy_disk(int drv)
282 {
283         fdc_tf20->close_disk(drv);
284 }
285
286 bool VM::is_floppy_disk_inserted(int drv)
287 {
288         return fdc_tf20->is_disk_inserted(drv);
289 }
290
291 void VM::is_floppy_disk_protected(int drv, bool value)
292 {
293         fdc_tf20->is_disk_protected(drv, value);
294 }
295
296 bool VM::is_floppy_disk_protected(int drv)
297 {
298         return fdc_tf20->is_disk_protected(drv);
299 }
300
301 uint32_t VM::is_floppy_disk_accessed()
302 {
303         return fdc_tf20->read_signal(0);
304 }
305
306 void VM::play_tape(int drv, const _TCHAR* file_path)
307 {
308         memory->play_tape(file_path);
309 }
310
311 void VM::rec_tape(int drv, const _TCHAR* file_path)
312 {
313         memory->rec_tape(file_path);
314 }
315
316 void VM::close_tape(int drv)
317 {
318         memory->close_tape();
319 }
320
321 bool VM::is_tape_inserted(int drv)
322 {
323         return memory->is_tape_inserted();
324 }
325
326 bool VM::is_frame_skippable()
327 {
328         return event->is_frame_skippable();
329 }
330
331
332 double VM::get_current_usec()
333 {
334         __UNLIKELY_IF(event == NULL) return 0.0;
335         return event->get_current_usec();
336 }
337
338 uint64_t VM::get_current_clock_uint64()
339 {
340         __UNLIKELY_IF(event == NULL) return (uint64_t)0;
341         return event->get_current_clock_uint64();
342 }
343
344 #define STATE_VERSION   3
345
346 bool VM::process_state(FILEIO* state_fio, bool loading)
347 {
348         if(!(VM_TEMPLATE::process_state_core(state_fio, loading, STATE_VERSION))) {
349                 return false;
350         }
351         return true;
352 }