More changes to timer 0 split mode 3 and how timer 1 operates than

* Quotes from the documentation added to the source as well
* Started DS5002FP integration
This commit is contained in:
Couriersud 2008-10-31 22:49:33 +00:00
parent 4791a80745
commit 10b85f1efe
2 changed files with 331 additions and 39 deletions

View File

@ -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 1s control bits are
stolen as described above. As a result, Timer 1s 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; i<mcs51.num_interrupts; i++)
@ -1527,7 +1661,8 @@ static void check_irqs(void)
* and the new request does not have a higher priority
*/
if(mcs51.irq_active && (priority_request <= mcs51.cur_irq_prio))
LOG(("Request: %d\n", priority_request));
if (mcs51.irq_active && (priority_request <= mcs51.cur_irq_prio))
{
LOG(("higher or equal priority irq in progress already, skipping ...\n"));
return;
@ -1545,6 +1680,8 @@ static void check_irqs(void)
mcs51.cur_irq_prio = priority_request;
mcs51.irq_active |= (1 << priority_request);
LOG(("Take: %d %02x\n", mcs51.cur_irq_prio, mcs51.irq_active));
//printf("irq cip %d, act %02x\n",mcs51.cur_irq_prio, mcs51.irq_active);
//Clear any interrupt flags that should be cleared since we're servicing the irq!
@ -1577,12 +1714,18 @@ static void check_irqs(void)
SET_TF1(0);
break;
case V_RITI:
// no flags are cleared, TI and RI remain set until reset by software
/* no flags are cleared, TI and RI remain set until reset by software */
break;
/* I8052 specific */
case V_TF2:
// no flags are cleared according to manual
/* no flags are cleared according to manual */
break;
/* DS5002FP specific */
/* case V_PFI:
* no flags are cleared, PFW is reset by software
* This has the same vector as V_TF2.
*/
}
}
@ -1611,9 +1754,9 @@ static void mcs51_set_irq_line(int irqline, int state)
* for at least one cycle (12 states)
*
*/
int new_state = (mcs51.last_line_state & ~(1 << irqline)) | ((state != CLEAR_LINE) << irqline);
UINT32 new_state = (mcs51.last_line_state & ~(1 << irqline)) | ((state != CLEAR_LINE) << irqline);
/* detect 0->1 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

View File

@ -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