2 NEC PC-98DO Emulator 'ePC-98DO'
3 NEC PC-8801MA Emulator 'ePC-8801MA'
4 NEC PC-8001mkIISR Emulator 'ePC-8001mkIISR'
6 Author : Takeda.Toshiya
15 #include "../pcm1bit.h"
16 #include "../upd1990a.h"
17 #include "../ym2203.h"
20 #ifdef SUPPORT_PC88_CDROM
21 #include "../scsi_cdrom.h"
22 #include "../scsi_host.h"
25 #define DEVICE_JOYSTICK 0
26 #define DEVICE_MOUSE 1
27 #define DEVICE_JOYMOUSE 2 // not supported yet
30 #define EVENT_BUSREQ 1
31 #define EVENT_CMT_SEND 2
32 #define EVENT_CMT_DCD 3
34 #ifdef SUPPORT_PC88_CDROM
35 #define EVENT_FADE_IN 5
36 #define EVENT_FADE_OUT 6
47 #define Port30_40 !(port[0x30] & 0x01)
48 #define Port30_COLOR !(port[0x30] & 0x02)
49 #define Port30_MTON (port[0x30] & 0x08)
50 #define Port30_CMT !(port[0x30] & 0x20)
51 #define Port30_RS232C (port[0x30] & 0x20)
53 #define Port31_MMODE (port[0x31] & 0x02)
54 #define Port31_RMODE (port[0x31] & 0x04)
55 #define Port31_GRAPH (port[0x31] & 0x08)
56 #define Port31_HCOLOR (port[0x31] & 0x10)
57 #if !defined(_PC8001SR)
58 #define Port31_400LINE !(port[0x31] & 0x11)
60 #define Port31_400LINE false
63 #define Port31_V1_320x200 (port[0x31] & 0x10) // PC-8001 (V1)
64 #define Port31_V1_MONO (port[0x31] & 0x04) // PC-8001 (V1)
66 #define Port31_320x200 (port[0x31] & 0x04) // PC-8001
68 #define Port32_EROMSL (port[0x32] & 0x03)
69 #define Port32_TMODE (port[0x32] & 0x10)
70 #if !defined(_PC8001SR)
71 #define Port32_PMODE (port[0x32] & 0x20)
73 #define Port32_PMODE false
75 #define Port32_GVAM (port[0x32] & 0x40)
76 #define Port32_SINTM (port[0x32] & 0x80)
78 #define Port33_SINTM (port[0x33] & 0x02) // PC-8001
79 #define Port33_GVAM (port[0x33] & 0x40) // PC-8001
80 #define Port33_N80SR (port[0x33] & 0x80) // PC-8001
82 #define Port34_ALU port[0x34]
84 #define Port35_PLN0 (port[0x35] & 0x01)
85 #define Port35_PLN1 (port[0x35] & 0x02)
86 #define Port35_PLN2 (port[0x35] & 0x04)
87 #define Port35_GDM (port[0x35] & 0x30)
88 #define Port35_GAM (port[0x35] & 0x80)
90 #define Port40_GHSM (port[0x40] & 0x10)
91 #define Port40_JOP1 (port[0x40] & 0x40)
93 #define Port44_OPNCH port[0x44]
95 #define Port53_TEXTDS (port[0x53] & 0x01)
96 #define Port53_G0DS (port[0x53] & 0x02)
97 #define Port53_G1DS (port[0x53] & 0x04)
98 #define Port53_G2DS (port[0x53] & 0x08)
99 #define Port53_G3DS (port[0x53] & 0x10) // PC-8001
100 #define Port53_G4DS (port[0x53] & 0x20) // PC-8001
101 #define Port53_G5DS (port[0x53] & 0x40) // PC-8001
103 #define Port70_TEXTWND port[0x70]
105 #define Port71_EROM port[0x71]
107 #ifdef SUPPORT_PC88_CDROM
108 #define Port99_CDREN (port[0x99] & 0x10)
112 #define PortA8_OPNCH port[0xa8]
113 #define PortAA_S2INTM (port[0xaa] & 0x80)
115 #define PortE2_RDEN (port[0xe2] & 0x01)
116 #define PortE2_WREN (port[0xe2] & 0x10)
118 #ifdef PC88_IODATA_EXRAM
119 #define PortE3_ERAMSL port[0xe3]
121 #define PortE3_ERAMSL (port[0xe3] & 0x0f)
124 #define PortE8E9_KANJI1 (port[0xe8] | (port[0xe9] << 8))
125 #define PortECED_KANJI2 (port[0xec] | (port[0xed] << 8))
127 #define PortF0_DICROMSL (port[0xf0] & 0x1f)
128 #define PortF1_DICROM !(port[0xf1] & 0x01)
130 #if defined(SUPPORT_PC88_VAB)
132 #define PortB4_VAB_DISP ((port[0xb4] & 0x41) == 0x41)
133 #define PortE3_VAB_SEL (((port[0xe3] >> 2) & 3) == PC88_VAB_PAGE)
136 #define SET_BANK(s, e, w, r) { \
137 int sb = (s) >> 12, eb = (e) >> 12; \
138 for(int i = sb; i <= eb; i++) { \
142 wbank[i] = (w) + 0x1000 * (i - sb); \
147 rbank[i] = (r) + 0x1000 * (i - sb); \
152 #define SET_BANK_W(s, e, w) { \
153 int sb = (s) >> 12, eb = (e) >> 12; \
154 for(int i = sb; i <= eb; i++) { \
158 wbank[i] = (w) + 0x1000 * (i - sb); \
163 #define SET_BANK_R(s, e, r) { \
164 int sb = (s) >> 12, eb = (e) >> 12; \
165 for(int i = sb; i <= eb; i++) { \
169 rbank[i] = (r) + 0x1000 * (i - sb); \
174 static const int key_table[15][8] = {
175 { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67 },
176 { 0x68, 0x69, 0x6a, 0x6b, 0x92, 0x6c, 0x6e, 0x0d }, // 0x92 = VK_OEM_NEC_EQUAL
177 { 0xc0, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 },
178 { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f },
179 { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57 },
180 { 0x58, 0x59, 0x5a, 0xdb, 0xdc, 0xdd, 0xde, 0xbd },
181 { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 },
182 { 0x38, 0x39, 0xba, 0xbb, 0xbc, 0xbe, 0xbf, 0xe2 },
183 // { 0x24, 0x26, 0x27, 0x2e, 0x12, 0x15, 0x10, 0x11 },
184 { 0x24, 0x26, 0x27, 0x08, 0x12, 0x15, 0x10, 0x11 },
185 { 0x13, 0x70, 0x71, 0x72, 0x73, 0x74, 0x20, 0x1b },
186 { 0x09, 0x28, 0x25, 0x23, 0x7b, 0x6d, 0x6f, 0x14 },
187 { 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
188 { 0x75, 0x76, 0x77, 0x78, 0x79, 0x08, 0x2d, 0x2e },
189 { 0x1c, 0x1d, 0x7a, 0x19, 0x00, 0x00, 0x00, 0x00 },
190 { 0x0d, 0x00, 0xa0, 0xa1, 0x00, 0x00, 0x00, 0x00 }
193 static const int key_conv_table[][3] = {
194 {0x2d, 0x2e, 1}, // INS -> SHIFT + DEL
195 {0x75, 0x70, 1}, // F6 -> SHIFT + F1
196 {0x76, 0x71, 1}, // F7 -> SHIFT + F2
197 {0x77, 0x72, 1}, // F8 -> SHIFT + F3
198 {0x78, 0x73, 1}, // F9 -> SHIFT + F4
199 {0x79, 0x74, 1}, // F10 -> SHIFT + F5
200 // {0x08, 0x2e, 0}, // BS -> DEL
201 {0x2e, 0x08, 0}, // DEL -> BS
202 {0x1c, 0x20, 0}, //
\95Ï
\8a·-> SPACE
203 {0x1d, 0x20, 0}, //
\8c\88\92è-> SPACE
206 static const uint8_t intr_mask2_table[8] = {
207 (uint8_t)~7, (uint8_t)~3, (uint8_t)~5, (uint8_t)~1, (uint8_t)~6, (uint8_t)~2, (uint8_t)~4, (uint8_t)~0
210 void PC88::initialize()
212 memset(rdmy, 0xff, sizeof(rdmy));
213 // memset(ram, 0, sizeof(ram));
214 #ifdef PC88_EXRAM_BANKS
215 memset(exram, 0, sizeof(exram));
217 memset(gvram, 0, sizeof(gvram));
218 memset(gvram_null, 0, sizeof(gvram_null));
219 memset(tvram, 0, sizeof(tvram));
220 #if defined(_PC8001SR)
221 memset(n80mk2rom, 0xff, sizeof(n80mk2rom));
222 memset(n80mk2srrom, 0xff, sizeof(n80mk2srrom));
224 memset(n88rom, 0xff, sizeof(n88rom));
225 memset(n88exrom, 0xff, sizeof(n88exrom));
226 memset(n80rom, 0xff, sizeof(n80rom));
228 memset(kanji1, 0xff, sizeof(kanji1));
229 memset(kanji2, 0xff, sizeof(kanji2));
230 #ifdef SUPPORT_PC88_DICTIONARY
231 memset(dicrom, 0xff, sizeof(dicrom));
233 #ifdef SUPPORT_PC88_CDROM
234 memset(cdbios, 0xff, sizeof(cdbios));
235 cdbios_loaded = false;
239 FILEIO* fio = new FILEIO();
240 #if defined(_PC8001SR)
241 if(fio->Fopen(create_local_path(_T("N80_2.ROM")), FILEIO_READ_BINARY)) {
242 fio->Fread(n80mk2rom, 0x8000, 1);
245 if(fio->Fopen(create_local_path(_T("N80_3.ROM")), FILEIO_READ_BINARY)) {
246 fio->Fread(n80mk2srrom, 0xa000, 1);
250 if(fio->Fopen(create_local_path(_T("PC88.ROM")), FILEIO_READ_BINARY)) {
251 fio->Fread(n88rom, 0x8000, 1);
252 fio->Fread(n80rom + 0x6000, 0x2000, 1);
253 fio->Fseek(0x2000, FILEIO_SEEK_CUR);
254 fio->Fread(n88exrom, 0x8000, 1);
255 fio->Fseek(0x2000, FILEIO_SEEK_CUR);
256 fio->Fread(n80rom, 0x6000, 1);
259 if(fio->Fopen(create_local_path(_T("N88.ROM")), FILEIO_READ_BINARY)) {
260 fio->Fread(n88rom, 0x8000, 1);
263 if(fio->Fopen(create_local_path(_T("N88_0.ROM")), FILEIO_READ_BINARY)) {
264 fio->Fread(n88exrom + 0x0000, 0x2000, 1);
267 if(fio->Fopen(create_local_path(_T("N88_1.ROM")), FILEIO_READ_BINARY)) {
268 fio->Fread(n88exrom + 0x2000, 0x2000, 1);
271 if(fio->Fopen(create_local_path(_T("N88_2.ROM")), FILEIO_READ_BINARY)) {
272 fio->Fread(n88exrom + 0x4000, 0x2000, 1);
275 if(fio->Fopen(create_local_path(_T("N88_3.ROM")), FILEIO_READ_BINARY)) {
276 fio->Fread(n88exrom + 0x6000, 0x2000, 1);
279 if(fio->Fopen(create_local_path(_T("N80.ROM")), FILEIO_READ_BINARY)) {
280 fio->Fread(n80rom, 0x8000, 1);
284 if(fio->Fopen(create_local_path(_T("KANJI1.ROM")), FILEIO_READ_BINARY)) {
285 fio->Fread(kanji1, 0x20000, 1);
288 if(fio->Fopen(create_local_path(_T("KANJI2.ROM")), FILEIO_READ_BINARY)) {
289 fio->Fread(kanji2, 0x20000, 1);
292 #ifdef SUPPORT_PC88_DICTIONARY
293 if(fio->Fopen(create_local_path(_T("JISYO.ROM")), FILEIO_READ_BINARY)) {
294 fio->Fread(dicrom, 0x80000, 1);
298 #ifdef SUPPORT_PC88_CDROM
299 if(config.boot_mode == MODE_PC88_V2) {
300 if(fio->Fopen(create_local_path(_T("CDBIOS.ROM")), FILEIO_READ_BINARY)) {
301 fio->Fread(cdbios, 0x10000, 1);
303 cdbios_loaded = true;
310 for(int i = 0, ofs = 0; i < 256; i++) {
311 for(int j = 0; j < 16; j++) {
312 static const uint8_t p0[256] = {
313 0,1,0,1,0,1,0,0,0,0,0,0,1,0,1,0, // 0000
314 0,1,0,1,0,1,0,0,0,0,1,0,1,0,1,0, // 1000
315 0,1,0,1,0,0,0,0,0,0,1,0,1,0,1,0, // 2000
316 0,1,0,1,0,0,0,0,0,0,1,0,1,0,1,0, // 3000
317 1,0,1,0,1,0,1,1,1,1,1,1,0,1,0,1, // 4000
318 1,0,1,0,1,0,1,1,1,1,0,1,0,1,0,1, // 5000
319 1,0,1,0,1,1,1,1,1,1,0,1,0,1,0,1, // 6000
320 1,0,1,0,1,1,1,1,1,1,0,1,0,1,0,1, // 7000
321 1,0,1,0,1,0,1,1,1,1,1,1,0,1,0,1, // 8000
322 1,0,1,0,1,0,1,1,1,1,1,1,0,1,0,1, // 9000
323 1,0,1,0,1,0,1,1,1,1,0,1,0,1,0,1, // a000
324 1,0,1,0,1,1,1,1,1,1,0,1,0,1,0,1, // b000
325 0,1,0,1,0,1,0,0,0,0,0,0,1,0,1,0, // c000
326 0,1,0,1,0,1,0,0,0,0,0,0,1,0,1,0, // d000
327 0,1,0,1,0,1,0,0,0,0,1,0,1,0,1,0, // e000
328 0,1,0,1,0,0,0,0,0,0,1,0,1,0,1,0, // f000
330 static const uint8_t p1[16] = {
331 0x00,0xff,0x00,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0x00,
333 memset(ram + ofs, (p0[i] == 0) ? p1[j] : ~p1[j], 16);
338 // create semi graphics pattern
339 for(int i = 0; i < 256; i++) {
340 uint8_t *dest = sg_pattern + 8 * i;
341 dest[0] = dest[1] = ((i & 1) ? 0xf0 : 0) | ((i & 0x10) ? 0x0f : 0);
342 dest[2] = dest[3] = ((i & 2) ? 0xf0 : 0) | ((i & 0x20) ? 0x0f : 0);
343 dest[4] = dest[5] = ((i & 4) ? 0xf0 : 0) | ((i & 0x40) ? 0x0f : 0);
344 dest[6] = dest[7] = ((i & 8) ? 0xf0 : 0) | ((i & 0x80) ? 0x0f : 0);
347 #ifdef SUPPORT_PC88_VAB
349 for(uint32_t g = 0; g < 64; g++) {
350 uint32_t gg = (255 * g) / 63;
351 for(uint32_t r = 0; r < 32; r++) {
352 uint32_t rr = (255 * r) / 31;
353 for(uint32_t b = 0; b < 32; b++) {
354 uint32_t bb = (255 * b) / 31;
355 palette_vab_pc[b | (r << 5) | (g << 10)] = RGB_COLOR(rr, gg, bb);
361 #ifdef SUPPORT_PC88_HIGH_CLOCK
362 cpu_clock_low = (config.cpu_type == 1); // 4MHz
363 cpu_clock_high_fe2 = (config.cpu_type == 2); // 8MHz (FE2/MC)
365 cpu_clock_low = true;
368 #ifdef SUPPORT_PC88_JOYSTICK
369 joystick_status = emu->get_joy_buffer();
370 mouse_status = emu->get_mouse_buffer();
371 mouse_strobe_clock_lim = (int)((cpu_clock_low ? 720 : 1440) * 1.25);
375 cmt_fio = new FILEIO();
376 cmt_play = cmt_rec = false;
378 register_frame_event(this);
379 register_vline_event(this);
380 register_event(this, EVENT_TIMER, 1000000.0 / 600.0, true, NULL);
381 register_event(this, EVENT_BEEP, 1000000.0 / 4800.0, true, NULL);
383 #if !defined(_PC8001SR)
384 // hack to update config.scan_line at first
385 hireso = !(config.monitor_type == 0);
387 #ifdef SUPPORT_PC88_CDROM
388 cdda_register_id = -1;
400 #if defined(_PC8001SR)
403 bool value = (config.monitor_type == 0);
404 if(hireso != value) {
405 // update config.scan_line when config.monitor_type is changed
406 //hireso = config.scan_line = value;
407 hireso = value; // Revert 20181217 K.O
412 memset(port, 0, sizeof(port));
415 for(int i = 0; i < 8; i++) {
418 // port[0x70] = 0x80; // XM8 version 1.10
419 port[0x71] = port[0xf1] = 0xff;
420 #if defined(SUPPORT_PC88_CDROM)
425 memset(alu_reg, 0, sizeof(alu_reg));
426 gvram_plane = gvram_sel = 0;
428 #if defined(_PC8001SR)
429 if(config.boot_mode == MODE_PC80_V2) {
430 SET_BANK(0x0000, 0x7fff, wdmy, n80mk2srrom);
433 SET_BANK(0x0000, 0x7fff, wdmy, n80mk2rom);
435 SET_BANK(0x8000, 0xffff, ram + 0x8000, ram + 0x8000);
437 // SET_BANK(0x0000, 0x7fff, ram, n88rom);
438 SET_BANK(0x8000, 0xefff, ram + 0x8000, ram + 0x8000);
440 update_tvram_memmap(); // XM8 version 1.10
448 mem_wait_on = ((config.dipswitch & 1) != 0);
450 m1_wait_clocks = get_m1_wait(false);
451 f000_m1_wait_clocks = get_m1_wait(true);
452 mem_wait_clocks_r = get_main_wait(true);
453 mem_wait_clocks_w = get_main_wait(false);
454 tvram_wait_clocks_r = get_tvram_wait(true);
455 tvram_wait_clocks_w = get_tvram_wait(false);
458 memset(&crtc, 0, sizeof(crtc));
462 memset(palette, 0, sizeof(palette));
463 for(int i = 1; i < 8; i++) {
464 palette[i].b = (i & 1) ? 7 : 0;
465 palette[i].r = (i & 2) ? 7 : 0;
466 palette[i].g = (i & 4) ? 7 : 0;
468 update_palette = true;
471 memset(&dmac, 0, sizeof(dmac));
472 dmac.ch[0].io = dmac.ch[3].io = vm->dummy;
473 #ifdef SUPPORT_PC88_CDROM
475 dmac.ch[1].io = d_scsi_host;
478 dmac.ch[1].io = vm->dummy;;
479 dmac.ch[2].io = dmac.mem = this;
480 dmac.ch[0].addr.b.l = 0x56; // XM8 version 1.10
481 dmac.ch[0].addr.b.h = 0x56;
482 dmac.ch[1].addr.b.l = 0x7a;
483 dmac.ch[1].addr.b.h = 0x7a;
486 key_kana = key_caps = 0;
489 #ifdef SUPPORT_PC88_JOYSTICK
490 mouse_strobe_clock = get_current_clock();
492 mouse_dx = mouse_dy = mouse_lx = mouse_ly = 0;
496 intr_req = intr_mask1 = intr_mask2 = 0;
497 intr_req_sound = false;
498 #ifdef SUPPORT_PC88_SB2
499 intr_req_sb2 = false;
503 d_pio->write_io8(1, 0);
504 d_pio->write_io8(2, 0);
508 cmt_play = cmt_rec = false;
509 cmt_register_id = -1;
512 beep_on = beep_signal = sing_signal = false;
514 #ifdef SUPPORT_PC88_PCG8100
516 memcpy(pcg_pattern, kanji1 + 0x1000, sizeof(pcg_pattern));
521 #ifdef SUPPORT_PC88_CDROM
522 if(cdda_register_id != -1) {
523 cancel_event(this, cdda_register_id);
524 cdda_register_id = -1;
527 d_scsi_cdrom->set_volume((int)cdda_volume);
530 // dirty patch for NIPPY
535 void PC88::write_data8w(uint32_t addr, uint32_t data, int* wait)
538 *wait = mem_wait_clocks_w;
540 #if !defined(_PC8001SR)
541 if((addr & 0xfc00) == 0x8000) {
543 if(!Port31_MMODE && !Port31_RMODE) {
544 addr = (Port70_TEXTWND << 8) + (addr & 0x3ff);
546 ram[addr & 0xffff] = data;
548 } else if((addr & 0xc000) == 0xc000) {
550 if((addr & 0xc000) == 0x8000) {
554 *wait = gvram_wait_clocks_w;
555 gvram[(addr & 0x3fff) | 0x0000] = data;
558 *wait = gvram_wait_clocks_w;
559 gvram[(addr & 0x3fff) | 0x4000] = data;
562 *wait = gvram_wait_clocks_w;
563 gvram[(addr & 0x3fff) | 0x8000] = data;
566 *wait = gvram_wait_clocks_w;
570 for(int i = 0; i < 3; i++) {
571 switch((Port34_ALU >> i) & 0x11) {
573 gvram[addr | (0x4000 * i)] &= ~data;
576 gvram[addr | (0x4000 * i)] |= data;
578 case 0x10: // reverse
579 gvram[addr | (0x4000 * i)] ^= data;
585 gvram[addr | 0x0000] = alu_reg[0];
586 gvram[addr | 0x4000] = alu_reg[1];
587 gvram[addr | 0x8000] = alu_reg[2];
590 gvram[addr | 0x0000] = alu_reg[1];
593 gvram[addr | 0x4000] = alu_reg[0];
599 #if !defined(_PC8001SR)
600 if((addr & 0xf000) == 0xf000) {
602 *wait += tvram_wait_clocks_w;
605 wbank[addr >> 12][addr & 0xfff] = data;
608 uint32_t PC88::read_data8w(uint32_t addr, int* wait)
611 *wait = mem_wait_clocks_r;
613 #if !defined(_PC8001SR)
614 if((addr & 0xfc00) == 0x8000) {
616 if(!Port31_MMODE && !Port31_RMODE) {
617 addr = (Port70_TEXTWND << 8) + (addr & 0x3ff);
619 return ram[addr & 0xffff];
620 } else if((addr & 0xc000) == 0xc000) {
622 if((addr & 0xc000) == 0x8000) {
627 *wait = gvram_wait_clocks_r;
628 return gvram[(addr & 0x3fff) | 0x0000];
630 *wait = gvram_wait_clocks_r;
631 return gvram[(addr & 0x3fff) | 0x4000];
633 *wait = gvram_wait_clocks_r;
634 return gvram[(addr & 0x3fff) | 0x8000];
636 *wait = gvram_wait_clocks_r;
638 alu_reg[0] = gvram[addr | 0x0000];
639 alu_reg[1] = gvram[addr | 0x4000];
640 alu_reg[2] = gvram[addr | 0x8000];
641 b = alu_reg[0]; if(!Port35_PLN0) b ^= 0xff;
642 r = alu_reg[1]; if(!Port35_PLN1) r ^= 0xff;
643 g = alu_reg[2]; if(!Port35_PLN2) g ^= 0xff;
646 #ifdef SUPPORT_PC88_DICTIONARY
648 return dicrom[(addr & 0x3fff) | (0x4000 * PortF0_DICROMSL)];
652 #if !defined(_PC8001SR)
653 if((addr & 0xf000) == 0xf000) {
655 *wait += tvram_wait_clocks_r;
658 return rbank[addr >> 12][addr & 0xfff];
661 uint32_t PC88::fetch_op(uint32_t addr, int *wait)
663 uint32_t data = read_data8w(addr, wait);
664 if((addr & 0xf000) == 0xf000) {
665 *wait += f000_m1_wait_clocks;
667 *wait += m1_wait_clocks;
672 void PC88::write_io8(uint32_t addr, uint32_t data)
676 this->out_debug_log(_T("%06x\tOUT8\t%02x,%02x\n"), d_cpu->get_pc(), addr, data);
679 // dirty patch for NIPPY
680 if(addr == 0x31 && data == 0x3f && d_cpu->get_pc() == 0xaa4f && nippy_patch) {
681 data = 0x39; // select n88rom
685 uint8_t mod = port[addr] ^ data;
690 #ifdef SUPPORT_PC88_PCG8100
693 // load tape image ??? (from QUASI88)
695 while(cmt_buffer[cmt_bufptr++] != 0x3a) {
696 if(!(cmt_bufptr <= cmt_bufcnt)) return;
698 int val, sum, ptr, len, wait;
699 sum = (val = cmt_buffer[cmt_bufptr++]);
701 sum += (val = cmt_buffer[cmt_bufptr++]);
703 sum += (val = cmt_buffer[cmt_bufptr++]);
704 if((sum & 0xff) != 0) return;
707 while(cmt_buffer[cmt_bufptr++] != 0x3a) {
708 if(!(cmt_bufptr <= cmt_bufcnt)) return;
710 sum = (len = cmt_buffer[cmt_bufptr++]);
713 sum += (val = cmt_buffer[cmt_bufptr++]);
714 write_data8w(ptr++, val, &wait);
716 sum += cmt_buffer[cmt_bufptr++];
717 if((sum & 0xff) != 0) return;
721 #ifdef SUPPORT_PC88_PCG8100
723 pcg_addr = (pcg_addr & 0x300) | data;
726 if((pcg_ctrl & 0x10) && !(data & 0x10)) {
727 if(pcg_ctrl & 0x20) {
728 pcg_pattern[0x400 | pcg_addr] = kanji1[0x1400 | pcg_addr];
730 pcg_pattern[0x400 | pcg_addr] = pcg_data;
733 pcg_addr = (pcg_addr & 0x0ff) | ((data & 3) << 8);
735 d_pcg_pcm0->write_signal(SIG_PCM1BIT_ON, data, 0x08);
736 d_pcg_pcm1->write_signal(SIG_PCM1BIT_ON, data, 0x40);
737 d_pcg_pcm2->write_signal(SIG_PCM1BIT_ON, data, 0x80);
743 d_pcg_pit->write_io8(addr & 3, data);
747 d_prn->write_signal(SIG_PRINTER_DATA, data, 0xff);
748 d_rtc->write_signal(SIG_UPD1990A_C0, data, 1);
749 d_rtc->write_signal(SIG_UPD1990A_C1, data, 2);
750 d_rtc->write_signal(SIG_UPD1990A_C2, data, 4);
751 d_rtc->write_signal(SIG_UPD1990A_DIN, data, 8);
755 d_sio->write_io8(addr, data);
761 if(cmt_play && cmt_bufptr < cmt_bufcnt) {
763 // skip to the top of next block
764 int tmp = cmt_bufptr;
765 while(cmt_bufptr < cmt_bufcnt) {
766 if(check_data_carrier()) {
771 if(cmt_bufptr == cmt_bufcnt) {
775 if(cmt_register_id != -1) {
776 cancel_event(this, cmt_register_id);
778 register_event(this, EVENT_CMT_SEND, 5000, false, &cmt_register_id);
782 if(cmt_register_id != -1) {
783 cancel_event(this, cmt_register_id);
784 cmt_register_id = -1;
786 usart_dcd = true; // for Jackie Chan no Spartan X
790 #if defined(_PC8001SR)
797 palette[8].b = (data & 0x20) ? 7 : 0;
798 palette[8].r = (data & 0x40) ? 7 : 0;
799 palette[8].g = (data & 0x80) ? 7 : 0;
800 update_palette = true;
807 update_palette = true;
813 if(intr_req_sound && !Port33_SINTM) {
814 request_intr(IRQ_SOUND, true);
825 update_palette = true;
829 update_palette = true;
832 // dirty patch for NIPPY
833 nippy_patch = (data == 0x37 && d_cpu->get_pc() == 0xaa32);
838 if(!(Port71_EROM & 1)) {
844 // if(config.boot_mode == MODE_PC88_V1H || config.boot_mode == MODE_PC88_V2) {
845 update_tvram_memmap();
846 f000_m1_wait_clocks = get_m1_wait(true);
853 if(intr_req_sound && !Port32_SINTM) {
854 request_intr(IRQ_SOUND, true);
865 d_prn->write_signal(SIG_PRINTER_STROBE, data, 1);
866 d_rtc->write_signal(SIG_UPD1990A_STB, ~data, 2);
867 d_rtc->write_signal(SIG_UPD1990A_CLK, data, 4);
868 // bit3: crtc i/f sync mode
872 beep_on = ((data & 0x20) != 0);
873 #ifdef SUPPORT_PC88_JOYSTICK
875 if(Port40_JOP1 && (mouse_phase == -1 || get_passed_clock(mouse_strobe_clock) > mouse_strobe_clock_lim)) {
876 mouse_phase = 0;//mouse_dx = mouse_dy = 0;
878 mouse_phase = (mouse_phase + 1) & 3;
880 if(mouse_phase == 0) {
882 mouse_lx = -((mouse_dx > 127) ? 127 : (mouse_dx < -127) ? -127 : mouse_dx);
883 mouse_ly = -((mouse_dy > 127) ? 127 : (mouse_dy < -127) ? -127 : mouse_dy);
884 mouse_dx = mouse_dy = 0;
886 mouse_strobe_clock = get_current_clock();
889 sing_signal = ((data & 0x80) != 0);
890 d_pcm->write_signal(SIG_PCM1BIT_SIGNAL, ((beep_on && beep_signal) || sing_signal) ? 1 : 0, 1);
894 d_opn->write_io8(addr, data);
896 #ifdef SUPPORT_PC88_OPNA
899 if(d_opn->is_ym2608) {
900 d_opn->write_io8(addr, data);
905 crtc.write_param(data);
906 if(crtc.timing_changed) {
908 crtc.timing_changed = false;
912 crtc.write_cmd(data);
914 #if !defined(_PC8001SR)
916 palette[8].b = (data & 0x10) ? 7 : 0;
917 palette[8].r = (data & 0x20) ? 7 : 0;
918 palette[8].g = (data & 0x40) ? 7 : 0;
919 update_palette = true;
930 #if !defined(_PC8001SR)
932 int n = (data & 0x80) ? 9 : (addr - 0x54);
934 palette[n].g = data & 7;
936 palette[n].b = data & 7;
937 palette[n].r = (data >> 3) & 7;
941 palette[n].b = (data & 1) ? 7 : 0;
942 palette[n].r = (data & 2) ? 7 : 0;
943 palette[n].g = (data & 4) ? 7 : 0;
946 update_palette = true;
949 if(gvram_plane != 1) {
955 if(gvram_plane != 2) {
961 if(gvram_plane != 4) {
967 if(gvram_plane != 0) {
981 dmac.write_io8(addr, data);
983 #if defined(_PC8001SR)
985 if((mod & 1) && Port33_N80SR) {
1006 update_low_memmap();
1012 #ifdef SUPPORT_PC88_HMB20
1015 d_opm->write_io8(addr, data);
1018 #ifdef SUPPORT_PC88_CDROM
1021 if(cdbios_loaded && (mod & 0x01)) {
1023 if(port[0x9f] & 0x01) {
1024 d_scsi_host->write_signal(SIG_SCSI_SEL, 0, 1);
1025 d_scsi_host->write_signal(SIG_SCSI_SEL, 1, 1);
1026 d_scsi_host->write_signal(SIG_SCSI_SEL, 0, 1);
1029 d_scsi_host->write_signal(SIG_SCSI_SEL, 0, 1);
1031 // d_scsi_host->write_signal(SIG_SCSI_SEL, data, 1);
1036 d_scsi_host->write_dma_io8(0, data);
1041 d_scsi_host->write_signal(SIG_SCSI_RST, data, 0x80);
1049 if(cdda_register_id != -1) {
1050 cancel_event(this, cdda_register_id);
1051 cdda_register_id = -1;
1053 d_scsi_cdrom->set_volume((int)(cdda_volume = 100.0));
1057 if(cdda_register_id != -1) {
1058 cancel_event(this, cdda_register_id);
1059 cdda_register_id = -1;
1061 d_scsi_cdrom->set_volume((int)(cdda_volume = 0.0));
1064 if(cdda_register_id != -1) {
1065 cancel_event(this, cdda_register_id);
1067 register_event(this, EVENT_FADE_IN, 100, true, &cdda_register_id); // 100ms
1068 d_scsi_cdrom->set_volume((int)(cdda_volume = 0.0));
1071 if(cdda_register_id != -1) {
1072 cancel_event(this, cdda_register_id);
1074 register_event(this, EVENT_FADE_IN, 1500, true, &cdda_register_id); // 1500ms
1075 d_scsi_cdrom->set_volume((int)(cdda_volume = 0.0));
1078 if(cdda_register_id != -1) {
1079 cancel_event(this, cdda_register_id);
1081 register_event(this, EVENT_FADE_OUT, 100, true, &cdda_register_id); // 100ms
1082 d_scsi_cdrom->set_volume((int)(cdda_volume = 100.0));
1085 if(cdda_register_id != -1) {
1086 cancel_event(this, cdda_register_id);
1088 register_event(this, EVENT_FADE_OUT, 5000, true, &cdda_register_id); // 5000ms
1089 d_scsi_cdrom->set_volume((int)(cdda_volume = 100.0));
1095 if(cdbios_loaded && (mod & 0x10)) {
1096 update_low_memmap();
1100 #ifdef SUPPORT_PC88_SB2
1104 d_sb2->write_io8(addr, data);
1109 if(intr_req_sb2 && !PortAA_S2INTM) {
1110 request_intr(IRQ_SOUND, true);
1114 #ifdef SUPPORT_PC88_OPNA
1117 if(d_sb2 != NULL && d_sb2->is_ym2608) {
1118 d_sb2->write_io8(addr | 2, data);
1125 update_low_memmap();
1129 #ifdef PC88_IODATA_EXRAM
1134 if(PortE2_RDEN || PortE2_WREN) {
1135 update_low_memmap();
1141 intr_mask1 = ~(0xff << (data < 8 ? data : 8));
1145 // for Romancia (XM8 version 1.00)
1146 if(intr_mask2_table[data & 7] != intr_mask2) {
1147 intr_req &= (intr_mask2_table[data & 7] & intr_mask2);
1149 intr_mask2 = intr_mask2_table[data & 7];
1150 intr_req &= intr_mask2;
1153 #ifdef SUPPORT_PC88_DICTIONARY
1156 if(port[0xf0] >= 0x20) {
1157 // no effect if data >= 0x20
1163 if(port[0xf1] != 0x00 && port[0xf1] != 0x01) {
1164 // effect only 0x00 or 0x01
1173 d_pio->write_io8(addr, data);
1178 uint32_t PC88::read_io8(uint32_t addr)
1179 #ifdef _IO_DEBUG_LOG
1181 uint32_t val = read_io8_debug(addr);
1182 this->out_debug_log(_T("%06x\tIN8\t%02x = %02x\n"), d_cpu->get_pc(), addr & 0xff, val);
1186 uint32_t PC88::read_io8_debug(uint32_t addr)
1189 uint32_t val = 0xff;
1208 for(int i = 0; i < 8; i++) {
1209 if(key_status[key_table[addr & 0x0f][i]]) {
1214 val &= ~0x80; // http://www.maroon.dti.ne.jp/youkan/pc88/iomap.html
1219 return d_sio->read_io8(addr);
1220 #if defined(_PC8001SR)
1222 return (config.boot_mode == MODE_PC80_N ? 0 : 1) | (config.boot_mode == MODE_PC80_V2 ? 0 : 2) | 0xfc;
1224 return (config.boot_mode == MODE_PC80_V2 ? 0 : 0x80) | 0x39;
1229 // return (config.boot_mode == MODE_PC88_N ? 0 : 1) | 0xca; // 80x20 (XM8 version 1.00)
1230 return (config.boot_mode == MODE_PC88_N ? 0 : 1) | 0xc2; // 80x25
1233 return (config.boot_mode == MODE_PC88_V2 ? 0 : 0x80) | (config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N ? 0 : 0x40) | 0x39;
1234 // return (config.boot_mode == MODE_PC88_V2 ? 0 : 0x80) | (config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N ? 0 : 0x40);
1240 // return (crtc.vblank ? 0x20 : 0) | (d_rtc->read_signal(0) ? 0x10 : 0) | (usart_dcd ? 4 : 0) | (hireso ? 0 : 2) | 0xc1;
1241 return (crtc.vblank ? 0x20 : 0) | (d_rtc->read_signal(0) ? 0x10 : 0) | (usart_dcd ? 4 : 0) | (hireso ? 0 : 2) | (d_prn->read_signal(SIG_PRINTER_BUSY) ? 1 : 0) | 0xc0;
1243 val = d_opn->read_io8(addr);
1245 // show busy flag for first access (for ALPHA)
1246 if(d_cpu->get_pc() == 0xe615) {
1253 if(Port44_OPNCH == 14) {
1254 #ifdef SUPPORT_PC88_JOYSTICK
1255 if(config.joystick_type == DEVICE_JOYSTICK) {
1256 return (~(joystick_status[0] >> 0) & 0x0f) | 0xf0;
1257 } else if(config.joystick_type == DEVICE_MOUSE) {
1258 switch(mouse_phase) {
1260 return ((mouse_lx >> 4) & 0x0f) | 0xf0;
1262 return ((mouse_lx >> 0) & 0x0f) | 0xf0;
1264 return ((mouse_ly >> 4) & 0x0f) | 0xf0;
1266 return ((mouse_ly >> 0) & 0x0f) | 0xf0;
1272 } else if(Port44_OPNCH == 15) {
1273 #ifdef SUPPORT_PC88_JOYSTICK
1274 if(config.joystick_type == DEVICE_JOYSTICK) {
1275 return (~(joystick_status[0] >> 4) & 0x03) | 0xfc;
1276 } else if(config.joystick_type == DEVICE_MOUSE) {
1277 return (~mouse_status[2] & 0x03) | 0xfc;
1282 return d_opn->read_io8(addr);
1283 #ifdef SUPPORT_PC88_OPNA
1286 if(d_opn->is_ym2608) {
1287 return d_opn->read_io8(addr);
1292 return crtc.read_param();
1294 return crtc.read_status();
1296 return gvram_plane | 0xf8;
1306 return dmac.read_io8(addr);
1309 return (cpu_clock_low ? 0x80 : 0) | (is_sr_mr() ? 0x7f : 0x10);
1312 return is_sr_mr() ? 0xff : (port[0x6f] | 0xf0);
1313 #if !defined(_PC8001SR)
1315 // PC-8001mkIISR returns the constant value
1316 // this port is used to detect PC-8001mkIISR or 8801mkIISR
1321 #ifdef SUPPORT_PC88_HMB20
1324 return d_opm->read_io8(addr);
1326 #ifdef SUPPORT_PC88_CDROM
1330 val = d_scsi_host->read_signal(SIG_SCSI_BSY) ? 0x80 : 0;
1331 val |= d_scsi_host->read_signal(SIG_SCSI_REQ) ? 0x40 : 0;
1332 val |= d_scsi_host->read_signal(SIG_SCSI_MSG) ? 0x20 : 0;
1333 val |= d_scsi_host->read_signal(SIG_SCSI_CD ) ? 0x10 : 0;
1334 val |= d_scsi_host->read_signal(SIG_SCSI_IO ) ? 0x08 : 0;
1335 // do not show BSY,MSG,CxD,IxD when SEL=1 (
\90M
\92·
\82Ì
\96ì
\96]
\95\90\8f«
\95\97\89_
\98^)
1336 if(port[0x90] & 0x01) {
1337 val &= ~(0x80 | 0x20 | 0x10 | 0x08);
1338 val |= (port[0x9f] & 0x01); // correct ???
1340 #ifdef _SCSI_DEBUG_LOG
1341 this->out_debug_log(_T("[SCSI_PC88] Status = %02X\n"), val);
1348 return d_scsi_host->read_dma_io8(0);
1360 // return 0xcd; // PC-8801MC
1366 port[0x98] ^= 0x80; // clock ???
1377 #ifdef SUPPORT_PC88_SB2
1380 return d_sb2->read_io8(addr);
1385 if(PortA8_OPNCH == 14) {
1386 #ifdef SUPPORT_PC88_JOYSTICK
1387 if(config.joystick_type == DEVICE_JOYSTICK) {
1388 return (~(joystick_status[0] >> 0) & 0x0f) | 0xf0;
1389 } else if(config.joystick_type == DEVICE_MOUSE) {
1390 switch(mouse_phase) {
1392 return ((mouse_lx >> 4) & 0x0f) | 0xf0;
1394 return ((mouse_lx >> 0) & 0x0f) | 0xf0;
1396 return ((mouse_ly >> 4) & 0x0f) | 0xf0;
1398 return ((mouse_ly >> 0) & 0x0f) | 0xf0;
1404 } else if(PortA8_OPNCH == 15) {
1405 #ifdef SUPPORT_PC88_JOYSTICK
1406 if(config.joystick_type == DEVICE_JOYSTICK) {
1407 return (~(joystick_status[0] >> 4) & 0x03) | 0xfc;
1408 } else if(config.joystick_type == DEVICE_MOUSE) {
1409 return (~mouse_status[2] & 0x03) | 0xfc;
1414 return d_sb2->read_io8(addr);
1418 return (PortAA_S2INTM) | 0x7f;
1419 #ifdef SUPPORT_PC88_OPNA
1422 if(d_sb2 != NULL && d_sb2->is_ym2608) {
1423 d_sb2->read_io8(addr | 2);
1428 #if defined(SUPPORT_PC88_VAB)
1432 if(PortE3_VAB_SEL) {
1438 return (~port[0xe2]) | 0xee;
1440 #ifdef PC88_IODATA_EXRAM
1443 return port[0xe3] | 0xf0;
1446 return kanji1[PortE8E9_KANJI1 * 2 + 1];
1448 return kanji1[PortE8E9_KANJI1 * 2];
1450 return kanji2[PortECED_KANJI2 * 2 + 1];
1452 return kanji2[PortECED_KANJI2 * 2];
1456 return d_pio->read_io8(addr);
1461 uint32_t PC88::read_dma_data8(uint32_t addr)
1464 #if defined(_PC8001SR)
1465 return ram[addr & 0xffff];
1467 if((addr & 0xf000) == 0xf000 && (config.boot_mode == MODE_PC88_V1H || config.boot_mode == MODE_PC88_V2)) {
1468 return tvram[addr & 0xfff];
1470 return ram[addr & 0xffff];
1475 void PC88::write_dma_data8(uint32_t addr, uint32_t data)
1478 ram[addr & 0xffff] = data;
1481 void PC88::write_dma_io8(uint32_t addr, uint32_t data)
1484 crtc.write_buffer(data);
1487 void PC88::update_timing()
1489 int lines_per_frame = (crtc.height + crtc.vretrace) * crtc.char_height;
1490 // 56.4229Hz (25line) on PC-8801MA2 (XM8 version 1.00)
1491 double frames_per_sec = (hireso ? 24860.0 * 56.423 / 56.5 : 15980.0) / (double)lines_per_frame;
1492 // double frames_per_sec = (hireso ? 24860.0 * 56.424 / 56.5 : 15980.0) / (double)lines_per_frame;
1494 set_frames_per_sec(frames_per_sec);
1495 set_lines_per_frame(lines_per_frame);
1498 int PC88::get_m1_wait(bool addr_f000)
1503 #if defined(_PC8001SR)
1504 if(config.boot_mode == MODE_PC80_V1 || config.boot_mode == MODE_PC80_N) {
1506 if(config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N) {
1510 // memory wait = off
1522 if(!gvram_sel && !Port32_TMODE) {
1534 int PC88::get_main_wait(bool read)
1543 // memory wait + read
1549 #if !defined(_PC8001SR)
1550 if(!cpu_clock_high_fe2) {
1556 // memory wait (read and write)
1563 int PC88::get_tvram_wait(bool read)
1571 // memory wait + read
1576 // 8MHz -> memory wait do not effect
1588 int PC88::get_gvram_wait(bool read)
1597 #if defined(_PC8001SR)
1598 if(config.boot_mode == MODE_PC80_V1 || config.boot_mode == MODE_PC80_N) {
1600 if(config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N) {
1603 if(!Port40_GHSM && !crtc.vblank) {
1604 // V1S + not GHSM, V-DISP
1628 #if defined(_PC8001SR)
1629 if(config.boot_mode == MODE_PC80_V1 || config.boot_mode == MODE_PC80_N) {
1631 if(config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N) {
1634 if(!Port40_GHSM && !crtc.vblank) {
1635 // V1S + not GHSM, V-DISP
1663 // memory wait + read
1668 // 8MHz -> memory wait do not effect
1675 void PC88::update_gvram_wait()
1677 gvram_wait_clocks_r = get_gvram_wait(true);
1678 gvram_wait_clocks_w = get_gvram_wait(false);
1681 void PC88::update_gvram_sel()
1683 #if defined(_PC8001SR)
1693 gvram_plane = 0; // from M88
1695 gvram_sel = gvram_plane;
1697 f000_m1_wait_clocks = get_m1_wait(true);
1700 #if defined(_PC8001SR)
1701 void PC88::update_n80_write()
1703 if(PortE2_WREN || Port31_MMODE) {
1704 if(PortE3_ERAMSL < PC88_EXRAM_BANKS) {
1705 SET_BANK_W(0x0000, 0x7fff, exram + 0x8000 * PortE3_ERAMSL);
1707 SET_BANK_W(0x0000, 0x7fff, exram);
1710 SET_BANK_W(0x0000, 0x7fff, wdmy);
1714 void PC88::update_n80_read()
1716 if(PortE2_RDEN || Port31_MMODE) {
1717 if(PortE3_ERAMSL < PC88_EXRAM_BANKS) {
1718 SET_BANK_R(0x0000, 0x7fff, exram + 0x8000 * PortE3_ERAMSL);
1720 SET_BANK_R(0x0000, 0x7fff, exram);
1722 } else if(Port33_N80SR) {
1723 if(port[0x71] & 1) {
1724 SET_BANK_R(0x0000, 0x7fff, n80mk2srrom);
1726 SET_BANK_R(0x0000, 0x5fff, n80mk2srrom);
1727 SET_BANK_R(0x6000, 0x7fff, n80mk2srrom + 0x8000);
1730 if(port[0x31] & 1) {
1731 SET_BANK_R(0x0000, 0x7fff, n80mk2rom);
1733 SET_BANK_R(0x0000, 0x5fff, n80mk2rom);
1734 SET_BANK_R(0x6000, 0x7fff, rdmy);
1739 void PC88::update_low_memmap()
1743 #ifdef PC88_EXRAM_BANKS
1744 if(PortE3_ERAMSL < PC88_EXRAM_BANKS) {
1745 SET_BANK_R(0x0000, 0x7fff, exram + 0x8000 * PortE3_ERAMSL);
1748 // SET_BANK_R(0x0000, 0x7fff, rdmy);
1749 #ifdef PC88_EXRAM_BANKS
1752 } else if(Port31_MMODE) {
1754 SET_BANK_R(0x0000, 0x7fff, ram);
1755 #ifdef SUPPORT_PC88_CDROM
1756 } else if(cdbios_loaded && Port99_CDREN) {
1758 SET_BANK_R(0x0000, 0x7fff, cdbios + 0x8000);
1760 SET_BANK_R(0x0000, 0x7fff, cdbios + 0x0000);
1763 } else if(Port31_RMODE) {
1765 SET_BANK_R(0x0000, 0x7fff, n80rom);
1768 SET_BANK_R(0x0000, 0x5fff, n88rom);
1769 if(Port71_EROM & 1) {
1770 SET_BANK_R(0x6000, 0x7fff, n88rom + 0x6000);
1772 SET_BANK_R(0x6000, 0x7fff, n88exrom + 0x2000 * Port32_EROMSL);
1778 #ifdef PC88_EXRAM_BANKS
1779 if(PortE3_ERAMSL < PC88_EXRAM_BANKS) {
1780 SET_BANK_W(0x0000, 0x7fff, exram + 0x8000 * PortE3_ERAMSL);
1783 // SET_BANK_W(0x0000, 0x7fff, wdmy);
1784 SET_BANK_W(0x0000, 0x7fff, ram);
1785 #ifdef PC88_EXRAM_BANKS
1789 SET_BANK_W(0x0000, 0x7fff, ram);
1793 void PC88::update_tvram_memmap()
1796 if(config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N || Port32_TMODE) {
1797 SET_BANK(0xf000, 0xffff, ram + 0xf000, ram + 0xf000);
1799 SET_BANK(0xf000, 0xffff, tvram, tvram);
1804 void PC88::write_signal(int id, uint32_t data, uint32_t mask)
1806 if(id == SIG_PC88_USART_IRQ) {
1807 request_intr(IRQ_USART, ((data & mask) != 0));
1808 } else if(id == SIG_PC88_SOUND_IRQ) {
1809 intr_req_sound = ((data & mask) != 0);
1810 #if defined(_PC8001SR)
1811 if(intr_req_sound && !Port33_SINTM) {
1813 if(intr_req_sound && !Port32_SINTM) {
1815 request_intr(IRQ_SOUND, true);
1817 #ifdef SUPPORT_PC88_SB2
1818 } else if(id == SIG_PC88_SB2_IRQ) {
1819 intr_req_sb2 = ((data & mask) != 0);
1820 if(intr_req_sb2 && !PortAA_S2INTM) {
1821 request_intr(IRQ_SOUND, true);
1824 #ifdef SUPPORT_PC88_CDROM
1825 } else if(id == SIG_PC88_SCSI_DRQ) {
1826 if((data & mask) && cdbios_loaded) {
1827 if(!dmac.ch[1].running) {
1830 if(dmac.ch[1].running) {
1835 } else if(id == SIG_PC88_USART_OUT) {
1839 if(cmt_rec && Port30_MTON) {
1840 cmt_buffer[cmt_bufptr++] = data & mask;
1841 if(cmt_bufptr >= CMT_BUFFER_SIZE) {
1842 cmt_fio->Fwrite(cmt_buffer, cmt_bufptr, 1);
1852 void PC88::event_callback(int event_id, int err)
1856 request_intr(IRQ_TIMER, true);
1859 d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 0);
1861 case EVENT_CMT_SEND:
1862 // check data carrier
1863 if(cmt_play && cmt_bufptr < cmt_bufcnt && Port30_MTON) {
1864 // detect the data carrier at the top of next block
1865 if(check_data_carrier()) {
1866 register_event(this, EVENT_CMT_DCD, 1000000, false, &cmt_register_id);
1874 if(cmt_play && cmt_bufptr < cmt_bufcnt && Port30_MTON) {
1875 d_sio->write_signal(SIG_I8251_RECV, cmt_buffer[cmt_bufptr++], 0xff);
1876 if(cmt_bufptr < cmt_bufcnt) {
1877 register_event(this, EVENT_CMT_SEND, 5000, false, &cmt_register_id);
1881 usart_dcd = true; // Jackie Chan no Spartan X
1882 cmt_register_id = -1;
1885 beep_signal = !beep_signal;
1886 d_pcm->write_signal(SIG_PCM1BIT_SIGNAL, ((beep_on && beep_signal) || sing_signal) ? 1 : 0, 1);
1888 #ifdef SUPPORT_PC88_CDROM
1890 if((cdda_volume += 0.1) >= 100.0) {
1891 cancel_event(this, cdda_register_id);
1892 cdda_register_id = -1;
1893 cdda_volume = 100.0;
1895 d_scsi_cdrom->set_volume((int)cdda_volume);
1897 case EVENT_FADE_OUT:
1898 if((cdda_volume -= 0.1) <= 0) {
1899 cancel_event(this, cdda_register_id);
1900 cdda_register_id = -1;
1903 d_scsi_cdrom->set_volume((int)cdda_volume);
1909 void PC88::event_frame()
1911 // update key status
1912 memcpy(key_status, emu->get_key_buffer(), sizeof(key_status));
1914 for(int i = 0; i < array_length(key_conv_table); i++) {
1915 // INS or F6-F10 -> SHIFT + DEL or F1-F5
1916 if(key_status[key_conv_table[i][0]]) {
1917 key_status[key_conv_table[i][1]] = 1;
1918 key_status[0x10] |= key_conv_table[i][2];
1921 if(key_status[0x11] && (key_status[0xbc] || key_status[0xbe])) {
1922 // CTRL + "," or "." -> NumPad "," or "."
1923 key_status[0x6c] = key_status[0xbc];
1924 key_status[0x6e] = key_status[0xbe];
1925 key_status[0x11] = key_status[0xbc] = key_status[0xbe] = 0;
1927 key_status[0x14] = key_caps;
1928 key_status[0x15] = key_kana;
1930 crtc.update_blink();
1932 #ifdef SUPPORT_PC88_JOYSTICK
1933 mouse_dx += mouse_status[0];
1934 mouse_dy += mouse_status[1];
1938 void PC88::event_vline(int v, int clock)
1940 int disp_line = crtc.height * crtc.char_height;
1943 if(crtc.status & 0x10) {
1944 // start dma transfer to crtc
1946 if(!dmac.ch[2].running) {
1947 // dma underrun occurs !!!
1949 // crtc.status &= ~0x10;
1954 // from memory access test on PC-8801MA2 (XM8 version 1.20)
1955 busreq_clocks = (int)((double)(dmac.ch[2].count.sd + 1) * (cpu_clock_low ? 5.95 : 10.58) / (double)disp_line + 0.5);
1956 // busreq_clocks = (int)((double)(dmac.ch[2].count.sd + 1) * (cpu_clock_low ? 7.0 : 16.0) / (double)disp_line + 0.5);
1959 // for Nobunaga Fuunroku Opening (XM8 version 1.00)
1960 // request_intr(IRQ_VRTC, false);
1961 update_gvram_wait();
1964 if(/*(crtc.status & 0x10) && */dmac.ch[2].running) {
1966 #if defined(_PC8001SR)
1967 if(config.boot_mode == MODE_PC80_V1 || config.boot_mode == MODE_PC80_N) {
1969 if(config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N) {
1971 d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
1972 register_event_by_clock(this, EVENT_BUSREQ, busreq_clocks, false, NULL);
1974 // run dma transfer to crtc
1975 if((v % crtc.char_height) == 0) {
1976 dmac.run(2, 80 + crtc.attrib.num * 2);
1979 } else if(v == disp_line) {
1980 if(/*(crtc.status & 0x10) && */dmac.ch[2].running) {
1982 // for Romancia (XM8 version 1.00)
1983 // crtc.expand_buffer(hireso, Port31_400LINE);
1985 // for Romancia (XM8 version 1.00)
1986 crtc.expand_buffer(hireso, Port31_400LINE);
1989 request_intr(IRQ_VRTC, true);
1990 update_gvram_wait();
1993 #if !defined(_PC8001SR)
1994 if(v < (disp_line <= 200 ? 200 : 400)) {
1998 if(update_palette) {
1999 static bool initialized = false;
2000 static palette_t initial[9] = {0};
2003 for(int i = 1; i < 8; i++) {
2004 initial[i].b = (i & 1) ? 7 : 0;
2005 initial[i].r = (i & 2) ? 7 : 0;
2006 initial[i].g = (i & 4) ? 7 : 0;
2010 for(int i = 0; i < 9; i++) {
2011 palette_digital[i] = palette_analog[i] = initial[i];
2013 #if defined(_PC8001SR)
2014 if(config.boot_mode != MODE_PC80_V2) {
2015 if(Port31_V1_320x200) {
2016 for(int i = 0; i < 3; i++) {
2017 palette_analog[i].b = (port[0x31] & 4) ? 7 : 0;
2018 palette_analog[i].r = (i & 1) ? 7 : 0;
2019 palette_analog[i].g = (i & 2) ? 7 : 0;
2021 palette_analog[3] = palette[8];
2022 } else if(Port31_V1_MONO) {
2023 // palette_analog[0] = {0, 0, 0};
2024 palette_analog[1] = palette[8];
2026 // for(int i = 1; i < 8; i++) {
2027 // palette_analog[i].b = (i & 1) ? 7 : 0;
2028 // palette_analog[i].r = (i & 2) ? 7 : 0;
2029 // palette_analog[i].g = (i & 4) ? 7 : 0;
2031 palette_analog[0] = palette[8];
2033 if(Port31_V1_320x200) {
2034 // palette_digital[0] = {0, 0, 0};
2036 palette_digital[0] = palette_analog[0];
2039 for(int i = 0; i < 8; i++) {
2040 palette_analog[i].b = (port[0x54 + i] & 1) ? 7 : 0;
2041 palette_analog[i].r = (port[0x54 + i] & 2) ? 7 : 0;
2042 palette_analog[i].g = (port[0x54 + i] & 4) ? 7 : 0;
2044 if(!Port31_HCOLOR) {
2045 palette_analog[0] = palette[8];
2047 palette_digital[0] = palette_analog[0];
2050 for(int i = 0; i < 8; i++) {
2051 palette_analog[i] = palette[i];
2053 if(!Port31_HCOLOR) {
2055 palette_analog[0] = palette[8];
2057 palette_analog[0] = palette[9];
2060 palette_digital[0] = palette_analog[0];
2064 memset(palette_line_changed, 0, sizeof(palette_line_changed));
2066 if((palette_line_changed[v] = (update_palette || v == 0)) == true) {
2067 for(int i = 0; i < 9; i++) {
2068 palette_line_digital[v][i] = palette_digital[i];
2069 palette_line_analog [v][i] = palette_analog [i];
2071 update_palette = false;
2076 void PC88::key_down(int code, bool repeat)
2081 } else if(code == 0x15) {
2087 void PC88::play_tape(const _TCHAR* file_path)
2091 if(cmt_fio->Fopen(file_path, FILEIO_READ_BINARY)) {
2092 if(check_file_extension(file_path, _T(".n80"))) {
2093 cmt_fio->Fread(ram + 0x8000, 0x7f40, 1);
2095 d_cpu->set_sp(ram[0xff3e] | (ram[0xff3f] << 8));
2096 d_cpu->set_pc(0xff3d);
2100 cmt_fio->Fseek(0, FILEIO_SEEK_END);
2101 cmt_bufcnt = cmt_fio->Ftell();
2103 cmt_data_carrier_cnt = 0;
2104 cmt_fio->Fseek(0, FILEIO_SEEK_SET);
2105 memset(cmt_buffer, 0, sizeof(cmt_buffer));
2106 cmt_fio->Fread(cmt_buffer, sizeof(cmt_buffer), 1);
2109 if(strncmp((char *)cmt_buffer, "PC-8801 Tape Image(T88)", 23) == 0) {
2110 // this is t88 format
2111 int ptr = 24, tag = -1, len = 0, prev_bufptr = 0;
2112 while(!(tag == 0 && len == 0)) {
2113 tag = cmt_buffer[ptr + 0] | (cmt_buffer[ptr + 1] << 8);
2114 len = cmt_buffer[ptr + 2] | (cmt_buffer[ptr + 3] << 8);
2119 for(int i = 12; i < len; i++) {
2120 cmt_buffer[cmt_bufptr++] = cmt_buffer[ptr + i];
2122 } else if(tag == 0x0102 || tag == 0x0103) {
2124 if(prev_bufptr != cmt_bufptr) {
2125 cmt_data_carrier[cmt_data_carrier_cnt++] = prev_bufptr = cmt_bufptr;
2130 cmt_bufcnt = cmt_bufptr;
2133 cmt_play = (cmt_bufcnt != 0);
2135 if(cmt_play && Port30_MTON) {
2136 // start motor and detect the data carrier at the top of tape
2137 if(cmt_register_id != -1) {
2138 cancel_event(this, cmt_register_id);
2140 register_event(this, EVENT_CMT_SEND, 5000, false, &cmt_register_id);
2145 void PC88::rec_tape(const _TCHAR* file_path)
2149 if(cmt_fio->Fopen(file_path, FILEIO_READ_WRITE_NEW_BINARY)) {
2150 my_tcscpy_s(rec_file_path, _MAX_PATH, file_path);
2156 void PC88::close_tape()
2162 d_sio->write_signal(SIG_I8251_CLEAR, 0, 0);
2165 void PC88::release_tape()
2168 if(cmt_fio->IsOpened()) {
2169 if(cmt_rec && cmt_bufptr) {
2170 cmt_fio->Fwrite(cmt_buffer, cmt_bufptr, 1);
2174 cmt_play = cmt_rec = false;
2177 bool PC88::is_frame_skippable()
2179 return (cmt_play && cmt_bufptr < cmt_bufcnt && Port30_MTON);
2182 bool PC88::check_data_carrier()
2184 if(cmt_bufptr == 0) {
2186 } else if(cmt_data_carrier_cnt) {
2187 for(int i = 0; i < cmt_data_carrier_cnt; i++) {
2188 if(cmt_data_carrier[i] == cmt_bufptr) {
2192 } else if(cmt_buffer[cmt_bufptr] == 0xd3) {
2193 for(int i = 1; i < 10; i++) {
2194 if(cmt_buffer[cmt_bufptr + i] != cmt_buffer[cmt_bufptr]) {
2199 } else if(cmt_buffer[cmt_bufptr] == 0x9c) {
2200 for(int i = 1; i < 6; i++) {
2201 if(cmt_buffer[cmt_bufptr + i] != cmt_buffer[cmt_bufptr]) {
2210 void PC88::draw_screen()
2212 // render text screen
2215 // render graph screen
2216 bool disp_color_graph = true;
2217 bool draw_scanline_black = config.scan_line;
2218 #if defined(_PC8001SR)
2219 if(config.boot_mode != MODE_PC80_V2) {
2220 if(Port31_V1_320x200) {
2221 disp_color_graph = draw_320x200_4color_graph();
2222 } else if(Port31_V1_MONO) {
2223 draw_640x200_mono_graph();
2226 draw_scanline_black = false;
2228 draw_640x200_attrib_graph();
2230 emu->set_vm_screen_lines(200);
2233 if(Port31_320x200) {
2234 disp_color_graph = draw_320x200_color_graph();
2236 disp_color_graph = draw_640x200_color_graph();
2238 emu->set_vm_screen_lines(200);
2240 if(Port31_320x200) {
2241 draw_320x200_attrib_graph();
2243 draw_640x200_attrib_graph();
2246 draw_scanline_black = false;
2248 emu->set_vm_screen_lines(200);
2253 disp_color_graph = draw_640x200_color_graph();
2254 emu->set_vm_screen_lines(200);
2255 } else if(!Port31_400LINE) {
2257 draw_scanline_black = false;
2259 draw_640x200_attrib_graph();
2260 // draw_640x200_mono_graph();
2261 emu->set_vm_screen_lines(200);
2264 draw_scanline_black = false;
2266 draw_640x400_attrib_graph();
2267 // draw_640x400_mono_graph();
2268 emu->set_vm_screen_lines(400);
2272 // create palette for each scanline
2273 #if !defined(_PC8001SR)
2274 int disp_line = crtc.height * crtc.char_height;
2275 int ymax = (disp_line <= 200) ? 200 : 400;
2279 static const uint32_t pex[8] = {
2280 0, 36, 73, 109, 146, 182, 219, 255 // from m88
2282 scrntype_t palette_digital_text_pc [9];
2283 scrntype_t palette_analog_text_pc [9];
2284 scrntype_t palette_digital_graph_pc[9];
2285 scrntype_t palette_analog_graph_pc [9];
2287 scrntype_t palette_line_digital_text_pc [400][9];
2288 scrntype_t palette_line_analog_graph_pc [400][9];
2289 #if !defined(_PC8001SR)
2290 scrntype_t palette_line_analog_text_pc [400][9];
2291 scrntype_t palette_line_digital_graph_pc[400][9];
2294 for(int y = 0; y < ymax; y++) {
2295 if(palette_line_changed[y]) {
2296 for(int i = 0; i < 9; i++) {
2297 // A is a flag for crt filter
2298 palette_digital_text_pc [i] = RGBA_COLOR(pex[palette_line_digital[y][i].r], pex[palette_line_digital[y][i].g], pex[palette_line_digital[y][i].b], 255);
2299 palette_analog_text_pc [i] = RGBA_COLOR(pex[palette_line_analog [y][i].r], pex[palette_line_analog [y][i].g], pex[palette_line_analog [y][i].b], 255);
2300 palette_digital_graph_pc[i] = RGBA_COLOR(pex[palette_line_digital[y][i].r], pex[palette_line_digital[y][i].g], pex[palette_line_digital[y][i].b], 0);
2301 palette_analog_graph_pc [i] = RGBA_COLOR(pex[palette_line_analog [y][i].r], pex[palette_line_analog [y][i].g], pex[palette_line_analog [y][i].b], 0);
2303 // set back color to black if cg screen is off in color mode
2304 if(!disp_color_graph) {
2305 palette_digital_text_pc [0] =
2306 palette_analog_text_pc [0] =
2307 palette_digital_graph_pc[0] =
2308 palette_analog_graph_pc [0] = 0;
2310 palette_analog_text_pc [8] = palette_digital_text_pc [0];
2311 palette_analog_graph_pc[8] = palette_digital_graph_pc[0];
2314 for(int i = 0; i < 9; i++) {
2315 palette_line_digital_text_pc [2 * y ][i] =
2316 palette_line_digital_text_pc [2 * y + 1][i] = palette_digital_text_pc [i];
2317 palette_line_analog_graph_pc [2 * y ][i] =
2318 palette_line_analog_graph_pc [2 * y + 1][i] = palette_analog_graph_pc [i];
2319 #if !defined(_PC8001SR)
2320 palette_line_analog_text_pc [2 * y ][i] =
2321 palette_line_analog_text_pc [2 * y + 1][i] = palette_analog_text_pc [i];
2322 palette_line_digital_graph_pc[2 * y ][i] =
2323 palette_line_digital_graph_pc[2 * y + 1][i] = palette_digital_graph_pc[i];
2327 for(int i = 0; i < 9; i++) {
2328 palette_line_digital_text_pc [y][i] = palette_digital_text_pc [i];
2329 palette_line_analog_graph_pc [y][i] = palette_analog_graph_pc [i];
2330 #if !defined(_PC8001SR)
2331 palette_line_analog_text_pc [y][i] = palette_analog_text_pc [i];
2332 palette_line_digital_graph_pc[y][i] = palette_digital_graph_pc[i];
2338 // copy to screen buffer
2339 #if !defined(_PC8001SR)
2340 #if defined(SUPPORT_PC88_VAB)
2342 if(PortB4_VAB_DISP) {
2343 uint8_t *src = &exram[(0x8000 * 4) * PC88_VAB_PAGE];
2345 for(int y = 0; y < 400; y += 2) {
2346 scrntype_t* dest0 = emu->get_screen_buffer(y);
2347 scrntype_t* dest1 = emu->get_screen_buffer(y + 1);
2349 for(int x = 0; x < 640; x += 2) {
2353 dest0[x] = dest0[x + 1] = palette_vab_pc[c.w];
2355 if(config.scan_line) {
2356 memset(dest1, 0, sizeof(scrntype_t) * 640);
2358 memcpy(dest1, dest0, sizeof(scrntype_t) * 640);
2361 emu->screen_skip_line(true);
2364 if(!Port31_HCOLOR && Port31_400LINE) {
2365 for(int y = 0; y < 400; y++) {
2366 scrntype_t* dest = emu->get_screen_buffer(y);
2367 uint8_t* src_t = text[y >> 1];
2368 uint8_t* src_g = graph[y];
2372 // if(Port31_HCOLOR) {
2373 // pal_t = palette_line_digital_text_pc [y];
2374 // pal_g = palette_line_analog_graph_pc [y];
2377 pal_t = palette_line_analog_text_pc [y];
2378 pal_g = palette_line_analog_graph_pc [y];
2380 pal_t = palette_line_digital_text_pc [y];
2381 pal_g = palette_line_digital_graph_pc[y];
2383 for(int x = 0; x < 640; x++) {
2384 uint32_t t = src_t[x];
2385 dest[x] = t ? pal_t[t] : pal_g[src_g[x]];
2388 emu->screen_skip_line(false);
2392 for(int y = 0; y < 400; y++) {
2393 scrntype_t* dest = emu->get_screen_buffer(y);
2394 uint8_t* src_t = text[y >> 1];
2395 uint8_t* src_g = graph[y];
2398 #if defined(_PC8001SR)
2399 pal_t = palette_line_digital_text_pc[y];
2400 pal_g = palette_line_analog_graph_pc[y];
2402 if(port[0x33] & 8) {
2403 for(int x = 0; x < 640; x++) {
2404 uint32_t t = src_t[x];
2405 uint32_t g = src_g[x];
2406 dest[x] = (!g && t) ? pal_t[t] : ((y & 1) && draw_scanline_black) ? 0 : pal_g[g];
2409 for(int x = 0; x < 640; x++) {
2410 uint32_t t = src_t[x];
2411 dest[x] = t ? pal_t[t] : ((y & 1) && draw_scanline_black) ? 0 : pal_g[src_g[x]];
2416 pal_t = palette_line_digital_text_pc [y];
2417 pal_g = palette_line_analog_graph_pc [y];
2418 } else if(Port32_PMODE) {
2419 pal_t = palette_line_analog_text_pc [y];
2420 pal_g = palette_line_analog_graph_pc [y];
2422 pal_t = palette_line_digital_text_pc [y];
2423 pal_g = palette_line_digital_graph_pc[y];
2425 for(int x = 0; x < 640; x++) {
2426 uint32_t t = src_t[x];
2427 dest[x] = t ? pal_t[t] : ((y & 1) && draw_scanline_black) ? 0 : pal_g[src_g[x]];
2431 emu->screen_skip_line(true);
2441 bit4: graph=1/character=0
2448 void PC88::draw_text()
2450 if(crtc.status & 0x88) {
2452 crtc.status &= ~0x80;
2453 memset(crtc.text.expand, 0, 200 * 80);
2454 memset(crtc.attrib.expand, crtc.reverse ? 3 : 2, 200 * 80);
2456 // for Advanced Fantasian Opening (20line) (XM8 version 1.00)
2457 if(!(crtc.status & 0x10) || Port53_TEXTDS) {
2458 // if(!(crtc.status & 0x10) || (crtc.status & 8) || Port53_TEXTDS) {
2459 memset(crtc.text.expand, 0, 200 * 80);
2460 for(int y = 0; y < 200; y++) {
2461 for(int x = 0; x < 80; x++) {
2462 crtc.attrib.expand[y][x] &= 0xe0;
2463 crtc.attrib.expand[y][x] |= 0x02;
2466 // memset(crtc.attrib.expand, 2, 200 * 80);
2470 memset(text, 8, sizeof(text));
2471 memset(text_color, 7, sizeof(text_color));
2472 memset(text_reverse, 0, sizeof(text_reverse));
2474 int char_height = crtc.char_height;
2475 uint8_t color_mask = Port30_COLOR ? 0 : 7;
2476 uint8_t code_expand, attr_expand;
2481 // if(Port31_400LINE || !crtc.skip_line) {
2482 // char_height >>= 1;
2484 if(crtc.skip_line) {
2487 // for(int cy = 0, ytop = 0; cy < 64 && ytop < 400; cy++, ytop += char_height) {
2488 for(int cy = 0, ytop = 0; cy < crtc.height && ytop < 400; cy++, ytop += char_height) {
2489 for(int x = 0, cx = 0; cx < crtc.width; x += 8, cx++) {
2490 if(Port30_40 && (cx & 1)) {
2491 // don't update code/attrib
2493 code_expand = crtc.text.expand[cy][cx];
2494 attr_expand = crtc.attrib.expand[cy][cx];
2496 uint8_t attrib = attr_expand;//crtc.attrib.expand[cy][cx];
2497 // uint8_t color = !(Port30_COLOR && (attrib & 8)) ? 7 : (attrib & 0xe0) ? (attrib >> 5) : 8;
2498 uint8_t color = (attrib & 0xe0) ? ((attrib >> 5) | color_mask) : 8;
2499 bool under_line = ((attrib & 8) != 0);
2500 bool upper_line = ((attrib & 4) != 0);
2501 bool secret = ((attrib & 2) != 0);
2502 bool reverse = ((attrib & 1) != 0);
2504 uint8_t color_tmp = color;
2505 bool reverse_tmp = reverse;
2507 // from ePC-8801MA
\89ü
2508 if(Port31_GRAPH && !Port31_HCOLOR) {
2514 uint8_t code = secret ? 0 : code_expand;//crtc.text.expand[cy][cx];
2515 #ifdef SUPPORT_PC88_PCG8100
2516 uint8_t *pattern = ((attrib & 0x10) ? sg_pattern : pcg_pattern) + code * 8;
2518 uint8_t *pattern = ((attrib & 0x10) ? sg_pattern : kanji1 + 0x1000) + code * 8;
2521 for(int l = 0, y = ytop; l < char_height / 2 && y < 400; l++, y += 2) {
2522 uint8_t pat = (l < 8) ? pattern[l] : 0;
2525 // from ePC-8801MA
\89ü
2526 static const uint8_t wct[16] = {
2527 0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff
2529 pat = wct[(cx & 1) ? (pat & 0x0f) : (pat >> 4)];
2531 if((upper_line && l == 0) || (under_line && l >= 7)) {
2537 uint8_t *dest = &text[y >> 1][x];
2538 dest[0] = (pat & 0x80) ? color : 0;
2539 dest[1] = (pat & 0x40) ? color : 0;
2540 dest[2] = (pat & 0x20) ? color : 0;
2541 dest[3] = (pat & 0x10) ? color : 0;
2542 dest[4] = (pat & 0x08) ? color : 0;
2543 dest[5] = (pat & 0x04) ? color : 0;
2544 dest[6] = (pat & 0x02) ? color : 0;
2545 dest[7] = (pat & 0x01) ? color : 0;
2547 // store text attributes for monocolor graph screen
2548 text_color[y >> 1][cx] = color_tmp;
2549 text_reverse[y >> 1][cx] = reverse_tmp;
2555 #if defined(_PC8001SR)
2556 bool PC88::draw_320x200_color_graph()
2558 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS)) {
2559 memset(graph, 0, sizeof(graph));
2562 uint8_t *gvram_b0 = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2563 uint8_t *gvram_r0 = Port53_G0DS ? gvram_null : (gvram + 0x4000);
2564 uint8_t *gvram_g0 = Port53_G0DS ? gvram_null : (gvram + 0x8000);
2565 uint8_t *gvram_b1 = Port53_G1DS ? gvram_null : (gvram + 0x2000);
2566 uint8_t *gvram_r1 = Port53_G1DS ? gvram_null : (gvram + 0x6000);
2567 uint8_t *gvram_g1 = Port53_G1DS ? gvram_null : (gvram + 0xa000);
2569 if(port[0x33] & 4) {
2572 tmp = gvram_b0; gvram_b0 = gvram_b1; gvram_b1 = tmp;
2573 tmp = gvram_r0; gvram_r0 = gvram_r1; gvram_r1 = tmp;
2574 tmp = gvram_g0; gvram_g0 = gvram_g1; gvram_g1 = tmp;
2577 for(int y = 0, addr = 0; y < 400; y += 2) {
2578 for(int x = 0; x < 640; x += 16) {
2579 uint8_t b0 = gvram_b0[addr];
2580 uint8_t r0 = gvram_r0[addr];
2581 uint8_t g0 = gvram_g0[addr];
2582 uint8_t b1 = gvram_b1[addr];
2583 uint8_t r1 = gvram_r1[addr];
2584 uint8_t g1 = gvram_g1[addr];
2586 uint8_t *dest = &graph[y][x];
2588 brg0 = ((b0 & 0x80) >> 7) | ((r0 & 0x80) >> 6) | ((g0 & 0x80) >> 5);
2589 brg1 = ((b1 & 0x80) >> 7) | ((r1 & 0x80) >> 6) | ((g1 & 0x80) >> 5);
2590 dest[ 0] = dest[ 1] = brg0 ? brg0 : brg1;
2591 brg0 = ((b0 & 0x40) >> 6) | ((r0 & 0x40) >> 5) | ((g0 & 0x40) >> 4);
2592 brg1 = ((b1 & 0x40) >> 6) | ((r1 & 0x40) >> 5) | ((g1 & 0x40) >> 4);
2593 dest[ 2] = dest[ 3] = brg0 ? brg0 : brg1;
2594 brg0 = ((b0 & 0x20) >> 5) | ((r0 & 0x20) >> 4) | ((g0 & 0x20) >> 3);
2595 brg1 = ((b1 & 0x20) >> 5) | ((r1 & 0x20) >> 4) | ((g1 & 0x20) >> 3);
2596 dest[ 4] = dest[ 5] = brg0 ? brg0 : brg1;
2597 brg0 = ((b0 & 0x10) >> 4) | ((r0 & 0x10) >> 3) | ((g0 & 0x10) >> 2);
2598 brg1 = ((b1 & 0x10) >> 4) | ((r1 & 0x10) >> 3) | ((g1 & 0x10) >> 2);
2599 dest[ 6] = dest[ 7] = brg0 ? brg0 : brg1;
2600 brg0 = ((b0 & 0x08) >> 3) | ((r0 & 0x08) >> 2) | ((g0 & 0x08) >> 1);
2601 brg1 = ((b1 & 0x08) >> 3) | ((r1 & 0x08) >> 2) | ((g1 & 0x08) >> 1);
2602 dest[ 8] = dest[ 9] = brg0 ? brg0 : brg1;
2603 brg0 = ((b0 & 0x04) >> 2) | ((r0 & 0x04) >> 1) | ((g0 & 0x04) );
2604 brg1 = ((b1 & 0x04) >> 2) | ((r1 & 0x04) >> 1) | ((g1 & 0x04) );
2605 dest[10] = dest[11] = brg0 ? brg0 : brg1;
2606 brg0 = ((b0 & 0x02) >> 1) | ((r0 & 0x02) ) | ((g0 & 0x02) << 1);
2607 brg1 = ((b1 & 0x02) >> 1) | ((r1 & 0x02) ) | ((g1 & 0x02) << 1);
2608 dest[12] = dest[13] = brg0 ? brg0 : brg1;
2609 brg0 = ((b0 & 0x01) ) | ((r0 & 0x01) << 1) | ((g0 & 0x01) << 2);
2610 brg1 = ((b1 & 0x01) ) | ((r1 & 0x01) << 1) | ((g1 & 0x01) << 2);
2611 dest[14] = dest[15] = brg0 ? brg0 : brg1;
2613 if(config.scan_line) {
2614 memset(graph[y + 1], 0, 640);
2616 memcpy(graph[y + 1], graph[y], 640);
2622 bool PC88::draw_320x200_4color_graph()
2624 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS && Port53_G2DS)) {
2625 memset(graph, 0, sizeof(graph));
2628 uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2629 uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2630 uint8_t *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
2632 for(int y = 0, addr = 0; y < 400; y += 2) {
2633 for(int x = 0; x < 640; x += 8) {
2634 uint8_t brg = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
2636 uint8_t *dest = &graph[y][x];
2637 dest[0] = dest[1] = (brg >> 6) & 3;
2638 dest[2] = dest[3] = (brg >> 4) & 3;
2639 dest[4] = dest[5] = (brg >> 2) & 3;
2640 dest[6] = dest[7] = (brg ) & 3;
2642 if(config.scan_line) {
2643 memset(graph[y + 1], 0, 640);
2645 memcpy(graph[y + 1], graph[y], 640);
2651 void PC88::draw_320x200_attrib_graph()
2653 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS && Port53_G2DS && Port53_G3DS && Port53_G4DS && Port53_G5DS)) {
2654 memset(graph, 0, sizeof(graph));
2657 uint8_t *gvram_b0 = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2658 uint8_t *gvram_r0 = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2659 uint8_t *gvram_g0 = Port53_G2DS ? gvram_null : (gvram + 0x8000);
2660 uint8_t *gvram_b1 = Port53_G3DS ? gvram_null : (gvram + 0x2000);
2661 uint8_t *gvram_r1 = Port53_G4DS ? gvram_null : (gvram + 0x6000);
2662 uint8_t *gvram_g1 = Port53_G5DS ? gvram_null : (gvram + 0xa000);
2665 for(int y = 0, addr = 0; y < 400; y += 2) {
2666 for(int x = 0, cx = 0; x < 640; x += 16, cx += 2) {
2667 uint8_t color = text_color[y >> 1][cx];
2668 uint8_t brg0 = gvram_b0[addr] | gvram_r0[addr] | gvram_g0[addr] |
2669 gvram_b1[addr] | gvram_r1[addr] | gvram_g1[addr];
2671 if(text_reverse[y >> 1][cx]) {
2676 uint8_t *dest0 = &graph[y ][x];
2677 uint8_t *dest1 = &graph[y + 1][x];
2678 dest0[ 0] = dest0[ 1] = (brg0 & 0x80) ? color : 0;
2679 dest0[ 2] = dest0[ 3] = (brg0 & 0x40) ? color : 0;
2680 dest0[ 4] = dest0[ 5] = (brg0 & 0x20) ? color : 0;
2681 dest0[ 6] = dest0[ 7] = (brg0 & 0x10) ? color : 0;
2682 dest0[ 8] = dest0[ 9] = (brg0 & 0x08) ? color : 0;
2683 dest0[10] = dest0[11] = (brg0 & 0x04) ? color : 0;
2684 dest0[12] = dest0[13] = (brg0 & 0x02) ? color : 0;
2685 dest0[14] = dest0[15] = (brg0 & 0x01) ? color : 0;
2686 if(!hireso) continue;
2687 dest1[ 0] = dest1[ 1] = (brg1 & 0x80) ? color : 0;
2688 dest1[ 2] = dest1[ 3] = (brg1 & 0x40) ? color : 0;
2689 dest1[ 4] = dest1[ 5] = (brg1 & 0x20) ? color : 0;
2690 dest1[ 6] = dest1[ 7] = (brg1 & 0x10) ? color : 0;
2691 dest1[ 8] = dest1[ 9] = (brg1 & 0x08) ? color : 0;
2692 dest1[10] = dest1[11] = (brg1 & 0x04) ? color : 0;
2693 dest1[12] = dest1[13] = (brg1 & 0x02) ? color : 0;
2694 dest1[14] = dest1[15] = (brg1 & 0x01) ? color : 0;
2697 if(config.scan_line) {
2698 memset(graph[y + 1], 0, 640);
2700 memcpy(graph[y + 1], graph[y], 640);
2705 for(int y = 0, addr = 0; y < 400; y += 2) {
2706 for(int x = 0, cx = 0; x < 640; x += 16, cx += 2) {
2707 uint8_t color_l = text_color[y >> 1][cx + 0];
2708 uint8_t color_r = text_color[y >> 1][cx + 1];
2709 uint8_t brg0 = gvram_b0[addr] | gvram_r0[addr] | gvram_g0[addr] |
2710 gvram_b1[addr] | gvram_r1[addr] | gvram_g1[addr];
2712 if(text_reverse[y >> 1][cx + 0]) {
2716 if(text_reverse[y >> 1][cx + 1]) {
2721 uint8_t *dest0 = &graph[y ][x];
2722 uint8_t *dest1 = &graph[y + 1][x];
2723 dest0[ 0] = dest0[ 1] = (brg0 & 0x80) ? color_l : 0;
2724 dest0[ 2] = dest0[ 3] = (brg0 & 0x40) ? color_l : 0;
2725 dest0[ 4] = dest0[ 5] = (brg0 & 0x20) ? color_l : 0;
2726 dest0[ 6] = dest0[ 7] = (brg0 & 0x10) ? color_l : 0;
2727 dest0[ 8] = dest0[ 9] = (brg0 & 0x08) ? color_r : 0;
2728 dest0[10] = dest0[11] = (brg0 & 0x04) ? color_r : 0;
2729 dest0[12] = dest0[13] = (brg0 & 0x02) ? color_r : 0;
2730 dest0[14] = dest0[15] = (brg0 & 0x01) ? color_r : 0;
2731 if(!hireso) continue;
2732 dest1[ 0] = dest1[ 1] = (brg1 & 0x80) ? color_l : 0;
2733 dest1[ 2] = dest1[ 3] = (brg1 & 0x40) ? color_l : 0;
2734 dest1[ 4] = dest1[ 5] = (brg1 & 0x20) ? color_l : 0;
2735 dest1[ 6] = dest1[ 7] = (brg1 & 0x10) ? color_l : 0;
2736 dest1[ 8] = dest1[ 9] = (brg1 & 0x08) ? color_r : 0;
2737 dest1[10] = dest1[11] = (brg1 & 0x04) ? color_r : 0;
2738 dest1[12] = dest1[13] = (brg1 & 0x02) ? color_r : 0;
2739 dest1[14] = dest1[15] = (brg1 & 0x01) ? color_r : 0;
2742 if(config.scan_line) {
2743 memset(graph[y + 1], 0, 640);
2745 memcpy(graph[y + 1], graph[y], 640);
2753 bool PC88::draw_640x200_color_graph()
2755 #if defined(_PC8001SR)
2756 if(!Port31_GRAPH || Port53_G0DS) {
2758 if(!Port31_GRAPH/* || (Port53_G0DS && Port53_G1DS && Port53_G2DS)*/) {
2760 memset(graph, 0, sizeof(graph));
2763 uint8_t *gvram_b = /*Port53_G0DS ? gvram_null : */(gvram + 0x0000);
2764 uint8_t *gvram_r = /*Port53_G1DS ? gvram_null : */(gvram + 0x4000);
2765 uint8_t *gvram_g = /*Port53_G2DS ? gvram_null : */(gvram + 0x8000);
2767 for(int y = 0, addr = 0; y < 400; y += 2) {
2768 for(int x = 0; x < 640; x += 8) {
2769 uint8_t b = gvram_b[addr];
2770 uint8_t r = gvram_r[addr];
2771 uint8_t g = gvram_g[addr];
2773 uint8_t *dest = &graph[y][x];
2774 dest[0] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
2775 dest[1] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
2776 dest[2] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
2777 dest[3] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
2778 dest[4] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
2779 dest[5] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04) );
2780 dest[6] = ((b & 0x02) >> 1) | ((r & 0x02) ) | ((g & 0x02) << 1);
2781 dest[7] = ((b & 0x01) ) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
2783 if(config.scan_line) {
2784 memset(graph[y + 1], 0, 640);
2786 memcpy(graph[y + 1], graph[y], 640);
2792 void PC88::draw_640x200_mono_graph()
2794 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS && Port53_G2DS)) {
2795 memset(graph, 0, sizeof(graph));
2798 uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2799 uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2800 uint8_t *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
2802 for(int y = 0, addr = 0; y < 400; y += 2) {
2803 for(int x = 0; x < 640; x += 8) {
2804 uint8_t brg = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
2806 uint8_t *dest = &graph[y][x];
2807 dest[0] = (brg & 0x80) >> 7;
2808 dest[1] = (brg & 0x40) >> 6;
2809 dest[2] = (brg & 0x20) >> 5;
2810 dest[3] = (brg & 0x10) >> 4;
2811 dest[4] = (brg & 0x08) >> 3;
2812 dest[5] = (brg & 0x04) >> 2;
2813 dest[6] = (brg & 0x02) >> 1;
2814 dest[7] = (brg & 0x01) ;
2816 if(config.scan_line) {
2817 memset(graph[y + 1], 0, 640);
2819 memcpy(graph[y + 1], graph[y], 640);
2824 void PC88::draw_640x200_attrib_graph()
2826 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS && Port53_G2DS)) {
2827 memset(graph, 0, sizeof(graph));
2830 uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2831 uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2832 uint8_t *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
2834 for(int y = 0, addr = 0; y < 400; y += 2) {
2835 for(int x = 0, cx = 0; x < 640; x += 8, cx++) {
2836 uint8_t color = text_color[y >> 1][cx];
2837 uint8_t brg0 = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
2839 if(text_reverse[y >> 1][cx]) {
2844 uint8_t *dest0 = &graph[y ][x];
2845 uint8_t *dest1 = &graph[y + 1][x];
2846 dest0[0] = (brg0 & 0x80) ? color : 0;
2847 dest0[1] = (brg0 & 0x40) ? color : 0;
2848 dest0[2] = (brg0 & 0x20) ? color : 0;
2849 dest0[3] = (brg0 & 0x10) ? color : 0;
2850 dest0[4] = (brg0 & 0x08) ? color : 0;
2851 dest0[5] = (brg0 & 0x04) ? color : 0;
2852 dest0[6] = (brg0 & 0x02) ? color : 0;
2853 dest0[7] = (brg0 & 0x01) ? color : 0;
2854 if(!hireso) continue;
2855 dest1[0] = (brg1 & 0x80) ? color : 0;
2856 dest1[1] = (brg1 & 0x40) ? color : 0;
2857 dest1[2] = (brg1 & 0x20) ? color : 0;
2858 dest1[3] = (brg1 & 0x10) ? color : 0;
2859 dest1[4] = (brg1 & 0x08) ? color : 0;
2860 dest1[5] = (brg1 & 0x04) ? color : 0;
2861 dest1[6] = (brg1 & 0x02) ? color : 0;
2862 dest1[7] = (brg1 & 0x01) ? color : 0;
2865 if(config.scan_line) {
2866 memset(graph[y + 1], 0, 640);
2868 memcpy(graph[y + 1], graph[y], 640);
2874 #if !defined(_PC8001SR)
2875 void PC88::draw_640x400_mono_graph()
2877 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS)) {
2878 memset(graph, 0, sizeof(graph));
2881 uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2882 uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2884 for(int y = 0, addr = 0; y < 200; y++) {
2885 for(int x = 0; x < 640; x += 8) {
2886 uint8_t b = gvram_b[addr];
2888 uint8_t *dest = &graph[y][x];
2889 dest[0] = (b & 0x80) >> 7;
2890 dest[1] = (b & 0x40) >> 6;
2891 dest[2] = (b & 0x20) >> 5;
2892 dest[3] = (b & 0x10) >> 4;
2893 dest[4] = (b & 0x08) >> 3;
2894 dest[5] = (b & 0x04) >> 2;
2895 dest[6] = (b & 0x02) >> 1;
2896 dest[7] = (b & 0x01) ;
2899 for(int y = 200, addr = 0; y < 400; y++) {
2900 for(int x = 0; x < 640; x += 8) {
2901 uint8_t r = gvram_r[addr];
2903 uint8_t *dest = &graph[y][x];
2904 dest[0] = (r & 0x80) >> 7;
2905 dest[1] = (r & 0x40) >> 6;
2906 dest[2] = (r & 0x20) >> 5;
2907 dest[3] = (r & 0x10) >> 4;
2908 dest[4] = (r & 0x08) >> 3;
2909 dest[5] = (r & 0x04) >> 2;
2910 dest[6] = (r & 0x02) >> 1;
2911 dest[7] = (r & 0x01) ;
2916 void PC88::draw_640x400_attrib_graph()
2918 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS)) {
2919 memset(graph, 0, sizeof(graph));
2922 uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2923 uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2925 for(int y = 0, addr = 0; y < 200; y++) {
2926 for(int x = 0, cx = 0; x < 640; x += 8, cx++) {
2927 uint8_t color = text_color[y >> 1][cx];
2928 uint8_t b = gvram_b[addr];
2929 if(text_reverse[y >> 1][cx]) {
2933 uint8_t *dest = &graph[y][x];
2934 dest[0] = (b & 0x80) ? color : 0;
2935 dest[1] = (b & 0x40) ? color : 0;
2936 dest[2] = (b & 0x20) ? color : 0;
2937 dest[3] = (b & 0x10) ? color : 0;
2938 dest[4] = (b & 0x08) ? color : 0;
2939 dest[5] = (b & 0x04) ? color : 0;
2940 dest[6] = (b & 0x02) ? color : 0;
2941 dest[7] = (b & 0x01) ? color : 0;
2944 for(int y = 200, addr = 0; y < 400; y++) {
2945 for(int x = 0, cx = 0; x < 640; x += 8, cx++) {
2946 uint8_t color = text_color[y >> 1][cx];
2947 uint8_t r = gvram_r[addr];
2948 if(text_reverse[y >> 1][cx]) {
2952 uint8_t *dest = &graph[y][x];
2953 dest[0] = (r & 0x80) ? color : 0;
2954 dest[1] = (r & 0x40) ? color : 0;
2955 dest[2] = (r & 0x20) ? color : 0;
2956 dest[3] = (r & 0x10) ? color : 0;
2957 dest[4] = (r & 0x08) ? color : 0;
2958 dest[5] = (r & 0x04) ? color : 0;
2959 dest[6] = (r & 0x02) ? color : 0;
2960 dest[7] = (r & 0x01) ? color : 0;
2966 void PC88::request_intr(int level, bool status)
2968 uint8_t bit = 1 << level;
2971 // for Nobunaga Fuunroku Opening & MID-GARTS Opening (XM8 version 1.00)
2972 // bit &= intr_mask2;
2973 if(!(intr_req & bit)) {
2978 if(intr_req & bit) {
2985 void PC88::update_intr()
2987 d_cpu->set_intr_line(((intr_req & intr_mask1 & intr_mask2) != 0), true, 0);
2990 uint32_t PC88::get_intr_ack()
2992 uint8_t ai = intr_req & intr_mask1 & intr_mask2;
2994 for(int i = 0; i < 8; i++, ai >>= 1) {
2996 intr_req &= ~(1 << i);
3004 void PC88::notify_intr_ei()
3009 /* ----------------------------------------------------------------------------
3011 ---------------------------------------------------------------------------- */
3013 void pc88_crtc_t::reset(bool hireso)
3016 cursor.type = cursor.mode = -1;
3017 cursor.x = cursor.y = -1;
3022 char_height = hireso ? 16 : 8;
3024 vretrace = hireso ? 3 : 7;
3025 timing_changed = false;
3030 void pc88_crtc_t::write_cmd(uint8_t data)
3032 cmd = (data >> 5) & 7;
3037 status |= 0x80; // fix
3038 cursor.x = cursor.y = -1;
3040 case 1: // start display
3043 status |= 0x90; // fix
3046 case 2: // set interrupt mask
3048 // status = 0; // from M88
3049 status = 0x80; // fix
3051 intr_mask = data & 3;
3053 case 3: // read light pen
3056 case 4: // load cursor position ON/OFF
3057 cursor.type = (data & 1) ? cursor.mode : -1;
3059 case 5: // reset interrupt
3062 case 6: // reset counters
3068 void pc88_crtc_t::write_param(uint8_t data)
3074 width = min((data & 0x7f) + 2, 80);
3077 if(height != (data & 0x3f) + 1) {
3078 height = (data & 0x3f) + 1;
3079 timing_changed = true;
3081 blink.rate = 32 * ((data >> 6) + 1);
3084 if(char_height != (data & 0x1f) + 1) {
3085 char_height = (data & 0x1f) + 1;
3086 timing_changed = true;
3088 cursor.mode = (data >> 5) & 3;
3089 skip_line = ((data & 0x80) != 0);
3092 if(vretrace != ((data >> 5) & 7) + 1) {
3093 vretrace = ((data >> 5) & 7) + 1;
3094 timing_changed = true;
3098 mode = (data >> 5) & 7;
3099 attrib.num = (mode & 1) ? 0 : min((data & 0x1f) + 1, 20);
3120 uint32_t pc88_crtc_t::read_param()
3122 uint32_t val = 0xff;
3125 case 3: // read light pen
3137 val = read_status();
3144 uint32_t pc88_crtc_t::read_status()
3147 return status & ~0x10;
3153 void pc88_crtc_t::start()
3155 memset(buffer, 0, sizeof(buffer));
3160 void pc88_crtc_t::finish()
3162 if((status & 0x10) && !(intr_mask & 1)) {
3168 void pc88_crtc_t::write_buffer(uint8_t data)
3170 buffer[(buffer_ptr++) & 0x3fff] = data;
3173 uint8_t pc88_crtc_t::read_buffer(int ofs)
3175 if(ofs < buffer_ptr) {
3178 // dma underrun occurs !!!
3184 void pc88_crtc_t::update_blink()
3187 if(++blink.counter > blink.rate) {
3190 blink.attrib = (blink.counter < blink.rate / 4) ? 2 : 0;
3191 blink.cursor = (blink.counter <= blink.rate / 4) || (blink.rate / 2 <= blink.counter && blink.counter <= 3 * blink.rate / 4);
3194 void pc88_crtc_t::expand_buffer(bool hireso, bool line400)
3196 int char_height_tmp = char_height;
3200 char_height_tmp <<= 1;
3202 if(line400 || !skip_line) {
3203 char_height_tmp >>= 1;
3205 if(!(status & 0x10)) {
3209 for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
3210 for(int cx = 0; cx < width; cx++) {
3211 text.expand[cy][cx] = read_buffer(ofs + cx);
3213 if((status & 8) && exitline == -1) {
3220 for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
3221 for(int cx = 0; cx < width; cx += 2) {
3222 set_attrib(read_buffer(ofs + cx + 1));
3223 attrib.expand[cy][cx] = attrib.expand[cy][cx + 1] = attrib.data;
3225 if((status & 8) && exitline == -1) {
3233 memset(attrib.expand, 0xe0, sizeof(attrib.expand));
3235 for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
3237 memset(flags, 0, sizeof(flags));
3238 for(int i = 2 * (attrib.num - 1); i >= 0; i -= 2) {
3239 flags[read_buffer(ofs + i + 80) & 0x7f] = 1;
3241 attrib.data &= 0xf3; // for PC-8801mkIIFR
\95t
\91®
\83f
\83\82
3243 for(int cx = 0, pos = 0; cx < width; cx++) {
3245 set_attrib(read_buffer(ofs + pos + 81));
3248 attrib.expand[cy][cx] = attrib.data;
3250 if((status & 8) && exitline == -1) {
3257 if(cursor.x < 80 && cursor.y < 200) {
3258 if((cursor.type & 1) && blink.cursor) {
3261 static const uint8_t ctype[5] = {0, 8, 8, 1, 1};
3262 attrib.expand[cursor.y][cursor.x] ^= ctype[cursor.type + 1];
3267 if(exitline != -1) {
3268 for(int cy = exitline; cy < 200; cy++) {
3269 memset(&text.expand[cy][0], 0, width);
3271 // SORCERIAN Music Library ver-2.1
3272 memset(&attrib.expand[cy][0], 0xe0, width); // color=7
3274 // from ePC-8801MA
\89ü
3275 memset(&attrib.expand[cy][0], 0x00, width);
3281 void pc88_crtc_t::set_attrib(uint8_t code)
3286 attrib.data = (attrib.data & 0x0f) | (code & 0xf0);
3288 attrib.data = (attrib.data & 0xf0) | ((code >> 2) & 0x0d) | ((code << 1) & 2);
3289 attrib.data ^= reverse;
3290 attrib.data ^= ((code & 2) && !(code & 1)) ? blink.attrib : 0;
3293 attrib.data = 0xe0 | ((code >> 3) & 0x10) | ((code >> 2) & 0x0d) | ((code << 1) & 2);
3294 attrib.data ^= reverse;
3295 attrib.data ^= ((code & 2) && !(code & 1)) ? blink.attrib : 0;
3299 /* ----------------------------------------------------------------------------
3301 ---------------------------------------------------------------------------- */
3303 void pc88_dmac_t::write_io8(uint32_t addr, uint32_t data)
3305 int c = (addr >> 1) & 3;
3307 switch(addr & 0x0f) {
3313 if((mode & 0x80) && c == 2) {
3314 ch[3].addr.b.l = data;
3316 ch[c].addr.b.l = data;
3318 if((mode & 0x80) && c == 2) {
3319 ch[3].addr.b.h = data;
3320 ch[3].addr.b.h2 = ch[3].addr.b.h3 = 0;
3322 ch[c].addr.b.h = data;
3323 ch[c].addr.b.h2 = ch[c].addr.b.h3 = 0;
3325 high_low = !high_low;
3332 if((mode & 0x80) && c == 2) {
3333 ch[3].count.b.l = data;
3335 ch[c].count.b.l = data;
3337 if((mode & 0x80) && c == 2) {
3338 ch[3].count.b.h = data & 0x3f;
3339 ch[3].count.b.h2 = ch[3].count.b.h3 = 0;
3340 ch[3].mode = data & 0xc0;
3342 ch[c].count.b.h = data & 0x3f;
3343 ch[c].count.b.h2 = ch[c].count.b.h3 = 0;
3344 ch[c].mode = data & 0xc0;
3346 high_low = !high_low;
3355 uint32_t pc88_dmac_t::read_io8(uint32_t addr)
3357 uint32_t val = 0xff;
3358 int c = (addr >> 1) & 3;
3360 switch(addr & 0x0f) {
3366 val = ch[c].addr.b.l;
3368 val = ch[c].addr.b.h;
3370 high_low = !high_low;
3377 val = ch[c].count.b.l;
3379 val = (ch[c].count.b.h & 0x3f) | ch[c].mode;
3381 high_low = !high_low;
3386 // high_low = false;
3392 void pc88_dmac_t::start(int c)
3394 if(mode & (1 << c)) {
3395 status &= ~(1 << c);
3396 ch[c].running = true;
3398 ch[c].running = false;
3402 void pc88_dmac_t::run(int c, int nbytes)
3405 while(nbytes > 0 && ch[c].count.sd >= 0) {
3406 if(ch[c].mode == 0x80) {
3407 ch[c].io->write_dma_io8(0, mem->read_dma_data8(ch[c].addr.w.l));
3408 } else if(ch[c].mode == 0x40) {
3409 mem->write_dma_data8(ch[c].addr.w.l, ch[c].io->read_dma_io8(0));
3410 } else if(ch[c].mode == 0x00) {
3411 ch[c].io->read_dma_io8(0); // verify
3417 if(ch[c].count.sd < 0) {
3423 void pc88_dmac_t::finish(int c)
3426 while(ch[c].count.sd >= 0) {
3427 if(ch[c].mode == 0x80) {
3428 ch[c].io->write_dma_io8(0, mem->read_dma_data8(ch[c].addr.w.l));
3429 } else if(ch[c].mode == 0x40) {
3430 mem->write_dma_data8(ch[c].addr.w.l, ch[c].io->read_dma_io8(0));
3431 } else if(ch[c].mode == 0x00) {
3432 ch[c].io->read_dma_io8(0); // verify
3437 if((mode & 0x80) && c == 2) {
3438 ch[2].addr.sd = ch[3].addr.sd;
3439 ch[2].count.sd = ch[3].count.sd;
3440 ch[2].mode = ch[3].mode;
3441 } else if(mode & 0x40) {
3445 ch[c].running = false;
3449 #define STATE_VERSION 10
3451 bool PC88::process_state(FILEIO* state_fio, bool loading)
3453 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
3456 if(!state_fio->StateCheckInt32(this_device_id)) {
3459 state_fio->StateArray(ram, sizeof(ram), 1);
3460 #if defined(PC88_EXRAM_BANKS)
3461 state_fio->StateArray(exram, sizeof(exram), 1);
3463 state_fio->StateArray(gvram, sizeof(gvram), 1);
3464 state_fio->StateArray(tvram, sizeof(tvram), 1);
3465 state_fio->StateArray(port, sizeof(port), 1);
3466 state_fio->StateValue(crtc.blink.rate);
3467 state_fio->StateValue(crtc.blink.counter);
3468 state_fio->StateValue(crtc.blink.cursor);
3469 state_fio->StateValue(crtc.blink.attrib);
3470 state_fio->StateValue(crtc.cursor.type);
3471 state_fio->StateValue(crtc.cursor.mode);
3472 state_fio->StateValue(crtc.cursor.x);
3473 state_fio->StateValue(crtc.cursor.y);
3474 state_fio->StateValue(crtc.attrib.data);
3475 state_fio->StateValue(crtc.attrib.num);
3476 state_fio->StateArray(&crtc.attrib.expand[0][0], sizeof(crtc.attrib.expand), 1);
3477 state_fio->StateArray(&crtc.text.expand[0][0], sizeof(crtc.text.expand), 1);
3478 state_fio->StateValue(crtc.width);
3479 state_fio->StateValue(crtc.height);
3480 state_fio->StateValue(crtc.char_height);
3481 state_fio->StateValue(crtc.skip_line);
3482 state_fio->StateValue(crtc.vretrace);
3483 state_fio->StateValue(crtc.timing_changed);
3484 state_fio->StateArray(crtc.buffer, sizeof(crtc.buffer), 1);
3485 state_fio->StateValue(crtc.buffer_ptr);
3486 state_fio->StateValue(crtc.cmd);
3487 state_fio->StateValue(crtc.cmd_ptr);
3488 state_fio->StateValue(crtc.mode);
3489 state_fio->StateValue(crtc.reverse);
3490 state_fio->StateValue(crtc.intr_mask);
3491 state_fio->StateValue(crtc.status);
3492 state_fio->StateValue(crtc.vblank);
3493 for(int i = 0; i < array_length(dmac.ch); i++) {
3494 state_fio->StateValue(dmac.ch[i].addr);
3495 state_fio->StateValue(dmac.ch[i].count);
3496 state_fio->StateValue(dmac.ch[i].mode);
3497 state_fio->StateValue(dmac.ch[i].nbytes);
3498 state_fio->StateValue(dmac.ch[i].running);
3500 state_fio->StateValue(dmac.mode);
3501 state_fio->StateValue(dmac.status);
3502 state_fio->StateValue(dmac.high_low);
3503 state_fio->StateArray(alu_reg, sizeof(alu_reg), 1);
3504 state_fio->StateValue(gvram_plane);
3505 state_fio->StateValue(gvram_sel);
3506 state_fio->StateValue(cpu_clock_low);
3507 #if defined(SUPPORT_PC88_HIGH_CLOCK)
3508 state_fio->StateValue(cpu_clock_high_fe2);
3510 state_fio->StateValue(mem_wait_on);
3511 state_fio->StateValue(m1_wait_clocks);
3512 state_fio->StateValue(f000_m1_wait_clocks);
3513 state_fio->StateValue(mem_wait_clocks_r);
3514 state_fio->StateValue(mem_wait_clocks_w);
3515 state_fio->StateValue(tvram_wait_clocks_r);
3516 state_fio->StateValue(tvram_wait_clocks_w);
3517 state_fio->StateValue(gvram_wait_clocks_r);
3518 state_fio->StateValue(gvram_wait_clocks_w);
3519 state_fio->StateValue(busreq_clocks);
3520 for(int i = 0; i < array_length(palette); i++) {
3521 state_fio->StateValue(palette[i].r);
3522 state_fio->StateValue(palette[i].g);
3523 state_fio->StateValue(palette[i].b);
3525 // state_fio->StateValue(update_palette);
3526 state_fio->StateValue(hireso);
3527 state_fio->StateArray(&text[0][0], sizeof(text), 1);
3528 state_fio->StateArray(&graph[0][0], sizeof(graph), 1);
3530 for(int i = 0; i < 9; i++) {
3531 state_fio->StateValue(palette_digital[i].b);
3532 state_fio->StateValue(palette_digital[i].r);
3533 state_fio->StateValue(palette_digital[i].g);
3534 state_fio->StateValue(palette_analog [i].b);
3535 state_fio->StateValue(palette_analog [i].r);
3536 state_fio->StateValue(palette_analog [i].g);
3539 state_fio->StateValue(usart_dcd);
3540 state_fio->StateValue(opn_busy);
3541 state_fio->StateValue(key_caps);
3542 state_fio->StateValue(key_kana);
3543 #ifdef SUPPORT_PC88_JOYSTICK
3544 state_fio->StateValue(mouse_strobe_clock);
3545 state_fio->StateValue(mouse_strobe_clock_lim);
3546 state_fio->StateValue(mouse_phase);
3547 state_fio->StateValue(mouse_dx);
3548 state_fio->StateValue(mouse_dy);
3549 state_fio->StateValue(mouse_lx);
3550 state_fio->StateValue(mouse_ly);
3552 state_fio->StateValue(intr_req);
3553 state_fio->StateValue(intr_req_sound);
3554 #ifdef SUPPORT_PC88_SB2
3555 state_fio->StateValue(intr_req_sb2);
3557 state_fio->StateValue(intr_mask1);
3558 state_fio->StateValue(intr_mask2);
3559 state_fio->StateValue(cmt_play);
3560 state_fio->StateValue(cmt_rec);
3561 state_fio->StateArray(rec_file_path, sizeof(rec_file_path), 1);
3563 int length_tmp = state_fio->FgetInt32_LE();
3565 cmt_fio->Fopen(rec_file_path, FILEIO_READ_WRITE_NEW_BINARY);
3566 while(length_tmp != 0) {
3567 uint8_t buffer[1024];
3568 int length_rw = min(length_tmp, (int)sizeof(buffer));
3569 state_fio->Fread(buffer, length_rw, 1);
3570 if(cmt_fio->IsOpened()) {
3571 cmt_fio->Fwrite(buffer, length_rw, 1);
3573 length_tmp -= length_rw;
3577 if(cmt_rec && cmt_fio->IsOpened()) {
3578 int length_tmp = (int)cmt_fio->Ftell();
3579 cmt_fio->Fseek(0, FILEIO_SEEK_SET);
3580 state_fio->FputInt32_LE(length_tmp);
3581 while(length_tmp != 0) {
3582 uint8_t buffer[1024];
3583 int length_rw = min(length_tmp, (int)sizeof(buffer));
3584 cmt_fio->Fread(buffer, length_rw, 1);
3585 state_fio->Fwrite(buffer, length_rw, 1);
3586 length_tmp -= length_rw;
3589 state_fio->FputInt32_LE(0);
3592 state_fio->StateValue(cmt_bufptr);
3593 state_fio->StateValue(cmt_bufcnt);
3594 state_fio->StateArray(cmt_buffer, sizeof(cmt_buffer), 1);
3595 state_fio->StateArray(cmt_data_carrier, sizeof(cmt_data_carrier), 1);
3596 state_fio->StateValue(cmt_data_carrier_cnt);
3597 state_fio->StateValue(cmt_register_id);
3598 state_fio->StateValue(beep_on);
3599 state_fio->StateValue(beep_signal);
3600 state_fio->StateValue(sing_signal);
3601 #ifdef SUPPORT_PC88_PCG8100
3602 state_fio->StateValue(pcg_addr);
3603 state_fio->StateValue(pcg_data);
3604 state_fio->StateValue(pcg_ctrl);
3605 state_fio->StateArray(pcg_pattern, sizeof(pcg_pattern), 1);
3607 #ifdef SUPPORT_PC88_CDROM
3608 state_fio->StateValue(cdda_register_id);
3609 state_fio->StateValue(cdda_volume);
3612 state_fio->StateValue(nippy_patch);
3617 #if defined(_PC8001SR)
3621 update_low_memmap();
3622 update_tvram_memmap();
3624 // force update palette when state file is loaded
3625 update_palette = true;