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 / msx / memory.cpp
1 /*
2         ASCII MSX1 Emulator 'yaMSX1'
3         ASCII MSX2 Emulator 'yaMSX2'
4         Pioneer PX-7 Emulator 'ePX-7'
5
6         Author : Takeda.Toshiya
7         Date   : 2014.01.09-
8
9         modified by tanam
10         modified by umaiboux
11
12         [ memory ]
13 */
14
15 #include "memory.h"
16 #if defined(_PX7)
17 #include "../ld700.h"
18 #include "../tms9918a.h"
19 #else
20 #include "../disk.h"
21 #endif
22
23 #define EVENT_CLOCK     0
24
25 namespace MSX {
26
27 #define SET_BANK(s, e, w, r) { \
28         int sb = (s) >> 13, eb = (e) >> 13; \
29         for(int i = sb; i <= eb; i++) { \
30                 if(((uintptr_t)w) == (uintptr_t)wdmy) { \
31                         wbank[i] = wdmy; \
32                 } else { \
33                         wbank[i] = (w) + 0x2000 * (i - sb); \
34                 } \
35                 if(((uintptr_t)r) == (uintptr_t)rdmy) { \
36                         rbank[i] = rdmy; \
37                 } else { \
38                         rbank[i] = (r) + 0x2000 * (i - sb); \
39                 } \
40         } \
41 }
42
43 #if !defined(_PX7)
44 static const struct {
45         int sectors;
46         uint8_t heads, names, per_track, per_fat, per_cluster;
47 } info[8] = {
48         { 720,  1, 112, 9, 2, 2 },
49         { 1440, 2, 112, 9, 3, 2 },
50         { 640,  1, 112, 8, 1, 2 },
51         { 1280, 2, 112, 8, 2, 2 },
52         { 360,  1, 64,  9, 2, 1 },
53         { 720,  2, 112, 9, 2, 2 },
54         { 320,  1, 64,  8, 1, 1 },
55         { 640,  2, 112, 8, 1, 2 }
56 };
57
58 static const uint8_t boot_block[] = {
59         0xeb, 0xfe, 0x90, 0x56, 0x46, 0x42, 0x2d, 0x31, 0x39, 0x38, 0x39, 0x00, 0x02, 0x02, 0x01, 0x00,
60         0x02, 0x70, 0x00, 0xa0, 0x05, 0xf9, 0x03, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0xd0, 0xed,
61         0x53, 0x58, 0xc0, 0x32, 0xc2, 0xc0, 0x36, 0x55, 0x23, 0x36, 0xc0, 0x31, 0x1f, 0xf5, 0x11, 0x9d,
62         0xc0, 0x0e, 0x0f, 0xcd, 0x7d, 0xf3, 0x3c, 0x28, 0x28, 0x11, 0x00, 0x01, 0x0e, 0x1a, 0xcd, 0x7d,
63         0xf3, 0x21, 0x01, 0x00, 0x22, 0xab, 0xc0, 0x21, 0x00, 0x3f, 0x11, 0x9d, 0xc0, 0x0e, 0x27, 0xcd,
64         0x7d, 0xf3, 0xc3, 0x00, 0x01, 0x57, 0xc0, 0xcd, 0x00, 0x00, 0x79, 0xe6, 0xfe, 0xfe, 0x02, 0x20,
65         0x07, 0x3a, 0xc2, 0xc0, 0xa7, 0xca, 0x22, 0x40, 0x11, 0x77, 0xc0, 0x0e, 0x09, 0xcd, 0x7d, 0xf3,
66         0x0e, 0x07, 0xcd, 0x7d, 0xf3, 0x18, 0xb4, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x65, 0x72, 0x72, 0x6f,
67         0x72, 0x0d, 0x0a, 0x50, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x6b, 0x65, 0x79,
68         0x20, 0x66, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x74, 0x72, 0x79, 0x0d, 0x0a, 0x24, 0x00, 0x4d, 0x53,
69         0x58, 0x44, 0x4f, 0x53, 0x20, 0x20, 0x53, 0x59, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x2a,
72         0x51, 0xf3, 0x11, 0x00, 0x01, 0x19, 0x01, 0x00, 0x01, 0x11, 0x00, 0xc1, 0xed, 0xb0, 0x3a, 0xee,
73         0xc0, 0x47, 0x11, 0xef, 0xc0, 0x21, 0x00, 0x00, 0xcd, 0x51, 0x52, 0xf3, 0x76, 0xc9, 0x18, 0x64,
74         0x3a, 0xaf, 0x80, 0xf9, 0xca, 0x6d, 0x48, 0xd3, 0xa5, 0x0c, 0x8c, 0x2f, 0x9c, 0xcb, 0xe9, 0x89,
75         0xd2, 0x00, 0x32, 0x26, 0x40, 0x94, 0x61, 0x19, 0x20, 0xe6, 0x80, 0x6d, 0x8a, 0x00, 0x00, 0x00,
76         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
91 };
92
93 static int DSKIO = -1, DSKCHG = -1, GETDPB = -1, DSKFMT = -1;
94 #endif
95
96 static bool load_cart(const _TCHAR *file_path, uint8_t *rom)
97 {
98         bool result = false;
99         FILEIO* fio = new FILEIO();
100         if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
101                 memset(rom, 0xff, 0x10000);
102                 
103                 fio->Fseek(0, FILEIO_SEEK_END);
104                 int file_size = fio->Ftell();
105                 fio->Fseek(0, FILEIO_SEEK_SET);
106                 
107                 if(file_size <= 0x2000) {
108                         // 8KB: 00000000
109                         fio->Fread(rom, 0x2000, 1);
110                         memcpy(rom + 0x2000, rom, 0x2000);
111                         memcpy(rom + 0x4000, rom, 0x4000);
112                         memcpy(rom + 0x8000, rom, 0x8000);
113                 } else if(file_size <= 0x4000) {
114                         // 16KB: 01010101
115                         fio->Fread(rom, 0x4000, 1);
116                         memcpy(rom + 0x4000, rom, 0x4000);
117                         memcpy(rom + 0x8000, rom, 0x8000);
118                 } else if(file_size <= 0x8000) {
119                         // 32KB: 01012323
120                         fio->Fread(rom + 0x4000, 0x8000, 1);
121                         memcpy(rom + 0x0000, rom + 0x4000, 0x4000);
122                         memcpy(rom + 0xc000, rom + 0x8000, 0x4000);
123                 } else {
124                         // 64KB: 01234567
125                         fio->Fread(rom, 0x10000, 1);
126                 }
127                 fio->Fclose();
128                 result = true;
129         }
130         delete fio;
131         return result;
132 }
133
134 // slot #0
135
136 void SLOT0::initialize()
137 {
138         memset(rom, 0xff, sizeof(rom));
139 #if defined(_PX7)
140         memset(ram, 0, sizeof(ram));
141 #endif
142         FILEIO* fio = new FILEIO();
143 #if defined(_MSX2)
144         if(fio->Fopen(create_local_path(_T("MSX2J.ROM")), FILEIO_READ_BINARY) ||
145            fio->Fopen(create_local_path(_T("MSX2.ROM" )), FILEIO_READ_BINARY) ||
146 #else
147         if(fio->Fopen(create_local_path(_T("MSXJ.ROM")), FILEIO_READ_BINARY) ||
148            fio->Fopen(create_local_path(_T("MSX.ROM" )), FILEIO_READ_BINARY) ||
149 #endif
150            fio->Fopen(create_local_path(_T("BASIC.ROM")), FILEIO_READ_BINARY)) {
151                 fio->Fread(rom, sizeof(rom), 1);
152                 fio->Fclose();
153         }
154         delete fio;
155         
156         SET_BANK(0x0000, 0x7fff, wdmy, rom);
157 #if defined(_PX7)
158         SET_BANK(0x8000, 0xffff, ram, ram);
159 #else
160         SET_BANK(0x8000, 0xffff, wdmy, rdmy);
161 #endif
162 }
163
164 void SLOT0::write_data8(uint32_t addr, uint32_t data)
165 {
166         wbank[addr >> 13][addr & 0x1fff] = data;
167 }
168
169 uint32_t SLOT0::read_data8(uint32_t addr)
170 {
171         return rbank[addr >> 13][addr & 0x1fff];
172 }
173
174 #define SLOT0_STATE_VERSION     1
175
176 bool SLOT0::process_state(FILEIO* state_fio, bool loading)
177 {
178         if(!state_fio->StateCheckUint32(SLOT0_STATE_VERSION)) {
179                 return false;
180         }
181         if(!state_fio->StateCheckInt32(this_device_id)) {
182                 return false;
183         }
184 #if defined(_PX7)
185         state_fio->StateArray(ram, sizeof(ram), 1);
186 #endif
187         return true;
188 }
189
190 // slot #1
191
192 void SLOT1::initialize()
193 {
194         memset(rdmy, 0xff, sizeof(rdmy));
195         close_cart();
196 }
197
198 void SLOT1::write_data8(uint32_t addr, uint32_t data)
199 {
200 #if defined(_MSX2)
201         if(addr >= 0x4000 && addr < 0xc000 && mapper[0] < 4) {
202                 addr >>= 15;
203                 addr &= 1;
204                 data &= 3;
205                 if(mapper[addr] != data) {
206                         mapper[addr] = data;
207                         SET_BANK(addr * 0x4000 + 0x4000, addr * 0x4000 + 0x7fff, wdmy, rom + data * 0x4000);
208                 }
209                 return;
210         }
211 #endif
212         wbank[addr >> 13][addr & 0x1fff] = data;
213 }
214
215 uint32_t SLOT1::read_data8(uint32_t addr)
216 {
217         return rbank[addr >> 13][addr & 0x1fff];
218 }
219
220 void SLOT1::open_cart(const _TCHAR *file_path)
221 {
222         if(load_cart(file_path, rom)) {
223                 SET_BANK(0x0000, 0xffff, wdmy, rom);
224                 inserted = true;
225 #if defined(_MSX2)
226                 mapper[0] = mapper[1] = 4;
227 #endif
228         }
229 }
230
231 void SLOT1::close_cart()
232 {
233         SET_BANK(0x0000, 0xffff, wdmy, rdmy);
234         inserted = false;
235 #if defined(_MSX2)
236         mapper[0] = mapper[1] = 4;
237         FILEIO* fio = new FILEIO();
238         if(fio->Fopen(create_local_path(_T("MSXDOS2.ROM")), FILEIO_READ_BINARY)) {
239                 fio->Fread(rom, sizeof(rom), 1);
240                 fio->Fclose();
241                 mapper[0] = 0;
242                 mapper[1] = 3;
243                 SET_BANK(0x4000, 0x7fff, wdmy, rom + mapper[0] * 0x4000);
244                 SET_BANK(0x8000, 0xbfff, wdmy, rom + mapper[1] * 0x4000);
245         }
246         delete fio;
247 #endif
248 }
249
250 #define SLOT1_STATE_VERSION     1
251
252 bool SLOT1::process_state(FILEIO* state_fio, bool loading)
253 {
254         if(!state_fio->StateCheckUint32(SLOT1_STATE_VERSION)) {
255                 return false;
256         }
257         if(!state_fio->StateCheckInt32(this_device_id)) {
258                 return false;
259         }
260         state_fio->StateValue(inserted);
261 #if defined(_MSX2)
262         state_fio->StateArray(mapper, sizeof(mapper), 1);
263 #endif
264         
265         // post process
266         if(loading) {
267                 if(inserted) {
268                         SET_BANK(0x0000, 0xffff, wdmy, rom);
269 #if defined(_MSX2)
270                 } else if(mapper[0] < 4) {
271                                 SET_BANK(0x0000, 0x3fff, wdmy, rdmy);
272                                 SET_BANK(0x4000, 0x7fff, wdmy, rom + mapper[0] * 0x4000);
273                                 SET_BANK(0x8000, 0xbfff, wdmy, rom + mapper[1] * 0x4000);
274                                 SET_BANK(0xc000, 0xffff, wdmy, rdmy);
275 #endif
276                 } else {
277                         SET_BANK(0x0000, 0xffff, wdmy, rdmy);
278                 }
279         }
280         return true;
281 }
282
283 // slot #2
284
285 #if defined(_PX7)
286 void SLOT2::initialize()
287 {
288         memset(rom, 0xff, sizeof(rom));
289         memset(rdmy, 0xff, sizeof(rdmy));
290         
291         FILEIO* fio = new FILEIO();
292         if(fio->Fopen(create_local_path(_T("PX7EXT.ROM")), FILEIO_READ_BINARY) ||
293            fio->Fopen(create_local_path(_T("EXT.ROM")   ), FILEIO_READ_BINARY)) {
294                 fio->Fread(rom, sizeof(rom), 1);
295                 fio->Fclose();
296         }
297         delete fio;
298         
299         SET_BANK(0x0000, 0x3fff, wdmy, rdmy);
300         SET_BANK(0x4000, 0x5fff, wdmy, rom);
301         SET_BANK(0x6000, 0xffff, wdmy, rdmy);
302         
303         clock = exv = ack = false;
304         
305         register_event(this, EVENT_CLOCK, 1000000.0 / 7812.5, true, NULL);
306 }
307
308 void SLOT2::reset()
309 {
310         super_impose = false;
311         req_intr = false;
312         pc4 = false;
313         mute_l = mute_r = true;
314         
315         d_ldp->write_signal(SIG_LD700_MUTE_L, 1, 1);
316         d_ldp->write_signal(SIG_LD700_MUTE_R, 1, 1);
317         d_vdp->write_signal(SIG_TMS9918A_SUPER_IMPOSE, 0, 0);
318 }
319
320 void SLOT2::write_data8(uint32_t addr, uint32_t data)
321 {
322         if(addr == 0x7ffe) {
323                 d_ldp->write_signal(SIG_LD700_REMOTE, data, 1);
324         } else if(addr == 0x7fff) {
325                 // super impose
326                 bool prev_super_impose = super_impose;
327                 super_impose = ((data & 1) == 0);
328                 if(super_impose) {
329                         if(req_intr && !prev_super_impose) {
330                                 d_cpu->write_signal(SIG_CPU_IRQ, 1, 1);
331                         }
332                 } else {
333                         d_cpu->write_signal(SIG_CPU_IRQ, 0, 0);
334                 }
335                 d_vdp->write_signal(SIG_TMS9918A_SUPER_IMPOSE, super_impose ? 1 : 0, 1);
336                 
337                 // mute
338                 bool prev_mute_l = mute_l;
339                 mute_l = ((data & 0x80) == 0);
340                 if(!prev_mute_l && mute_l) {
341                         mute_r = !pc4;
342                 }
343                 d_ldp->write_signal(SIG_LD700_MUTE_L, mute_l ? 1 : 0, 1);
344                 d_ldp->write_signal(SIG_LD700_MUTE_R, mute_r ? 1 : 0, 1);
345         } else {
346                 wbank[addr >> 13][addr & 0x1fff] = data;
347         }
348 }
349
350 uint32_t SLOT2::read_data8(uint32_t addr)
351 {
352         if(addr == 0x7ffe) {
353                 return (clock ? 0 : 1) | (ack ? 0 : 0x80) | 0x7e;
354         } else if(addr == 0x7fff) {
355                 uint32_t data = (req_intr ? 1 : 0) | (exv ? 0 : 0x80) | 0x7e;
356                 req_intr = false;
357                 d_cpu->write_signal(SIG_CPU_IRQ, 0, 0);
358                 return data;
359         } else {
360                 return rbank[addr >> 13][addr & 0x1fff];
361         }
362 }
363
364 void SLOT2::write_signal(int id, uint32_t data, uint32_t mask)
365 {
366         if(id == SIG_SLOT2_EXV) {
367                 bool prev = exv;
368                 exv = ((data & mask) != 0);
369                 if(prev && !exv) {
370                         req_intr = true;
371                         if(super_impose) {
372                                 d_cpu->write_signal(SIG_CPU_IRQ, 1, 1);
373                         }
374                 }
375         } else if(id == SIG_SLOT2_ACK) {
376                 ack = ((data & mask) != 0);
377         } else if(id == SIG_SLOT2_MUTE) {
378                 pc4 = ((data & mask) != 0);
379         }
380 }
381
382 void SLOT2::event_callback(int event_id, int err)
383 {
384         if(event_id == EVENT_CLOCK) {
385                 clock = !clock;
386         }
387 }
388
389 #define SLOT2_STATE_VERSION     1
390
391 bool SLOT2::process_state(FILEIO* state_fio, bool loading)
392 {
393         if(!state_fio->StateCheckUint32(SLOT2_STATE_VERSION)) {
394                 return false;
395         }
396         if(!state_fio->StateCheckInt32(this_device_id)) {
397                 return false;
398         }
399         state_fio->StateValue(clock);
400         state_fio->StateValue(exv);
401         state_fio->StateValue(ack);
402         state_fio->StateValue(super_impose);
403         state_fio->StateValue(req_intr);
404         state_fio->StateValue(pc4);
405         state_fio->StateValue(mute_l);
406         state_fio->StateValue(mute_r);
407         return true;
408 }
409 #else
410 void SLOT2::initialize()
411 {
412         memset(rom, 0xff, sizeof(rom));
413         memset(rdmy, 0xff, sizeof(rdmy));
414         
415         FILEIO* fio = new FILEIO();
416 #if defined(_MSX2)
417         if(fio->Fopen(create_local_path(_T("MSX2JEXT.ROM")), FILEIO_READ_BINARY) ||
418            fio->Fopen(create_local_path(_T("MSX2EXT.ROM" )), FILEIO_READ_BINARY)) {
419                 fio->Fread(rom, sizeof(rom), 1);
420                 fio->Fclose();
421         }
422 #endif
423         if(fio->Fopen(create_local_path(_T("DISK.ROM")), FILEIO_READ_BINARY)) {
424                 fio->Fread(rom + 0x4000, sizeof(rom) - 0x4000, 1);
425                 fio->Fclose();
426         }
427         delete fio;
428         
429         // patch for pseudo disk bios
430         if(rom[0x4010] == 0xc3) {
431                 rom[DSKIO  = rom[0x4011] + (int)rom[0x4012] * 256] = 0xc9;
432         }
433         if(rom[0x4013] == 0xc3) {
434                 rom[DSKCHG = rom[0x4014] + (int)rom[0x4015] * 256] = 0xc9;
435         }
436         if(rom[0x4016] == 0xc3) {
437                 rom[GETDPB = rom[0x4017] + (int)rom[0x4018] * 256] = 0xc9;
438         }
439         if(rom[0x401c] == 0xc3) {
440                 rom[DSKFMT = rom[0x401d] + (int)rom[0x401e] * 256] = 0xc9;
441         }
442         if(rom[0x401f] == 0xc3) {
443                 rom[            rom[0x4020] + (int)rom[0x4021] * 256] = 0xc9;
444         }
445         SET_BANK(0x0000, 0x7fff, wdmy, rom);
446         SET_BANK(0x8000, 0xffff, wdmy, rdmy);
447 }
448
449 void SLOT2::write_data8(uint32_t addr, uint32_t data)
450 {
451         wbank[addr >> 13][addr & 0x1fff] = data;
452 }
453
454 uint32_t SLOT2::read_data8(uint32_t addr)
455 {
456         return rbank[addr >> 13][addr & 0x1fff];
457 }
458 #endif
459
460 // slot #3
461
462 void SLOT3::initialize()
463 {
464         memset(ram, 0xff, sizeof(ram));
465         close_cart();
466 }
467
468 void SLOT3::write_data8(uint32_t addr, uint32_t data)
469 {
470         wbank[addr >> 13][addr & 0x1fff] = data;
471 }
472
473 uint32_t SLOT3::read_data8(uint32_t addr)
474 {
475         return rbank[addr >> 13][addr & 0x1fff];
476 }
477
478 void SLOT3::write_io8(uint32_t addr, uint32_t data)
479 {
480         switch(addr & 0xff) {
481         case 0xfc:
482         case 0xfd:
483         case 0xfe:
484         case 0xff:
485                 if(!inserted) {
486                         addr &= 3;
487                         data &= 7;
488                         if(mapper[addr] != data) {
489                                 mapper[addr] = data;
490                                 SET_BANK(addr * 0x4000, addr * 0x4000 + 0x3fff, ram + data * 0x4000, ram + data * 0x4000);
491                         }
492                 }
493                 break;
494         }
495 }
496
497 void SLOT3::open_cart(const _TCHAR *file_path)
498 {
499         if(load_cart(file_path, rom)) {
500                 SET_BANK(0x0000, 0xffff, wdmy, rom);
501                 inserted = true;
502         }
503 }
504
505 void SLOT3::close_cart()
506 {
507         for(int i = 0; i < 4; i++) {
508                 mapper[i] = i;
509         }
510         SET_BANK(0x0000, 0xffff, ram, ram);
511         inserted = false;
512 }
513
514
515 #define SLOT3_STATE_VERSION     1
516
517 bool SLOT3::process_state(FILEIO* state_fio, bool loading)
518 {
519         if(!state_fio->StateCheckUint32(SLOT3_STATE_VERSION)) {
520                 return false;
521         }
522         if(!state_fio->StateCheckInt32(this_device_id)) {
523                 return false;
524         }
525         state_fio->StateArray(ram, sizeof(ram), 1);
526         state_fio->StateValue(inserted);
527         state_fio->StateArray(mapper, sizeof(mapper), 1);
528         
529         // post process
530         if(loading) {
531                 if(inserted) {
532                         SET_BANK(0x0000, 0xffff, wdmy, rom);
533                 } else {
534                         SET_BANK(0x0000, 0x3fff, ram + mapper[0] * 0x4000, ram + mapper[0] * 0x4000);
535                         SET_BANK(0x4000, 0x7fff, ram + mapper[1] * 0x4000, ram + mapper[1] * 0x4000);
536                         SET_BANK(0x8000, 0xbfff, ram + mapper[2] * 0x4000, ram + mapper[2] * 0x4000);
537                         SET_BANK(0xc000, 0xffff, ram + mapper[3] * 0x4000, ram + mapper[3] * 0x4000);
538                 }
539         }
540         return true;
541 }
542
543 // memory bus
544
545 #if !defined(_PX7)
546 void MEMORY::initialize()
547 {
548         for(int i = 0; i < MAX_DRIVE; i++) {
549                 disk[i] = new DISK(emu);
550                 disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
551                 disk[i]->drive_type = DRIVE_TYPE_2DD;
552         }
553 }
554
555 void MEMORY::release()
556 {
557         for(int i = 0; i < MAX_DRIVE; i++) {
558                 if(disk[i]) {
559                         disk[i]->close();
560                         delete disk[i];
561                 }
562         }
563 }
564 #endif
565
566 void MEMORY::reset()
567 {
568 #if !defined(_PX7)
569         for(int i = 0; i < MAX_DRIVE; i++) {
570                 access[i] = false;
571         }
572 #endif
573         update_map((0 << 0) | (1 << 2) | (2 << 4) | (3 << 6));
574 }
575
576 void MEMORY::write_data8(uint32_t addr, uint32_t data)
577 {
578         addr &= 0xffff;
579         d_map[addr >> 14]->write_data8(addr, data);
580 }
581
582 uint32_t MEMORY::read_data8(uint32_t addr)
583 {
584         addr &= 0xffff;
585         return d_map[addr >> 14]->read_data8(addr);
586 }
587
588 uint32_t MEMORY::fetch_op(uint32_t addr, int* wait)
589 {
590         *wait = 1;
591         return read_data8(addr);
592 }
593
594 void MEMORY::write_io8(uint32_t addr, uint32_t data)
595 {
596 #if !defined(_PX7)
597 //      if(d_map[3] == d_slot[3]) {
598                 d_slot[3]->write_io8(addr, data);
599 //      }
600 #endif
601 }
602
603 void MEMORY::write_signal(int id, uint32_t data, uint32_t mask)
604 {
605         if(id == SIG_MEMORY_SEL) {
606                 if(slot_select != (data & mask)) {
607                         update_map(data & mask);
608                 }
609         }
610 }
611
612 void MEMORY::update_map(uint32_t val)
613 {
614         d_map[0] = d_slot[(val >> 0) & 3];
615         d_map[1] = d_slot[(val >> 2) & 3];
616         d_map[2] = d_slot[(val >> 4) & 3];
617         d_map[3] = d_slot[(val >> 6) & 3];
618         slot_select = val;
619 }
620
621 #if !defined(_PX7)
622 static int get_track_number(int desc, int sector)
623 {
624         int trkside = sector / info[desc].per_track;
625         return trkside >> (info[desc].heads - 1);
626 }
627
628 static int get_side_number(int desc, int sector)
629 {
630         int trkside = sector / info[desc].per_track;
631         return trkside & (info[desc].heads - 1);
632 }
633
634 static bool get_track(DISK *disk, int desc, int sector)
635 {
636         return disk->get_track(get_track_number(desc, sector), get_side_number(desc, sector));
637 }
638
639 static bool get_sector(DISK *disk, int desc, int sector)
640 {
641         if(get_track(disk, desc, sector)) {
642                 for(int i = 0; i < disk->sector_num.sd; i++) {
643                         disk->get_sector(-1, -1, i);
644                         if(disk->id[2] == (sector % info[desc].per_track) + 1) {
645                                 return true;
646                         }
647                 }
648         }
649         return false;
650 }
651
652 static bool get_boot_sector(DISK *disk)
653 {
654         if(disk->get_track(0, 0)) {
655                 for(int i = 0; i < disk->sector_num.sd; i++) {
656                         disk->get_sector(0, 0, i);
657                         if(disk->id[2] == 1) {
658                                 return true;
659                         }
660                 }
661         }
662         return false;
663 }
664
665 uint32_t MEMORY::read_signal(int id)
666 {
667         uint32_t stat = 0;
668         for(int i = 0; i < MAX_DRIVE; i++) {
669                 if(access[i]) {
670                         stat |= 1 << i;
671                         access[i] = false;
672                 }
673         }
674         return stat;
675 }
676
677 bool MEMORY::bios_ret_z80(uint16_t PC, pair32_t* af, pair32_t* bc, pair32_t* de, pair32_t* hl, pair32_t* ix, pair32_t* iy, uint8_t* iff1)
678 {
679         #define AF      af->w.l
680         #define A       af->b.h
681         #define F       af->b.l
682         #define BC      bc->w.l
683         #define B       bc->b.h
684         #define C       bc->b.l
685         #define DE      de->w.l
686         #define D       de->b.h
687         #define E       de->b.l
688         #define HL      hl->w.l
689         #define H       hl->b.h
690         #define L       hl->b.l
691         
692         #define CF      0x01
693         
694         if(d_map[1] == d_slot[2]) {
695                 // pseudo disk bios from fMSX
696                 if(PC == DSKIO) {
697                         // read/write sectors
698                         *iff1 |= 1;
699                         int desc = C & 7;
700                         int drv = A;
701                         int addr = HL;
702                         if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
703                                 AF = 0x0201; // not ready
704                                 return true;
705                         }
706                         if(F & CF) {
707                                 if(disk[drv]->write_protected) {
708                                         AF = 0x0001; // write protected
709                                         return true;
710                                 }
711                                 for(int sector = DE; B != 0; sector++) {
712                                         if(!get_sector(disk[drv], desc, sector)) {
713                                                 AF = 0x0801; // record not found
714                                                 return true;
715                                         }
716                                         access[drv] = true;
717                                         
718                                         if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
719                                                 AF = 0x0801; // record not found
720                                                 return true;
721                                         }
722                                         if(addr + 512/*disk[drv]->sector_size.sd*/ > 0xffff) {
723                                                 F &= ~CF;
724                                                 return true;
725                                         }
726                                         d_map[1] = d_slot[read_data8(0xf342) & 3];
727                                         for(int i = 0; i < 512/*disk[drv]->sector_size.sd*/; i++) {
728                                                 disk[drv]->sector[i] = read_data8(addr++);
729                                         }
730                                         d_map[1] = d_slot[2];
731                                         B--;
732                                 }
733                         } else {
734                                 for(int sector = DE; B != 0; sector++) {
735                                         if(!get_sector(disk[drv], desc, sector)) {
736                                                 AF = 0x0801; // record not found
737                                                 return true;
738                                         }
739                                         access[drv] = true;
740                                         
741                                         if(disk[drv]->addr_crc_error && !disk[drv]->ignore_crc()) {
742                                                 AF = 0x0801; // record not found
743                                                 return true;
744                                         }
745                                         if(addr + 512/*disk[drv]->sector_size.sd*/ > 0xffff) {
746                                                 F &= ~CF;
747                                                 return true;
748                                         }
749                                         d_map[1] = d_slot[read_data8(0xf342) & 3];
750                                         for(int i = 0; i < 512/*disk[drv]->sector_size.sd*/; i++) {
751                                                 write_data8(addr++, disk[drv]->sector[i]);
752                                         }
753                                         d_map[1] = d_slot[2];
754                                         B--;
755                                         if(disk[drv]->data_crc_error && !disk[drv]->ignore_crc()) {
756                                                 AF = 0x0401; // data crc error
757                                                 return true;
758                                         }
759                                 }
760                         }
761                         F &= ~CF;
762                         return true;
763                 } else if(PC == DSKCHG) {
764                         // detect disk changed
765                         *iff1 |= 1;
766                         int drv = A;
767                         if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
768                                 AF = 0x0201; // not ready
769                                 return true;
770                         }
771                         B = disk[drv]->changed ? 0xff : 0x01;
772                         disk[drv]->changed = false;
773                         F &= ~CF;
774                         return true;
775                 } else if(PC == GETDPB) {
776                         // get drive parameter block
777                         int drv = A;
778                         if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
779                                 AF = 0x0201; // not ready
780                                 return true;
781                         }
782                         if(!get_boot_sector(disk[drv])) {
783                                 AF = 0x0c01; // other error
784                                 return true;
785                         }
786                         access[drv] = true;
787                         
788                         if(disk[drv]->data_crc_error && !disk[drv]->ignore_crc()) {
789                                 AF = 0x0401; // data crc error
790                                 return true;
791                         }
792                         int bytes_per_sector = (int)disk[drv]->sector[0x0c] * 256 + disk[drv]->sector[0x0b];
793                         int sectors_per_disk = (int)disk[drv]->sector[0x14] * 256 + disk[drv]->sector[0x13];
794                         int sectors_per_fat  = (int)disk[drv]->sector[0x17] * 256 + disk[drv]->sector[0x16];
795                         int reserved_sectors = (int)disk[drv]->sector[0x0f] * 256 + disk[drv]->sector[0x0e];
796                         int addr = HL + 1, num, bits;
797                         d_map[1] = d_slot[read_data8(0xf342) & 3];
798                         write_data8(addr++, disk[drv]->sector[0x15]);   // format id [f8h-ffh]
799                         write_data8(addr++, disk[drv]->sector[0x0b]);   // sector size
800                         write_data8(addr++, disk[drv]->sector[0x0c]);
801                         num = (bytes_per_sector >> 5) - 1;
802                         for(bits = 0; num & (1 << bits); bits++);
803                         write_data8(addr++, num);                       // directory mask/shft
804                         write_data8(addr++, bits);
805                         num = disk[drv]->sector[0x0d] - 1;
806                         for(bits = 0; num & (1 << bits); bits++);
807                         write_data8(addr++, num);                       // cluster mask/shift
808                         write_data8(addr++, bits + 1);
809                         write_data8(addr++, disk[drv]->sector[0x0e]);   // sector # of 1st fat
810                         write_data8(addr++, disk[drv]->sector[0x0f]);
811                         write_data8(addr++, disk[drv]->sector[0x10]);   // number of fats
812                         write_data8(addr++, disk[drv]->sector[0x11]);   // number of dirent-s
813                         num = reserved_sectors + disk[drv]->sector[0x10] * sectors_per_fat;
814                         num += 32 * disk[drv]->sector[0x11] / bytes_per_sector;
815                         write_data8(addr++, num & 0xff);                // sector # of data
816                         write_data8(addr++, (num >> 8) & 0xff);
817                         num = (sectors_per_disk - num) / disk[drv]->sector[0x0d];
818                         write_data8(addr++, num & 0xff);                // number of clusters
819                         write_data8(addr++, (num >> 8) & 0xff);
820                         write_data8(addr++, disk[drv]->sector[0x16]);   // sectors per fat
821                         num = reserved_sectors + disk[drv]->sector[0x10] * sectors_per_fat;
822                         write_data8(addr++, num & 0xff);                // sector # of dir.
823                         write_data8(addr, (num >> 8) & 0xff);
824                         d_map[1] = d_slot[2];
825                         F &= ~CF;
826                         return true;
827                 } else if(PC == DSKFMT) {
828                         // format disk
829                         *iff1 |= 1;
830 //                      int desc = 2 - A;
831                         int desc = A - 1; // A: 1=single-side 2=double-side
832                         int drv = D;
833                         if(desc != 0 && desc != 1) {
834                                 AF = 0x0c01; // bad parameter
835                                 return true;
836                         }
837                         if(!(drv < MAX_DRIVE && disk[drv]->inserted)) {
838                                 AF = 0x0201; // not ready
839                                 return true;
840                         }
841                         if(disk[drv]->write_protected) {
842                                 AF = 0x0001; // write protected
843                                 return true;
844                         }
845                         access[drv] = true;
846                         
847                         // physical format
848                         int max_trkside = info[desc].sectors / info[desc].per_track;
849                         for(int trkside = 0; trkside < max_trkside; trkside++) {
850                                 int trk = trkside >> (info[desc].heads - 1);
851                                 int side = trkside & (info[desc].heads - 1);
852                                 disk[drv]->format_track(trk, side);
853                                 for(int sct = 0; sct < info[desc].per_track; sct++) {
854                                         disk[drv]->insert_sector(trk, side, sct + 1, 2, false, false, 0, 512);
855                                 }
856                         }
857                         // fill boot block with data:
858                         int sector = 0;
859                         get_sector(disk[drv], desc, sector++);
860                         memcpy(disk[drv]->sector, boot_block, 512);
861                         uint8_t *ptr = disk[drv]->sector + 3;
862                         memcpy(ptr, "fMSXdisk", 8); ptr += 10;          // manufacturer's id
863                         *ptr   = info[desc].per_cluster; ptr += 4;      // sectors per cluster
864                         *ptr++ = info[desc].names; *ptr++ = 0x00;       // number of names
865                         *ptr++ = info[desc].sectors & 0xff;             // number of sectors
866                         *ptr++ = (info[desc].sectors >> 8) & 0xff;
867                         *ptr++ = desc + 0xf8;                           // format id [f8h-ffh]
868                         *ptr++ = info[desc].per_fat; *ptr++ = 0x00;     // sectors per fat
869                         *ptr++ = info[desc].per_track; *ptr++ = 0x00;   // sectors per track
870                         *ptr++ = info[desc].heads; *ptr = 0x00;         // number of heads
871                         // writing fats:
872                         for(int j = 0; j < 2; j++) {
873                                 get_sector(disk[drv], desc, sector++);
874                                 memset(disk[drv]->sector, 0x00, 512);
875                                 disk[drv]->sector[0] = desc + 0xf8;
876                                 disk[drv]->sector[1] = disk[drv]->sector[2] = 0xff;
877                                 for(int i = info[desc].per_fat; i > 1; i--) {
878                                         get_sector(disk[drv], desc, sector++);
879                                         memset(disk[drv]->sector, 0x00, 512);
880                                 }
881                         }
882                         for(int i = info[desc].names / 16; i; i--) {
883                                 get_sector(disk[drv], desc, sector++);
884                                 memset(disk[drv]->sector, 0x00, 512);
885                         }
886                         for(int i = info[desc].sectors - 2 * info[desc].per_fat - info[desc].names / 16 - 1; i; i--) {
887                                 get_sector(disk[drv], desc, sector++);
888                                 memset(disk[drv]->sector, 0xff, 512);
889                         }
890                         F &= ~CF;
891                         return true;
892                 }
893         }
894         return false;
895 }
896
897 void MEMORY::open_disk(int drv, const _TCHAR* file_path, int bank)
898 {
899         if(drv < MAX_DRIVE) {
900                 disk[drv]->open(file_path, bank);
901         }
902 }
903
904 void MEMORY::close_disk(int drv)
905 {
906         if(drv < MAX_DRIVE && disk[drv]->inserted) {
907                 disk[drv]->close();
908         }
909 }
910
911 bool MEMORY::is_disk_inserted(int drv)
912 {
913         if(drv < MAX_DRIVE) {
914                 return disk[drv]->inserted;
915         }
916         return false;
917 }
918
919 void MEMORY::is_disk_protected(int drv, bool value)
920 {
921         if(drv < MAX_DRIVE) {
922                 disk[drv]->write_protected = value;
923         }
924 }
925
926 bool MEMORY::is_disk_protected(int drv)
927 {
928         if(drv < MAX_DRIVE) {
929                 return disk[drv]->write_protected;
930         }
931         return false;
932 }
933
934 #endif
935
936 #define STATE_VERSION   1
937
938 bool MEMORY::process_state(FILEIO* state_fio, bool loading)
939 {
940         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
941                 return false;
942         }
943         if(!state_fio->StateCheckInt32(this_device_id)) {
944                 return false;
945         }
946 #if !defined(_PX7)
947         for(int i = 0; i < MAX_DRIVE; i++) {
948                 if(!disk[i]->process_state(state_fio, loading)) {
949                         return false;
950                 }
951         }
952 #endif
953         state_fio->StateValue(slot_select);
954         
955         // post process
956         if(loading) {
957                 update_map(slot_select);
958         }
959         return true;
960 }
961
962 }