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);
1052 d_scsi_cdrom->set_volume((int)(cdda_volume = 100.0));
1056 if(cdda_register_id != -1) {
1057 cancel_event(this, cdda_register_id);
1059 d_scsi_cdrom->set_volume((int)(cdda_volume = 0.0));
1062 if(cdda_register_id != -1) {
1063 cancel_event(this, cdda_register_id);
1065 register_event(this, EVENT_FADE_IN, 100, true, &cdda_register_id); // 100ms
1066 d_scsi_cdrom->set_volume((int)(cdda_volume = 0.0));
1069 if(cdda_register_id != -1) {
1070 cancel_event(this, cdda_register_id);
1072 register_event(this, EVENT_FADE_IN, 1500, true, &cdda_register_id); // 1500ms
1073 d_scsi_cdrom->set_volume((int)(cdda_volume = 0.0));
1076 if(cdda_register_id != -1) {
1077 cancel_event(this, cdda_register_id);
1079 register_event(this, EVENT_FADE_OUT, 100, true, &cdda_register_id); // 100ms
1080 d_scsi_cdrom->set_volume((int)(cdda_volume = 100.0));
1083 if(cdda_register_id != -1) {
1084 cancel_event(this, cdda_register_id);
1086 register_event(this, EVENT_FADE_OUT, 5000, true, &cdda_register_id); // 5000ms
1087 d_scsi_cdrom->set_volume((int)(cdda_volume = 100.0));
1093 if(cdbios_loaded && (mod & 0x10)) {
1094 update_low_memmap();
1098 #ifdef SUPPORT_PC88_SB2
1102 d_sb2->write_io8(addr, data);
1107 if(intr_req_sb2 && !PortAA_S2INTM) {
1108 request_intr(IRQ_SOUND, true);
1112 #ifdef SUPPORT_PC88_OPNA
1115 if(d_sb2 != NULL && d_sb2->is_ym2608) {
1116 d_sb2->write_io8(addr | 2, data);
1123 update_low_memmap();
1127 #ifdef PC88_IODATA_EXRAM
1132 if(PortE2_RDEN || PortE2_WREN) {
1133 update_low_memmap();
1139 intr_mask1 = ~(0xff << (data < 8 ? data : 8));
1143 // for Romancia (XM8 version 1.00)
1144 if(intr_mask2_table[data & 7] != intr_mask2) {
1145 intr_req &= (intr_mask2_table[data & 7] & intr_mask2);
1147 intr_mask2 = intr_mask2_table[data & 7];
1148 intr_req &= intr_mask2;
1151 #ifdef SUPPORT_PC88_DICTIONARY
1154 if(port[0xf0] >= 0x20) {
1155 // no effect if data >= 0x20
1161 if(port[0xf1] != 0x00 && port[0xf1] != 0x01) {
1162 // effect only 0x00 or 0x01
1171 d_pio->write_io8(addr, data);
1176 uint32_t PC88::read_io8(uint32_t addr)
1177 #ifdef _IO_DEBUG_LOG
1179 uint32_t val = read_io8_debug(addr);
1180 this->out_debug_log(_T("%06x\tIN8\t%02x = %02x\n"), d_cpu->get_pc(), addr & 0xff, val);
1184 uint32_t PC88::read_io8_debug(uint32_t addr)
1187 uint32_t val = 0xff;
1206 for(int i = 0; i < 8; i++) {
1207 if(key_status[key_table[addr & 0x0f][i]]) {
1212 val &= ~0x80; // http://www.maroon.dti.ne.jp/youkan/pc88/iomap.html
1217 return d_sio->read_io8(addr);
1218 #if defined(_PC8001SR)
1220 return (config.boot_mode == MODE_PC80_N ? 0 : 1) | (config.boot_mode == MODE_PC80_V2 ? 0 : 2) | 0xfc;
1222 return (config.boot_mode == MODE_PC80_V2 ? 0 : 0x80) | 0x39;
1227 // return (config.boot_mode == MODE_PC88_N ? 0 : 1) | 0xca; // 80x20 (XM8 version 1.00)
1228 return (config.boot_mode == MODE_PC88_N ? 0 : 1) | 0xc2; // 80x25
1231 return (config.boot_mode == MODE_PC88_V2 ? 0 : 0x80) | (config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N ? 0 : 0x40) | 0x39;
1232 // return (config.boot_mode == MODE_PC88_V2 ? 0 : 0x80) | (config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N ? 0 : 0x40);
1238 // return (crtc.vblank ? 0x20 : 0) | (d_rtc->read_signal(0) ? 0x10 : 0) | (usart_dcd ? 4 : 0) | (hireso ? 0 : 2) | 0xc1;
1239 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;
1241 val = d_opn->read_io8(addr);
1243 // show busy flag for first access (for ALPHA)
1244 if(d_cpu->get_pc() == 0xe615) {
1251 if(Port44_OPNCH == 14) {
1252 #ifdef SUPPORT_PC88_JOYSTICK
1253 if(config.joystick_type == DEVICE_JOYSTICK) {
1254 return (~(joystick_status[0] >> 0) & 0x0f) | 0xf0;
1255 } else if(config.joystick_type == DEVICE_MOUSE) {
1256 switch(mouse_phase) {
1258 return ((mouse_lx >> 4) & 0x0f) | 0xf0;
1260 return ((mouse_lx >> 0) & 0x0f) | 0xf0;
1262 return ((mouse_ly >> 4) & 0x0f) | 0xf0;
1264 return ((mouse_ly >> 0) & 0x0f) | 0xf0;
1270 } else if(Port44_OPNCH == 15) {
1271 #ifdef SUPPORT_PC88_JOYSTICK
1272 if(config.joystick_type == DEVICE_JOYSTICK) {
1273 return (~(joystick_status[0] >> 4) & 0x03) | 0xfc;
1274 } else if(config.joystick_type == DEVICE_MOUSE) {
1275 return (~mouse_status[2] & 0x03) | 0xfc;
1280 return d_opn->read_io8(addr);
1281 #ifdef SUPPORT_PC88_OPNA
1284 if(d_opn->is_ym2608) {
1285 return d_opn->read_io8(addr);
1290 return crtc.read_param();
1292 return crtc.read_status();
1294 return gvram_plane | 0xf8;
1304 return dmac.read_io8(addr);
1307 return (cpu_clock_low ? 0x80 : 0) | (is_sr_mr() ? 0x7f : 0x10);
1310 return is_sr_mr() ? 0xff : (port[0x6f] | 0xf0);
1311 #if !defined(_PC8001SR)
1313 // PC-8001mkIISR returns the constant value
1314 // this port is used to detect PC-8001mkIISR or 8801mkIISR
1319 #ifdef SUPPORT_PC88_HMB20
1322 return d_opm->read_io8(addr);
1324 #ifdef SUPPORT_PC88_CDROM
1328 val = d_scsi_host->read_signal(SIG_SCSI_BSY) ? 0x80 : 0;
1329 val |= d_scsi_host->read_signal(SIG_SCSI_REQ) ? 0x40 : 0;
1330 val |= d_scsi_host->read_signal(SIG_SCSI_MSG) ? 0x20 : 0;
1331 val |= d_scsi_host->read_signal(SIG_SCSI_CD ) ? 0x10 : 0;
1332 val |= d_scsi_host->read_signal(SIG_SCSI_IO ) ? 0x08 : 0;
1333 // do not show BSY,MSG,CxD,IxD when SEL=1 (
\90M
\92·
\82Ì
\96ì
\96]
\95\90\8f«
\95\97\89_
\98^)
1334 if(port[0x90] & 0x01) {
1335 val &= ~(0x80 | 0x20 | 0x10 | 0x08);
1336 val |= (port[0x9f] & 0x01); // correct ???
1338 #ifdef _SCSI_DEBUG_LOG
1339 this->out_debug_log(_T("[SCSI_PC88] Status = %02X\n"), val);
1346 return d_scsi_host->read_dma_io8(0);
1358 // return 0xcd; // PC-8801MC
1364 port[0x98] ^= 0x80; // clock ???
1375 #ifdef SUPPORT_PC88_SB2
1378 return d_sb2->read_io8(addr);
1383 if(PortA8_OPNCH == 14) {
1384 #ifdef SUPPORT_PC88_JOYSTICK
1385 if(config.joystick_type == DEVICE_JOYSTICK) {
1386 return (~(joystick_status[0] >> 0) & 0x0f) | 0xf0;
1387 } else if(config.joystick_type == DEVICE_MOUSE) {
1388 switch(mouse_phase) {
1390 return ((mouse_lx >> 4) & 0x0f) | 0xf0;
1392 return ((mouse_lx >> 0) & 0x0f) | 0xf0;
1394 return ((mouse_ly >> 4) & 0x0f) | 0xf0;
1396 return ((mouse_ly >> 0) & 0x0f) | 0xf0;
1402 } else if(PortA8_OPNCH == 15) {
1403 #ifdef SUPPORT_PC88_JOYSTICK
1404 if(config.joystick_type == DEVICE_JOYSTICK) {
1405 return (~(joystick_status[0] >> 4) & 0x03) | 0xfc;
1406 } else if(config.joystick_type == DEVICE_MOUSE) {
1407 return (~mouse_status[2] & 0x03) | 0xfc;
1412 return d_sb2->read_io8(addr);
1416 return (PortAA_S2INTM) | 0x7f;
1417 #ifdef SUPPORT_PC88_OPNA
1420 if(d_sb2 != NULL && d_sb2->is_ym2608) {
1421 d_sb2->read_io8(addr | 2);
1426 #if defined(SUPPORT_PC88_VAB)
1430 if(PortE3_VAB_SEL) {
1436 return (~port[0xe2]) | 0xee;
1438 #ifdef PC88_IODATA_EXRAM
1441 return port[0xe3] | 0xf0;
1444 return kanji1[PortE8E9_KANJI1 * 2 + 1];
1446 return kanji1[PortE8E9_KANJI1 * 2];
1448 return kanji2[PortECED_KANJI2 * 2 + 1];
1450 return kanji2[PortECED_KANJI2 * 2];
1454 return d_pio->read_io8(addr);
1459 uint32_t PC88::read_dma_data8(uint32_t addr)
1462 #if defined(_PC8001SR)
1463 return ram[addr & 0xffff];
1465 if((addr & 0xf000) == 0xf000 && (config.boot_mode == MODE_PC88_V1H || config.boot_mode == MODE_PC88_V2)) {
1466 return tvram[addr & 0xfff];
1468 return ram[addr & 0xffff];
1473 void PC88::write_dma_data8(uint32_t addr, uint32_t data)
1476 ram[addr & 0xffff] = data;
1479 void PC88::write_dma_io8(uint32_t addr, uint32_t data)
1482 crtc.write_buffer(data);
1485 void PC88::update_timing()
1487 int lines_per_frame = (crtc.height + crtc.vretrace) * crtc.char_height;
1488 // 56.4229Hz (25line) on PC-8801MA2 (XM8 version 1.00)
1489 double frames_per_sec = (hireso ? 24860.0 * 56.423 / 56.5 : 15980.0) / (double)lines_per_frame;
1490 // double frames_per_sec = (hireso ? 24860.0 * 56.424 / 56.5 : 15980.0) / (double)lines_per_frame;
1492 set_frames_per_sec(frames_per_sec);
1493 set_lines_per_frame(lines_per_frame);
1496 int PC88::get_m1_wait(bool addr_f000)
1501 #if defined(_PC8001SR)
1502 if(config.boot_mode == MODE_PC80_V1 || config.boot_mode == MODE_PC80_N) {
1504 if(config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N) {
1508 // memory wait = off
1520 if(!gvram_sel && !Port32_TMODE) {
1532 int PC88::get_main_wait(bool read)
1541 // memory wait + read
1547 #if !defined(_PC8001SR)
1548 if(!cpu_clock_high_fe2) {
1554 // memory wait (read and write)
1561 int PC88::get_tvram_wait(bool read)
1569 // memory wait + read
1574 // 8MHz -> memory wait do not effect
1586 int PC88::get_gvram_wait(bool read)
1595 #if defined(_PC8001SR)
1596 if(config.boot_mode == MODE_PC80_V1 || config.boot_mode == MODE_PC80_N) {
1598 if(config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N) {
1601 if(!Port40_GHSM && !crtc.vblank) {
1602 // V1S + not GHSM, V-DISP
1626 #if defined(_PC8001SR)
1627 if(config.boot_mode == MODE_PC80_V1 || config.boot_mode == MODE_PC80_N) {
1629 if(config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N) {
1632 if(!Port40_GHSM && !crtc.vblank) {
1633 // V1S + not GHSM, V-DISP
1661 // memory wait + read
1666 // 8MHz -> memory wait do not effect
1673 void PC88::update_gvram_wait()
1675 gvram_wait_clocks_r = get_gvram_wait(true);
1676 gvram_wait_clocks_w = get_gvram_wait(false);
1679 void PC88::update_gvram_sel()
1681 #if defined(_PC8001SR)
1691 gvram_plane = 0; // from M88
1693 gvram_sel = gvram_plane;
1695 f000_m1_wait_clocks = get_m1_wait(true);
1698 #if defined(_PC8001SR)
1699 void PC88::update_n80_write()
1701 if(PortE2_WREN || Port31_MMODE) {
1702 if(PortE3_ERAMSL < PC88_EXRAM_BANKS) {
1703 SET_BANK_W(0x0000, 0x7fff, exram + 0x8000 * PortE3_ERAMSL);
1705 SET_BANK_W(0x0000, 0x7fff, exram);
1708 SET_BANK_W(0x0000, 0x7fff, wdmy);
1712 void PC88::update_n80_read()
1714 if(PortE2_RDEN || Port31_MMODE) {
1715 if(PortE3_ERAMSL < PC88_EXRAM_BANKS) {
1716 SET_BANK_R(0x0000, 0x7fff, exram + 0x8000 * PortE3_ERAMSL);
1718 SET_BANK_R(0x0000, 0x7fff, exram);
1720 } else if(Port33_N80SR) {
1721 if(port[0x71] & 1) {
1722 SET_BANK_R(0x0000, 0x7fff, n80mk2srrom);
1724 SET_BANK_R(0x0000, 0x5fff, n80mk2srrom);
1725 SET_BANK_R(0x6000, 0x7fff, n80mk2srrom + 0x8000);
1728 if(port[0x31] & 1) {
1729 SET_BANK_R(0x0000, 0x7fff, n80mk2rom);
1731 SET_BANK_R(0x0000, 0x5fff, n80mk2rom);
1732 SET_BANK_R(0x6000, 0x7fff, rdmy);
1737 void PC88::update_low_memmap()
1741 #ifdef PC88_EXRAM_BANKS
1742 if(PortE3_ERAMSL < PC88_EXRAM_BANKS) {
1743 SET_BANK_R(0x0000, 0x7fff, exram + 0x8000 * PortE3_ERAMSL);
1746 // SET_BANK_R(0x0000, 0x7fff, rdmy);
1747 #ifdef PC88_EXRAM_BANKS
1750 } else if(Port31_MMODE) {
1752 SET_BANK_R(0x0000, 0x7fff, ram);
1753 #ifdef SUPPORT_PC88_CDROM
1754 } else if(cdbios_loaded && Port99_CDREN) {
1756 SET_BANK_R(0x0000, 0x7fff, cdbios + 0x8000);
1758 SET_BANK_R(0x0000, 0x7fff, cdbios + 0x0000);
1761 } else if(Port31_RMODE) {
1763 SET_BANK_R(0x0000, 0x7fff, n80rom);
1766 SET_BANK_R(0x0000, 0x5fff, n88rom);
1767 if(Port71_EROM & 1) {
1768 SET_BANK_R(0x6000, 0x7fff, n88rom + 0x6000);
1770 SET_BANK_R(0x6000, 0x7fff, n88exrom + 0x2000 * Port32_EROMSL);
1776 #ifdef PC88_EXRAM_BANKS
1777 if(PortE3_ERAMSL < PC88_EXRAM_BANKS) {
1778 SET_BANK_W(0x0000, 0x7fff, exram + 0x8000 * PortE3_ERAMSL);
1781 // SET_BANK_W(0x0000, 0x7fff, wdmy);
1782 SET_BANK_W(0x0000, 0x7fff, ram);
1783 #ifdef PC88_EXRAM_BANKS
1787 SET_BANK_W(0x0000, 0x7fff, ram);
1791 void PC88::update_tvram_memmap()
1794 if(config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N || Port32_TMODE) {
1795 SET_BANK(0xf000, 0xffff, ram + 0xf000, ram + 0xf000);
1797 SET_BANK(0xf000, 0xffff, tvram, tvram);
1802 void PC88::write_signal(int id, uint32_t data, uint32_t mask)
1804 if(id == SIG_PC88_USART_IRQ) {
1805 request_intr(IRQ_USART, ((data & mask) != 0));
1806 } else if(id == SIG_PC88_SOUND_IRQ) {
1807 intr_req_sound = ((data & mask) != 0);
1808 #if defined(_PC8001SR)
1809 if(intr_req_sound && !Port33_SINTM) {
1811 if(intr_req_sound && !Port32_SINTM) {
1813 request_intr(IRQ_SOUND, true);
1815 #ifdef SUPPORT_PC88_SB2
1816 } else if(id == SIG_PC88_SB2_IRQ) {
1817 intr_req_sb2 = ((data & mask) != 0);
1818 if(intr_req_sb2 && !PortAA_S2INTM) {
1819 request_intr(IRQ_SOUND, true);
1822 #ifdef SUPPORT_PC88_CDROM
1823 } else if(id == SIG_PC88_SCSI_DRQ) {
1824 if((data & mask) && cdbios_loaded) {
1825 if(!dmac.ch[1].running) {
1828 if(dmac.ch[1].running) {
1833 } else if(id == SIG_PC88_USART_OUT) {
1837 if(cmt_rec && Port30_MTON) {
1838 cmt_buffer[cmt_bufptr++] = data & mask;
1839 if(cmt_bufptr >= CMT_BUFFER_SIZE) {
1840 cmt_fio->Fwrite(cmt_buffer, cmt_bufptr, 1);
1850 void PC88::event_callback(int event_id, int err)
1854 request_intr(IRQ_TIMER, true);
1857 d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 0);
1859 case EVENT_CMT_SEND:
1860 // check data carrier
1861 if(cmt_play && cmt_bufptr < cmt_bufcnt && Port30_MTON) {
1862 // detect the data carrier at the top of next block
1863 if(check_data_carrier()) {
1864 register_event(this, EVENT_CMT_DCD, 1000000, false, &cmt_register_id);
1872 if(cmt_play && cmt_bufptr < cmt_bufcnt && Port30_MTON) {
1873 d_sio->write_signal(SIG_I8251_RECV, cmt_buffer[cmt_bufptr++], 0xff);
1874 if(cmt_bufptr < cmt_bufcnt) {
1875 register_event(this, EVENT_CMT_SEND, 5000, false, &cmt_register_id);
1879 usart_dcd = true; // Jackie Chan no Spartan X
1880 cmt_register_id = -1;
1883 beep_signal = !beep_signal;
1884 d_pcm->write_signal(SIG_PCM1BIT_SIGNAL, ((beep_on && beep_signal) || sing_signal) ? 1 : 0, 1);
1886 #ifdef SUPPORT_PC88_CDROM
1888 if((cdda_volume += 0.1) >= 100.0) {
1889 cancel_event(this, cdda_register_id);
1890 cdda_register_id = -1;
1891 cdda_volume = 100.0;
1893 d_scsi_cdrom->set_volume((int)cdda_volume);
1895 case EVENT_FADE_OUT:
1896 if((cdda_volume -= 0.1) <= 0) {
1897 cancel_event(this, cdda_register_id);
1898 cdda_register_id = -1;
1901 d_scsi_cdrom->set_volume((int)cdda_volume);
1907 void PC88::event_frame()
1909 // update key status
1910 memcpy(key_status, emu->get_key_buffer(), sizeof(key_status));
1912 for(int i = 0; i < array_length(key_conv_table); i++) {
1913 // INS or F6-F10 -> SHIFT + DEL or F1-F5
1914 if(key_status[key_conv_table[i][0]]) {
1915 key_status[key_conv_table[i][1]] = 1;
1916 key_status[0x10] |= key_conv_table[i][2];
1919 if(key_status[0x11] && (key_status[0xbc] || key_status[0xbe])) {
1920 // CTRL + "," or "." -> NumPad "," or "."
1921 key_status[0x6c] = key_status[0xbc];
1922 key_status[0x6e] = key_status[0xbe];
1923 key_status[0x11] = key_status[0xbc] = key_status[0xbe] = 0;
1925 key_status[0x14] = key_caps;
1926 key_status[0x15] = key_kana;
1928 crtc.update_blink();
1930 #ifdef SUPPORT_PC88_JOYSTICK
1931 mouse_dx += mouse_status[0];
1932 mouse_dy += mouse_status[1];
1936 void PC88::event_vline(int v, int clock)
1938 int disp_line = crtc.height * crtc.char_height;
1941 if(crtc.status & 0x10) {
1942 // start dma transfer to crtc
1944 if(!dmac.ch[2].running) {
1945 // dma underrun occurs !!!
1947 // crtc.status &= ~0x10;
1952 // from memory access test on PC-8801MA2 (XM8 version 1.20)
1953 busreq_clocks = (int)((double)(dmac.ch[2].count.sd + 1) * (cpu_clock_low ? 5.95 : 10.58) / (double)disp_line + 0.5);
1954 // busreq_clocks = (int)((double)(dmac.ch[2].count.sd + 1) * (cpu_clock_low ? 7.0 : 16.0) / (double)disp_line + 0.5);
1957 // for Nobunaga Fuunroku Opening (XM8 version 1.00)
1958 // request_intr(IRQ_VRTC, false);
1959 update_gvram_wait();
1962 if(/*(crtc.status & 0x10) && */dmac.ch[2].running) {
1964 #if defined(_PC8001SR)
1965 if(config.boot_mode == MODE_PC80_V1 || config.boot_mode == MODE_PC80_N) {
1967 if(config.boot_mode == MODE_PC88_V1S || config.boot_mode == MODE_PC88_N) {
1969 d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
1970 register_event_by_clock(this, EVENT_BUSREQ, busreq_clocks, false, NULL);
1972 // run dma transfer to crtc
1973 if((v % crtc.char_height) == 0) {
1974 dmac.run(2, 80 + crtc.attrib.num * 2);
1977 } else if(v == disp_line) {
1978 if(/*(crtc.status & 0x10) && */dmac.ch[2].running) {
1980 // for Romancia (XM8 version 1.00)
1981 // crtc.expand_buffer(hireso, Port31_400LINE);
1983 // for Romancia (XM8 version 1.00)
1984 crtc.expand_buffer(hireso, Port31_400LINE);
1987 request_intr(IRQ_VRTC, true);
1988 update_gvram_wait();
1991 #if !defined(_PC8001SR)
1992 if(v < (disp_line <= 200 ? 200 : 400)) {
1996 if(update_palette) {
1997 static bool initialized = false;
1998 static palette_t initial[9] = {0};
2001 for(int i = 1; i < 8; i++) {
2002 initial[i].b = (i & 1) ? 7 : 0;
2003 initial[i].r = (i & 2) ? 7 : 0;
2004 initial[i].g = (i & 4) ? 7 : 0;
2008 for(int i = 0; i < 9; i++) {
2009 palette_digital[i] = palette_analog[i] = initial[i];
2011 #if defined(_PC8001SR)
2012 if(config.boot_mode != MODE_PC80_V2) {
2013 if(Port31_V1_320x200) {
2014 for(int i = 0; i < 3; i++) {
2015 palette_analog[i].b = (port[0x31] & 4) ? 7 : 0;
2016 palette_analog[i].r = (i & 1) ? 7 : 0;
2017 palette_analog[i].g = (i & 2) ? 7 : 0;
2019 palette_analog[3] = palette[8];
2020 } else if(Port31_V1_MONO) {
2021 // palette_analog[0] = {0, 0, 0};
2022 palette_analog[1] = palette[8];
2024 // for(int i = 1; i < 8; i++) {
2025 // palette_analog[i].b = (i & 1) ? 7 : 0;
2026 // palette_analog[i].r = (i & 2) ? 7 : 0;
2027 // palette_analog[i].g = (i & 4) ? 7 : 0;
2029 palette_analog[0] = palette[8];
2031 if(Port31_V1_320x200) {
2032 // palette_digital[0] = {0, 0, 0};
2034 palette_digital[0] = palette_analog[0];
2037 for(int i = 0; i < 8; i++) {
2038 palette_analog[i].b = (port[0x54 + i] & 1) ? 7 : 0;
2039 palette_analog[i].r = (port[0x54 + i] & 2) ? 7 : 0;
2040 palette_analog[i].g = (port[0x54 + i] & 4) ? 7 : 0;
2042 if(!Port31_HCOLOR) {
2043 palette_analog[0] = palette[8];
2045 palette_digital[0] = palette_analog[0];
2048 for(int i = 0; i < 8; i++) {
2049 palette_analog[i] = palette[i];
2051 if(!Port31_HCOLOR) {
2053 palette_analog[0] = palette[8];
2055 palette_analog[0] = palette[9];
2058 palette_digital[0] = palette_analog[0];
2062 memset(palette_line_changed, 0, sizeof(palette_line_changed));
2064 if((palette_line_changed[v] = (update_palette || v == 0)) == true) {
2065 for(int i = 0; i < 9; i++) {
2066 palette_line_digital[v][i] = palette_digital[i];
2067 palette_line_analog [v][i] = palette_analog [i];
2069 update_palette = false;
2074 void PC88::key_down(int code, bool repeat)
2079 } else if(code == 0x15) {
2085 void PC88::play_tape(const _TCHAR* file_path)
2089 if(cmt_fio->Fopen(file_path, FILEIO_READ_BINARY)) {
2090 if(check_file_extension(file_path, _T(".n80"))) {
2091 cmt_fio->Fread(ram + 0x8000, 0x7f40, 1);
2093 d_cpu->set_sp(ram[0xff3e] | (ram[0xff3f] << 8));
2094 d_cpu->set_pc(0xff3d);
2098 cmt_fio->Fseek(0, FILEIO_SEEK_END);
2099 cmt_bufcnt = cmt_fio->Ftell();
2101 cmt_data_carrier_cnt = 0;
2102 cmt_fio->Fseek(0, FILEIO_SEEK_SET);
2103 memset(cmt_buffer, 0, sizeof(cmt_buffer));
2104 cmt_fio->Fread(cmt_buffer, sizeof(cmt_buffer), 1);
2107 if(strncmp((char *)cmt_buffer, "PC-8801 Tape Image(T88)", 23) == 0) {
2108 // this is t88 format
2109 int ptr = 24, tag = -1, len = 0, prev_bufptr = 0;
2110 while(!(tag == 0 && len == 0)) {
2111 tag = cmt_buffer[ptr + 0] | (cmt_buffer[ptr + 1] << 8);
2112 len = cmt_buffer[ptr + 2] | (cmt_buffer[ptr + 3] << 8);
2117 for(int i = 12; i < len; i++) {
2118 cmt_buffer[cmt_bufptr++] = cmt_buffer[ptr + i];
2120 } else if(tag == 0x0102 || tag == 0x0103) {
2122 if(prev_bufptr != cmt_bufptr) {
2123 cmt_data_carrier[cmt_data_carrier_cnt++] = prev_bufptr = cmt_bufptr;
2128 cmt_bufcnt = cmt_bufptr;
2131 cmt_play = (cmt_bufcnt != 0);
2133 if(cmt_play && Port30_MTON) {
2134 // start motor and detect the data carrier at the top of tape
2135 if(cmt_register_id != -1) {
2136 cancel_event(this, cmt_register_id);
2138 register_event(this, EVENT_CMT_SEND, 5000, false, &cmt_register_id);
2143 void PC88::rec_tape(const _TCHAR* file_path)
2147 if(cmt_fio->Fopen(file_path, FILEIO_READ_WRITE_NEW_BINARY)) {
2148 my_tcscpy_s(rec_file_path, _MAX_PATH, file_path);
2154 void PC88::close_tape()
2160 d_sio->write_signal(SIG_I8251_CLEAR, 0, 0);
2163 void PC88::release_tape()
2166 if(cmt_fio->IsOpened()) {
2167 if(cmt_rec && cmt_bufptr) {
2168 cmt_fio->Fwrite(cmt_buffer, cmt_bufptr, 1);
2172 cmt_play = cmt_rec = false;
2175 bool PC88::is_frame_skippable()
2177 return (cmt_play && cmt_bufptr < cmt_bufcnt && Port30_MTON);
2180 bool PC88::check_data_carrier()
2182 if(cmt_bufptr == 0) {
2184 } else if(cmt_data_carrier_cnt) {
2185 for(int i = 0; i < cmt_data_carrier_cnt; i++) {
2186 if(cmt_data_carrier[i] == cmt_bufptr) {
2190 } else if(cmt_buffer[cmt_bufptr] == 0xd3) {
2191 for(int i = 1; i < 10; i++) {
2192 if(cmt_buffer[cmt_bufptr + i] != cmt_buffer[cmt_bufptr]) {
2197 } else if(cmt_buffer[cmt_bufptr] == 0x9c) {
2198 for(int i = 1; i < 6; i++) {
2199 if(cmt_buffer[cmt_bufptr + i] != cmt_buffer[cmt_bufptr]) {
2208 void PC88::draw_screen()
2210 // render text screen
2213 // render graph screen
2214 bool disp_color_graph = true;
2215 bool draw_scanline_black = config.scan_line;
2216 #if defined(_PC8001SR)
2217 if(config.boot_mode != MODE_PC80_V2) {
2218 if(Port31_V1_320x200) {
2219 disp_color_graph = draw_320x200_4color_graph();
2220 } else if(Port31_V1_MONO) {
2221 draw_640x200_mono_graph();
2224 draw_scanline_black = false;
2226 draw_640x200_attrib_graph();
2228 emu->set_vm_screen_lines(200);
2231 if(Port31_320x200) {
2232 disp_color_graph = draw_320x200_color_graph();
2234 disp_color_graph = draw_640x200_color_graph();
2236 emu->set_vm_screen_lines(200);
2238 if(Port31_320x200) {
2239 draw_320x200_attrib_graph();
2241 draw_640x200_attrib_graph();
2244 draw_scanline_black = false;
2246 emu->set_vm_screen_lines(200);
2251 disp_color_graph = draw_640x200_color_graph();
2252 emu->set_vm_screen_lines(200);
2253 } else if(!Port31_400LINE) {
2255 draw_scanline_black = false;
2257 draw_640x200_attrib_graph();
2258 // draw_640x200_mono_graph();
2259 emu->set_vm_screen_lines(200);
2262 draw_scanline_black = false;
2264 draw_640x400_attrib_graph();
2265 // draw_640x400_mono_graph();
2266 emu->set_vm_screen_lines(400);
2270 // create palette for each scanline
2271 #if !defined(_PC8001SR)
2272 int disp_line = crtc.height * crtc.char_height;
2273 int ymax = (disp_line <= 200) ? 200 : 400;
2277 static const uint32_t pex[8] = {
2278 0, 36, 73, 109, 146, 182, 219, 255 // from m88
2280 scrntype_t palette_digital_text_pc [9];
2281 scrntype_t palette_analog_text_pc [9];
2282 scrntype_t palette_digital_graph_pc[9];
2283 scrntype_t palette_analog_graph_pc [9];
2285 scrntype_t palette_line_digital_text_pc [400][9];
2286 scrntype_t palette_line_analog_graph_pc [400][9];
2287 #if !defined(_PC8001SR)
2288 scrntype_t palette_line_analog_text_pc [400][9];
2289 scrntype_t palette_line_digital_graph_pc[400][9];
2292 for(int y = 0; y < ymax; y++) {
2293 if(palette_line_changed[y]) {
2294 for(int i = 0; i < 9; i++) {
2295 // A is a flag for crt filter
2296 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);
2297 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);
2298 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);
2299 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);
2301 // set back color to black if cg screen is off in color mode
2302 if(!disp_color_graph) {
2303 palette_digital_text_pc [0] =
2304 palette_analog_text_pc [0] =
2305 palette_digital_graph_pc[0] =
2306 palette_analog_graph_pc [0] = 0;
2308 palette_analog_text_pc [8] = palette_digital_text_pc [0];
2309 palette_analog_graph_pc[8] = palette_digital_graph_pc[0];
2312 for(int i = 0; i < 9; i++) {
2313 palette_line_digital_text_pc [2 * y ][i] =
2314 palette_line_digital_text_pc [2 * y + 1][i] = palette_digital_text_pc [i];
2315 palette_line_analog_graph_pc [2 * y ][i] =
2316 palette_line_analog_graph_pc [2 * y + 1][i] = palette_analog_graph_pc [i];
2317 #if !defined(_PC8001SR)
2318 palette_line_analog_text_pc [2 * y ][i] =
2319 palette_line_analog_text_pc [2 * y + 1][i] = palette_analog_text_pc [i];
2320 palette_line_digital_graph_pc[2 * y ][i] =
2321 palette_line_digital_graph_pc[2 * y + 1][i] = palette_digital_graph_pc[i];
2325 for(int i = 0; i < 9; i++) {
2326 palette_line_digital_text_pc [y][i] = palette_digital_text_pc [i];
2327 palette_line_analog_graph_pc [y][i] = palette_analog_graph_pc [i];
2328 #if !defined(_PC8001SR)
2329 palette_line_analog_text_pc [y][i] = palette_analog_text_pc [i];
2330 palette_line_digital_graph_pc[y][i] = palette_digital_graph_pc[i];
2336 // copy to screen buffer
2337 #if !defined(_PC8001SR)
2338 #if defined(SUPPORT_PC88_VAB)
2340 if(PortB4_VAB_DISP) {
2341 uint8_t *src = &exram[(0x8000 * 4) * PC88_VAB_PAGE];
2343 for(int y = 0; y < 400; y += 2) {
2344 scrntype_t* dest0 = emu->get_screen_buffer(y);
2345 scrntype_t* dest1 = emu->get_screen_buffer(y + 1);
2347 for(int x = 0; x < 640; x += 2) {
2351 dest0[x] = dest0[x + 1] = palette_vab_pc[c.w];
2353 if(config.scan_line) {
2354 memset(dest1, 0, sizeof(scrntype_t) * 640);
2356 memcpy(dest1, dest0, sizeof(scrntype_t) * 640);
2359 emu->screen_skip_line(true);
2362 if(!Port31_HCOLOR && Port31_400LINE) {
2363 for(int y = 0; y < 400; y++) {
2364 scrntype_t* dest = emu->get_screen_buffer(y);
2365 uint8_t* src_t = text[y >> 1];
2366 uint8_t* src_g = graph[y];
2370 // if(Port31_HCOLOR) {
2371 // pal_t = palette_line_digital_text_pc [y];
2372 // pal_g = palette_line_analog_graph_pc [y];
2375 pal_t = palette_line_analog_text_pc [y];
2376 pal_g = palette_line_analog_graph_pc [y];
2378 pal_t = palette_line_digital_text_pc [y];
2379 pal_g = palette_line_digital_graph_pc[y];
2381 for(int x = 0; x < 640; x++) {
2382 uint32_t t = src_t[x];
2383 dest[x] = t ? pal_t[t] : pal_g[src_g[x]];
2386 emu->screen_skip_line(false);
2390 for(int y = 0; y < 400; y++) {
2391 scrntype_t* dest = emu->get_screen_buffer(y);
2392 uint8_t* src_t = text[y >> 1];
2393 uint8_t* src_g = graph[y];
2396 #if defined(_PC8001SR)
2397 pal_t = palette_line_digital_text_pc[y];
2398 pal_g = palette_line_analog_graph_pc[y];
2400 if(port[0x33] & 8) {
2401 for(int x = 0; x < 640; x++) {
2402 uint32_t t = src_t[x];
2403 uint32_t g = src_g[x];
2404 dest[x] = (!g && t) ? pal_t[t] : ((y & 1) && draw_scanline_black) ? 0 : pal_g[g];
2407 for(int x = 0; x < 640; x++) {
2408 uint32_t t = src_t[x];
2409 dest[x] = t ? pal_t[t] : ((y & 1) && draw_scanline_black) ? 0 : pal_g[src_g[x]];
2414 pal_t = palette_line_digital_text_pc [y];
2415 pal_g = palette_line_analog_graph_pc [y];
2416 } else if(Port32_PMODE) {
2417 pal_t = palette_line_analog_text_pc [y];
2418 pal_g = palette_line_analog_graph_pc [y];
2420 pal_t = palette_line_digital_text_pc [y];
2421 pal_g = palette_line_digital_graph_pc[y];
2423 for(int x = 0; x < 640; x++) {
2424 uint32_t t = src_t[x];
2425 dest[x] = t ? pal_t[t] : ((y & 1) && draw_scanline_black) ? 0 : pal_g[src_g[x]];
2429 emu->screen_skip_line(true);
2439 bit4: graph=1/character=0
2446 void PC88::draw_text()
2448 if(crtc.status & 0x88) {
2450 crtc.status &= ~0x80;
2451 memset(crtc.text.expand, 0, 200 * 80);
2452 memset(crtc.attrib.expand, crtc.reverse ? 3 : 2, 200 * 80);
2454 // for Advanced Fantasian Opening (20line) (XM8 version 1.00)
2455 if(!(crtc.status & 0x10) || Port53_TEXTDS) {
2456 // if(!(crtc.status & 0x10) || (crtc.status & 8) || Port53_TEXTDS) {
2457 memset(crtc.text.expand, 0, 200 * 80);
2458 for(int y = 0; y < 200; y++) {
2459 for(int x = 0; x < 80; x++) {
2460 crtc.attrib.expand[y][x] &= 0xe0;
2461 crtc.attrib.expand[y][x] |= 0x02;
2464 // memset(crtc.attrib.expand, 2, 200 * 80);
2468 memset(text, 8, sizeof(text));
2469 memset(text_color, 7, sizeof(text_color));
2470 memset(text_reverse, 0, sizeof(text_reverse));
2472 int char_height = crtc.char_height;
2473 uint8_t color_mask = Port30_COLOR ? 0 : 7;
2474 uint8_t code_expand, attr_expand;
2479 // if(Port31_400LINE || !crtc.skip_line) {
2480 // char_height >>= 1;
2482 if(crtc.skip_line) {
2485 // for(int cy = 0, ytop = 0; cy < 64 && ytop < 400; cy++, ytop += char_height) {
2486 for(int cy = 0, ytop = 0; cy < crtc.height && ytop < 400; cy++, ytop += char_height) {
2487 for(int x = 0, cx = 0; cx < crtc.width; x += 8, cx++) {
2488 if(Port30_40 && (cx & 1)) {
2489 // don't update code/attrib
2491 code_expand = crtc.text.expand[cy][cx];
2492 attr_expand = crtc.attrib.expand[cy][cx];
2494 uint8_t attrib = attr_expand;//crtc.attrib.expand[cy][cx];
2495 // uint8_t color = !(Port30_COLOR && (attrib & 8)) ? 7 : (attrib & 0xe0) ? (attrib >> 5) : 8;
2496 uint8_t color = (attrib & 0xe0) ? ((attrib >> 5) | color_mask) : 8;
2497 bool under_line = ((attrib & 8) != 0);
2498 bool upper_line = ((attrib & 4) != 0);
2499 bool secret = ((attrib & 2) != 0);
2500 bool reverse = ((attrib & 1) != 0);
2502 uint8_t color_tmp = color;
2503 bool reverse_tmp = reverse;
2505 // from ePC-8801MA
\89ü
2506 if(Port31_GRAPH && !Port31_HCOLOR) {
2512 uint8_t code = secret ? 0 : code_expand;//crtc.text.expand[cy][cx];
2513 #ifdef SUPPORT_PC88_PCG8100
2514 uint8_t *pattern = ((attrib & 0x10) ? sg_pattern : pcg_pattern) + code * 8;
2516 uint8_t *pattern = ((attrib & 0x10) ? sg_pattern : kanji1 + 0x1000) + code * 8;
2519 for(int l = 0, y = ytop; l < char_height / 2 && y < 400; l++, y += 2) {
2520 uint8_t pat = (l < 8) ? pattern[l] : 0;
2523 // from ePC-8801MA
\89ü
2524 static const uint8_t wct[16] = {
2525 0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff
2527 pat = wct[(cx & 1) ? (pat & 0x0f) : (pat >> 4)];
2529 if((upper_line && l == 0) || (under_line && l >= 7)) {
2535 uint8_t *dest = &text[y >> 1][x];
2536 dest[0] = (pat & 0x80) ? color : 0;
2537 dest[1] = (pat & 0x40) ? color : 0;
2538 dest[2] = (pat & 0x20) ? color : 0;
2539 dest[3] = (pat & 0x10) ? color : 0;
2540 dest[4] = (pat & 0x08) ? color : 0;
2541 dest[5] = (pat & 0x04) ? color : 0;
2542 dest[6] = (pat & 0x02) ? color : 0;
2543 dest[7] = (pat & 0x01) ? color : 0;
2545 // store text attributes for monocolor graph screen
2546 text_color[y >> 1][cx] = color_tmp;
2547 text_reverse[y >> 1][cx] = reverse_tmp;
2553 #if defined(_PC8001SR)
2554 bool PC88::draw_320x200_color_graph()
2556 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS)) {
2557 memset(graph, 0, sizeof(graph));
2560 uint8_t *gvram_b0 = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2561 uint8_t *gvram_r0 = Port53_G0DS ? gvram_null : (gvram + 0x4000);
2562 uint8_t *gvram_g0 = Port53_G0DS ? gvram_null : (gvram + 0x8000);
2563 uint8_t *gvram_b1 = Port53_G1DS ? gvram_null : (gvram + 0x2000);
2564 uint8_t *gvram_r1 = Port53_G1DS ? gvram_null : (gvram + 0x6000);
2565 uint8_t *gvram_g1 = Port53_G1DS ? gvram_null : (gvram + 0xa000);
2567 if(port[0x33] & 4) {
2570 tmp = gvram_b0; gvram_b0 = gvram_b1; gvram_b1 = tmp;
2571 tmp = gvram_r0; gvram_r0 = gvram_r1; gvram_r1 = tmp;
2572 tmp = gvram_g0; gvram_g0 = gvram_g1; gvram_g1 = tmp;
2575 for(int y = 0, addr = 0; y < 400; y += 2) {
2576 for(int x = 0; x < 640; x += 16) {
2577 uint8_t b0 = gvram_b0[addr];
2578 uint8_t r0 = gvram_r0[addr];
2579 uint8_t g0 = gvram_g0[addr];
2580 uint8_t b1 = gvram_b1[addr];
2581 uint8_t r1 = gvram_r1[addr];
2582 uint8_t g1 = gvram_g1[addr];
2584 uint8_t *dest = &graph[y][x];
2586 brg0 = ((b0 & 0x80) >> 7) | ((r0 & 0x80) >> 6) | ((g0 & 0x80) >> 5);
2587 brg1 = ((b1 & 0x80) >> 7) | ((r1 & 0x80) >> 6) | ((g1 & 0x80) >> 5);
2588 dest[ 0] = dest[ 1] = brg0 ? brg0 : brg1;
2589 brg0 = ((b0 & 0x40) >> 6) | ((r0 & 0x40) >> 5) | ((g0 & 0x40) >> 4);
2590 brg1 = ((b1 & 0x40) >> 6) | ((r1 & 0x40) >> 5) | ((g1 & 0x40) >> 4);
2591 dest[ 2] = dest[ 3] = brg0 ? brg0 : brg1;
2592 brg0 = ((b0 & 0x20) >> 5) | ((r0 & 0x20) >> 4) | ((g0 & 0x20) >> 3);
2593 brg1 = ((b1 & 0x20) >> 5) | ((r1 & 0x20) >> 4) | ((g1 & 0x20) >> 3);
2594 dest[ 4] = dest[ 5] = brg0 ? brg0 : brg1;
2595 brg0 = ((b0 & 0x10) >> 4) | ((r0 & 0x10) >> 3) | ((g0 & 0x10) >> 2);
2596 brg1 = ((b1 & 0x10) >> 4) | ((r1 & 0x10) >> 3) | ((g1 & 0x10) >> 2);
2597 dest[ 6] = dest[ 7] = brg0 ? brg0 : brg1;
2598 brg0 = ((b0 & 0x08) >> 3) | ((r0 & 0x08) >> 2) | ((g0 & 0x08) >> 1);
2599 brg1 = ((b1 & 0x08) >> 3) | ((r1 & 0x08) >> 2) | ((g1 & 0x08) >> 1);
2600 dest[ 8] = dest[ 9] = brg0 ? brg0 : brg1;
2601 brg0 = ((b0 & 0x04) >> 2) | ((r0 & 0x04) >> 1) | ((g0 & 0x04) );
2602 brg1 = ((b1 & 0x04) >> 2) | ((r1 & 0x04) >> 1) | ((g1 & 0x04) );
2603 dest[10] = dest[11] = brg0 ? brg0 : brg1;
2604 brg0 = ((b0 & 0x02) >> 1) | ((r0 & 0x02) ) | ((g0 & 0x02) << 1);
2605 brg1 = ((b1 & 0x02) >> 1) | ((r1 & 0x02) ) | ((g1 & 0x02) << 1);
2606 dest[12] = dest[13] = brg0 ? brg0 : brg1;
2607 brg0 = ((b0 & 0x01) ) | ((r0 & 0x01) << 1) | ((g0 & 0x01) << 2);
2608 brg1 = ((b1 & 0x01) ) | ((r1 & 0x01) << 1) | ((g1 & 0x01) << 2);
2609 dest[14] = dest[15] = brg0 ? brg0 : brg1;
2611 if(config.scan_line) {
2612 memset(graph[y + 1], 0, 640);
2614 memcpy(graph[y + 1], graph[y], 640);
2620 bool PC88::draw_320x200_4color_graph()
2622 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS && Port53_G2DS)) {
2623 memset(graph, 0, sizeof(graph));
2626 uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2627 uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2628 uint8_t *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
2630 for(int y = 0, addr = 0; y < 400; y += 2) {
2631 for(int x = 0; x < 640; x += 8) {
2632 uint8_t brg = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
2634 uint8_t *dest = &graph[y][x];
2635 dest[0] = dest[1] = (brg >> 6) & 3;
2636 dest[2] = dest[3] = (brg >> 4) & 3;
2637 dest[4] = dest[5] = (brg >> 2) & 3;
2638 dest[6] = dest[7] = (brg ) & 3;
2640 if(config.scan_line) {
2641 memset(graph[y + 1], 0, 640);
2643 memcpy(graph[y + 1], graph[y], 640);
2649 void PC88::draw_320x200_attrib_graph()
2651 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS && Port53_G2DS && Port53_G3DS && Port53_G4DS && Port53_G5DS)) {
2652 memset(graph, 0, sizeof(graph));
2655 uint8_t *gvram_b0 = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2656 uint8_t *gvram_r0 = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2657 uint8_t *gvram_g0 = Port53_G2DS ? gvram_null : (gvram + 0x8000);
2658 uint8_t *gvram_b1 = Port53_G3DS ? gvram_null : (gvram + 0x2000);
2659 uint8_t *gvram_r1 = Port53_G4DS ? gvram_null : (gvram + 0x6000);
2660 uint8_t *gvram_g1 = Port53_G5DS ? gvram_null : (gvram + 0xa000);
2663 for(int y = 0, addr = 0; y < 400; y += 2) {
2664 for(int x = 0, cx = 0; x < 640; x += 16, cx += 2) {
2665 uint8_t color = text_color[y >> 1][cx];
2666 uint8_t brg0 = gvram_b0[addr] | gvram_r0[addr] | gvram_g0[addr] |
2667 gvram_b1[addr] | gvram_r1[addr] | gvram_g1[addr];
2669 if(text_reverse[y >> 1][cx]) {
2674 uint8_t *dest0 = &graph[y ][x];
2675 uint8_t *dest1 = &graph[y + 1][x];
2676 dest0[ 0] = dest0[ 1] = (brg0 & 0x80) ? color : 0;
2677 dest0[ 2] = dest0[ 3] = (brg0 & 0x40) ? color : 0;
2678 dest0[ 4] = dest0[ 5] = (brg0 & 0x20) ? color : 0;
2679 dest0[ 6] = dest0[ 7] = (brg0 & 0x10) ? color : 0;
2680 dest0[ 8] = dest0[ 9] = (brg0 & 0x08) ? color : 0;
2681 dest0[10] = dest0[11] = (brg0 & 0x04) ? color : 0;
2682 dest0[12] = dest0[13] = (brg0 & 0x02) ? color : 0;
2683 dest0[14] = dest0[15] = (brg0 & 0x01) ? color : 0;
2684 if(!hireso) continue;
2685 dest1[ 0] = dest1[ 1] = (brg1 & 0x80) ? color : 0;
2686 dest1[ 2] = dest1[ 3] = (brg1 & 0x40) ? color : 0;
2687 dest1[ 4] = dest1[ 5] = (brg1 & 0x20) ? color : 0;
2688 dest1[ 6] = dest1[ 7] = (brg1 & 0x10) ? color : 0;
2689 dest1[ 8] = dest1[ 9] = (brg1 & 0x08) ? color : 0;
2690 dest1[10] = dest1[11] = (brg1 & 0x04) ? color : 0;
2691 dest1[12] = dest1[13] = (brg1 & 0x02) ? color : 0;
2692 dest1[14] = dest1[15] = (brg1 & 0x01) ? color : 0;
2695 if(config.scan_line) {
2696 memset(graph[y + 1], 0, 640);
2698 memcpy(graph[y + 1], graph[y], 640);
2703 for(int y = 0, addr = 0; y < 400; y += 2) {
2704 for(int x = 0, cx = 0; x < 640; x += 16, cx += 2) {
2705 uint8_t color_l = text_color[y >> 1][cx + 0];
2706 uint8_t color_r = text_color[y >> 1][cx + 1];
2707 uint8_t brg0 = gvram_b0[addr] | gvram_r0[addr] | gvram_g0[addr] |
2708 gvram_b1[addr] | gvram_r1[addr] | gvram_g1[addr];
2710 if(text_reverse[y >> 1][cx + 0]) {
2714 if(text_reverse[y >> 1][cx + 1]) {
2719 uint8_t *dest0 = &graph[y ][x];
2720 uint8_t *dest1 = &graph[y + 1][x];
2721 dest0[ 0] = dest0[ 1] = (brg0 & 0x80) ? color_l : 0;
2722 dest0[ 2] = dest0[ 3] = (brg0 & 0x40) ? color_l : 0;
2723 dest0[ 4] = dest0[ 5] = (brg0 & 0x20) ? color_l : 0;
2724 dest0[ 6] = dest0[ 7] = (brg0 & 0x10) ? color_l : 0;
2725 dest0[ 8] = dest0[ 9] = (brg0 & 0x08) ? color_r : 0;
2726 dest0[10] = dest0[11] = (brg0 & 0x04) ? color_r : 0;
2727 dest0[12] = dest0[13] = (brg0 & 0x02) ? color_r : 0;
2728 dest0[14] = dest0[15] = (brg0 & 0x01) ? color_r : 0;
2729 if(!hireso) continue;
2730 dest1[ 0] = dest1[ 1] = (brg1 & 0x80) ? color_l : 0;
2731 dest1[ 2] = dest1[ 3] = (brg1 & 0x40) ? color_l : 0;
2732 dest1[ 4] = dest1[ 5] = (brg1 & 0x20) ? color_l : 0;
2733 dest1[ 6] = dest1[ 7] = (brg1 & 0x10) ? color_l : 0;
2734 dest1[ 8] = dest1[ 9] = (brg1 & 0x08) ? color_r : 0;
2735 dest1[10] = dest1[11] = (brg1 & 0x04) ? color_r : 0;
2736 dest1[12] = dest1[13] = (brg1 & 0x02) ? color_r : 0;
2737 dest1[14] = dest1[15] = (brg1 & 0x01) ? color_r : 0;
2740 if(config.scan_line) {
2741 memset(graph[y + 1], 0, 640);
2743 memcpy(graph[y + 1], graph[y], 640);
2751 bool PC88::draw_640x200_color_graph()
2753 #if defined(_PC8001SR)
2754 if(!Port31_GRAPH || Port53_G0DS) {
2756 if(!Port31_GRAPH/* || (Port53_G0DS && Port53_G1DS && Port53_G2DS)*/) {
2758 memset(graph, 0, sizeof(graph));
2761 uint8_t *gvram_b = /*Port53_G0DS ? gvram_null : */(gvram + 0x0000);
2762 uint8_t *gvram_r = /*Port53_G1DS ? gvram_null : */(gvram + 0x4000);
2763 uint8_t *gvram_g = /*Port53_G2DS ? gvram_null : */(gvram + 0x8000);
2765 for(int y = 0, addr = 0; y < 400; y += 2) {
2766 for(int x = 0; x < 640; x += 8) {
2767 uint8_t b = gvram_b[addr];
2768 uint8_t r = gvram_r[addr];
2769 uint8_t g = gvram_g[addr];
2771 uint8_t *dest = &graph[y][x];
2772 dest[0] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
2773 dest[1] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
2774 dest[2] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
2775 dest[3] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
2776 dest[4] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
2777 dest[5] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04) );
2778 dest[6] = ((b & 0x02) >> 1) | ((r & 0x02) ) | ((g & 0x02) << 1);
2779 dest[7] = ((b & 0x01) ) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
2781 if(config.scan_line) {
2782 memset(graph[y + 1], 0, 640);
2784 memcpy(graph[y + 1], graph[y], 640);
2790 void PC88::draw_640x200_mono_graph()
2792 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS && Port53_G2DS)) {
2793 memset(graph, 0, sizeof(graph));
2796 uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2797 uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2798 uint8_t *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
2800 for(int y = 0, addr = 0; y < 400; y += 2) {
2801 for(int x = 0; x < 640; x += 8) {
2802 uint8_t brg = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
2804 uint8_t *dest = &graph[y][x];
2805 dest[0] = (brg & 0x80) >> 7;
2806 dest[1] = (brg & 0x40) >> 6;
2807 dest[2] = (brg & 0x20) >> 5;
2808 dest[3] = (brg & 0x10) >> 4;
2809 dest[4] = (brg & 0x08) >> 3;
2810 dest[5] = (brg & 0x04) >> 2;
2811 dest[6] = (brg & 0x02) >> 1;
2812 dest[7] = (brg & 0x01) ;
2814 if(config.scan_line) {
2815 memset(graph[y + 1], 0, 640);
2817 memcpy(graph[y + 1], graph[y], 640);
2822 void PC88::draw_640x200_attrib_graph()
2824 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS && Port53_G2DS)) {
2825 memset(graph, 0, sizeof(graph));
2828 uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2829 uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2830 uint8_t *gvram_g = Port53_G2DS ? gvram_null : (gvram + 0x8000);
2832 for(int y = 0, addr = 0; y < 400; y += 2) {
2833 for(int x = 0, cx = 0; x < 640; x += 8, cx++) {
2834 uint8_t color = text_color[y >> 1][cx];
2835 uint8_t brg0 = gvram_b[addr] | gvram_r[addr] | gvram_g[addr];
2837 if(text_reverse[y >> 1][cx]) {
2842 uint8_t *dest0 = &graph[y ][x];
2843 uint8_t *dest1 = &graph[y + 1][x];
2844 dest0[0] = (brg0 & 0x80) ? color : 0;
2845 dest0[1] = (brg0 & 0x40) ? color : 0;
2846 dest0[2] = (brg0 & 0x20) ? color : 0;
2847 dest0[3] = (brg0 & 0x10) ? color : 0;
2848 dest0[4] = (brg0 & 0x08) ? color : 0;
2849 dest0[5] = (brg0 & 0x04) ? color : 0;
2850 dest0[6] = (brg0 & 0x02) ? color : 0;
2851 dest0[7] = (brg0 & 0x01) ? color : 0;
2852 if(!hireso) continue;
2853 dest1[0] = (brg1 & 0x80) ? color : 0;
2854 dest1[1] = (brg1 & 0x40) ? color : 0;
2855 dest1[2] = (brg1 & 0x20) ? color : 0;
2856 dest1[3] = (brg1 & 0x10) ? color : 0;
2857 dest1[4] = (brg1 & 0x08) ? color : 0;
2858 dest1[5] = (brg1 & 0x04) ? color : 0;
2859 dest1[6] = (brg1 & 0x02) ? color : 0;
2860 dest1[7] = (brg1 & 0x01) ? color : 0;
2863 if(config.scan_line) {
2864 memset(graph[y + 1], 0, 640);
2866 memcpy(graph[y + 1], graph[y], 640);
2872 #if !defined(_PC8001SR)
2873 void PC88::draw_640x400_mono_graph()
2875 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS)) {
2876 memset(graph, 0, sizeof(graph));
2879 uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2880 uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2882 for(int y = 0, addr = 0; y < 200; y++) {
2883 for(int x = 0; x < 640; x += 8) {
2884 uint8_t b = gvram_b[addr];
2886 uint8_t *dest = &graph[y][x];
2887 dest[0] = (b & 0x80) >> 7;
2888 dest[1] = (b & 0x40) >> 6;
2889 dest[2] = (b & 0x20) >> 5;
2890 dest[3] = (b & 0x10) >> 4;
2891 dest[4] = (b & 0x08) >> 3;
2892 dest[5] = (b & 0x04) >> 2;
2893 dest[6] = (b & 0x02) >> 1;
2894 dest[7] = (b & 0x01) ;
2897 for(int y = 200, addr = 0; y < 400; y++) {
2898 for(int x = 0; x < 640; x += 8) {
2899 uint8_t r = gvram_r[addr];
2901 uint8_t *dest = &graph[y][x];
2902 dest[0] = (r & 0x80) >> 7;
2903 dest[1] = (r & 0x40) >> 6;
2904 dest[2] = (r & 0x20) >> 5;
2905 dest[3] = (r & 0x10) >> 4;
2906 dest[4] = (r & 0x08) >> 3;
2907 dest[5] = (r & 0x04) >> 2;
2908 dest[6] = (r & 0x02) >> 1;
2909 dest[7] = (r & 0x01) ;
2914 void PC88::draw_640x400_attrib_graph()
2916 if(!Port31_GRAPH || (Port53_G0DS && Port53_G1DS)) {
2917 memset(graph, 0, sizeof(graph));
2920 uint8_t *gvram_b = Port53_G0DS ? gvram_null : (gvram + 0x0000);
2921 uint8_t *gvram_r = Port53_G1DS ? gvram_null : (gvram + 0x4000);
2923 for(int y = 0, addr = 0; y < 200; y++) {
2924 for(int x = 0, cx = 0; x < 640; x += 8, cx++) {
2925 uint8_t color = text_color[y >> 1][cx];
2926 uint8_t b = gvram_b[addr];
2927 if(text_reverse[y >> 1][cx]) {
2931 uint8_t *dest = &graph[y][x];
2932 dest[0] = (b & 0x80) ? color : 0;
2933 dest[1] = (b & 0x40) ? color : 0;
2934 dest[2] = (b & 0x20) ? color : 0;
2935 dest[3] = (b & 0x10) ? color : 0;
2936 dest[4] = (b & 0x08) ? color : 0;
2937 dest[5] = (b & 0x04) ? color : 0;
2938 dest[6] = (b & 0x02) ? color : 0;
2939 dest[7] = (b & 0x01) ? color : 0;
2942 for(int y = 200, addr = 0; y < 400; y++) {
2943 for(int x = 0, cx = 0; x < 640; x += 8, cx++) {
2944 uint8_t color = text_color[y >> 1][cx];
2945 uint8_t r = gvram_r[addr];
2946 if(text_reverse[y >> 1][cx]) {
2950 uint8_t *dest = &graph[y][x];
2951 dest[0] = (r & 0x80) ? color : 0;
2952 dest[1] = (r & 0x40) ? color : 0;
2953 dest[2] = (r & 0x20) ? color : 0;
2954 dest[3] = (r & 0x10) ? color : 0;
2955 dest[4] = (r & 0x08) ? color : 0;
2956 dest[5] = (r & 0x04) ? color : 0;
2957 dest[6] = (r & 0x02) ? color : 0;
2958 dest[7] = (r & 0x01) ? color : 0;
2964 void PC88::request_intr(int level, bool status)
2966 uint8_t bit = 1 << level;
2969 // for Nobunaga Fuunroku Opening & MID-GARTS Opening (XM8 version 1.00)
2970 // bit &= intr_mask2;
2971 if(!(intr_req & bit)) {
2976 if(intr_req & bit) {
2983 void PC88::update_intr()
2985 d_cpu->set_intr_line(((intr_req & intr_mask1 & intr_mask2) != 0), true, 0);
2988 uint32_t PC88::get_intr_ack()
2990 uint8_t ai = intr_req & intr_mask1 & intr_mask2;
2992 for(int i = 0; i < 8; i++, ai >>= 1) {
2994 intr_req &= ~(1 << i);
3002 void PC88::notify_intr_ei()
3007 /* ----------------------------------------------------------------------------
3009 ---------------------------------------------------------------------------- */
3011 void pc88_crtc_t::reset(bool hireso)
3014 cursor.type = cursor.mode = -1;
3015 cursor.x = cursor.y = -1;
3020 char_height = hireso ? 16 : 8;
3022 vretrace = hireso ? 3 : 7;
3023 timing_changed = false;
3028 void pc88_crtc_t::write_cmd(uint8_t data)
3030 cmd = (data >> 5) & 7;
3035 status |= 0x80; // fix
3036 cursor.x = cursor.y = -1;
3038 case 1: // start display
3041 status |= 0x90; // fix
3044 case 2: // set interrupt mask
3046 // status = 0; // from M88
3047 status = 0x80; // fix
3049 intr_mask = data & 3;
3051 case 3: // read light pen
3054 case 4: // load cursor position ON/OFF
3055 cursor.type = (data & 1) ? cursor.mode : -1;
3057 case 5: // reset interrupt
3060 case 6: // reset counters
3066 void pc88_crtc_t::write_param(uint8_t data)
3072 width = min((data & 0x7f) + 2, 80);
3075 if(height != (data & 0x3f) + 1) {
3076 height = (data & 0x3f) + 1;
3077 timing_changed = true;
3079 blink.rate = 32 * ((data >> 6) + 1);
3082 if(char_height != (data & 0x1f) + 1) {
3083 char_height = (data & 0x1f) + 1;
3084 timing_changed = true;
3086 cursor.mode = (data >> 5) & 3;
3087 skip_line = ((data & 0x80) != 0);
3090 if(vretrace != ((data >> 5) & 7) + 1) {
3091 vretrace = ((data >> 5) & 7) + 1;
3092 timing_changed = true;
3096 mode = (data >> 5) & 7;
3097 attrib.num = (mode & 1) ? 0 : min((data & 0x1f) + 1, 20);
3118 uint32_t pc88_crtc_t::read_param()
3120 uint32_t val = 0xff;
3123 case 3: // read light pen
3135 val = read_status();
3142 uint32_t pc88_crtc_t::read_status()
3145 return status & ~0x10;
3151 void pc88_crtc_t::start()
3153 memset(buffer, 0, sizeof(buffer));
3158 void pc88_crtc_t::finish()
3160 if((status & 0x10) && !(intr_mask & 1)) {
3166 void pc88_crtc_t::write_buffer(uint8_t data)
3168 buffer[(buffer_ptr++) & 0x3fff] = data;
3171 uint8_t pc88_crtc_t::read_buffer(int ofs)
3173 if(ofs < buffer_ptr) {
3176 // dma underrun occurs !!!
3182 void pc88_crtc_t::update_blink()
3185 if(++blink.counter > blink.rate) {
3188 blink.attrib = (blink.counter < blink.rate / 4) ? 2 : 0;
3189 blink.cursor = (blink.counter <= blink.rate / 4) || (blink.rate / 2 <= blink.counter && blink.counter <= 3 * blink.rate / 4);
3192 void pc88_crtc_t::expand_buffer(bool hireso, bool line400)
3194 int char_height_tmp = char_height;
3198 char_height_tmp <<= 1;
3200 if(line400 || !skip_line) {
3201 char_height_tmp >>= 1;
3203 if(!(status & 0x10)) {
3207 for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
3208 for(int cx = 0; cx < width; cx++) {
3209 text.expand[cy][cx] = read_buffer(ofs + cx);
3211 if((status & 8) && exitline == -1) {
3218 for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
3219 for(int cx = 0; cx < width; cx += 2) {
3220 set_attrib(read_buffer(ofs + cx + 1));
3221 attrib.expand[cy][cx] = attrib.expand[cy][cx + 1] = attrib.data;
3223 if((status & 8) && exitline == -1) {
3231 memset(attrib.expand, 0xe0, sizeof(attrib.expand));
3233 for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
3235 memset(flags, 0, sizeof(flags));
3236 for(int i = 2 * (attrib.num - 1); i >= 0; i -= 2) {
3237 flags[read_buffer(ofs + i + 80) & 0x7f] = 1;
3239 attrib.data &= 0xf3; // for PC-8801mkIIFR
\95t
\91®
\83f
\83\82
3241 for(int cx = 0, pos = 0; cx < width; cx++) {
3243 set_attrib(read_buffer(ofs + pos + 81));
3246 attrib.expand[cy][cx] = attrib.data;
3248 if((status & 8) && exitline == -1) {
3255 if(cursor.x < 80 && cursor.y < 200) {
3256 if((cursor.type & 1) && blink.cursor) {
3259 static const uint8_t ctype[5] = {0, 8, 8, 1, 1};
3260 attrib.expand[cursor.y][cursor.x] ^= ctype[cursor.type + 1];
3265 if(exitline != -1) {
3266 for(int cy = exitline; cy < 200; cy++) {
3267 memset(&text.expand[cy][0], 0, width);
3269 // SORCERIAN Music Library ver-2.1
3270 memset(&attrib.expand[cy][0], 0xe0, width); // color=7
3272 // from ePC-8801MA
\89ü
3273 memset(&attrib.expand[cy][0], 0x00, width);
3279 void pc88_crtc_t::set_attrib(uint8_t code)
3284 attrib.data = (attrib.data & 0x0f) | (code & 0xf0);
3286 attrib.data = (attrib.data & 0xf0) | ((code >> 2) & 0x0d) | ((code << 1) & 2);
3287 attrib.data ^= reverse;
3288 attrib.data ^= ((code & 2) && !(code & 1)) ? blink.attrib : 0;
3291 attrib.data = 0xe0 | ((code >> 3) & 0x10) | ((code >> 2) & 0x0d) | ((code << 1) & 2);
3292 attrib.data ^= reverse;
3293 attrib.data ^= ((code & 2) && !(code & 1)) ? blink.attrib : 0;
3297 /* ----------------------------------------------------------------------------
3299 ---------------------------------------------------------------------------- */
3301 void pc88_dmac_t::write_io8(uint32_t addr, uint32_t data)
3303 int c = (addr >> 1) & 3;
3305 switch(addr & 0x0f) {
3311 if((mode & 0x80) && c == 2) {
3312 ch[3].addr.b.l = data;
3314 ch[c].addr.b.l = data;
3316 if((mode & 0x80) && c == 2) {
3317 ch[3].addr.b.h = data;
3318 ch[3].addr.b.h2 = ch[3].addr.b.h3 = 0;
3320 ch[c].addr.b.h = data;
3321 ch[c].addr.b.h2 = ch[c].addr.b.h3 = 0;
3323 high_low = !high_low;
3330 if((mode & 0x80) && c == 2) {
3331 ch[3].count.b.l = data;
3333 ch[c].count.b.l = data;
3335 if((mode & 0x80) && c == 2) {
3336 ch[3].count.b.h = data & 0x3f;
3337 ch[3].count.b.h2 = ch[3].count.b.h3 = 0;
3338 ch[3].mode = data & 0xc0;
3340 ch[c].count.b.h = data & 0x3f;
3341 ch[c].count.b.h2 = ch[c].count.b.h3 = 0;
3342 ch[c].mode = data & 0xc0;
3344 high_low = !high_low;
3353 uint32_t pc88_dmac_t::read_io8(uint32_t addr)
3355 uint32_t val = 0xff;
3356 int c = (addr >> 1) & 3;
3358 switch(addr & 0x0f) {
3364 val = ch[c].addr.b.l;
3366 val = ch[c].addr.b.h;
3368 high_low = !high_low;
3375 val = ch[c].count.b.l;
3377 val = (ch[c].count.b.h & 0x3f) | ch[c].mode;
3379 high_low = !high_low;
3384 // high_low = false;
3390 void pc88_dmac_t::start(int c)
3392 if(mode & (1 << c)) {
3393 status &= ~(1 << c);
3394 ch[c].running = true;
3396 ch[c].running = false;
3400 void pc88_dmac_t::run(int c, int nbytes)
3403 while(nbytes > 0 && ch[c].count.sd >= 0) {
3404 if(ch[c].mode == 0x80) {
3405 ch[c].io->write_dma_io8(0, mem->read_dma_data8(ch[c].addr.w.l));
3406 } else if(ch[c].mode == 0x40) {
3407 mem->write_dma_data8(ch[c].addr.w.l, ch[c].io->read_dma_io8(0));
3408 } else if(ch[c].mode == 0x00) {
3409 ch[c].io->read_dma_io8(0); // verify
3415 if(ch[c].count.sd < 0) {
3421 void pc88_dmac_t::finish(int c)
3424 while(ch[c].count.sd >= 0) {
3425 if(ch[c].mode == 0x80) {
3426 ch[c].io->write_dma_io8(0, mem->read_dma_data8(ch[c].addr.w.l));
3427 } else if(ch[c].mode == 0x40) {
3428 mem->write_dma_data8(ch[c].addr.w.l, ch[c].io->read_dma_io8(0));
3429 } else if(ch[c].mode == 0x00) {
3430 ch[c].io->read_dma_io8(0); // verify
3435 if((mode & 0x80) && c == 2) {
3436 ch[2].addr.sd = ch[3].addr.sd;
3437 ch[2].count.sd = ch[3].count.sd;
3438 ch[2].mode = ch[3].mode;
3439 } else if(mode & 0x40) {
3443 ch[c].running = false;
3447 #define STATE_VERSION 10
3449 bool PC88::process_state(FILEIO* state_fio, bool loading)
3451 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
3454 if(!state_fio->StateCheckInt32(this_device_id)) {
3457 state_fio->StateArray(ram, sizeof(ram), 1);
3458 #if defined(PC88_EXRAM_BANKS)
3459 state_fio->StateArray(exram, sizeof(exram), 1);
3461 state_fio->StateArray(gvram, sizeof(gvram), 1);
3462 state_fio->StateArray(tvram, sizeof(tvram), 1);
3463 state_fio->StateArray(port, sizeof(port), 1);
3464 state_fio->StateValue(crtc.blink.rate);
3465 state_fio->StateValue(crtc.blink.counter);
3466 state_fio->StateValue(crtc.blink.cursor);
3467 state_fio->StateValue(crtc.blink.attrib);
3468 state_fio->StateValue(crtc.cursor.type);
3469 state_fio->StateValue(crtc.cursor.mode);
3470 state_fio->StateValue(crtc.cursor.x);
3471 state_fio->StateValue(crtc.cursor.y);
3472 state_fio->StateValue(crtc.attrib.data);
3473 state_fio->StateValue(crtc.attrib.num);
3474 state_fio->StateArray(&crtc.attrib.expand[0][0], sizeof(crtc.attrib.expand), 1);
3475 state_fio->StateArray(&crtc.text.expand[0][0], sizeof(crtc.text.expand), 1);
3476 state_fio->StateValue(crtc.width);
3477 state_fio->StateValue(crtc.height);
3478 state_fio->StateValue(crtc.char_height);
3479 state_fio->StateValue(crtc.skip_line);
3480 state_fio->StateValue(crtc.vretrace);
3481 state_fio->StateValue(crtc.timing_changed);
3482 state_fio->StateArray(crtc.buffer, sizeof(crtc.buffer), 1);
3483 state_fio->StateValue(crtc.buffer_ptr);
3484 state_fio->StateValue(crtc.cmd);
3485 state_fio->StateValue(crtc.cmd_ptr);
3486 state_fio->StateValue(crtc.mode);
3487 state_fio->StateValue(crtc.reverse);
3488 state_fio->StateValue(crtc.intr_mask);
3489 state_fio->StateValue(crtc.status);
3490 state_fio->StateValue(crtc.vblank);
3491 for(int i = 0; i < array_length(dmac.ch); i++) {
3492 state_fio->StateValue(dmac.ch[i].addr);
3493 state_fio->StateValue(dmac.ch[i].count);
3494 state_fio->StateValue(dmac.ch[i].mode);
3495 state_fio->StateValue(dmac.ch[i].nbytes);
3496 state_fio->StateValue(dmac.ch[i].running);
3498 state_fio->StateValue(dmac.mode);
3499 state_fio->StateValue(dmac.status);
3500 state_fio->StateValue(dmac.high_low);
3501 state_fio->StateArray(alu_reg, sizeof(alu_reg), 1);
3502 state_fio->StateValue(gvram_plane);
3503 state_fio->StateValue(gvram_sel);
3504 state_fio->StateValue(cpu_clock_low);
3505 #if defined(SUPPORT_PC88_HIGH_CLOCK)
3506 state_fio->StateValue(cpu_clock_high_fe2);
3508 state_fio->StateValue(mem_wait_on);
3509 state_fio->StateValue(m1_wait_clocks);
3510 state_fio->StateValue(f000_m1_wait_clocks);
3511 state_fio->StateValue(mem_wait_clocks_r);
3512 state_fio->StateValue(mem_wait_clocks_w);
3513 state_fio->StateValue(tvram_wait_clocks_r);
3514 state_fio->StateValue(tvram_wait_clocks_w);
3515 state_fio->StateValue(gvram_wait_clocks_r);
3516 state_fio->StateValue(gvram_wait_clocks_w);
3517 state_fio->StateValue(busreq_clocks);
3518 for(int i = 0; i < array_length(palette); i++) {
3519 state_fio->StateValue(palette[i].r);
3520 state_fio->StateValue(palette[i].g);
3521 state_fio->StateValue(palette[i].b);
3523 // state_fio->StateValue(update_palette);
3524 state_fio->StateValue(hireso);
3525 state_fio->StateArray(&text[0][0], sizeof(text), 1);
3526 state_fio->StateArray(&graph[0][0], sizeof(graph), 1);
3528 for(int i = 0; i < 9; i++) {
3529 state_fio->StateValue(palette_digital[i].b);
3530 state_fio->StateValue(palette_digital[i].r);
3531 state_fio->StateValue(palette_digital[i].g);
3532 state_fio->StateValue(palette_analog [i].b);
3533 state_fio->StateValue(palette_analog [i].r);
3534 state_fio->StateValue(palette_analog [i].g);
3537 state_fio->StateValue(usart_dcd);
3538 state_fio->StateValue(opn_busy);
3539 state_fio->StateValue(key_caps);
3540 state_fio->StateValue(key_kana);
3541 #ifdef SUPPORT_PC88_JOYSTICK
3542 state_fio->StateValue(mouse_strobe_clock);
3543 state_fio->StateValue(mouse_strobe_clock_lim);
3544 state_fio->StateValue(mouse_phase);
3545 state_fio->StateValue(mouse_dx);
3546 state_fio->StateValue(mouse_dy);
3547 state_fio->StateValue(mouse_lx);
3548 state_fio->StateValue(mouse_ly);
3550 state_fio->StateValue(intr_req);
3551 state_fio->StateValue(intr_req_sound);
3552 #ifdef SUPPORT_PC88_SB2
3553 state_fio->StateValue(intr_req_sb2);
3555 state_fio->StateValue(intr_mask1);
3556 state_fio->StateValue(intr_mask2);
3557 state_fio->StateValue(cmt_play);
3558 state_fio->StateValue(cmt_rec);
3559 state_fio->StateArray(rec_file_path, sizeof(rec_file_path), 1);
3561 int length_tmp = state_fio->FgetInt32_LE();
3563 cmt_fio->Fopen(rec_file_path, FILEIO_READ_WRITE_NEW_BINARY);
3564 while(length_tmp != 0) {
3565 uint8_t buffer[1024];
3566 int length_rw = min(length_tmp, (int)sizeof(buffer));
3567 state_fio->Fread(buffer, length_rw, 1);
3568 if(cmt_fio->IsOpened()) {
3569 cmt_fio->Fwrite(buffer, length_rw, 1);
3571 length_tmp -= length_rw;
3575 if(cmt_rec && cmt_fio->IsOpened()) {
3576 int length_tmp = (int)cmt_fio->Ftell();
3577 cmt_fio->Fseek(0, FILEIO_SEEK_SET);
3578 state_fio->FputInt32_LE(length_tmp);
3579 while(length_tmp != 0) {
3580 uint8_t buffer[1024];
3581 int length_rw = min(length_tmp, (int)sizeof(buffer));
3582 cmt_fio->Fread(buffer, length_rw, 1);
3583 state_fio->Fwrite(buffer, length_rw, 1);
3584 length_tmp -= length_rw;
3587 state_fio->FputInt32_LE(0);
3590 state_fio->StateValue(cmt_bufptr);
3591 state_fio->StateValue(cmt_bufcnt);
3592 state_fio->StateArray(cmt_buffer, sizeof(cmt_buffer), 1);
3593 state_fio->StateArray(cmt_data_carrier, sizeof(cmt_data_carrier), 1);
3594 state_fio->StateValue(cmt_data_carrier_cnt);
3595 state_fio->StateValue(cmt_register_id);
3596 state_fio->StateValue(beep_on);
3597 state_fio->StateValue(beep_signal);
3598 state_fio->StateValue(sing_signal);
3599 #ifdef SUPPORT_PC88_PCG8100
3600 state_fio->StateValue(pcg_addr);
3601 state_fio->StateValue(pcg_data);
3602 state_fio->StateValue(pcg_ctrl);
3603 state_fio->StateArray(pcg_pattern, sizeof(pcg_pattern), 1);
3605 #ifdef SUPPORT_PC88_CDROM
3606 state_fio->StateValue(cdda_register_id);
3607 state_fio->StateValue(cdda_volume);
3610 state_fio->StateValue(nippy_patch);
3615 #if defined(_PC8001SR)
3619 update_low_memmap();
3620 update_tvram_memmap();
3622 // force update palette when state file is loaded
3623 update_palette = true;