// license:BSD-3-Clause
// copyright-holders:Carl
#ifndef MAME_CPU_I86_I286_H
#define MAME_CPU_I86_I286_H
#pragma once
#include "i86.h"
#define INPUT_LINE_A20 1
DECLARE_DEVICE_TYPE(I80286, i80286_cpu_device)
enum
{ // same order as I8086 registers
I286_PC = STATE_GENPC,
I286_IP = 1,
I286_AX,
I286_CX,
I286_DX,
I286_BX,
I286_SP,
I286_BP,
I286_SI,
I286_DI,
I286_FLAGS,
I286_ES,
I286_CS,
I286_SS,
I286_DS,
I286_VECTOR,
I286_HALT,
I286_ES_BASE,
I286_ES_LIMIT,
I286_ES_FLAGS,
I286_CS_BASE,
I286_CS_LIMIT,
I286_CS_FLAGS,
I286_SS_BASE,
I286_SS_LIMIT,
I286_SS_FLAGS,
I286_DS_BASE,
I286_DS_LIMIT,
I286_DS_FLAGS,
I286_MSW,
I286_GDTR_BASE,
I286_GDTR_LIMIT,
I286_IDTR_BASE,
I286_IDTR_LIMIT,
I286_TR,
I286_TR_BASE,
I286_TR_LIMIT,
I286_TR_FLAGS,
I286_LDTR,
I286_LDTR_BASE,
I286_LDTR_LIMIT,
I286_LDTR_FLAGS
};
class i80286_cpu_device : public i8086_common_cpu_device
{
public:
// construction/destruction
i80286_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// device_memory_interface overrides
virtual space_config_vector memory_space_config() const override;
typedef delegate<uint32_t (bool)> a20_cb;
template <typename Object> void set_a20_callback(Object &&cb) { m_a20_callback = std::forward<Object>(cb); }
template <class Object> devcb_base &set_shutdown_callback(Object &&cb) { return m_out_shutdown_func.set_callback(std::forward<Object>(cb)); }
protected:
virtual void execute_run() override;
virtual void device_reset() override;
virtual void device_start() override;
// device_state_interface overrides
virtual void state_import(const device_state_entry &entry) override;
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
virtual uint32_t execute_input_lines() const override { return 1; }
virtual void execute_set_input(int inputnum, int state) override;
bool memory_translate(int spacenum, int intention, offs_t &address) override;
virtual void interrupt(int int_num, int trap = 1) override { if(trap) throw TRAP(int_num, (uint16_t)-1); else interrupt_descriptor(int_num, 0, 0); }
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;
// Executing instructions
virtual uint8_t fetch() override;
virtual uint32_t calc_addr(int seg, uint16_t offset, int size, int op, bool override = true) override;
private:
void check_permission(uint8_t check_seg, uint32_t offset, uint16_t size, int operation);
void code_descriptor(uint16_t selector, uint16_t offset, int gate);
void data_descriptor(int reg, uint16_t selector);
void data_descriptor(int reg, uint16_t selector, int cpl, uint32_t trap, uint16_t offset = 0, int size = 0);
uint16_t far_return(int iret, int bytes);
void interrupt_descriptor(int number, int hwint, int error);
void load_flags(uint16_t flags, int cpl);
void pop_seg(int reg);
uint32_t selector_address(uint16_t sel);
void switch_task(uint16_t ntask, int type);
void trap(uint32_t error);
int verify(uint16_t selector, int operation, uint8_t rights, bool valid);
uint32_t update_pc() { return m_pc = m_base[CS] + m_ip; }
int m_trap_level;
uint16_t m_msw;
uint32_t m_base[4];
uint16_t m_limit[4];
uint8_t m_rights[4];
bool m_valid[4];
uint32_t m_amask;
struct {
uint32_t base;
uint16_t limit;
} m_gdtr, m_idtr;
struct {
uint16_t sel;
uint32_t base;
uint16_t limit;
uint8_t rights;
} m_ldtr, m_tr;
uint32_t TRAP(uint16_t fault, uint16_t code) { return ((((uint32_t)fault&0xffff)<<16)|(code&0xffff)); }
address_space_config m_program_config;
address_space_config m_opcodes_config;
address_space_config m_io_config;
static const uint8_t m_i80286_timing[200];
enum {
FAULT_DE = 0,
FAULT_DB,
NMI,
FAULT_BP,
FAULT_OF,
FAULT_BR,
FAULT_UD,
FAULT_NM,
FAULT_DF,
FAULT_MP,
FAULT_TS,
FAULT_NP,
FAULT_SS,
FAULT_GP
};
a20_cb m_a20_callback;
bool m_shutdown;
devcb_write_line m_out_shutdown_func;
};
#define MCFG_80286_A20(_class, _a20_cb) \
downcast<i80286_cpu_device &>(*device).set_a20_callback(i80286_cpu_device::a20_cb(&_class::_a20_cb, this));
#define MCFG_80286_SHUTDOWN(_devcb) \
downcast<i80286_cpu_device &>(*device).set_shutdown_callback(DEVCB_##_devcb);
#endif // MAME_CPU_I86_I286_H