summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/nanoprocessor/nanoprocessor.h
blob: 2aa8cf3a4abb5137807ff0a420268d2885155f32 (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
// license:BSD-3-Clause
// copyright-holders:F. Ulivi
//
// *****************************
// Emulator for HP nanoprocessor
// *****************************
//
// Nanoprocessor is a very simple microcontroller developed by HP in 1974 for
// its own internal use. It's used, for example, in HP9845 built-in printer, in
// 98034 & 98035 modules, etc.
// Here's a summary of its features:
// * 8-bit word size
// * 1 Accumulator
// * 16 general purpose registers
// * 11-bit Program Counter
// * 2048 bytes of program space
// * 16 input 8-bit ports (DS0-DS15)
// * 15 output 8-bit ports (DS0-DS14)
// * 8 "direct control" I/O lines that can be individually tested/set/cleared
// * 1 interrupt input with 8-bit vector
// * One level nesting of subroutine call through a 11-bit subroutine stack register (SSR)
// * One level nesting of interruption through a 11-bit interrupt stack register (ISR)
// * No built-in ROM or RAM
// * All instructions execute in 2 clock cycles
// * NO arithmetic capabilities, except binary/BCD increment/decrement, bit
//   manipulation, left/right shift and comparison between A and R0
// * Register access can be indexed to use GP registers as a "poor man's RAM"
//                            _____   _____
//                   PA0   1 |*    \_/     | 40  VGG
//                   PA1   2 |             | 39  VDD
//                   PA2   3 |             | 38  VBG
//                   PA3   4 |             | 37  DC0
//                   PA4   5 |             | 36  DC1
//                   PA5   6 |             | 35  DC2
//                   PA6   7 |             | 34  DC3
//                   PA7   8 |             | 33  DC4
//                   PA8   9 |             | 32  DC5
//                   PA9  10 |Nanoprocessor| 31  DC6
//                  PA10  11 |             | 30  DC7/INT ENA
//                   DS3  12 |             | 29  _INT
//                   DS2  13 |             | 28  ACK
//                   DS1  14 |             | 27  CLK
//                   DS0  15 |             | 26  STM
//                  _R/W  16 |             | 25  DB7
//                   GND  17 |             | 24  DB6
//                   DB0  18 |             | 23  DB5
//                   DB1  19 |             | 22  DB4
//                   DB2  20 |_____________| 21  DB3
//
// The HP manual of Nanoprocessor is available here:
// http://www.hp9845.net/9845/downloads/manuals/Nanoprocessor.pdf
// Thanks to anyone who made the manual available.
//
// My reverse engineering of Nanoprocessor from mask set
// https://github.com/fulivi/nanoprocessor_re
//
// Mask set is published here
// http://cpushack.com/2020/08/20/hp-nanoprocessor-mask-set/
//
// Ken Shirriff's articles
// http://www.righto.com/2020/09/inside-hp-nanoprocessor-high-speed.html
// http://www.righto.com/2020/09/hp-nanoprocessor-part-ii-reverse.html
//
#ifndef MAME_CPU_NANOPROCESSOR_NANOPROCESSOR_H
#define MAME_CPU_NANOPROCESSOR_NANOPROCESSOR_H

#pragma once

constexpr unsigned HP_NANO_IE_DC   = 7;   // DC line used as interrupt enable/mask (DC7)

class hp_nanoprocessor_device : public cpu_device
{
public:
	hp_nanoprocessor_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	// DC changed callback
	// The callback receives a 8-bit word holding the state of all DC lines.
	// DC0 is in bit 0, DC1 in bit 1 and so on.
	// Keep in mind that DC7 usually masks the interrupt signal.
	auto dc_changed() { return m_dc_changed_func.bind(); }

	// Callback to read the input state of DC lines
	// All lines that are not in input are to be reported at "1"
	auto read_dc() { return m_read_dc_func.bind(); }

	// Callback to fetch interrupt vector
	auto int_ack() { return m_int_ack_func.bind(); }

	// device_execute_interface overrides
	virtual uint32_t execute_min_cycles() const noexcept override { return 2; }
	// 3 cycles is for int. acknowledge + 1 instruction
	virtual uint32_t execute_max_cycles() const noexcept override { return 3; }
	virtual uint32_t execute_input_lines() const noexcept override { return 1; }
	virtual uint32_t execute_default_irq_vector(int inputnum) const noexcept override { return 0xff; }

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

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

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

private:
	static constexpr unsigned HP_NANO_REGS    = 16;  // Number of GP registers
	static constexpr unsigned HP_NANO_PC_MASK = 0x7ff;   // Mask of PC meaningful bits: 11 bits available
	static constexpr unsigned HP_NANO_DC_NO   = 8;   // Number of direct control lines (DC7 is typically used as interrupt mask)

	devcb_write8 m_dc_changed_func;
	devcb_read8 m_read_dc_func;
	devcb_read8 m_int_ack_func;

	int m_icount;

	// State of processor
	uint8_t  m_reg_A;   // Accumulator
	uint8_t  m_reg_R[ HP_NANO_REGS ];   // General purpose registers
	uint16_t m_reg_PA;  // Program counter ("Program Address" in HP doc)
	uint16_t m_reg_SSR; // Subroutine stack register
	uint16_t m_reg_ISR; // Interrupt stack register
	uint16_t m_flags;   // Flags: extend flag (E) & direct control lines (DC0-7)

	// Bits in m_flags
	static constexpr unsigned NANO_DC0_BIT  = 0;    // DC0
	static constexpr unsigned NANO_E_BIT    = NANO_DC0_BIT + HP_NANO_DC_NO; // Extend flag
	static constexpr unsigned NANO_I_BIT    = NANO_E_BIT + 1;   // Interrupt flag

	address_space_config m_program_config;
	address_space_config m_io_config;

	memory_access<11, 0, 0, ENDIANNESS_BIG>::cache m_cache;
	memory_access<11, 0, 0, ENDIANNESS_BIG>::specific m_program;
	memory_access< 4, 0, 0, ENDIANNESS_BIG>::specific m_io;

	// device_t overrides
	virtual void device_start() override;
	virtual void device_reset() override;

	virtual void execute_run() override;
	virtual void execute_set_input(int linenum, int state) override;

	void execute_one(uint8_t opcode);
	uint16_t pa_offset(unsigned off) const;
	uint8_t fetch(void);
	void skip(void);
	void dc_update(void);
	void dc_set(unsigned bit_no);
	void dc_clr(unsigned bit_no);
};

DECLARE_DEVICE_TYPE(HP_NANOPROCESSOR, hp_nanoprocessor_device)

#endif /* _NANOPROCESSOR_H_ */