summaryrefslogtreecommitdiffstats
path: root/src/devices/cpu/cosmac/cosmac.h
blob: 4a535f3c4c126dfdeec33ec41a05f3e23836b787 (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
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
// license:BSD-3-Clause
// copyright-holders:Curt Coder
/**********************************************************************

    RCA COSMAC CPU emulation

**********************************************************************
                            _____   _____
                   Vcc   1 |*    \_/     | 40  Vdd
                _BUS 3   2 |             | 39  _BUS 4
                _BUS 2   3 |             | 38  _BUS 5
                _BUS 1   4 |             | 37  _BUS 6
                _BUS 0   5 |             | 36  _BUS 7
                   _N0   6 |             | 35  Vss
                   _N1   7 |             | 34  _EF1
                   _N2   8 |             | 33  _EF2
                   _N3   9 |             | 32  _EF3
                     *  10 |   CDP1801U  | 31  _EF4
                     *  11 |             | 30  _DMA OUT
                     *  12 |             | 29  _INTERRUPT
                     *  13 |             | 28  _DMA IN
                     *  14 |             | 27  _CLEAR
                _CLOCK  15 |             | 26  _LOAD
                  _TPB  16 |             | 25  _SC2
                  _TPA  17 |             | 24  _SC1
                     *  18 |             | 23  _SC0
                   MWR  19 |             | 22  _M READ
                   Vss  20 |_____________| 21  *

                            _____   _____
                   Vcc   1 |*    \_/     | 28  Vdd
                _BUS 4   2 |             | 27  _BUS 3
                _BUS 5   3 |             | 26  _BUS 2
                _BUS 6   4 |             | 25  _BUS 1
                _BUS 7   5 |             | 24  _BUS 0
                  _MA0   6 |             | 23  *
                  _MA1   7 |   CDP1801C  | 22  _TPB
                  _MA2   8 |             | 21  *
                  _MA3   9 |             | 20  *
                  _MA4  10 |             | 19  *
                  _MA5  11 |             | 18  *
                  _MA6  12 |             | 17  *
                  _MA7  13 |             | 16  *
                   Vss  14 |_____________| 15  _CLEAR

                            _____   _____
                 CLOCK   1 |*    \_/     | 40  Vdd
                 _WAIT   2 |             | 39  _XTAL
                _CLEAR   3 |             | 38  _DMA IN
                     Q   4 |             | 37  _DMA OUT
                   SC1   5 |             | 36  _INTERRUPT
                   SC0   6 |             | 35  _MWR
                  _MRD   7 |             | 34  TPA
                 BUS 7   8 |             | 33  TPB
                 BUS 6   9 |   CDP1802   | 32  MA7
                 BUS 5  10 |   CDP1803   | 31  MA6
                 BUS 4  11 |   CDP1804   | 30  MA5
                 BUS 3  12 |   CDP1805   | 29  MA4
                 BUS 2  13 |   CDP1806   | 28  MA3
                 BUS 1  14 |             | 27  MA2
                 BUS 0  15 |             | 26  MA1
                     *  16 |             | 25  MA0
                    N2  17 |             | 24  _EF1
                    N1  18 |             | 23  _EF2
                    N0  19 |             | 22  _EF3
                   Vss  20 |_____________| 21  _EF4


    Type            Internal ROM    Internal RAM    Timer   Pin 16 (*)
    ------------------------------------------------------------------
    CDP1802         none            none            no          Vcc
    CDP1803         ?               ?               ?           ?
    CDP1804         2 KB            64 bytes        yes         ?
    CDP1805         none            64 bytes        yes         _ME
    CDP1806         none            none            yes         Vdd

**********************************************************************/

#ifndef MAME_CPU_COSMAC_COSMAC_H
#define MAME_CPU_COSMAC_COSMAC_H

#pragma once



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

#define MCFG_COSMAC_WAIT_CALLBACK(_read) \
	devcb = &downcast<cosmac_device &>(*device).set_wait_rd_callback(DEVCB_##_read);

#define MCFG_COSMAC_CLEAR_CALLBACK(_read) \
	devcb = &downcast<cosmac_device &>(*device).set_clear_rd_callback(DEVCB_##_read);

#define MCFG_COSMAC_EF1_CALLBACK(_read) \
	devcb = &downcast<cosmac_device &>(*device).set_ef1_rd_callback(DEVCB_##_read);

#define MCFG_COSMAC_EF2_CALLBACK(_read) \
	devcb = &downcast<cosmac_device &>(*device).set_ef2_rd_callback(DEVCB_##_read);

#define MCFG_COSMAC_EF3_CALLBACK(_read) \
	devcb = &downcast<cosmac_device &>(*device).set_ef3_rd_callback(DEVCB_##_read);

#define MCFG_COSMAC_EF4_CALLBACK(_read) \
	devcb = &downcast<cosmac_device &>(*device).set_ef4_rd_callback(DEVCB_##_read);

#define MCFG_COSMAC_Q_CALLBACK(_write) \
	devcb = &downcast<cosmac_device &>(*device).set_q_wr_callback(DEVCB_##_write);

#define MCFG_COSMAC_DMAR_CALLBACK(_read) \
	devcb = &downcast<cosmac_device &>(*device).set_dma_rd_callback(DEVCB_##_read);

#define MCFG_COSMAC_DMAW_CALLBACK(_write) \
	devcb = &downcast<cosmac_device &>(*device).set_dma_wr_callback(DEVCB_##_write);

#define MCFG_COSMAC_SC_CALLBACK(_write) \
	devcb = &downcast<cosmac_device &>(*device).set_sc_wr_callback(DEVCB_##_write);



//**************************************************************************
//  ENUMERATIONS
//**************************************************************************

// input lines
enum
{
	COSMAC_INPUT_LINE_WAIT = 0,
	COSMAC_INPUT_LINE_CLEAR,
	COSMAC_INPUT_LINE_INT,
	COSMAC_INPUT_LINE_DMAIN,
	COSMAC_INPUT_LINE_DMAOUT,
	COSMAC_INPUT_LINE_EF1,
	COSMAC_INPUT_LINE_EF2,
	COSMAC_INPUT_LINE_EF3,
	COSMAC_INPUT_LINE_EF4
};


// state codes
enum cosmac_state_code
{
	COSMAC_STATE_CODE_S0_FETCH = 0,
	COSMAC_STATE_CODE_S1_EXECUTE,
	COSMAC_STATE_CODE_S2_DMA,
	COSMAC_STATE_CODE_S3_INTERRUPT
};



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

// ======================> cosmac_device

class cosmac_device : public cpu_device
{
public:
	// registers
	// public because machine/pecom.cpp accesses registers through the state interface - there should be a proper way to get address on bus for this
	// drivers/microkit.cpp and drivers/eti660.cpp are even worse setting R0 through the state interface to hack around running boot code or something
	enum
	{
		COSMAC_P,
		COSMAC_X,
		COSMAC_D,
		COSMAC_B,
		COSMAC_T,
		COSMAC_R0,
		COSMAC_R1,
		COSMAC_R2,
		COSMAC_R3,
		COSMAC_R4,
		COSMAC_R5,
		COSMAC_R6,
		COSMAC_R7,
		COSMAC_R8,
		COSMAC_R9,
		COSMAC_Ra,
		COSMAC_Rb,
		COSMAC_Rc,
		COSMAC_Rd,
		COSMAC_Re,
		COSMAC_Rf,
		COSMAC_DF,
		COSMAC_IE,
		COSMAC_Q,
		COSMAC_N,
		COSMAC_I,
		COSMAC_SC
	};


	template <class Object> devcb_base &set_wait_rd_callback(Object &&cb) { return m_read_wait.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_clear_rd_callback(Object &&cb) { return m_read_clear.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_ef1_rd_callback(Object &&cb) { return m_read_ef1.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_ef2_rd_callback(Object &&cb) { return m_read_ef2.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_ef3_rd_callback(Object &&cb) { return m_read_ef3.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_ef4_rd_callback(Object &&cb) { return m_read_ef4.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_q_wr_callback(Object &&cb) { return m_write_q.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_dma_rd_callback(Object &&cb) { return m_read_dma.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_dma_wr_callback(Object &&cb) { return m_write_dma.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_sc_wr_callback(Object &&cb) { return m_write_sc.set_callback(std::forward<Object>(cb)); }

	// public interfaces
	offs_t get_memory_address();

	DECLARE_WRITE_LINE_MEMBER( wait_w ) { set_input_line(COSMAC_INPUT_LINE_WAIT, state); }
	DECLARE_WRITE_LINE_MEMBER( clear_w ) { set_input_line(COSMAC_INPUT_LINE_CLEAR, state); }
	DECLARE_WRITE_LINE_MEMBER( int_w ) { set_input_line(COSMAC_INPUT_LINE_INT, state); }
	DECLARE_WRITE_LINE_MEMBER( dma_in_w ) { set_input_line(COSMAC_INPUT_LINE_DMAIN, state); }
	DECLARE_WRITE_LINE_MEMBER( dma_out_w ) { set_input_line(COSMAC_INPUT_LINE_DMAOUT, state); }
	DECLARE_WRITE_LINE_MEMBER( ef1_w ) { set_input_line(COSMAC_INPUT_LINE_EF1, state); }
	DECLARE_WRITE_LINE_MEMBER( ef2_w ) { set_input_line(COSMAC_INPUT_LINE_EF2, state); }
	DECLARE_WRITE_LINE_MEMBER( ef3_w ) { set_input_line(COSMAC_INPUT_LINE_EF3, state); }
	DECLARE_WRITE_LINE_MEMBER( ef4_w ) { set_input_line(COSMAC_INPUT_LINE_EF4, state); }

protected:
	// construction/destruction
	cosmac_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

	// device-level overrides
	virtual void device_start() override;
	virtual void device_reset() override;

	// device_execute_interface overrides
	virtual uint32_t execute_min_cycles() const override;
	virtual uint32_t execute_max_cycles() const override;
	virtual uint32_t execute_input_lines() const override;
	virtual void execute_run() override;
	virtual void execute_set_input(int inputnum, int state) override;

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

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

	// helpers
	inline uint8_t read_opcode(offs_t pc);
	inline uint8_t read_byte(offs_t address);
	inline uint8_t read_io_byte(offs_t address);
	inline void write_byte(offs_t address, uint8_t data);
	inline void write_io_byte(offs_t address, uint8_t data);

	// execution logic
	inline void run();
	inline void debug();
	inline void reset();
	inline void initialize();
	inline void fetch_instruction();
	inline void execute_instruction();
	inline void dma_input();
	inline void dma_output();
	inline void interrupt();
	inline void sample_wait_clear();
	inline void sample_ef_lines();
	inline void output_state_code();
	inline void set_q_flag(int state);

	// arithmetic handlers
	void add(int left, int right);
	void add_with_carry(int left, int right);
	void subtract(int left, int right);
	void subtract_with_borrow(int left, int right);

	// condition handlers
	void short_branch(int taken);
	void long_branch(int taken);
	void long_skip(int taken);

	// control handlers
	void return_from_interrupt(int ie);

	// memory reference opcode handlers
	void ldn();
	void lda();
	void ldx();
	void ldxa();
	void ldi();
	void str();
	void stxd();

	// register operations opcode handlers
	void inc();
	void dec();
	void irx();
	void glo();
	void plo();
	void ghi();
	void phi();

	// logic operations opcode handlers
	void _or();
	void ori();
	void _xor();
	void xri();
	void _and();
	void ani();
	void shr();
	void shrc();
	void shl();
	void shlc();

	// arithmetic operations opcode handlers
	void add();
	void adi();
	void adc();
	void adci();
	void sd();
	void sdi();
	void sdb();
	void sdbi();
	void sm();
	void smi();
	void smb();
	void smbi();

	// short branch instructions opcode handlers
	void br();
	void nbr();
	void bz();
	void bnz();
	void bdf();
	void bnf();
	void bq();
	void bnq();
	void b();
	void bn();

	// long branch instructions opcode handlers
	void lbr();
	void nlbr();
	void lbz();
	void lbnz();
	void lbdf();
	void lbnf();
	void lbq();
	void lbnq();

	// skip instructions opcode handlers
	void lsz();
	void lsnz();
	void lsdf();
	void lsnf();
	void lsq();
	void lsnq();
	void lsie();

	// control instructions opcode handlers
	void idl();
	void nop();
	void und();
	void sep();
	void sex();
	void seq();
	void req();
	void sav();
	void mark();
	void ret();
	void dis();

	// input/output byte transfer opcode handlers
	void out();
	void inp();

	const address_space_config      m_program_config;
	const address_space_config      m_io_config;

	// device callbacks
	devcb_read_line        m_read_wait;
	devcb_read_line        m_read_clear;
	devcb_read_line        m_read_ef1;
	devcb_read_line        m_read_ef2;
	devcb_read_line        m_read_ef3;
	devcb_read_line        m_read_ef4;
	devcb_write_line       m_write_q;
	devcb_read8            m_read_dma;
	devcb_write8           m_write_dma;
	devcb_write8           m_write_sc;

	// control modes
	enum class cosmac_mode : u8
	{
		LOAD = 0,
		RESET,
		PAUSE,
		RUN
	};

	// execution states
	enum class cosmac_state : u8
	{
		STATE_0_FETCH = 0,
		STATE_1_RESET,
		STATE_1_INIT,
		STATE_1_EXECUTE,
		STATE_2_DMA_IN,
		STATE_2_DMA_OUT,
		STATE_3_INT
	};

	// internal state
	uint16_t              m_pc;               // fake program counter
	uint8_t               m_op;               // current opcode
	uint8_t               m_flagsio;          // flags storage for state saving
	cosmac_state        m_state;            // state
	cosmac_mode         m_mode;             // control mode
	cosmac_mode         m_pmode;            // previous control mode
	bool m_wait;
	bool m_clear;
	int                 m_irq;              // interrupt request
	int                 m_dmain;            // DMA input request
	int                 m_dmaout;           // DMA output request
	int                 m_ef[4];            // external flags

	// registers
	uint8_t               m_d;                // data register (accumulator)
	uint8_t               m_b;                // auxiliary holding register
	uint16_t              m_r[16];            // scratchpad registers
	uint8_t               m_p;                // designates which register is Program Counter
	uint8_t               m_x;                // designates which register is Data Pointer
	uint8_t               m_n;                // low-order instruction digit
	uint8_t               m_i;                // high-order instruction digit
	uint8_t               m_t;                // temporary register

	// flags
	int                 m_df;               // data flag (ALU carry)
	int                 m_ie;               // interrupt enable
	int                 m_q;                // output flip-flop

	// internal stuff
	int                 m_icount;
	address_space *     m_program;
	address_space *     m_io;
	memory_access_cache<0, 0, ENDIANNESS_LITTLE> *m_cache;

	// opcode/condition tables
	typedef void (cosmac_device::*ophandler)();
	virtual cosmac_device::ophandler get_ophandler(uint8_t opcode) = 0;
};


// ======================> cdp1801_device

class cdp1801_device : public cosmac_device
{
public:
	// construction/destruction
	cdp1801_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

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

	virtual cosmac_device::ophandler get_ophandler(uint8_t opcode) override;

	static const ophandler s_opcodetable[256];
};


// ======================> cdp1802_device

class cdp1802_device : public cosmac_device
{
public:
	// construction/destruction
	cdp1802_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

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

	virtual cosmac_device::ophandler get_ophandler(uint8_t opcode) override;

	static const ophandler s_opcodetable[256];
};


// device type definition
DECLARE_DEVICE_TYPE(CDP1801, cdp1801_device)
DECLARE_DEVICE_TYPE(CDP1802, cdp1802_device)


#endif // MAME_CPU_COSMAC_COSMAC_H