diff --git a/src/emu/cpu/mcs51/mcs51.c b/src/emu/cpu/mcs51/mcs51.c index 0be098299d2..82d1412d7a1 100644 --- a/src/emu/cpu/mcs51/mcs51.c +++ b/src/emu/cpu/mcs51/mcs51.c @@ -118,6 +118,7 @@ enum FEATURE_I8052 = 0x01, FEATURE_CMOS = 0x02, FEATURE_I80C52 = 0x04, + FEATURE_DS5002FP = 0x08, }; /* Internal address in SFR of registers */ @@ -159,8 +160,18 @@ enum ADDR_SADEN = 0xb9, /* Philips 80C52 */ - AUXR = 0x8e, - AUXR1 = 0xa2, + ADDR_AUXR = 0x8e, + ADDR_AUXR1 = 0xa2, + + /* DS5002FP */ + ADDR_CRCR = 0xc1, + ADDR_CRCL = 0xc2, + ADDR_CRCH = 0xc3, + ADDR_MCON = 0xc6, + ADDR_TA = 0xc7, + ADDR_RNR = 0xcf, + ADDR_RPCTL = 0xd8, + ADDR_RPS = 0xda, }; @@ -177,6 +188,9 @@ enum /* 8052 Only Vectors */ V_TF2 = 0x02b, /* Timer 2 Overflow */ + + /* DS5002FP */ + V_PFI = 0x02b, /* Power Failure Interrupt */ }; /*************************************************************************** @@ -208,7 +222,7 @@ struct _mcs51_regs int ram_mask; /* second ram bank for indirect access available ? */ int num_interrupts; /* number of interrupts supported */ int recalc_parity; /* recalculate parity before next instruction */ - int last_line_state; /* last state of input lines line */ + UINT32 last_line_state; /* last state of input lines line */ int t0_cnt; /* number of 0->1 transistions on T0 line */ int t1_cnt; /* number of 0->1 transistions on T1 line */ int t2_cnt; /* number of 0->1 transistions on T2 line */ @@ -223,18 +237,27 @@ struct _mcs51_regs UINT8 *internal_ram; /* 128 RAM (8031/51) + 128 RAM in second bank (8032/52) */ UINT8 *sfr_ram; /* 128 SFR - these are in 0x80 - 0xFF */ - // SFR Callbacks + /* SFR Callbacks */ void (*sfr_write)(size_t offset, UINT8 data); UINT8 (*sfr_read)(size_t offset); - //Interrupt Callback + /* Interrupt Callback */ int (*irq_callback)(int irqline); - //Serial Port TX/RX Callbacks + /* Serial Port TX/RX Callbacks */ // TODO: Move to special port r/w void (*serial_tx_callback)(int data); //Call back funciton when sending data out of serial port int (*serial_rx_callback)(void); //Call back function to retrieve data when receiving serial port data + /* DS5002FP */ + struct { + UINT8 previous_ta; /* Previous Timed Access value */ + UINT8 ta_window; /* Limed Access window */ + UINT8 range; /* Memory Range */ + const ds5002fp_config *config; /* Bootstrap Configuration */ + } ds5002fp; + + }; /*************************************************************************** @@ -349,6 +372,17 @@ struct _mcs51_regs */ #define AUXR1 SFR_A(ADDR_AUXR1) +/* DS5002FP only registers */ +#define CRCR SFR_A(ADDR_CRCR) +#define CRCL SFR_A(ADDR_CRCL) +#define CRCH SFR_A(ADDR_CRCH) +#define MCON SFR_A(ADDR_MCON) +#define TA SFR_A(ADDR_TA) +#define RNR SFR_A(ADDR_RNR) +#define RPCTL SFR_A(ADDR_RPCTL) +#define RPS SFR_A(ADDR_RPS) + + /* WRITE accessors */ /* Shortcuts */ @@ -517,6 +551,36 @@ struct _mcs51_regs #define GET_CT2 GET_BIT(T2CON, 1) #define GET_CP GET_BIT(T2CON, 0) +/* DS5002FP Only flags */ + +/* PCON Flags - DS5002FP */ + +#define GET_POR GET_BIT(PCON, 6) +#define GET_PFW GET_BIT(PCON, 5) +#define GET_WTR GET_BIT(PCON, 4) +#define GET_EPFW GET_BIT(PCON, 3) +#define GET_EWT GET_BIT(PCON, 2) + +#define SET_PFW(n) SET_BIT(PCON, 5, n) + +/* MCON Flags - DS5002FP */ + +#define GET_PA ((MCON & 0xf0)>>4) +#define GET_RG1 GET_BIT(MCON, 3) +#define GET_PES GET_BIT(MCON, 2) +#define GET_PM GET_BIT(MCON, 1) +#define GET_SL GET_BIT(MCON, 0) + +/* RPCTL Flags - DS5002FP */ +#define GET_RNR GET_BIT(RPCTL, 7) /* Bit 6 ?? */ +#define GET_EXBS GET_BIT(RPCTL, 5) +#define GET_AE GET_BIT(RPCTL, 4) +#define GET_IBI GET_BIT(RPCTL, 3) +#define GET_DMA GET_BIT(RPCTL, 2) +#define GET_RPCON GET_BIT(RPCTL, 1) +#define GET_RG0 GET_BIT(RPCTL, 0) + + /*Add and Subtract Flag settings*/ #define DO_ADD_FLAGS(a,d,c) do_add_flags(a,d,c) #define DO_SUB_FLAGS(a,d,c) do_sub_flags(a,d,c) @@ -581,6 +645,7 @@ INLINE void clear_current_irq(void) mcs51.cur_irq_prio = 0; else mcs51.cur_irq_prio = -1; + LOG(("New: %d %02x\n", mcs51.cur_irq_prio, mcs51.irq_active)); } INLINE UINT8 r_acc(void) { return SFR_A(ADDR_ACC); } @@ -900,28 +965,90 @@ INLINE void update_timer_t0(int cycles) } } +/* From the DS5002FP User Manual +When Timer 1 is selected for operation in Mode 3, it stops counting and holds its current value. This +action is the same as setting TR1 = 0. When Timer 0 is selected in Mode 3, Timer 1’s control bits are +stolen as described above. As a result, Timer 1’s functions are limited in this MODE. It is forced to +operate as a timer whose clock in-put is 12 tCLK and it cannot generate an interrupt on overflow. In +addition, it also cannot be used with the GATE function. However, it can be started and stopped by +switching it into or out of Mode 3 or it can be assigned as a baud rate generator for the serial port. +*/ + +/* Intel documentation: + * Timer 1 may still be used in modes 0, 1, and 2, while timer 0 + * is in mode 3. With one important exception: No interrupts + * will be generated by timer 1 while timer 0 is using the TF1 + * overflow flag + */ + INLINE void update_timer_t1(int cycles) { - int mode = (GET_M1_1<<1) | GET_M1_0; - int mode_0 = (GET_M0_1<<1) | GET_M0_0; + UINT8 mode = (GET_M1_1<<1) | GET_M1_0; + UINT8 mode_0 = (GET_M0_1<<1) | GET_M0_0; UINT32 count = 0; - if (GET_TR1) + if (mode_0 != 3) + { + if (GET_TR1) + { + UINT32 delta; + UINT32 overflow = 0; + + /* counter / external input */ + delta = GET_CT1 ? mcs51.t1_cnt : cycles; + /* taken, reset */ + mcs51.t1_cnt = 0; + /* TODO: Not sure about IE0. The manual specifies INT0=high, + * which in turn means CLEAR_LINE. Change to access last_state? + * IE0 may be edge triggered depending on IT0 */ + if (GET_GATE1 && !GET_IE1) + delta = 0; + + //printf("mode: %d\n", mode); + switch(mode) { + case 0: /* 13 Bit Timer Mode */ + count = ((TH1<<5) | ( TL1 & 0x1f ) ); + count += delta; + overflow = count & 0xffffe000; /* Check for overflow */ + TH1 = (count>>5) & 0xff; + TL1 = count & 0x1f ; + break; + case 1: /* 16 Bit Timer Mode */ + count = ((TH1<<8) | TL1); + count += delta; + overflow = count & 0xffff0000; /* Check for overflow */ + TH1 = (count>>8) & 0xff; + TL1 = count & 0xff; + break; + case 2: /* 8 Bit Autoreload */ + count = ((UINT32) TL1) + delta; + overflow = count & 0xffffff00; /* Check for overflow */ + if ( overflow ) + { + count += TH1; /* Reload timer */ + } + /* Update new values of the counter */ + TL1 = count & 0xff; + break; + case 3: + /* do nothing */ + break; + } + if (overflow) + { + SET_TF1(1); + transmit_receive(1); + } + } + } + else { UINT32 delta; UINT32 overflow = 0; - - /* counter / external input */ - delta = GET_CT1 ? mcs51.t1_cnt : cycles; + + delta = cycles; /* taken, reset */ mcs51.t1_cnt = 0; - /* TODO: Not sure about IE0. The manual specifies INT0=high, - * which in turn means CLEAR_LINE. Change to access last_state? - * IE0 may be edge triggered depending on IT0 */ - if (GET_GATE1 && !GET_IE1) - delta = 0; - - //printf("mode: %d\n", mode); switch(mode) { case 0: /* 13 Bit Timer Mode */ count = ((TH1<<5) | ( TL1 & 0x1f ) ); @@ -953,13 +1080,6 @@ INLINE void update_timer_t1(int cycles) } if (overflow) { - /* Timer 1 may still be used in modes 0, 1, and 2, while timer 0 - * is in mode 3. With one important exception: No interrupts - * will be generated by timer 1 while timer 0 is using the TF1 - * overflow flag - */ - if (mode_0 != 3) - SET_TF1(1); transmit_receive(1); } } @@ -1487,18 +1607,30 @@ static void check_irqs(void) UINT8 ints = (GET_IE0 | (GET_TF0<<1) | (GET_IE1<<2) | (GET_TF1<<3) | ((GET_RI|GET_TI)<<4)); UINT8 int_vec = 0; + UINT8 int_mask = 0; int priority_request = -1; int i; //If All Inerrupts Disabled or no pending abort.. - if(!GET_EA) return; + int_mask = (GET_EA ? IE : 0x00); if (mcs51.features & FEATURE_I8052) ints |= ((GET_TF2|GET_EXF2)<<5); - /* mask out interrupts not enabled */ - ints &= IE; - + if (mcs51.features & FEATURE_DS5002FP) + { + printf("Here\n"); + ints |= ((GET_PFW)<<5); + mcs51.irq_prio[6] = 3; /* force highest priority */ + /* mask out interrupts not enabled */ + ints &= ((int_mask & 0x1f) | ((GET_EPFW)<<5)); + } + else + { + /* mask out interrupts not enabled */ + ints &= int_mask; + } + if (!ints) return; /* CLear IDL - got enabled interrupt */ @@ -1508,7 +1640,9 @@ static void check_irqs(void) SET_IDL(0); /* external interrupt wakes up */ if (ints & (GET_IE0 | GET_IE1)) - SET_PD(0); + /* but not the DS5002FP */ + if (!(mcs51.features & FEATURE_DS5002FP)) + SET_PD(0); } for (i=0; i1 transistions */ - int tr_state = (~mcs51.last_line_state) & new_state; + UINT32 tr_state = (~mcs51.last_line_state) & new_state; switch( irqline ) { @@ -1689,14 +1832,26 @@ static void mcs51_set_irq_line(int irqline, int state) else fatalerror("mcs51: Trying to set T2EX_LINE on a non I8052 type cpu.\n"); break; - //Serial Port Receive - case MCS51_RX_LINE: - //Is the enable flags for this interrupt set? + + case MCS51_RX_LINE: /* Serial Port Receive */ + /* Is the enable flags for this interrupt set? */ if (state != CLEAR_LINE) { serial_receive(); } break; + + /* Power Fail Interrupt */ + case DS5002FP_PFI_LINE: + if (mcs51.features & FEATURE_DS5002FP) + { + /* Need cleared->active line transition? (Logical 1-0 Pulse on the line) - CLEAR->ASSERT Transition since INT1 active lo! */ + if (GET_BIT(tr_state, MCS51_INT1_LINE)) + SET_PFW(1); + } + else + fatalerror("mcs51: Trying to set DS5002FP_PFI_LINE on a non DS5002FP type cpu.\n"); + break; } mcs51.last_line_state = new_state; } @@ -1746,8 +1901,21 @@ static int mcs51_execute(int cycles) /* burn the cycles */ mcs51_icount -= mcs51.inst_cycles; + + /* if in powerdown, just return */ + if ((mcs51.features & FEATURE_CMOS) && GET_PD) + return cycles - mcs51_icount; + burn_cycles(mcs51.inst_cycles); + /* decrement the timed access window */ + if (mcs51.features & FEATURE_DS5002FP) + mcs51.ds5002fp.ta_window = (mcs51.ds5002fp.ta_window ? mcs51.ds5002fp.ta_window-- : 0x00); + + /* If the chip entered in idle mode, end the loop */ + if ((mcs51.features & FEATURE_CMOS) && GET_IDL) + return cycles - mcs51_icount; + } while( mcs51_icount > 0 ); return cycles - mcs51_icount; @@ -1933,6 +2101,25 @@ static void mcs51_reset(void) SADEN = 0; } + /* DS5002FP Only registers */ + if (mcs51.features & FEATURE_DS5002FP) + { + // set initial values (some of them are set using the bootstrap loader) + PCON = 0; + MCON = mcs51.ds5002fp.config->mcon & 0xfb; + RPCTL = mcs51.ds5002fp.config->rpctl & 0x01; + RPS = 0; + RNR = 0; + CRCR = mcs51.ds5002fp.config->crc & 0xf0; + CRCL = 0; + CRCH = 0; + TA = 0; + + // set internal CPU state + mcs51.ds5002fp.previous_ta = 0; + mcs51.ds5002fp.ta_window = 0; + mcs51.ds5002fp.range = (GET_RG1 << 1) | GET_RG0; + } } @@ -2048,6 +2235,97 @@ static void i80c31_init(int index, int clock, const void *config, int (*irqcallb mcs51.ram_mask = 0x7F; /* 128 bytes of ram */ } +/**************************************************************************** + * DS5002FP Section + ****************************************************************************/ +#if 0 + +#define DS5_LOGW(a, d) LOG(("ds5002fp #%d: write to " # a " register at 0x%04x, data=%x\n", cpu_getactivecpu(), PC, d)) +#define DS5_LOGR(a, d) LOG(("ds5002fp #%d: read from " # a " register at 0x%04x\n", cpu_getactivecpu(), PC)) + +INLINE UINT8 ds5002fp_protected(size_t offset, UINT8 data, UINT8 ta_mask, UINT8 mask) +{ + UINT8 is_timed_access; + + is_timed_access = (mcs51.ds5002fp.ta_window > 0) && (TA == 0x55); + if (is_timed_access) + { + ta_mask = 0xff; + } + data = (mcs51.sfr_ram[offset] & (~ta_mask)) | (data & ta_mask); + return (mcs51.sfr_ram[offset] & (~mask)) | (data & mask); +} + +static void ds5002fp_sfr_write(size_t offset, UINT8 data) +{ + switch (offset) + { + + case ADDR_TA: + mcs51.ds5002fp.previous_ta = TA; + /* init the time window after having wrote 0xaa */ + if ((data == 0xaa) && (mcs51.ds5002fp.ta_window == 0)) + { + mcs51.ds5002fp.ta_window = 6; /* 4*12 + 2*12 */ + LOG(("ds5002fp #%d: TA window initiated at 0x%04x\n", cpu_getactivecpu(), PC)); + } + break; + case ADDR_MCON: data = ds5002fp_protected(ADDR_MCON, data, 0x0f, 0xf7); DS5_LOGW(MCON, data); break; + case ADDR_RPCTL: data = ds5002fp_protected(ADDR_RPCTL, data, 0xef, 0xfe); DS5_LOGW(RPCTL, data); break; + case ADDR_CRCR: data = ds5002fp_protected(ADDR_CRCR, data, 0xff, 0x0f); DS5_LOGW(CRCR, data); break; + case ADDR_PCON: data = ds5002fp_protected(ADDR_PCON, data, 0xb9, 0xff); break; + case ADDR_IP: data = ds5002fp_protected(ADDR_IP, data, 0x7f, 0xff); break; + case ADDR_CRCL: DS5_LOGW(CRCL, data); break; + case ADDR_CRCH: DS5_LOGW(CRCH, data); break; + case ADDR_RNR: DS5_LOGW(RNR, data); break; + case ADDR_RPS: DS5_LOGW(RPS, data); break; + default: + mcs51_sfr_write(offset, data); + return; + } + data_write_byte_8le((size_t) offset | 0x100, data); +} + +static UINT8 ds5002fp_sfr_read(size_t offset) +{ + switch (offset) + { + case ADDR_CRCR: DS5_LOGR(CRCR, data); break; + case ADDR_CRCL: DS5_LOGR(CRCL, data); break; + case ADDR_CRCH: DS5_LOGR(CRCH, data); break; + case ADDR_MCON: DS5_LOGR(MCON, data); break; + case ADDR_TA: DS5_LOGR(TA, data); break; + case ADDR_RNR: DS5_LOGR(RNR, data); break; + case ADDR_RPCTL: DS5_LOGR(RPCTL, data); break; + case ADDR_RPS: DS5_LOGR(RPS, data); break; + case ADDR_PCON: + SET_PFW(0); /* reset PFW flag */ + return mcs51_sfr_read(offset); /* FIXME: cmos features ??? */ + default: + return mcs51_sfr_read(offset); /* FIXME: cmos features ??? */ + } + return data_read_byte_8le((size_t) offset | 0x100); +} + +static void ds5002fp_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + /* default configuration */ + static const ds5002fp_config default_config = { 0x00, 0x00, 0x00 }; + const ds5002fp_config *sconfig = config ? config : &default_config; + + mcs51_init(index, clock, config, irqcallback); + + mcs51.ds5002fp.config = sconfig; + mcs51.features |= (FEATURE_DS5002FP | FEATURE_CMOS); + mcs51.sfr_read = ds5002fp_sfr_read; + mcs51.sfr_write = ds5002fp_sfr_write; + + state_save_register_item("mcs51", index, mcs51.ds5002fp.previous_ta ); + state_save_register_item("mcs51", index, mcs51.ds5002fp.ta_window ); + state_save_register_item("mcs51", index, mcs51.ds5002fp.range ); + +} +#endif /*************************************************************************** ADDRESS MAPS diff --git a/src/emu/cpu/mcs51/mcs51.h b/src/emu/cpu/mcs51/mcs51.h index 5b26997318e..80e9a0612cb 100644 --- a/src/emu/cpu/mcs51/mcs51.h +++ b/src/emu/cpu/mcs51/mcs51.h @@ -58,6 +58,8 @@ enum MCS51_T1_LINE, /* P3.5: Timer 1 External Input */ MCS51_T2_LINE, /* P1.0: Timer 2 External Input */ MCS51_T2EX_LINE, /* P1.1: Timer 2 Capture Reload Trigger */ + + DS5002FP_PFI_LINE, /* DS5002FP Power fail interrupt */ }; /* special I/O space ports */ @@ -71,6 +73,18 @@ enum MCS51_PORT_TX = 0x10004, /* P3.1 */ }; +/*************************************************************************** + CONFIGURATION +***************************************************************************/ + +/* configuration of the DS5002FP */ +typedef struct _ds5002fp_config ds5002fp_config; +struct _ds5002fp_config +{ + UINT8 mcon; /* bootstrap loader MCON register */ + UINT8 rpctl; /* bootstrap loader RPCTL register */ + UINT8 crc; /* bootstrap loader CRC register */ +}; /*************************************************************************** FUNCTION PROTOTYPES