summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/mcs40/mcs40.h
blob: 73cc2a10fe455349dc32dd75dfdb513b958c7851 (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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
#ifndef MAME_CPU_MCS40_MCS40_H
#define MAME_CPU_MCS40_MCS40_H

#pragma once

#include <memory>
#include <utility>


/***********************************************************************
    CONSTANTS
***********************************************************************/

enum
{
	I4004_TEST_LINE = 0,

	I4040_TEST_LINE = I4004_TEST_LINE,
	I4040_INT_LINE = 1,
	I4040_STP_LINE = 2
};



/***********************************************************************
    CONFIGURATION MACROS
***********************************************************************/

#define MCS40CB_BUSCYCLE(cls, fnc) \
		mcs40_cpu_device_base::bus_cycle_delegate((&cls::fnc), (#cls "::" #fnc), DEVICE_SELF, (cls *)nullptr)


#define MCFG_I4004_BUS_CYCLE_CB(obj) \
		downcast<i4004_cpu_device &>(*device).set_bus_cycle_cb((MCS40CB_##obj));

#define MCFG_I4004_SYNC_CB(obj) \
		downcast<i4004_cpu_device &>(*device).set_sync_cb(DEVCB_##obj);

#define MCFG_I4004_CM_ROM_CB(obj) \
		downcast<i4004_cpu_device &>(*device).set_cm_rom_cb(DEVCB_##obj);

#define MCFG_I4004_CM_RAM0_CB(obj) \
		downcast<i4004_cpu_device &>(*device).set_cm_ram_cb<0>(DEVCB_##obj);

#define MCFG_I4004_CM_RAM1_CB(obj) \
		downcast<i4004_cpu_device &>(*device).set_cm_ram_cb<1>(DEVCB_##obj);

#define MCFG_I4004_CM_RAM2_CB(obj) \
		downcast<i4004_cpu_device &>(*device).set_cm_ram_cb<2>(DEVCB_##obj);

#define MCFG_I4004_CM_RAM3_CB(obj) \
		downcast<i4004_cpu_device &>(*device).set_cm_ram_cb<3>(DEVCB_##obj);

#define MCFG_I4004_4289_PM_CB(obj) \
		downcast<i4004_cpu_device &>(*device).set_4289_pm_cb(DEVCB_##obj);

#define MCFG_I4004_4289_F_L_CB(obj) \
		downcast<i4004_cpu_device &>(*device).set_4289_f_l_cb(DEVCB_##obj);


#define MCFG_I4040_BUS_CYCLE_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_bus_cycle_cb((MCS40CB_##obj));

#define MCFG_I4040_SYNC_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_sync_cb(DEVCB_##obj);

#define MCFG_I4040_CM_ROM0_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_cm_rom_cb<0>(DEVCB_##obj);

#define MCFG_I4040_CM_ROM1_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_cm_rom_cb<1>(DEVCB_##obj);

#define MCFG_I4040_CM_RAM0_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_cm_ram_cb<0>(DEVCB_##obj);

#define MCFG_I4040_CM_RAM1_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_cm_ram_cb<1>(DEVCB_##obj);

#define MCFG_I4040_CM_RAM2_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_cm_ram_cb<2>(DEVCB_##obj);

#define MCFG_I4040_CM_RAM3_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_cm_ram_cb<3>(DEVCB_##obj);

#define MCFG_I4040_CY_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_cy_cb(DEVCB_##obj);

#define MCFG_I4040_STP_ACK_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_stp_ack_cb(DEVCB_##obj);

#define MCFG_I4040_4289_PM_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_4289_pm_cb(DEVCB_##obj);

#define MCFG_I4040_4289_F_L_CB(obj) \
		downcast<i4040_cpu_device &>(*device).set_4289_f_l_cb(DEVCB_##obj);



/***********************************************************************
    TYPE DEFINITIONS
***********************************************************************/

class mcs40_cpu_device_base : public cpu_device
{
public:
	enum {
		AS_ROM              = AS_PROGRAM,
		AS_RAM_MEMORY       = AS_DATA,
		AS_ROM_PORTS        = AS_IO,
		AS_RAM_STATUS       = AS_OPCODES + 1,
		AS_RAM_PORTS,
		AS_PROGRAM_MEMORY
	};
	enum class phase : u8 { A1, A2, A3, M1, M2, X1, X2, X3 };

	// step isn't a real signal, but realistically anything watching the bus will have a counter to track it
	typedef device_delegate<void (phase step, u8 sync, u8 data)> bus_cycle_delegate;

	// configuration helpers
	template <typename... T> void set_rom_map(T &&... args) { set_addrmap(AS_ROM, std::forward<T>(args)...); }
	template <typename... T> void set_ram_memory_map(T &&... args) { set_addrmap(AS_RAM_MEMORY, std::forward<T>(args)...); }
	template <typename... T> void set_rom_ports_map(T &&... args) { set_addrmap(AS_ROM_PORTS, std::forward<T>(args)...); }
	template <typename... T> void set_ram_status_map(T &&... args) { set_addrmap(AS_RAM_STATUS, std::forward<T>(args)...); }
	template <typename... T> void set_ram_ports_map(T &&... args) { set_addrmap(AS_RAM_PORTS, std::forward<T>(args)...); }
	template <typename... T> void set_program_memory_map(T &&... args) { set_addrmap(AS_PROGRAM_MEMORY, std::forward<T>(args)...); }
	template <typename Obj> void set_bus_cycle_cb(Obj &&cb) { m_bus_cycle_cb = std::forward<Obj>(cb); }
	template <typename Obj> devcb_base &set_4289_pm_cb(Obj &&cb) { return m_4289_pm_cb.set_callback(std::forward<Obj>(cb)); }
	template <typename Obj> devcb_base &set_4289_f_l_cb(Obj &&cb) { return m_4289_f_l_cb.set_callback(std::forward<Obj>(cb)); }

	// chip select outputs
	u8 get_cm_rom() const { return m_cm_rom; }
	u8 get_cm_ram() const { return m_cm_ram; }

	// 4008/4009 or 4289 outputs
	u8 get_4289_a() const { return m_4289_a; } // 8-bit address
	u8 get_4289_c() const { return m_4289_c; } // 4-bit chip select
	DECLARE_READ_LINE_MEMBER(get_4289_pm) const { return BIT(m_4289_pm, 0); } // 0 = active
	DECLARE_READ_LINE_MEMBER(get_4289_f_l) const { return BIT(m_4289_f_l, 0); } // 1 = odd, 0 = even

protected:
	enum class cycle : u8 { OP, IM, IN };
	enum class pmem : u8 { NONE, READ, WRITE };

	mcs40_cpu_device_base(
			machine_config const &mconfig,
			device_type type,
			char const *tag,
			device_t *owner,
			u32 clock,
			bool extended_cm,
			unsigned rom_width,
			unsigned stack_ptr_mask,
			unsigned index_reg_cnt,
			unsigned cr_mask);

	// device_t implementation
	void device_start() override;
	void device_reset() override;

	// device_execute_interface implementation
	virtual void execute_run() override;

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

	// device_state_interface implementation
	virtual void state_import(device_state_entry const &entry) override;
	virtual void state_export(device_state_entry const &entry) override;
	virtual void state_string_export(device_state_entry const &entry, std::string &str) const override;

	// instruction execution
	virtual bool is_io_op(u8 opr) = 0;
	virtual cycle do_cycle1(u8 opr, u8 opa, pmem &program_op) = 0;
	virtual void do_cycle2(u8 opr, u8 opa, u8 arg) = 0;
	virtual u8 do_io(u8 opr, u8 opa) = 0;

	// register access
	u8 get_a() const;
	u8 get_c() const;
	void set_a(u8 val);
	void set_c(u8 val);
	void set_a_c(u8 val);
	void set_pc(u16 addr, u16 mask);
	void push_pc();
	void pop_pc();
	u8 &index_reg_pair(unsigned n);
	u8 get_index_reg(unsigned n);
	void set_index_reg(unsigned n, u8 val);
	void set_index_reg_bank(u8 val);

	// I/O control
	void halt_decoded();
	void set_rom_addr(u16 addr, u16 mask);
	u8 get_cr();
	void set_cr(u8 val, u8 mask);
	void set_pending_rom_bank(u8 val);
	void set_rc(u8 val);
	u8 read_memory();
	void write_memory(u8 val);
	u8 read_status();
	void write_status(u8 val);
	u8 read_rom_port();
	void write_rom_port(u8 val);
	void write_memory_port(u8 val);

	// input lines
	bool get_test();
	void set_test(int state);
	void set_stp(int state);

	// configuration helpers
	template <typename Obj> devcb_base &set_sync_cb(Obj &&cb) { return m_sync_cb.set_callback(std::forward<Obj>(cb)); }
	template <unsigned N, typename Obj> devcb_base &set_cm_rom_cb(Obj &&cb) { return m_cm_rom_cb[N].set_callback(std::forward<Obj>(cb)); }
	template <unsigned N, typename Obj> devcb_base &set_cm_ram_cb(Obj &&cb) { return m_cm_ram_cb[N].set_callback(std::forward<Obj>(cb)); }
	template <typename Obj> devcb_base &set_cy_cb(Obj &&cb) { return m_cy_cb.set_callback(std::forward<Obj>(cb)); }
	template <typename Obj> devcb_base &set_stp_ack_cb(Obj &&cb) { return m_stp_ack_cb.set_callback(std::forward<Obj>(cb)); }

private:
	enum
	{
		I4004_A = 1,
		I4004_R01, I4004_R23, I4004_R45, I4004_R67, I4004_R89, I4004_RAB, I4004_RCD, I4004_REF,
		I4040_RGH, I4040_RIJ, I4040_RKL, I4040_RMN,
		I4004_R0, I4004_R1, I4004_R2, I4004_R3, I4004_R4, I4004_R5, I4004_R6, I4004_R7,
		I4004_R8, I4004_R9, I4004_R10, I4004_R11, I4004_R12, I4004_R13, I4004_R14, I4004_R15,
		I4040_R16, I4040_R17, I4040_R18, I4040_R19, I4040_R20, I4040_R21, I4040_R22, I4040_R23,
		I4004_SP,
		I4004_ADDR0, I4004_ADDR1, I4004_ADDR2, I4004_ADDR3,
		I4040_ADDR4, I4040_ADDR5, I4040_ADDR6, I4040_ADDR7,
		I4004_CR, I4004_RC, I4004_RCN,
		I4040_SRC
	};

	// instruction phases
	void do_a1();
	void do_a2();
	void do_a3();
	void do_m1();
	void do_m2();
	void do_x1();
	void do_x2();
	void do_x3();

	// internal helpers
	u16 &pc() { return m_addr_stack[m_stack_ptr]; }
	u16 rom_bank() const { return BIT(m_cr, 3) ? 0x1000U : 0x0000U; }
	u16 program_addr() const { return (u16(BIT(m_cr, 3)) << 9) | (u16(m_4289_a) << 1) | BIT(m_4289_f_l, 0); }
	void update_cm_rom(u8 val);
	void update_cm_ram(u8 val);
	void update_cy(u8 val);
	void update_4289_pm(u8 val);
	void update_4289_f_l(u8 val);

	// address spaces
	address_space_config const  m_space_config[7];
	address_space               *m_spaces[7];
	memory_access_cache<0, 0, ENDIANNESS_LITTLE> *m_cache;

	// bus snooping callback
	bus_cycle_delegate      m_bus_cycle_cb;

	// output callbacks
	devcb_write_line        m_sync_cb;
	devcb_write_line        m_cm_rom_cb[2], m_cm_ram_cb[4];
	devcb_write_line        m_cy_cb, m_stp_ack_cb;

	// 4008/4009 or 4289 output callbacks
	devcb_write_line        m_4289_pm_cb, m_4289_f_l_cb;

	// configuration
	bool const  m_extended_cm;
	u8 const    m_stack_ptr_mask;
	u8 const    m_index_reg_cnt;
	u8 const    m_cr_mask;
	u16 const   m_pc_mask;

	// machine/instruction phase
	int     m_icount;
	phase   m_phase;
	cycle   m_cycle;
	bool    m_io_pending;
	pmem    m_program_op;

	// stop/halt control
	bool    m_stop_latch, m_stop_ff, m_decoded_halt, m_resume;

	// instruction ROM fetch/decode
	u16     m_rom_bank, m_rom_addr;
	u8      m_opr, m_opa, m_arg;
	bool    m_4289_first;

	// ALU registers
	u8      m_a, m_c;

	// address stack
	std::unique_ptr<u16 []> m_addr_stack;
	u8                      m_stack_ptr;

	// index registers
	std::unique_ptr<u8 []>  m_index_regs;
	u8                      m_index_reg_bank;

	// RAM/I/O control
	u8          m_cr, m_pending_cr3, m_latched_rc, m_new_rc, m_src;
	bool        m_rc_pending;

	// input/output lines
	int m_test, m_stp;
	u8  m_cm_rom, m_cm_ram, m_cy;
	u8  m_4289_a, m_4289_c, m_4289_pm, m_4289_f_l;

	// state export/import
	std::unique_ptr<u8 []>  m_index_reg_halves;
	u16                     m_pc, m_pcbase;
	u8                      m_genflags;
};


class i4004_cpu_device : public mcs40_cpu_device_base
{
public:
	// configuration helpers
	template <typename Obj> devcb_base &set_sync_cb(Obj &&cb) { return mcs40_cpu_device_base::set_sync_cb(std::forward<Obj>(cb)); }
	template <typename Obj> devcb_base &set_cm_rom_cb(Obj &&cb) { return set_cm_rom_cb<0>(std::forward<Obj>(cb)); }
	template <unsigned N, typename Obj> devcb_base &set_cm_ram_cb(Obj &&cb) { return mcs40_cpu_device_base::set_cm_ram_cb<N>(std::forward<Obj>(cb)); }

	i4004_cpu_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);

protected:
	using mcs40_cpu_device_base::mcs40_cpu_device_base;

	// device_execute_interface implementation
	virtual u32 execute_input_lines() const override;
	virtual void execute_set_input(int inputnum, int state) override;

	// device_disasm_interface implementation
	virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;

	// mcs40_cpu_device_base implementation
	virtual bool is_io_op(u8 opr) override;
	virtual cycle do_cycle1(u8 opr, u8 opa, pmem &program_op) override;
	virtual void do_cycle2(u8 opr, u8 opa, u8 arg) override;
	virtual u8 do_io(u8 opr, u8 opa) override;

	// configuration helpers
	using mcs40_cpu_device_base::set_sync_cb;
	using mcs40_cpu_device_base::set_cm_rom_cb;
	using mcs40_cpu_device_base::set_cm_ram_cb;
};


class i4040_cpu_device : public i4004_cpu_device
{
public:
	// configuration helpers
	template <typename Obj> devcb_base &set_sync_cb(Obj &&cb) { return i4004_cpu_device::set_sync_cb(std::forward<Obj>(cb)); }
	template <unsigned N, typename Obj> devcb_base &set_cm_rom_cb(Obj &&cb) { return set_cm_rom_cb<N>(std::forward<Obj>(cb)); }
	template <unsigned N, typename Obj> devcb_base &set_cm_ram_cb(Obj &&cb) { return set_cm_ram_cb<N>(std::forward<Obj>(cb)); }
	template <typename Obj> devcb_base &set_cy_cb(Obj &&cb) { return i4004_cpu_device::set_cy_cb(std::forward<Obj>(cb)); }
	template <typename Obj> devcb_base &set_stp_ack_cb(Obj &&cb) { return i4004_cpu_device::set_stp_ack_cb(std::forward<Obj>(cb)); }

	i4040_cpu_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);

protected:
	// device_disasm_interface implementation
	virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;

	// device_execute_interface implementation
	virtual u32 execute_input_lines() const override;
	virtual void execute_set_input(int inputnum, int state) override;

	// mcs40_cpu_device_base implementation
	virtual cycle do_cycle1(u8 opr, u8 opa, pmem &program_op) override;

	// configuration helpers
	using mcs40_cpu_device_base::set_sync_cb;
	using mcs40_cpu_device_base::set_cm_rom_cb;
	using mcs40_cpu_device_base::set_cm_ram_cb;
	using mcs40_cpu_device_base::set_cy_cb;
	using mcs40_cpu_device_base::set_stp_ack_cb;
};



/***********************************************************************
    DEVICE TYPE DECLARATIONS
***********************************************************************/

DECLARE_DEVICE_TYPE(I4004, i4004_cpu_device)
DECLARE_DEVICE_TYPE(I4040, i4040_cpu_device)

#endif // MAME_CPU_MCS40_MCS40_H