mirror of
https://github.com/holub/mame
synced 2025-04-25 09:50:04 +03:00
pit8253: Counters are now subdevices
This commit is contained in:
parent
6d854de3e5
commit
6228bbe942
File diff suppressed because it is too large
Load Diff
@ -35,46 +35,111 @@
|
||||
***************************************************************************/
|
||||
|
||||
#define MCFG_PIT8253_CLK0(_clk) \
|
||||
downcast<pit8253_device &>(*device).set_clk0(_clk);
|
||||
downcast<pit8253_device &>(*device).set_clk<0>(_clk);
|
||||
|
||||
#define MCFG_PIT8253_CLK1(_clk) \
|
||||
downcast<pit8253_device &>(*device).set_clk1(_clk);
|
||||
downcast<pit8253_device &>(*device).set_clk<1>(_clk);
|
||||
|
||||
#define MCFG_PIT8253_CLK2(_clk) \
|
||||
downcast<pit8253_device &>(*device).set_clk2(_clk);
|
||||
downcast<pit8253_device &>(*device).set_clk<2>(_clk);
|
||||
|
||||
#define MCFG_PIT8253_OUT0_HANDLER(_devcb) \
|
||||
devcb = &downcast<pit8253_device &>(*device).set_out0_handler(DEVCB_##_devcb);
|
||||
devcb = &downcast<pit8253_device &>(*device).set_out_handler<0>(DEVCB_##_devcb);
|
||||
|
||||
#define MCFG_PIT8253_OUT1_HANDLER(_devcb) \
|
||||
devcb = &downcast<pit8253_device &>(*device).set_out1_handler(DEVCB_##_devcb);
|
||||
devcb = &downcast<pit8253_device &>(*device).set_out_handler<1>(DEVCB_##_devcb);
|
||||
|
||||
#define MCFG_PIT8253_OUT2_HANDLER(_devcb) \
|
||||
devcb = &downcast<pit8253_device &>(*device).set_out2_handler(DEVCB_##_devcb);
|
||||
devcb = &downcast<pit8253_device &>(*device).set_out_handler<2>(DEVCB_##_devcb);
|
||||
|
||||
|
||||
enum class pit_type
|
||||
{
|
||||
I8254,
|
||||
I8253,
|
||||
FE2010
|
||||
};
|
||||
|
||||
class pit_counter_device : public device_t
|
||||
{
|
||||
friend class pit8253_device;
|
||||
friend class pit8254_device;
|
||||
|
||||
public:
|
||||
// construction/destruction
|
||||
pit_counter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
private:
|
||||
inline uint32_t adjusted_count() const;
|
||||
void decrease_counter_value(int64_t cycles);
|
||||
void load_counter_value();
|
||||
void set_output(int output);
|
||||
void simulate2(int64_t elapsed_cycles);
|
||||
void simulate(int64_t elapsed_cycles);
|
||||
void update();
|
||||
uint16_t masked_value() const;
|
||||
uint8_t read();
|
||||
void load_count(uint16_t newcount);
|
||||
void readback(int command);
|
||||
void control_w(uint8_t data);
|
||||
void count_w(uint8_t data);
|
||||
void gate_w(int state);
|
||||
void set_clock_signal(int state);
|
||||
void set_clockin(double new_clockin);
|
||||
|
||||
// internal state
|
||||
int m_index; // index number of the timer
|
||||
double m_clockin; // input clock frequency in Hz
|
||||
int m_clock_signal; // clock signal when clockin is 0
|
||||
|
||||
attotime m_last_updated; // time when last updated
|
||||
|
||||
emu_timer *m_updatetimer; // MAME timer to process updates
|
||||
|
||||
uint16_t m_value; // current counter value ("CE" in Intel docs)
|
||||
uint16_t m_latch; // latched counter value ("OL" in Intel docs)
|
||||
uint16_t m_count; // new counter value ("CR" in Intel docs)
|
||||
uint8_t m_control; // 6-bit control byte
|
||||
uint8_t m_status; // status byte - 8254 only
|
||||
uint8_t m_lowcount; // LSB of new counter value for 16-bit writes
|
||||
bool m_rmsb; // true = Next read is MSB of 16-bit value
|
||||
bool m_wmsb; // true = Next write is MSB of 16-bit value
|
||||
int m_output; // 0 = low, 1 = high
|
||||
|
||||
int m_gate; // gate input (0 = low, 1 = high)
|
||||
int m_latched_count; // number of bytes of count latched
|
||||
int m_latched_status; // 1 = status latched (8254 only)
|
||||
int m_null_count; // 1 = mode control or count written, 0 = count loaded
|
||||
int m_phase; // see phase definition tables in simulate2(), below
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(PIT_COUNTER, pit_counter_device)
|
||||
|
||||
class pit8253_device : public device_t
|
||||
{
|
||||
friend class pit_counter_device;
|
||||
|
||||
public:
|
||||
// construction/destruction
|
||||
pit8253_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// configuration helpers
|
||||
void set_clk0(double clk0) { m_clk0 = clk0; }
|
||||
void set_clk1(double clk1) { m_clk1 = clk1; }
|
||||
void set_clk2(double clk2) { m_clk2 = clk2; }
|
||||
void set_clk0(const XTAL &xtal) { set_clk0(xtal.dvalue()); }
|
||||
void set_clk1(const XTAL &xtal) { set_clk1(xtal.dvalue()); }
|
||||
void set_clk2(const XTAL &xtal) { set_clk2(xtal.dvalue()); }
|
||||
template <class Object> devcb_base &set_out0_handler(Object &&cb) { return m_out0_handler.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> devcb_base &set_out1_handler(Object &&cb) { return m_out1_handler.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> devcb_base &set_out2_handler(Object &&cb) { return m_out2_handler.set_callback(std::forward<Object>(cb)); }
|
||||
template <unsigned N> void set_clk(double clk) { m_clk[N] = clk; }
|
||||
template <unsigned N> void set_clk(const XTAL &xtal) { set_clk<N>(xtal.dvalue()); }
|
||||
template <unsigned N, class Object> devcb_base &set_out_handler(Object &&cb) { return m_out_handler[N].set_callback(std::forward<Object>(cb)); }
|
||||
|
||||
DECLARE_READ8_MEMBER(read);
|
||||
DECLARE_WRITE8_MEMBER(write);
|
||||
|
||||
WRITE_LINE_MEMBER(write_gate0);
|
||||
WRITE_LINE_MEMBER(write_gate1);
|
||||
WRITE_LINE_MEMBER(write_gate2);
|
||||
WRITE_LINE_MEMBER(write_gate0) { m_counter[0]->gate_w(state); }
|
||||
WRITE_LINE_MEMBER(write_gate1) { m_counter[1]->gate_w(state); }
|
||||
WRITE_LINE_MEMBER(write_gate2) { m_counter[2]->gate_w(state); }
|
||||
|
||||
/* In the 8253/8254 the CLKx input lines can be attached to a regular clock
|
||||
signal. Another option is to use the output from one timer as the input
|
||||
@ -86,87 +151,28 @@ public:
|
||||
to 0 with pit8253_set_clockin and call pit8253_clkX_w to change
|
||||
the state of the input CLKx signal.
|
||||
*/
|
||||
WRITE_LINE_MEMBER(write_clk0);
|
||||
WRITE_LINE_MEMBER(write_clk1);
|
||||
WRITE_LINE_MEMBER(write_clk2);
|
||||
WRITE_LINE_MEMBER(write_clk0) { m_counter[0]->set_clock_signal(state); }
|
||||
WRITE_LINE_MEMBER(write_clk1) { m_counter[1]->set_clock_signal(state); }
|
||||
WRITE_LINE_MEMBER(write_clk2) { m_counter[2]->set_clock_signal(state); }
|
||||
|
||||
void set_clockin(int timer, double new_clockin);
|
||||
void set_clockin(int timer, double new_clockin) { m_counter[timer]->set_clockin(new_clockin); }
|
||||
|
||||
protected:
|
||||
pit8253_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int chip_type);
|
||||
pit8253_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, pit_type chip_type);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual void device_resolve_objects() override;
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
// internal state
|
||||
struct pit8253_timer
|
||||
{
|
||||
int index; /* index number of the timer */
|
||||
double clockin; /* input clock frequency in Hz */
|
||||
int clock; /* clock signal when clockin is 0 */
|
||||
|
||||
attotime last_updated; /* time when last updated */
|
||||
|
||||
emu_timer *updatetimer; /* MAME timer to process updates */
|
||||
|
||||
uint16_t value; /* current counter value ("CE" in Intel docs) */
|
||||
uint16_t latch; /* latched counter value ("OL" in Intel docs) */
|
||||
uint16_t count; /* new counter value ("CR" in Intel docs) */
|
||||
uint8_t control; /* 6-bit control byte */
|
||||
uint8_t status; /* status byte - 8254 only */
|
||||
uint8_t lowcount; /* LSB of new counter value for 16-bit writes */
|
||||
int rmsb; /* 1 = Next read is MSB of 16-bit value */
|
||||
int wmsb; /* 1 = Next write is MSB of 16-bit value */
|
||||
int output; /* 0 = low, 1 = high */
|
||||
|
||||
int gate; /* gate input (0 = low, 1 = high) */
|
||||
int latched_count; /* number of bytes of count latched */
|
||||
int latched_status; /* 1 = status latched (8254 only) */
|
||||
int null_count; /* 1 = mode control or count written, 0 = count loaded */
|
||||
int phase; /* see phase definition tables in simulate2(), below */
|
||||
};
|
||||
|
||||
void readback(pit8253_timer *timer, int command);
|
||||
virtual void readback_command(uint8_t data);
|
||||
pit8253_timer *get_timer(int which);
|
||||
|
||||
enum
|
||||
{
|
||||
I8254,
|
||||
I8253,
|
||||
FE2010
|
||||
};
|
||||
double m_clk[3];
|
||||
devcb_write_line m_out_handler[3];
|
||||
|
||||
private:
|
||||
double m_clk0;
|
||||
double m_clk1;
|
||||
double m_clk2;
|
||||
devcb_write_line m_out0_handler;
|
||||
devcb_write_line m_out1_handler;
|
||||
devcb_write_line m_out2_handler;
|
||||
required_device_array<pit_counter_device, 3> m_counter;
|
||||
|
||||
enum
|
||||
{
|
||||
PIT8253_MAX_TIMER = 3
|
||||
};
|
||||
|
||||
pit8253_timer m_timers[PIT8253_MAX_TIMER];
|
||||
|
||||
inline uint32_t adjusted_count(int bcd, uint16_t val);
|
||||
void decrease_counter_value(pit8253_timer *timer, int64_t cycles);
|
||||
void load_counter_value(pit8253_timer *timer);
|
||||
void set_output(pit8253_timer *timer, int output);
|
||||
void simulate2(pit8253_timer *timer, int64_t elapsed_cycles);
|
||||
void simulate(pit8253_timer *timer, int64_t elapsed_cycles);
|
||||
void update(pit8253_timer *timer);
|
||||
uint16_t masked_value(pit8253_timer *timer);
|
||||
void load_count(pit8253_timer *timer, uint16_t newcount);
|
||||
void gate_w(int gate, int state);
|
||||
void set_clock_signal(int timerno, int state);
|
||||
|
||||
int m_type;
|
||||
pit_type m_type;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(PIT8253, pit8253_device)
|
||||
|
Loading…
Reference in New Issue
Block a user