summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/hphybrid/hphybrid.h
blob: 5ef9f927d0e8e2d9b4f9a2da6c6c0112c5420db7 (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
// license:BSD-3-Clause
// copyright-holders:F. Ulivi
//
// *****************************************
// Emulator for HP "hybrid" processor series
// *****************************************
//
// The HP hybrid processor series is composed of a few different models with different
// capabilities. The series was derived from HP's own 2116 processor by translating a
// discrete implementation of the 1960s into a multi-chip module (hence the "hybrid" name).
// This emulator currently supports the 5061-3011 version only.
//
// For this emulator I mainly relied on these sources:
// - http://www.hp9845.net/ website
// - HP manual "Assembly development ROM manual for the HP9845": this is the most precious
//   and "enabling" resource of all
// - US Patent 4,180,854 describing the HP9845 system
// - Study of disassembly of firmware of HP64000 system
// - A lot of "educated" guessing

#ifndef _HPHYBRID_H_
#define _HPHYBRID_H_

// Input lines
#define HPHYBRID_IRH    0       // High-level interrupt
#define HPHYBRID_IRL    1       // Low-level interrupt
#define HPHYBRID_INT_LVLS   2   // Levels of interrupt

#define HPHYBRID_DMAR   2       // DMA request
#define HPHYBRID_HALT   3       // "Halt" input
#define HPHYBRID_STS    4       // "Status" input
#define HPHYBRID_FLG    5       // "Flag" input

// I/O addressing space (16-bit wide)
// Addresses into this space are composed as follows:
// b[5..2] = Peripheral address 0..15
// b[1..0] = Register address (IC) 0..3
#define HP_IOADDR_PA_SHIFT      2
#define HP_IOADDR_IC_SHIFT      0

// Compose an I/O address from PA & IC
#define HP_MAKE_IOADDR(pa , ic)    (((pa) << HP_IOADDR_PA_SHIFT) | ((ic) << HP_IOADDR_IC_SHIFT))

// Addresses of memory mapped registers
#define HP_REG_A_ADDR   0x0000
#define HP_REG_B_ADDR   0x0001
#define HP_REG_P_ADDR   0x0002
#define HP_REG_R_ADDR   0x0003
#define HP_REG_R4_ADDR  0x0004
#define HP_REG_R5_ADDR  0x0005
#define HP_REG_R6_ADDR  0x0006
#define HP_REG_R7_ADDR  0x0007
#define HP_REG_IV_ADDR  0x0008
#define HP_REG_PA_ADDR  0x0009
#define HP_REG_DMAPA_ADDR       0x000B
#define HP_REG_DMAMA_ADDR       0x000C
#define HP_REG_DMAC_ADDR        0x000D
#define HP_REG_C_ADDR   0x000e
#define HP_REG_D_ADDR   0x000f
#define HP_REG_LAST_ADDR        0x001f

#define HP_REG_IV_MASK  0xfff0
#define HP_REG_PA_MASK  0x000f

class hp_hybrid_cpu_device : public cpu_device
{
public:
        DECLARE_WRITE_LINE_MEMBER(dmar_w);

protected:
		hp_hybrid_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname);

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

		// device_execute_interface overrides
		virtual UINT32 execute_min_cycles() const { return 6; }
		virtual UINT32 execute_max_cycles() const { return 25; }
		virtual UINT32 execute_input_lines() const { return 2; }
		virtual UINT32 execute_default_irq_vector() const { return 0xffff; }
		virtual void execute_run();
		virtual void execute_set_input(int inputnum, int state);

		UINT16 execute_one(UINT16 opcode);
		UINT16 execute_one_sub(UINT16 opcode);

		// device_memory_interface overrides
		virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); }

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

		// device_disasm_interface overrides
		virtual UINT32 disasm_min_opcode_bytes() const { return 2; }
		virtual UINT32 disasm_max_opcode_bytes() const { return 2; }
		virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);

private:
		address_space_config m_program_config;
		address_space_config m_io_config;

		address_space *m_program;
		direct_read_data *m_direct;
		address_space *m_io;
		int m_icount;

		// State of processor
		UINT16 m_reg_A;     // Register A
		UINT16 m_reg_B;     // Register B
		UINT16 m_reg_P;     // Register P
		UINT16 m_reg_R;     // Register R
		UINT16 m_reg_C;     // Register C
		UINT16 m_reg_D;     // Register D
		UINT16 m_reg_IV;    // Register IV
		UINT8  m_reg_PA[ HPHYBRID_INT_LVLS + 1 ];   // Stack of register PA (4 bit-long)
		UINT16 m_flags;     // Flags (carry, overflow, cb, db, int en, dma en, dma dir)
		UINT8  m_dmapa;     // DMA peripheral address (4 bits)
		UINT16 m_dmama;     // DMA address
		UINT16 m_dmac;      // DMA counter
		UINT16 m_reg_I;     // Instruction register

		UINT16 get_ea(UINT16 opcode);
		void do_add(UINT16& addend1 , UINT16 addend2);
		UINT16 get_skip_addr(UINT16 opcode , bool condition) const;
		UINT16 get_skip_addr_sc(UINT16 opcode , UINT16& v , unsigned n);
		void do_pw(UINT16 opcode);
		void check_for_interrupts(void);
                void handle_dma(void);

		UINT16 RM(UINT16 addr);
		void   WM(UINT16 addr , UINT16 v);
		void   WMB(UINT32 addr , UINT8 v);
		UINT16 RIO(UINT8 pa , UINT8 ic);
		void   WIO(UINT8 pa , UINT8 ic , UINT16 v);
};

class hp_5061_3011_cpu_device : public hp_hybrid_cpu_device
{
public:
		hp_5061_3011_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
};

extern const device_type HP_5061_3011;

#endif /* _HPHYBRID_H_ */