OSDN Git Service

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