1 // license:BSD-3-Clause
2 // copyright-holders:Nathan Woods
3 /*********************************************************************
4 
5     m6809.h
6 
7     Portable Motorola 6809 emulator
8 
9 **********************************************************************/
10 
11 #ifndef MAME_CPU_M6809_M6809_H
12 #define MAME_CPU_M6809_M6809_H
13 
14 #pragma once
15 
16 
17 //**************************************************************************
18 //  TYPE DEFINITIONS
19 //**************************************************************************
20 
21 // device type definition
DECLARE_DEVICE_TYPE(MC6809,mc6809_device)22 DECLARE_DEVICE_TYPE(MC6809, mc6809_device)
23 DECLARE_DEVICE_TYPE(MC6809E, mc6809e_device)
24 DECLARE_DEVICE_TYPE(M6809, m6809_device)
25 
26 // ======================> m6809_base_device
27 
28 // Used by core CPU interface
29 class m6809_base_device : public cpu_device
30 {
31 protected:
32 	// construction/destruction
33 	m6809_base_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, const device_type type, int divider);
34 
35 	class memory_interface {
36 	public:
37 		memory_access<16, 0, 0, ENDIANNESS_BIG>::cache cprogram, csprogram;
38 		memory_access<16, 0, 0, ENDIANNESS_BIG>::specific program;
39 
40 		virtual ~memory_interface() {}
41 		virtual uint8_t read(uint16_t adr) = 0;
42 		virtual uint8_t read_opcode(uint16_t adr) = 0;
43 		virtual uint8_t read_opcode_arg(uint16_t adr) = 0;
44 		virtual void write(uint16_t adr, uint8_t val) = 0;
45 	};
46 
47 	class mi_default : public memory_interface {
48 	public:
49 		virtual ~mi_default() {}
50 		virtual uint8_t read(uint16_t adr) override;
51 		virtual uint8_t read_opcode(uint16_t adr) override;
52 		virtual uint8_t read_opcode_arg(uint16_t adr) override;
53 		virtual void write(uint16_t adr, uint8_t val) override;
54 	};
55 
56 	// device-level overrides
57 	virtual void device_start() override;
58 	virtual void device_reset() override;
59 	virtual void device_pre_save() override;
60 	virtual void device_post_load() override;
61 
62 	// device_execute_interface overrides
63 	virtual uint32_t execute_min_cycles() const noexcept override;
64 	virtual uint32_t execute_max_cycles() const noexcept override;
65 	virtual uint32_t execute_input_lines() const noexcept override;
66 	virtual void execute_run() override;
67 	virtual void execute_set_input(int inputnum, int state) override;
68 	virtual bool execute_input_edge_triggered(int inputnum) const noexcept override { return inputnum == INPUT_LINE_NMI; }
69 	virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const noexcept override;
70 	virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const noexcept override;
71 
72 	// device_memory_interface overrides
73 	virtual space_config_vector memory_space_config() const override;
74 
75 	// device_disasm_interface overrides
76 	virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
77 
78 	// device_state_interface overrides
79 	virtual void state_import(const device_state_entry &entry) override;
80 	virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
81 
82 	virtual bool is_6809() { return true; };
83 
84 	// addressing modes
85 	enum
86 	{
87 		ADDRESSING_MODE_IMMEDIATE   = 0,
88 		ADDRESSING_MODE_EA          = 1,
89 		ADDRESSING_MODE_REGISTER_A  = 2,
90 		ADDRESSING_MODE_REGISTER_B  = 3,
91 		ADDRESSING_MODE_REGISTER_D = 4
92 	};
93 
94 	// register transfer
95 	struct exgtfr_register
96 	{
97 		uint8_t   byte_value;
98 		uint16_t  word_value;
99 	};
100 
101 	// flag bits in the cc register
102 	enum
103 	{
104 		CC_C        = 0x01,         // Carry
105 		CC_V        = 0x02,         // Overflow
106 		CC_Z        = 0x04,         // Zero
107 		CC_N        = 0x08,         // Negative
108 		CC_I        = 0x10,         // Inhibit IRQ
109 		CC_H        = 0x20,         // Half (auxiliary) carry
110 		CC_F        = 0x40,         // Inhibit FIRQ
111 		CC_E        = 0x80          // Entire state pushed
112 	};
113 
114 	// flag combinations
115 	enum
116 	{
117 		CC_VC   = CC_V | CC_C,
118 		CC_ZC   = CC_Z | CC_C,
119 		CC_NZ   = CC_N | CC_Z,
120 		CC_NZC  = CC_N | CC_Z | CC_C,
121 		CC_NZV  = CC_N | CC_Z | CC_V,
122 		CC_NZVC = CC_N | CC_Z | CC_V | CC_C,
123 		CC_HNZVC = CC_H | CC_N | CC_Z | CC_V | CC_C
124 	};
125 
126 	// interrupt vectors
127 	enum
128 	{
129 		VECTOR_SWI3         = 0xFFF2,
130 		VECTOR_SWI2         = 0xFFF4,
131 		VECTOR_FIRQ         = 0xFFF6,
132 		VECTOR_IRQ          = 0xFFF8,
133 		VECTOR_SWI          = 0xFFFA,
134 		VECTOR_NMI          = 0xFFFC,
135 		VECTOR_RESET_FFFE   = 0xFFFE
136 	};
137 
138 	union M6809Q
139 	{
140 		#ifdef LSB_FIRST
141 			union
142 			{
143 				struct { uint8_t f, e, b, a; };
144 				struct { uint16_t w, d; };
145 			} r;
146 			struct { PAIR16 w, d; } p;
147 		#else
148 			union
149 			{
150 				struct { uint8_t a, b, e, f; };
151 				struct { uint16_t d, w; };
152 			} r;
153 			struct { PAIR16 d, w; } p;
154 		#endif
155 		uint32_t q;
156 	};
157 
158 	// Memory interface
159 	std::unique_ptr<memory_interface> m_mintf;
160 
161 	// CPU registers
162 	PAIR16                      m_pc;               // program counter
163 	PAIR16                      m_ppc;              // previous program counter
164 	M6809Q                      m_q;                // accumulator a and b (plus e and f on 6309)
165 	PAIR16                      m_x, m_y;           // index registers
166 	PAIR16                      m_u, m_s;           // stack pointers
167 	uint8_t                       m_dp;               // direct page register
168 	uint8_t                       m_cc;
169 	PAIR16                      m_temp;
170 	uint8_t                       m_opcode;
171 
172 	// other internal state
173 	uint8_t *                     m_reg8;
174 	PAIR16 *                    m_reg16;
175 	int                         m_reg;
176 	bool                        m_nmi_line;
177 	bool                        m_nmi_asserted;
178 	bool                        m_firq_line;
179 	bool                        m_irq_line;
180 	bool                        m_lds_encountered;
181 	int                         m_icount;
182 	int                         m_addressing_mode;
183 	PAIR16                      m_ea;               // effective address
184 
185 	// Callbacks
186 	devcb_write_line           m_lic_func;         // LIC pin on the 6809E
187 
188 	// eat cycles
189 	inline void eat(int cycles)                          { m_icount -= cycles; }
190 	void eat_remaining();
191 
192 	// read a byte from given memory location
193 	inline uint8_t read_memory(uint16_t address)             { eat(1); return m_mintf->read(address); }
194 
195 	// write a byte to given memory location
196 	inline void write_memory(uint16_t address, uint8_t data) { eat(1); m_mintf->write(address, data); }
197 
198 	// read_opcode() is like read_memory() except it is used for reading opcodes. In  the case of a system
199 	// with memory mapped I/O, this function can be used  to greatly speed up emulation.
200 	inline uint8_t read_opcode(uint16_t address)             { eat(1); return m_mintf->read_opcode(address); }
201 
202 	// read_opcode_arg() is identical to read_opcode() except it is used for reading opcode  arguments. This
203 	// difference can be used to support systems that use different encoding mechanisms for opcodes
204 	// and opcode arguments.
205 	inline uint8_t read_opcode_arg(uint16_t address)         { eat(1); return m_mintf->read_opcode_arg(address); }
206 
207 	// read_opcode() and bump the program counter
208 	inline uint8_t read_opcode()                           { return read_opcode(m_pc.w++); }
209 	inline uint8_t read_opcode_arg()                       { return read_opcode_arg(m_pc.w++); }
210 
211 	// state stack - implemented as a uint32_t
212 	void push_state(uint8_t state)                    { m_state = (m_state << 8) | state; }
213 	uint8_t pop_state()                               { uint8_t result = (uint8_t) m_state; m_state >>= 8; return result; }
214 	void reset_state()                              { m_state = 0; }
215 
216 	// effective address reading/writing
217 	uint8_t read_ea()                                 { return read_memory(m_ea.w); }
218 	void write_ea(uint8_t data)                       { write_memory(m_ea.w, data); }
219 	void set_ea(uint16_t ea)                          { m_ea.w = ea; m_addressing_mode = ADDRESSING_MODE_EA; }
220 	void set_ea_h(uint8_t ea_h)                       { m_ea.b.h = ea_h; }
221 	void set_ea_l(uint8_t ea_l)                       { m_ea.b.l = ea_l; m_addressing_mode = ADDRESSING_MODE_EA; }
222 
223 	// operand reading/writing
224 	uint8_t read_operand();
225 	uint8_t read_operand(int ordinal);
226 	void write_operand(uint8_t data);
227 	void write_operand(int ordinal, uint8_t data);
228 
229 	// instructions
230 	void daa();
231 	void mul();
232 
233 	// miscellaneous
234 	void nop()                                      { }
235 	template<class T> T rotate_right(T value);
236 	template<class T> uint32_t rotate_left(T value);
237 	void set_a()                                    { m_addressing_mode = ADDRESSING_MODE_REGISTER_A; }
238 	void set_b()                                    { m_addressing_mode = ADDRESSING_MODE_REGISTER_B; }
239 	void set_d()                                    { m_addressing_mode = ADDRESSING_MODE_REGISTER_D; }
240 	void set_imm()                                  { m_addressing_mode = ADDRESSING_MODE_IMMEDIATE; }
241 	void set_regop8(uint8_t &reg)                     { m_reg8 = &reg; m_reg16 = nullptr; }
242 	void set_regop16(PAIR16 &reg)                   { m_reg16 = &reg; m_reg8 = nullptr; }
243 	uint8_t &regop8()                                 { assert(m_reg8 != nullptr); return *m_reg8; }
244 	PAIR16 &regop16()                               { assert(m_reg16 != nullptr); return *m_reg16; }
245 	bool is_register_register_op_16_bit()           { return m_reg16 != nullptr; }
246 	bool add8_sets_h()                              { return true; }
247 	bool hd6309_native_mode()                       { return false; }
248 
249 	// index reg
250 	uint16_t &ireg();
251 
252 	// flags
253 	template<class T> T set_flags(uint8_t mask, T a, T b, uint32_t r);
254 	template<class T> T set_flags(uint8_t mask, T r);
255 
256 	// branch conditions
257 	inline bool cond_hi() { return !(m_cc & CC_ZC); }                                                // BHI/BLS
258 	inline bool cond_cc() { return !(m_cc & CC_C);   }                                               // BCC/BCS
259 	inline bool cond_ne() { return !(m_cc & CC_Z);   }                                               // BNE/BEQ
260 	inline bool cond_vc() { return !(m_cc & CC_V);   }                                               // BVC/BVS
261 	inline bool cond_pl() { return !(m_cc & CC_N);   }                                               // BPL/BMI
262 	inline bool cond_ge() { return (m_cc & CC_N ? true : false) == (m_cc & CC_V ? true : false); }   // BGE/BLT
263 	inline bool cond_gt() { return cond_ge() && !(m_cc & CC_Z); }                                    // BGT/BLE
264 	inline void set_cond(bool cond)  { m_cond = cond; }
265 	inline bool branch_taken()       { return m_cond; }
266 
267 	// interrupt registers
268 	bool firq_saves_entire_state()      { return false; }
269 	uint16_t partial_state_registers()    { return 0x81; }
270 	uint16_t entire_state_registers()     { return 0xFF; }
271 
272 	// miscellaneous
273 	inline exgtfr_register read_exgtfr_register(uint8_t reg);
274 	inline void write_exgtfr_register(uint8_t reg, exgtfr_register value);
275 	bool is_register_addressing_mode();
276 	bool is_ea_addressing_mode() { return m_addressing_mode == ADDRESSING_MODE_EA; }
277 	uint16_t get_pending_interrupt();
278 	void log_illegal();
279 
280 private:
281 	// address spaces
282 	const address_space_config  m_program_config;
283 	const address_space_config  m_sprogram_config;
284 
285 	// other state
286 	uint32_t                      m_state;
287 	bool                        m_cond;
288 
289 	// incidentals
290 	int                         m_clock_divider;
291 
292 	// functions
293 	inline void execute_one();
294 	const char *inputnum_string(int inputnum);
295 };
296 
297 // ======================> mc6809_device
298 
299 class mc6809_device : public m6809_base_device
300 {
301 public:
302 	// construction/destruction
303 	mc6809_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
304 };
305 
306 // ======================> mc6809e_device
307 
308 class mc6809e_device : public m6809_base_device
309 {
310 public:
311 	// construction/destruction
312 	mc6809e_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
313 
314 	// MC6809E has LIC line to indicate opcode/data fetch
lic()315 	auto lic() { return m_lic_func.bind(); }
316 };
317 
318 // ======================> m6809_device (LEGACY)
319 
320 class m6809_device : public m6809_base_device
321 {
322 public:
323 	// construction/destruction
324 	m6809_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
325 };
326 
327 enum
328 {
329 	M6809_PC = STATE_GENPC, M6809_S = 0, M6809_CC ,M6809_A, M6809_B, M6809_D, M6809_U, M6809_X, M6809_Y,
330 	M6809_DP
331 };
332 
333 #define M6809_IRQ_LINE  0   /* IRQ line number */
334 #define M6809_FIRQ_LINE 1   /* FIRQ line number */
335 #define M6809_SWI       2   /* Virtual SWI line to be used during SWI acknowledge cycle */
336 
337 #endif // MAME_CPU_M6809_M6809_H
338