1 // license:BSD-3-Clause
2 // copyright-holders:Carl
3 #ifndef MAME_CPU_I86_I86_H
4 #define MAME_CPU_I86_I86_H
5 
6 #pragma once
7 
8 #include <cpu/i386/i386dasm.h>
9 
10 /////////////////////////////////////////////////////////////////
11 
12 DECLARE_DEVICE_TYPE(I8086, i8086_cpu_device)
13 DECLARE_DEVICE_TYPE(I8088, i8088_cpu_device)
14 
15 #define INPUT_LINE_INT0         INPUT_LINE_IRQ0
16 #define INPUT_LINE_TEST         20
17 
18 
19 enum
20 {
21 	I8086_PC = STATE_GENPC,
22 	I8086_IP = 1, I8086_AX, I8086_CX, I8086_DX, I8086_BX, I8086_SP, I8086_BP, I8086_SI, I8086_DI,
23 	I8086_AL, I8086_AH, I8086_CL, I8086_CH, I8086_DL, I8086_DH, I8086_BL, I8086_BH,
24 	I8086_FLAGS, I8086_ES, I8086_CS, I8086_SS, I8086_DS,
25 	I8086_VECTOR, I8086_HALT
26 };
27 
28 
29 class i8086_common_cpu_device : public cpu_device, public i386_disassembler::config
30 {
31 public:
lock_handler()32 	auto lock_handler() { return m_lock_handler.bind(); }
33 
34 protected:
35 	enum
36 	{
37 		EXCEPTION, IRET,                                /* EXCEPTION, iret */
38 		INT3, INT_IMM, INTO_NT, INTO_T,                 /* intS */
39 		OVERRIDE,                                       /* SEGMENT OVERRIDES */
40 		FLAG_OPS, LAHF, SAHF,                           /* FLAG OPERATIONS */
41 		AAA, AAS, AAM, AAD,                             /* ARITHMETIC ADJUSTS */
42 		DAA, DAS,                                       /* DECIMAL ADJUSTS */
43 		CBW, CWD,                                       /* SIGN EXTENSION */
44 		HLT, LOAD_PTR, LEA, NOP, WAIT, XLAT,            /* MISC */
45 
46 		JMP_SHORT, JMP_NEAR, JMP_FAR,                   /* DIRECT jmpS */
47 		JMP_R16, JMP_M16, JMP_M32,                      /* INDIRECT jmpS */
48 		CALL_NEAR, CALL_FAR,                            /* DIRECT callS */
49 		CALL_R16, CALL_M16, CALL_M32,                   /* INDIRECT callS */
50 		RET_NEAR, RET_FAR, RET_NEAR_IMM, RET_FAR_IMM,   /* RETURNS */
51 		JCC_NT, JCC_T, JCXZ_NT, JCXZ_T,                 /* CONDITIONAL jmpS */
52 		LOOP_NT, LOOP_T, LOOPE_NT, LOOPE_T,             /* LOOPS */
53 
54 		IN_IMM8, IN_IMM16, IN_DX8, IN_DX16,             /* PORT READS */
55 		OUT_IMM8, OUT_IMM16, OUT_DX8, OUT_DX16,         /* PORT WRITES */
56 
57 		MOV_RR8, MOV_RM8, MOV_MR8,                      /* MOVE, 8-BIT */
58 		MOV_RI8, MOV_MI8,                               /* MOVE, 8-BIT IMMEDIATE */
59 		MOV_RR16, MOV_RM16, MOV_MR16,                   /* MOVE, 16-BIT */
60 		MOV_RI16, MOV_MI16,                             /* MOVE, 16-BIT IMMEDIATE */
61 		MOV_AM8, MOV_AM16, MOV_MA8, MOV_MA16,           /* MOVE, al/ax MEMORY */
62 		MOV_SR, MOV_SM, MOV_RS, MOV_MS,                 /* MOVE, SEGMENT REGISTERS */
63 		XCHG_RR8, XCHG_RM8,                             /* EXCHANGE, 8-BIT */
64 		XCHG_RR16, XCHG_RM16, XCHG_AR16,                /* EXCHANGE, 16-BIT */
65 
66 		PUSH_R16, PUSH_M16, PUSH_SEG, PUSHF,            /* PUSHES */
67 		POP_R16, POP_M16, POP_SEG, POPF,                /* POPS */
68 
69 		ALU_RR8, ALU_RM8, ALU_MR8,                      /* alu OPS, 8-BIT */
70 		ALU_RI8, ALU_MI8, ALU_MI8_RO,                   /* alu OPS, 8-BIT IMMEDIATE */
71 		ALU_RR16, ALU_RM16, ALU_MR16,                   /* alu OPS, 16-BIT */
72 		ALU_RI16, ALU_MI16, ALU_MI16_RO,                /* alu OPS, 16-BIT IMMEDIATE */
73 		ALU_R16I8, ALU_M16I8, ALU_M16I8_RO,             /* alu OPS, 16-BIT W/8-BIT IMMEDIATE */
74 		MUL_R8, MUL_R16, MUL_M8, MUL_M16,               /* mul */
75 		IMUL_R8, IMUL_R16, IMUL_M8, IMUL_M16,           /* imul */
76 		DIV_R8, DIV_R16, DIV_M8, DIV_M16,               /* div */
77 		IDIV_R8, IDIV_R16, IDIV_M8, IDIV_M16,           /* idiv */
78 		INCDEC_R8, INCDEC_R16, INCDEC_M8, INCDEC_M16,   /* inc/dec */
79 		NEGNOT_R8, NEGNOT_R16, NEGNOT_M8, NEGNOT_M16,   /* neg/not */
80 
81 		ROT_REG_1, ROT_REG_BASE, ROT_REG_BIT,           /* REG SHIFT/ROTATE */
82 		ROT_M8_1, ROT_M8_BASE, ROT_M8_BIT,              /* M8 SHIFT/ROTATE */
83 		ROT_M16_1, ROT_M16_BASE, ROT_M16_BIT,           /* M16 SHIFT/ROTATE */
84 
85 		CMPS8, REP_CMPS8_BASE, REP_CMPS8_COUNT,         /* cmps 8-BIT */
86 		CMPS16, REP_CMPS16_BASE, REP_CMPS16_COUNT,      /* cmps 16-BIT */
87 		SCAS8, REP_SCAS8_BASE, REP_SCAS8_COUNT,         /* scas 8-BIT */
88 		SCAS16, REP_SCAS16_BASE, REP_SCAS16_COUNT,      /* scas 16-BIT */
89 		LODS8, REP_LODS8_BASE, REP_LODS8_COUNT,         /* lods 8-BIT */
90 		LODS16, REP_LODS16_BASE, REP_LODS16_COUNT,      /* lods 16-BIT */
91 		STOS8, REP_STOS8_BASE, REP_STOS8_COUNT,         /* stos 8-BIT */
92 		STOS16, REP_STOS16_BASE, REP_STOS16_COUNT,      /* stos 16-BIT */
93 		MOVS8, REP_MOVS8_BASE, REP_MOVS8_COUNT,         /* movs 8-BIT */
94 		MOVS16, REP_MOVS16_BASE, REP_MOVS16_COUNT,      /* movs 16-BIT */
95 
96 		INS8, REP_INS8_BASE, REP_INS8_COUNT,            /* (80186) ins 8-BIT */
97 		INS16, REP_INS16_BASE, REP_INS16_COUNT,         /* (80186) ins 16-BIT */
98 		OUTS8, REP_OUTS8_BASE, REP_OUTS8_COUNT,         /* (80186) outs 8-BIT */
99 		OUTS16, REP_OUTS16_BASE, REP_OUTS16_COUNT,      /* (80186) outs 16-BIT */
100 		PUSH_IMM, PUSHA, POPA,                          /* (80186) push IMMEDIATE, pusha/popa */
101 		IMUL_RRI8, IMUL_RMI8,                           /* (80186) imul IMMEDIATE 8-BIT */
102 		IMUL_RRI16, IMUL_RMI16,                         /* (80186) imul IMMEDIATE 16-BIT */
103 		ENTER0, ENTER1, ENTER_BASE, ENTER_COUNT, LEAVE, /* (80186) enter/leave */
104 		BOUND                                           /* (80186) bound */
105 	};
106 
107 	enum SREGS { ES=0, CS, SS, DS };
108 	enum WREGS { AX=0, CX, DX, BX, SP, BP, SI, DI };
109 
110 	// construction/destruction
111 	i8086_common_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
112 
113 	// device-level overrides
114 	virtual void device_start() override;
115 	virtual void device_reset() override;
116 
117 	// device_execute_interface overrides
execute_min_cycles()118 	virtual uint32_t execute_min_cycles() const noexcept override { return 1; }
execute_max_cycles()119 	virtual uint32_t execute_max_cycles() const noexcept override { return 50; }
120 	virtual void execute_set_input(int inputnum, int state) override;
execute_input_edge_triggered(int inputnum)121 	virtual bool execute_input_edge_triggered(int inputnum) const noexcept override { return inputnum == INPUT_LINE_NMI; }
122 
123 	// device_disasm_interface overrides
124 	virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
125 	virtual int get_mode() const override;
126 
127 	// device_state_interface overrides
128 	virtual void state_import(const device_state_entry &entry) override;
129 	virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
130 
131 	virtual void interrupt(int int_num, int trap = 1);
132 	virtual bool common_op(uint8_t op);
133 
134 	// Accessing memory and io
135 	virtual uint8_t read_byte(uint32_t addr);
136 	virtual uint16_t read_word(uint32_t addr);
137 	virtual void write_byte(uint32_t addr, uint8_t data);
138 	virtual void write_word(uint32_t addr, uint16_t data);
139 	virtual uint8_t read_port_byte(uint16_t port);
140 	virtual uint16_t read_port_word(uint16_t port);
141 	virtual void write_port_byte(uint16_t port, uint8_t data);
142 	virtual void write_port_word(uint16_t port, uint16_t data);
143 
144 	// Executing instructions
fetch_op()145 	uint8_t fetch_op() { return fetch(); }
146 	virtual uint8_t fetch() = 0;
147 	inline uint16_t fetch_word();
148 	inline uint8_t repx_op();
149 
150 	// Cycles passed while executing instructions
151 	inline void CLK(uint8_t op);
152 	inline void CLKM(uint8_t op_reg, uint8_t op_mem);
153 
154 	// Memory handling while executing instructions
155 	virtual uint32_t calc_addr(int seg, uint16_t offset, int size, int op, bool override = true);
156 	inline uint32_t get_ea(int size, int op);
157 	inline void PutbackRMByte(uint8_t data);
158 	inline void PutbackRMWord(uint16_t data);
159 	inline void RegByte(uint8_t data);
160 	inline void RegWord(uint16_t data);
161 	inline uint8_t RegByte();
162 	inline uint16_t RegWord();
163 	inline uint16_t GetRMWord();
164 	inline uint16_t GetnextRMWord();
165 	inline uint8_t GetRMByte();
166 	inline void PutMemB(int seg, uint16_t offset, uint8_t data);
167 	inline void PutMemW(int seg, uint16_t offset, uint16_t data);
168 	inline uint8_t GetMemB(int seg, uint16_t offset);
169 	inline uint16_t GetMemW(int seg, uint16_t offset);
170 	inline void PutImmRMWord();
171 	inline void PutRMWord(uint16_t val);
172 	inline void PutRMByte(uint8_t val);
173 	inline void PutImmRMByte();
174 	inline void DEF_br8();
175 	inline void DEF_wr16();
176 	inline void DEF_r8b();
177 	inline void DEF_r16w();
178 	inline void DEF_ald8();
179 	inline void DEF_axd16();
180 
181 	// Flags
182 	inline void set_CFB(uint32_t x);
183 	inline void set_CFW(uint32_t x);
184 	inline void set_AF(uint32_t x,uint32_t y,uint32_t z);
185 	inline void set_SF(uint32_t x);
186 	inline void set_ZF(uint32_t x);
187 	inline void set_PF(uint32_t x);
188 	inline void set_SZPF_Byte(uint32_t x);
189 	inline void set_SZPF_Word(uint32_t x);
190 	inline void set_OFW_Add(uint32_t x,uint32_t y,uint32_t z);
191 	inline void set_OFB_Add(uint32_t x,uint32_t y,uint32_t z);
192 	inline void set_OFW_Sub(uint32_t x,uint32_t y,uint32_t z);
193 	inline void set_OFB_Sub(uint32_t x,uint32_t y,uint32_t z);
194 	inline uint16_t CompressFlags() const;
195 	inline void ExpandFlags(uint16_t f);
196 
197 	// rep instructions
198 	inline void i_insb();
199 	inline void i_insw();
200 	inline void i_outsb();
201 	inline void i_outsw();
202 	inline void i_movsb();
203 	inline void i_movsw();
204 	inline void i_cmpsb();
205 	inline void i_cmpsw();
206 	inline void i_stosb();
207 	inline void i_stosw();
208 	inline void i_lodsb();
209 	inline void i_lodsw();
210 	inline void i_scasb();
211 	inline void i_scasw();
212 	inline void i_popf();
213 
214 	// sub implementations
215 	inline uint32_t ADDB();
216 	inline uint32_t ADDX();
217 	inline uint32_t SUBB();
218 	inline uint32_t SUBX();
219 	inline void ORB();
220 	inline void ORW();
221 	inline void ANDB();
222 	inline void ANDX();
223 	inline void XORB();
224 	inline void XORW();
225 	inline void ROL_BYTE();
226 	inline void ROL_WORD();
227 	inline void ROR_BYTE();
228 	inline void ROR_WORD();
229 	inline void ROLC_BYTE();
230 	inline void ROLC_WORD();
231 	inline void RORC_BYTE();
232 	inline void RORC_WORD();
233 	inline void SHL_BYTE(uint8_t c);
234 	inline void SHL_WORD(uint8_t c);
235 	inline void SHR_BYTE(uint8_t c);
236 	inline void SHR_WORD(uint8_t c);
237 	inline void SHRA_BYTE(uint8_t c);
238 	inline void SHRA_WORD(uint8_t c);
239 	inline void XchgAXReg(uint8_t reg);
240 	inline void IncWordReg(uint8_t reg);
241 	inline void DecWordReg(uint8_t reg);
242 	inline void PUSH(uint16_t data);
243 	inline uint16_t POP();
244 	inline void JMP(bool cond);
245 	inline void ADJ4(int8_t param1, int8_t param2);
246 	inline void ADJB(int8_t param1, int8_t param2);
247 
248 	union
249 	{                   /* eight general registers */
250 		uint16_t w[8];    /* viewed as 16 bits registers */
251 		uint8_t  b[16];   /* or as 8 bit registers */
252 	} m_regs;
253 
254 	enum BREGS {
255 		AL = NATIVE_ENDIAN_VALUE_LE_BE(0x0, 0x1),
256 		AH = NATIVE_ENDIAN_VALUE_LE_BE(0x1, 0x0),
257 		CL = NATIVE_ENDIAN_VALUE_LE_BE(0x2, 0x3),
258 		CH = NATIVE_ENDIAN_VALUE_LE_BE(0x3, 0x2),
259 		DL = NATIVE_ENDIAN_VALUE_LE_BE(0x4, 0x5),
260 		DH = NATIVE_ENDIAN_VALUE_LE_BE(0x5, 0x4),
261 		BL = NATIVE_ENDIAN_VALUE_LE_BE(0x6, 0x7),
262 		BH = NATIVE_ENDIAN_VALUE_LE_BE(0x7, 0x6),
263 		SPL = NATIVE_ENDIAN_VALUE_LE_BE(0x8, 0x9),
264 		SPH = NATIVE_ENDIAN_VALUE_LE_BE(0x9, 0x8),
265 		BPL = NATIVE_ENDIAN_VALUE_LE_BE(0xa, 0xb),
266 		BPH = NATIVE_ENDIAN_VALUE_LE_BE(0xb, 0xa),
267 		SIL = NATIVE_ENDIAN_VALUE_LE_BE(0xc, 0xd),
268 		SIH = NATIVE_ENDIAN_VALUE_LE_BE(0xd, 0xc),
269 		DIL = NATIVE_ENDIAN_VALUE_LE_BE(0xe, 0xf),
270 		DIH = NATIVE_ENDIAN_VALUE_LE_BE(0xf, 0xe)
271 	};
272 
273 	enum {
274 		I8086_READ,
275 		I8086_WRITE,
276 		I8086_FETCH,
277 		I8086_NONE
278 	};
279 
280 	uint16_t  m_sregs[4];
281 
282 	uint16_t  m_ip;
283 	uint16_t  m_prev_ip;
284 
285 	int32_t   m_SignVal;
286 	uint32_t  m_AuxVal, m_OverVal, m_ZeroVal, m_CarryVal, m_ParityVal; /* 0 or non-0 valued flags */
287 	uint8_t   m_TF, m_IF, m_DF;     /* 0 or 1 valued flags */
288 	uint8_t   m_IOPL, m_NT, m_MF;
289 	uint32_t  m_int_vector;
290 	uint32_t  m_pending_irq;
291 	uint32_t  m_nmi_state;
292 	uint32_t  m_irq_state;
293 	uint8_t   m_no_interrupt;
294 	uint8_t   m_fire_trap;
295 	uint8_t   m_test_state;
296 
297 	address_space *m_program, *m_opcodes;
298 	memory_access<20, 0, 0, ENDIANNESS_LITTLE>::cache m_cache8;
299 	memory_access<20, 1, 0, ENDIANNESS_LITTLE>::cache m_cache16;
300 
301 	std::function<u8 (offs_t)> m_or8;
302 	address_space *m_io;
303 	int m_icount;
304 
305 	uint32_t m_prefix_seg;   /* the latest prefix segment */
306 	bool m_seg_prefix;      /* prefix segment indicator */
307 	bool m_seg_prefix_next; /* prefix segment for next instruction */
308 
309 	uint32_t m_ea;
310 	uint16_t m_eo;
311 	int m_easeg;
312 
313 	// Used during execution of instructions
314 	uint8_t   m_modrm;
315 	uint32_t  m_dst;
316 	uint32_t  m_src;
317 	uint32_t  m_pc;
318 
319 	// Lookup tables
320 	uint8_t m_parity_table[256];
321 	struct {
322 		struct {
323 			int w[256];
324 			int b[256];
325 		} reg;
326 		struct {
327 			int w[256];
328 			int b[256];
329 		} RM;
330 	} m_Mod_RM;
331 
332 	uint8_t m_timing[200];
333 	bool m_halt;
334 
335 	bool m_lock;
336 	devcb_write_line m_lock_handler;
337 };
338 
339 class i8086_cpu_device : public i8086_common_cpu_device
340 {
341 public:
342 	enum {
343 		AS_STACK = AS_OPCODES + 1,
344 		AS_CODE, // data reads from CS are still different from opcode fetches
345 		AS_EXTRA
346 	};
347 	// construction/destruction
348 	i8086_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
349 
350 	// device_memory_interface overrides
351 	virtual space_config_vector memory_space_config() const override;
if_handler()352 	auto if_handler() { return m_out_if_func.bind(); }
esc_opcode_handler()353 	auto esc_opcode_handler() { return m_esc_opcode_handler.bind(); }
esc_data_handler()354 	auto esc_data_handler() { return m_esc_data_handler.bind(); }
355 
356 protected:
357 	i8086_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int data_bus_size);
358 
359 	virtual void execute_run() override;
360 	virtual void device_start() override;
execute_input_lines()361 	virtual uint32_t execute_input_lines() const noexcept override { return 1; }
362 	virtual uint8_t fetch() override;
363 	inline address_space *sreg_to_space(int sreg) const;
364 	virtual uint8_t read_byte(uint32_t addr) override;
365 	virtual uint16_t read_word(uint32_t addr) override;
366 	virtual void write_byte(uint32_t addr, uint8_t data) override;
367 	virtual void write_word(uint32_t addr, uint16_t data) override;
368 
369 	address_space_config m_program_config;
370 	address_space_config m_opcodes_config;
371 	address_space_config m_stack_config;
372 	address_space_config m_code_config;
373 	address_space_config m_extra_config;
374 	address_space_config m_io_config;
375 	static const uint8_t m_i8086_timing[200];
376 	devcb_write_line m_out_if_func;
377 	devcb_write32 m_esc_opcode_handler;
378 	devcb_write32 m_esc_data_handler;
379 
380 	address_space *m_stack, *m_code, *m_extra;
381 
382 protected:
update_pc()383 	uint32_t update_pc() { return m_pc = (m_sregs[CS] << 4) + m_ip; }
384 };
385 
386 class i8088_cpu_device : public i8086_cpu_device
387 {
388 public:
389 	// construction/destruction
390 	i8088_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
391 };
392 
393 
394 #endif // MAME_CPU_I86_I86_H
395