OSDN Git Service

[VM][BMJR][FM7][MB8877][MSX][MZ80K][MZ700][MZ2500][T3444A][uPD765A] Add playing sound...
[csp-qt/common_source_project-fm7.git] / source / src / vm / bmjr / memory.cpp
1 /*
2         HITACH BASIC Master Jr Emulator 'eBASICMasterJr'
3
4         Author : Takeda.Toshiya
5         Date   : 2015.08.28-
6
7         [ memory bus ]
8 */
9
10 #include "memory.h"
11 #include "../datarec.h"
12
13 #define SET_BANK(s, e, w, r) { \
14         int sb = (s) >> 11, eb = (e) >> 11; \
15         for(int i = sb; i <= eb; i++) { \
16                 if((w) == wdmy) { \
17                         wbank[i] = wdmy; \
18                 } else { \
19                         wbank[i] = (w) + 0x800 * (i - sb); \
20                 } \
21                 if((r) == rdmy) { \
22                         rbank[i] = rdmy; \
23                 } else { \
24                         rbank[i] = (r) + 0x800 * (i - sb); \
25                 } \
26         } \
27 }
28
29 #define SOUND_VOLUME    8000
30
31 static const int key_table[13][4] = {
32         {0x5a, 0x41, 0x51, 0x31},       //      'Z'     'A'     'Q'     '1'
33         {0x58, 0x53, 0x57, 0x32},       //      'X'     'S'     'W'     '2'
34         {0x43, 0x44, 0x45, 0x33},       //      'C'     'D'     'E'     '3'
35         {0x56, 0x46, 0x52, 0x34},       //      'V'     'F'     'R'     '4'
36         {0x42, 0x47, 0x54, 0x35},       //      'B'     'G'     'T'     '5'
37         {0x4e, 0x48, 0x59, 0x36},       //      'N'     'H'     'Y'     '6'
38         {0x4d, 0x4a, 0x55, 0x37},       //      'M'     'J'     'U'     '7'
39         {0xbc, 0x4b, 0x49, 0x38},       //      ','     'K'     'I'     '8'
40         {0xbe, 0x4c, 0x4f, 0x39},       //      '.'     'L'     'O'     '9'
41         {0xbf, 0xbb, 0x50, 0x30},       //      '/'     ';'     'P'     '0'
42         {0xe2, 0xba, 0xc0, 0xbd},       //      '_'     ':'     '@'     '-'
43         {0x20, 0xdd, 0xdb, 0xde},       //      SPACE   ']'     '['     '^'
44         {0x00, 0x0d, 0x2e, 0xdc},       //              RETURN  DEL     '\'
45 };
46
47 void MEMORY::initialize()
48 {
49         // initialize memory
50         memset(ram, 0, sizeof(ram));
51         memset(basic, 0xff, sizeof(basic));
52         memset(printer, 0xff, sizeof(printer));
53         memset(monitor, 0xff, sizeof(monitor));
54         memset(rdmy, 0xff, sizeof(rdmy));
55         
56         // load rom images
57         FILEIO* fio = new FILEIO();
58         if(fio->Fopen(create_local_path(_T("BASIC.ROM")), FILEIO_READ_BINARY)) {
59                 fio->Fread(basic, sizeof(basic), 1);
60                 fio->Fclose();
61         } else if(fio->Fopen(create_local_path(_T("BAS.ROM")), FILEIO_READ_BINARY)) {
62                 fio->Fread(basic, sizeof(basic), 1);
63                 fio->Fclose();
64         }
65         if(fio->Fopen(create_local_path(_T("PRINTER.ROM")), FILEIO_READ_BINARY)) {
66                 fio->Fread(printer, sizeof(printer), 1);
67                 fio->Fclose();
68         } else if(fio->Fopen(create_local_path(_T("PRT.ROM")), FILEIO_READ_BINARY)) {
69                 fio->Fread(printer, sizeof(printer), 1);
70                 fio->Fclose();
71         }
72         if(fio->Fopen(create_local_path(_T("MONITOR.ROM")), FILEIO_READ_BINARY)) {
73                 fio->Fread(monitor, sizeof(monitor), 1);
74                 fio->Fclose();
75         } else if(fio->Fopen(create_local_path(_T("MON.ROM")), FILEIO_READ_BINARY)) {
76                 fio->Fread(monitor, sizeof(monitor), 1);
77                 fio->Fclose();
78         }
79         if(fio->Fopen(create_local_path(_T("FONT.ROM")), FILEIO_READ_BINARY)) {
80                 fio->Fread(font, sizeof(font), 1);
81                 fio->Fclose();
82         }
83         delete fio;
84         
85         SET_BANK(0x0000, 0xafff, ram,  ram);
86         memory_bank = 0;
87         update_bank();
88         
89         // initialize inputs
90         key_stat = emu->get_key_buffer();
91         
92         // initialize display
93         for(int i = 0; i < 8; i++) {
94                 palette_pc[i] = RGB_COLOR((i & 2) ? 0xff : 0, (i & 4) ? 0xff : 0, (i & 1) ? 0xff : 0);
95         }
96         
97         // register event
98         register_frame_event(this);
99 }
100
101 void MEMORY::reset()
102 {
103         memory_bank = 0;
104         update_bank();
105         
106         memset(color_table, 7, sizeof(color_table));
107         char_color = 7;
108         back_color = mp1710_enb = 0;
109         
110         screen_mode = 0;
111         screen_reversed = false;
112         
113         drec_in = false;
114         
115         key_column = 0;
116         nmi_enb = break_pressed = false;
117         
118         sound_sample = 0;
119         sound_accum = 0;
120         sound_clock = sound_mix_clock = get_current_clock();
121 }
122
123 void MEMORY::write_data8(uint32_t addr, uint32_t data)
124 {
125         if((addr & 0xfe00) == 0xee00) {
126                 // EE00h - EFFFh
127                 switch(addr & 0xffff) {
128                 case 0xee40:
129                         screen_reversed = ((data & 0x80) != 0);
130                         break;
131                 case 0xee80:
132                         if(sound_sample != ((data >> 1) & 0x1f)) {
133                                 sound_accum += (double)sound_sample * get_passed_usec(sound_clock);
134                                 sound_clock = get_current_clock();
135                                 sound_sample = (data >> 1) & 0x1f;
136                         }
137                         d_drec->write_signal(SIG_DATAREC_MIC, ~data, 0x01);
138                         break;
139                 case 0xeec0:
140                         key_column = data & 0x0f;
141                         nmi_enb = ((data & 0x80) != 0);
142                         event_frame(); // update keyboard
143                         break;
144                 case 0xefd0:
145                         // bit4: unknown (timer on/off)
146                         memory_bank = data;
147                         update_bank();
148                         break;
149                 case 0xefe0:
150                         screen_mode = data;
151                         break;
152                 }
153                 return;
154         }
155         if((addr & 0xf800) == 0xe800 && !(memory_bank & 2)) {
156                 // E800h - EDFFh
157                 switch(addr & 0xffff) {
158                 case 0xe800:
159                 case 0xe801:
160                 case 0xe802:
161                 case 0xe803:
162                         d_pia->write_io8(addr, data);
163                         break;
164                 case 0xe890:
165                         // bit0-3: fore color
166                         // bit4-7: back color
167                         char_color = data;
168                         break;
169                 case 0xe891:
170                         back_color = data;
171                         break;
172                 case 0xe892:
173                         mp1710_enb = data;
174                         break;
175                 }
176                 return;
177         }
178         if(addr >= 0x100 && addr < 0x400) {
179                 color_table[addr - 0x100] = char_color;
180         }
181         wbank[(addr >> 11) & 0x1f][addr & 0x7ff] = data;
182 }
183
184 uint32_t MEMORY::read_data8(uint32_t addr)
185 {
186         if((addr & 0xfe00) == 0xee00) {
187                 // EE00h - EFFFh
188                 switch(addr & 0xffff) {
189                 case 0xee00:
190                 case 0xee20:
191                         d_drec->write_signal(SIG_DATAREC_REMOTE, addr, 0x20);
192 #if defined(USE_SOUND_FILES)
193                         if(addr & 0x20) {
194                                 d_drec->write_signal(SIG_SOUNDER_ADD + DATAREC_SNDFILE_RELAY_ON, 1, 1);
195                         } else {
196                                 d_drec->write_signal(SIG_SOUNDER_ADD + DATAREC_SNDFILE_RELAY_OFF, 1, 1);
197                         }
198 #endif
199                         return 0x01;
200                 case 0xee80:
201                         return drec_in ? 0x80 : 0;
202                 case 0xeec0:
203                         return key_data;
204                 case 0xef00:
205                         // unknown (timer)
206                         break;
207                 case 0xef80:
208                         if(break_pressed) {
209                                 break_pressed = false;
210                                 return 0x80;
211                         }
212                         return 0x00;
213                 case 0xefd0:
214                         return memory_bank;
215                 }
216                 return 0xff;
217         }
218         if((addr & 0xf800) == 0xe800 && !(memory_bank & 2)) {
219                 // E800h - EDFFh
220                 switch(addr & 0xffff) {
221                 case 0xe800:
222                 case 0xe801:
223                 case 0xe802:
224                 case 0xe803:
225                         return d_pia->read_io8(addr);
226                 case 0xe890:
227                         return char_color;
228                 case 0xe891:
229                         return back_color;
230                 case 0xe892:
231                         return mp1710_enb;
232                 }
233                 return 0xff;
234         }
235         return rbank[(addr >> 11) & 0x1f][addr & 0x7ff];
236 }
237
238 void MEMORY::write_signal(int id, uint32_t data, uint32_t mask)
239 {
240         if(id == SIG_MEMORY_DATAREC_EAR) {
241                 drec_in = ((data & mask) != 0);
242         }
243 }
244
245 void MEMORY::event_frame()
246 {
247         key_data = 0xff;
248         if(key_column < 13) {
249                 if(key_stat[key_table[key_column][0]]) key_data &= ~0x01;
250                 if(key_stat[key_table[key_column][1]]) key_data &= ~0x02;
251                 if(key_stat[key_table[key_column][2]]) key_data &= ~0x04;
252                 if(key_stat[key_table[key_column][3]]) key_data &= ~0x08;
253         }
254
255 #if defined(_USE_QT)
256         // If same as bm2, not effect below keys at Qt version.
257         if(key_stat[VK_LCONTROL]) key_data &= ~0x10; // \89p\90\94     -> LCTRL
258         if(key_stat[VK_LSHIFT]) key_data &= ~0x20; // \89p\8bL\8d\86   -> L-SHIFT
259         if(key_stat[VK_RWIN]) key_data &= ~0x40; // \83J\83i\8bL\8d\86 -> R-Win
260         if(key_stat[VK_KANA]) key_data &= ~0x80; // \83J\83i     -> \83J\83^\83J\83i\82Ð\82ç\82ª\82È
261 #else
262         // this is same as "\93ú\97§\83x\81[\83V\83b\83N\83}\83X\83^\81[Jr.(MB-6885)\83G\83~\83\85\83\8c\81[\83^ bm2"
263         if(key_stat[0xa2]) key_data &= ~0x10; // \89p\90\94     -> L-CTRL
264         if(key_stat[0xa0]) key_data &= ~0x20; // \89p\8bL\8d\86   -> L-SHIFT
265         if(key_stat[0xa1]) key_data &= ~0x40; // \83J\83i\8bL\8d\86 -> R-SHIFT
266         if(key_stat[0xa3]) key_data &= ~0x80; // \83J\83i     -> R-CTRL
267 #endif  
268 }
269
270 void MEMORY::key_down(int code)
271 {
272         // pause -> break
273         if(code == 0x13) {
274                 if(nmi_enb) {
275                         d_cpu->write_signal(SIG_CPU_NMI, 1, 1);
276                 }
277                 break_pressed = true;
278         }
279 }
280
281 void MEMORY::update_bank()
282 {
283         if(memory_bank & 1) {
284                 SET_BANK(0xb000, 0xdfff, ram + 0xb000, ram + 0xb000);
285         } else {
286                 SET_BANK(0xb000, 0xdfff, wdmy, basic);
287         }
288         if(memory_bank & 2) {
289                 SET_BANK(0xe000, 0xefff, ram + 0xe000, ram + 0xe000);
290         } else {
291                 SET_BANK(0xe000, 0xe7ff, wdmy, printer);
292                 SET_BANK(0xe800, 0xefff, wdmy, rdmy);   // memory mapped i/o
293         }
294         if(memory_bank & 4) {
295                 SET_BANK(0xf000, 0xffff, ram + 0xf000, ram + 0xf000);
296         } else {
297                 SET_BANK(0xf000, 0xffff, wdmy, monitor);
298         }
299 }
300
301 void MEMORY::mix(int32_t* buffer, int cnt)
302 {
303         int32_t volume = 0;
304         if(get_passed_clock(sound_mix_clock) != 0) {
305                 sound_accum += (double)sound_sample * get_passed_usec(sound_clock);
306                 volume = (int32_t)(SOUND_VOLUME * sound_accum / (31.0 * get_passed_usec(sound_mix_clock)));
307         }
308         sound_accum = 0;
309         sound_clock = sound_mix_clock = get_current_clock();
310         
311         for(int i = 0; i < cnt; i++) {
312                 *buffer++ = apply_volume(volume, volume_l); // L
313                 *buffer++ = apply_volume(volume, volume_r); // R
314         }
315 }
316
317 void MEMORY::set_volume(int ch, int decibel_l, int decibel_r)
318 {
319         volume_l = decibel_to_volume(decibel_l);
320         volume_r = decibel_to_volume(decibel_r);
321 }
322
323 void MEMORY::draw_screen()
324 {
325         if(!(screen_mode & 0x80)) {
326                 // text
327                 scrntype_t fore = palette_pc[screen_reversed ? 0 : 7];
328                 scrntype_t back = palette_pc[screen_reversed ? 7 : 0];
329                 int taddr = 0x100;
330                 
331                 for(int y = 0, yy = 0; y < 24; y++, yy += 8) {
332                         for(int x = 0, xx = 0; x < 32; x++, xx += 8) {
333                                 if(mp1710_enb & 1) {
334                                         uint8_t color = color_table[taddr];
335                                         if(screen_reversed) {
336                                                 color = (color >> 4) | (color << 4);
337                                         }
338                                         fore = palette_pc[(color     ) & 7];
339                                         back = palette_pc[(color >> 4) & 7];
340                                 }
341                                 int code = ram[taddr] << 3;
342                                 for(int l = 0; l < 8; l++) {
343                                         scrntype_t* dest = emu->get_screen_buffer(yy + l) + xx;
344                                         uint8_t pat = font[code + l];
345                                         dest[0] = (pat & 0x80) ? fore : back;
346                                         dest[1] = (pat & 0x40) ? fore : back;
347                                         dest[2] = (pat & 0x20) ? fore : back;
348                                         dest[3] = (pat & 0x10) ? fore : back;
349                                         dest[4] = (pat & 0x08) ? fore : back;
350                                         dest[5] = (pat & 0x04) ? fore : back;
351                                         dest[6] = (pat & 0x02) ? fore : back;
352                                         dest[7] = (pat & 0x01) ? fore : back;
353                                 }
354                                 taddr++;
355                         }
356                 }
357         } else {
358                 // graph
359                 scrntype_t fore = palette_pc[screen_reversed ? 0 : 7];
360                 scrntype_t back = palette_pc[screen_reversed ? 7 : 0];
361                 int taddr = 0x100;
362                 int gaddr = 0x900 + ((screen_mode & 0x0f) << 9);
363                 
364                 for(int y = 0, yy = 0; y < 24; y++, yy += 8) {
365                         for(int x = 0, xx = 0; x < 32; x++, xx += 8) {
366                                 if(mp1710_enb & 1) {
367                                         uint8_t color = color_table[taddr];
368                                         if(screen_reversed) {
369                                                 color = (color >> 4) | (color << 4);
370                                         }
371                                         fore = palette_pc[(color     ) & 7];
372                                         back = palette_pc[(color >> 4) & 7];
373                                 }
374                                 for(int l = 0, ll = 0; l < 8; l++, ll += 32) {
375                                         scrntype_t* dest = emu->get_screen_buffer(yy + l) + xx;
376                                         uint8_t pat = ram[gaddr + ll];
377                                         dest[0] = (pat & 0x80) ? fore : back;
378                                         dest[1] = (pat & 0x40) ? fore : back;
379                                         dest[2] = (pat & 0x20) ? fore : back;
380                                         dest[3] = (pat & 0x10) ? fore : back;
381                                         dest[4] = (pat & 0x08) ? fore : back;
382                                         dest[5] = (pat & 0x04) ? fore : back;
383                                         dest[6] = (pat & 0x02) ? fore : back;
384                                         dest[7] = (pat & 0x01) ? fore : back;
385                                 }
386                                 taddr++;
387                                 gaddr++;
388                         }
389                         gaddr += 32 * 7;
390                 }
391         }
392 //      emu->screen_skip_line(false);
393 }
394
395 #define STATE_VERSION   1
396
397 void MEMORY::save_state(FILEIO* state_fio)
398 {
399         state_fio->FputUint32(STATE_VERSION);
400         state_fio->FputInt32(this_device_id);
401         
402         state_fio->Fwrite(ram, sizeof(ram), 1);
403         state_fio->FputUint8(memory_bank);
404         state_fio->Fwrite(color_table, sizeof(color_table), 1);
405         state_fio->FputUint8(char_color);
406         state_fio->FputUint8(back_color);
407         state_fio->FputUint8(mp1710_enb);
408         state_fio->FputUint8(screen_mode);
409         state_fio->FputBool(screen_reversed);
410         state_fio->FputBool(drec_in);
411         state_fio->FputUint8(key_column);
412         state_fio->FputUint8(key_data);
413         state_fio->FputBool(nmi_enb);
414         state_fio->FputBool(break_pressed);
415         state_fio->FputUint8(sound_sample);
416         state_fio->FputDouble(sound_accum);
417         state_fio->FputUint32(sound_clock);
418         state_fio->FputUint32(sound_mix_clock);
419 }
420
421 bool MEMORY::load_state(FILEIO* state_fio)
422 {
423         if(state_fio->FgetUint32() != STATE_VERSION) {
424                 return false;
425         }
426         if(state_fio->FgetInt32() != this_device_id) {
427                 return false;
428         }
429         state_fio->Fread(ram, sizeof(ram), 1);
430         memory_bank = state_fio->FgetUint8();
431         state_fio->Fread(color_table, sizeof(color_table), 1);
432         char_color = state_fio->FgetUint8();
433         back_color = state_fio->FgetUint8();
434         mp1710_enb = state_fio->FgetUint8();
435         screen_mode = state_fio->FgetUint8();
436         screen_reversed = state_fio->FgetBool();
437         drec_in = state_fio->FgetBool();
438         key_column = state_fio->FgetUint8();
439         key_data = state_fio->FgetUint8();
440         nmi_enb = state_fio->FgetBool();
441         break_pressed = state_fio->FgetBool();
442         sound_sample = state_fio->FgetUint8();
443         sound_accum = state_fio->FgetDouble();
444         sound_clock = state_fio->FgetUint32();
445         sound_mix_clock = state_fio->FgetUint32();
446         
447         // post process
448         update_bank();
449         return true;
450 }
451