/*************************************************************************** machine/pc8801.c Implementation of the PC8801 On the PC8801, there are two CPUs. The main CPU and the FDC CPU. Two 8255 PPIs are used for cross CPU communication. These ports are connected as below: Main CPU 8255 port A <--> FDC CPU 8255 port B Main CPU 8255 port B <--> FDC CPU 8255 port A Main CPU 8255 port C (bits 7-4) <--> FDC CPU 8255 port C (bits 0-3) Main CPU 8255 port C (bits 0-3) <--> FDC CPU 8255 port C (bits 7-4) ***************************************************************************/ #include "mscommon.h" #include "driver.h" #include "timer.h" #include "includes/pc8801.h" #include "machine/8255ppi.h" #include "machine/nec765.h" #include "sound/beep.h" static int ROMmode,RAMmode,maptvram; static int no4throm,no4throm2,port71_save; static unsigned char *mainROM; unsigned char *pc8801_mainRAM=NULL; static int is_V2mode,is_Nbasic,is_8MHz; int pc88sr_is_highspeed; static int port32_save; static int text_window; static int extmem_mode=-1; static unsigned char *extRAM=NULL; static void *ext_bank_80[4],*ext_bank_88[256]; static UINT8 extmem_ctrl[2]; static int use_5FD; void pc8801_init_5fd(void); static void pc88sr_init_fmsound(void); static int enable_FM_IRQ; static int FM_IRQ_save; #define FM_IRQ_LEVEL 4 /* calender IC (PD1990) */ static UINT8 calender_reg[5]; static int calender_save; static int calender_hold; WRITE8_HANDLER(pc8801_calender) { calender_save=data; /* printer (not yet) */ /* UOP3 (bit 7 -- not yet) */ } static void calender_strobe(void) { mame_system_time systime; switch(calender_save&0x07) { case 0: calender_hold = 1; break; case 1: calender_hold = 0; break; case 2: /* time set (not yet) */ calender_hold = 1; break; case 3: /* get the current date/time from the core */ mame_get_current_datetime(Machine, &systime); calender_reg[4] = (systime.local_time.month + 1) * 16 + systime.local_time.weekday; calender_reg[3] = dec_2_bcd(systime.local_time.mday); calender_reg[2] = dec_2_bcd(systime.local_time.hour); calender_reg[1] = dec_2_bcd(systime.local_time.minute); calender_reg[0] = dec_2_bcd(systime.local_time.second); calender_hold = 1; break; } } static void calender_shift(void) { if(!calender_hold) { calender_reg[0] = (calender_reg[0] >> 1) | ((calender_reg[1] << 7) & 0x80); calender_reg[1] = (calender_reg[1] >> 1) | ((calender_reg[2] << 7) & 0x80); calender_reg[2] = (calender_reg[2] >> 1) | ((calender_reg[3] << 7) & 0x80); calender_reg[3] = (calender_reg[3] >> 1) | ((calender_reg[4] << 7) & 0x80); calender_reg[4] = (calender_reg[4] >> 1) | ((calender_save << 4) & 0x80); } } static int calender_data(void) { return (calender_reg[0]&0x01)!=0x00; } /* interrupt staff */ static int interrupt_level_reg; static int interrupt_mask_reg; static int interrupt_trig_reg; static void pc8801_update_interrupt(void) { int level, i; level = -1; for (i = 0; i < 8; i++) { if ((interrupt_trig_reg & (1<= 0 && level>2) | 0xf8; } static void pc8801_raise_interrupt(int level) { interrupt_trig_reg |= interrupt_mask_reg & (1<>2)|(i&0xc0)]=e; e+=0x8000; } } else { for(i=0;i> 4) & 0x0F) | ((port_c << 4) & 0xF0); } /* NPW 11-Feb-2006 - This is a brutal no-good hack to work around bug #759 * * The problem is that in MESS 0.96, a regression was introduced that * prevented the PC8801 from booting up. The source of this regression * was the 8255 PPI rewrite. * * What seems to happen is CPU #0 does a write to 8255 #0 port C at PC=37CF * and this causes a communication to be made to CPU #1. Under the * previous 8255 code, this write would not actually make it to the the * slave CPU, CPU #1. After examining the data sheet, all indications are * that the new 8255 behavior is indeed correct. * * So what I'm doing is an ugly hack so that when the slave CPU #1 sees the * value written to it, I actually change this to the previous value, * cloaking the communication. So the PC8801 now boots up, but hopefully * a correct fix can be made. */ if ((chip == 1) && (result == 0xF8)) result = 0xF0; return result; } static READ8_HANDLER( load_8255_chip0_A ) { return load_8255_A(0); } static READ8_HANDLER( load_8255_chip1_A ) { return load_8255_A(1); } static READ8_HANDLER( load_8255_chip0_B ) { return load_8255_B(0); } static READ8_HANDLER( load_8255_chip1_B ) { return load_8255_B(1); } static READ8_HANDLER( load_8255_chip0_C ) { return load_8255_C(0); } static READ8_HANDLER( load_8255_chip1_C ) { return load_8255_C(1); } const ppi8255_interface pc8801_8255_config = { 2, { load_8255_chip0_A, load_8255_chip1_A }, { load_8255_chip0_B, load_8255_chip1_B }, { load_8255_chip0_C, load_8255_chip1_C }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, }; READ8_HANDLER(pc8801fd_nec765_tc) { nec765_set_tc_state(1); nec765_set_tc_state(0); return 0; } /* callback for /INT output from FDC */ static void pc8801_fdc_interrupt(int state) { cpunum_set_input_line (1, 0, state ? HOLD_LINE : CLEAR_LINE); } /* callback for /DRQ output from FDC */ static void pc8801_fdc_dma_drq(int state, int read_) { } static struct nec765_interface pc8801_fdc_interface= { pc8801_fdc_interrupt, pc8801_fdc_dma_drq }; void pc8801_init_5fd(void) { use_5FD = (input_port_18_r(0)&0x80)!=0x00; ppi8255_init(&pc8801_8255_config); if (!use_5FD) cpunum_suspend(1, SUSPEND_REASON_DISABLE, 1); else cpunum_resume(1, SUSPEND_REASON_DISABLE); nec765_init(&pc8801_fdc_interface,NEC765A); cpunum_set_input_line_vector(1,0,0); floppy_drive_set_motor_state(image_from_devtype_and_index(IO_FLOPPY, 0), 1); floppy_drive_set_motor_state(image_from_devtype_and_index(IO_FLOPPY, 1), 1); floppy_drive_set_ready_state(image_from_devtype_and_index(IO_FLOPPY, 0), 1,0); floppy_drive_set_ready_state(image_from_devtype_and_index(IO_FLOPPY, 1), 1,0); } /* FM sound */ static void pc88sr_init_fmsound(void) { enable_FM_IRQ=0; FM_IRQ_save=0; } void pc88sr_sound_interupt(int irq) { FM_IRQ_save=irq; if(FM_IRQ_save && enable_FM_IRQ) pc8801_raise_interrupt(FM_IRQ_LEVEL); } /* KANJI ROM */ static UINT8 kanji_high,kanji_low; WRITE8_HANDLER(pc8801_write_kanji1) { switch(offset) { case 0: kanji_low=data; break; case 1: kanji_high=data; break; } } READ8_HANDLER(pc8801_read_kanji1) { switch(offset) { case 0: return *(memory_region(REGION_GFX1)+kanji_high*0x200+kanji_low*0x2+1); case 1: return *(memory_region(REGION_GFX1)+kanji_high*0x200+kanji_low*0x2+0); default: return 0xff; } } static UINT8 kanji_high2,kanji_low2; WRITE8_HANDLER(pc8801_write_kanji2) { switch(offset) { case 0: kanji_low2=data; break; case 1: kanji_high2=data; break; } } READ8_HANDLER(pc8801_read_kanji2) { switch(offset) { case 0: return *(memory_region(REGION_GFX1)+kanji_high2*0x200+kanji_low2*0x2+1+0x20000); case 1: return *(memory_region(REGION_GFX1)+kanji_high2*0x200+kanji_low2*0x2+0+0x20000); default: return 0xff; } }