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 ®) { m_reg8 = ® m_reg16 = nullptr; }
242 void set_regop16(PAIR16 ®) { m_reg16 = ® m_reg8 = nullptr; }
243 uint8_t ®op8() { assert(m_reg8 != nullptr); return *m_reg8; }
244 PAIR16 ®op16() { 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