summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/i86/i186.h
blob: ec7acac9bea9a635405fde1aefb403ce537a0e74 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// license:BSD-3-Clause
// copyright-holders:Carl
#ifndef MAME_CPU_I86_I186_H
#define MAME_CPU_I86_I186_H

#pragma once

#include "i86.h"

DECLARE_DEVICE_TYPE(I80186, i80186_cpu_device)
DECLARE_DEVICE_TYPE(I80188, i80188_cpu_device)

class i80186_cpu_device : public i8086_common_cpu_device
{
public:
	// construction/destruction
	i80186_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	template <class Object> static devcb_base &static_set_read_slave_ack_callback(device_t &device, Object &&cb) { return downcast<i80186_cpu_device &>(device).m_read_slave_ack_func.set_callback(std::forward<Object>(cb)); }
	template <class Object> static devcb_base &static_set_chip_select_callback(device_t &device, Object &&cb) { return downcast<i80186_cpu_device &>(device).m_out_chip_select_func.set_callback(std::forward<Object>(cb)); }
	template <class Object> static devcb_base &static_set_tmrout0_handler(device_t &device, Object &&cb) { return downcast<i80186_cpu_device &>(device).m_out_tmrout0_func.set_callback(std::forward<Object>(cb)); }
	template <class Object> static devcb_base &static_set_tmrout1_handler(device_t &device, Object &&cb) { return downcast<i80186_cpu_device &>(device).m_out_tmrout1_func.set_callback(std::forward<Object>(cb)); }

	IRQ_CALLBACK_MEMBER(int_callback);
	DECLARE_WRITE_LINE_MEMBER(drq0_w) { if(state) drq_callback(0); m_dma[0].drq_state = state; }
	DECLARE_WRITE_LINE_MEMBER(drq1_w) { if(state) drq_callback(1); m_dma[1].drq_state = state; }
	DECLARE_WRITE_LINE_MEMBER(tmrin0_w) { if(state && (m_timer[0].control & 0x8004) == 0x8004) { inc_timer(0); } }
	DECLARE_WRITE_LINE_MEMBER(tmrin1_w) { if(state && (m_timer[1].control & 0x8004) == 0x8004) { inc_timer(1); } }
	DECLARE_WRITE_LINE_MEMBER(int0_w) { external_int(0, state); }
	DECLARE_WRITE_LINE_MEMBER(int1_w) { external_int(1, state); }
	DECLARE_WRITE_LINE_MEMBER(int2_w) { external_int(2, state); }
	DECLARE_WRITE_LINE_MEMBER(int3_w) { external_int(3, state); }

	// device_memory_interface overrides
	virtual space_config_vector memory_space_config() const override;

protected:
	enum
	{
		I80186_RELOC = I8086_HALT + 1,
		I80186_UMCS, I80186_LMCS, I80186_PACS, I80186_MMCS, I80186_MPCS,
		I80186_DMA_SP,
		I80186_DMA_DP = I80186_DMA_SP + 2,
		I80186_DMA_TC = I80186_DMA_DP + 2,
		I80186_DMA_CR = I80186_DMA_TC + 2,
		I80186_T_COUNT = I80186_DMA_CR + 2,
		I80186_T_MAX_A = I80186_T_COUNT + 3,
		I80186_T_MAX_B = I80186_T_MAX_A + 3,
		I80186_T_CONTROL = I80186_T_MAX_B + 2
	};

	i80186_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int data_bus_size);

	// device_execute_interface overrides
	virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const override { return (clocks / 2); }
	virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const override { return (cycles * 2); }
	virtual void execute_run() 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;
	virtual uint32_t execute_input_lines() const override { return 1; }
	virtual uint8_t fetch() override;
	uint32_t update_pc() { return m_pc = (m_sregs[CS] << 4) + m_ip; }

	virtual uint8_t read_port_byte(uint16_t port) override;
	virtual uint16_t read_port_word(uint16_t port) override;
	virtual void write_port_byte(uint16_t port, uint8_t data) override;
	virtual void write_port_word(uint16_t port, uint16_t data) override;

	static const uint8_t m_i80186_timing[200];

private:
	void update_interrupt_state();
	void handle_eoi(int data);
	void external_int(uint16_t intno, int state);
	void internal_timer_sync(int which);
	void internal_timer_update(int which, int new_count, int new_maxA, int new_maxB, int new_control);
	void update_dma_control(int which, int new_control);
	void drq_callback(int which);
	void inc_timer(int which);
	DECLARE_READ16_MEMBER(internal_port_r);
	DECLARE_WRITE16_MEMBER(internal_port_w);

	struct mem_state
	{
		uint16_t      lower;
		uint16_t      upper;
		uint16_t      middle;
		uint16_t      middle_size;
		uint16_t      peripheral;
	};

	struct timer_state
	{
		uint16_t      control;
		uint16_t      maxA;
		uint16_t      maxB;
		bool        active_count;
		uint16_t      count;
		emu_timer   *int_timer;
	};

	struct dma_state
	{
		bool        drq_state;
		uint32_t      source;
		uint32_t      dest;
		uint16_t      count;
		uint16_t      control;
	};

	struct intr_state
	{
		uint8_t       pending;
		uint16_t      ack_mask;
		uint16_t      priority_mask;
		uint16_t      in_service;
		uint16_t      request;
		uint16_t      status;
		uint16_t      poll_status;
		uint16_t      timer;
		uint16_t      dma[2];
		uint16_t      ext[4];
		uint8_t       ext_state;
	};

	timer_state     m_timer[3];
	dma_state       m_dma[2];
	intr_state      m_intr;
	mem_state       m_mem;

	static const device_timer_id TIMER_INT0 = 0;
	static const device_timer_id TIMER_INT1 = 1;
	static const device_timer_id TIMER_INT2 = 2;

	uint16_t m_reloc;

	address_space_config m_program_config;
	address_space_config m_opcodes_config;
	address_space_config m_io_config;

	devcb_read8 m_read_slave_ack_func;
	devcb_write16 m_out_chip_select_func;
	devcb_write_line m_out_tmrout0_func;
	devcb_write_line m_out_tmrout1_func;
};

class i80188_cpu_device : public i80186_cpu_device
{
public:
	// construction/destruction
	i80188_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};

#define MCFG_80186_IRQ_SLAVE_ACK(_devcb) \
		devcb = &i80186_cpu_device::static_set_read_slave_ack_callback(*device, DEVCB_##_devcb);

#define MCFG_80186_CHIP_SELECT_CB(_devcb) \
		devcb = &i80186_cpu_device::static_set_chip_select_callback(*device, DEVCB_##_devcb);

#define MCFG_80186_TMROUT0_HANDLER(_devcb) \
		devcb = &i80186_cpu_device::static_set_tmrout0_handler(*device, DEVCB_##_devcb);

#define MCFG_80186_TMROUT1_HANDLER(_devcb) \
		devcb = &i80186_cpu_device::static_set_tmrout1_handler(*device, DEVCB_##_devcb);

#endif // MAME_CPU_I86_I186_H