summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/drcbeut.h
blob: 889459134292826607adef6475473876ced85060 (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
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    Utility functions for dynamic recompiling backends.

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

#ifndef MAME_CPU_DRCBEUT_H
#define MAME_CPU_DRCBEUT_H

#pragma once

#include "drcuml.h"

#include "mfpresolve.h"

#include <cassert>
#include <list>
#include <utility>
#include <vector>


namespace drc {

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

// ======================> drc_hash_table

// common hash table management
class drc_hash_table
{
public:
	// construction/destruction
	drc_hash_table(drc_cache &cache, uint32_t modes, uint8_t addrbits, uint8_t ignorebits);

	// getters
	drccodeptr ***base() const noexcept { return m_base; }
	uint8_t l1bits() const noexcept { return m_l1bits; }
	uint8_t l2bits() const noexcept { return m_l2bits; }
	uint8_t l1shift() const noexcept { return m_l1shift; }
	uint8_t l2shift() const noexcept { return m_l2shift; }
	offs_t l1mask() const noexcept { return m_l1mask; }
	offs_t l2mask() const noexcept { return m_l2mask; }
	bool is_mode_populated(uint32_t mode) const noexcept { return m_base[mode] != m_emptyl1; }

	// set up and configuration
	bool reset();
	void set_default_codeptr(drccodeptr code);

	// block begin/end
	void block_begin(drcuml_block &block, const uml::instruction *instlist, uint32_t numinst);
	void block_end(drcuml_block &block);

	// code pointer access
	bool set_codeptr(uint32_t mode, uint32_t pc, drccodeptr code);
	drccodeptr get_codeptr(uint32_t mode, uint32_t pc) const noexcept { assert(mode < m_modes); return m_base[mode][(pc >> m_l1shift) & m_l1mask][(pc >> m_l2shift) & m_l2mask]; }
	bool code_exists(uint32_t mode, uint32_t pc) const noexcept { return get_codeptr(mode, pc) != m_nocodeptr; }

private:
	// internal state
	drc_cache &     m_cache;                // cache where allocations come from
	uint32_t        m_modes;                // number of modes supported

	drccodeptr      m_nocodeptr;            // pointer to code which will handle missing entries

	uint8_t         m_l1bits;               // bits worth of entries in l1 hash tables
	uint8_t         m_l2bits;               // bits worth of entries in l2 hash tables
	uint8_t         m_l1shift;              // shift to apply to the PC to get the l1 hash entry
	uint8_t         m_l2shift;              // shift to apply to the PC to get the l2 hash entry
	offs_t          m_l1mask;               // mask to apply after shifting
	offs_t          m_l2mask;               // mask to apply after shifting

	drccodeptr ***  m_base;                 // pointer to the l1 table for each mode
	drccodeptr **   m_emptyl1;              // pointer to empty l1 hash table
	drccodeptr *    m_emptyl2;              // pointer to empty l2 hash table
};


// ======================> drc_map_variables

// common map variable management
class drc_map_variables
{
public:
	// construction/destruction
	drc_map_variables(drc_cache &cache, uint64_t uniquevalue);
	~drc_map_variables();

	// block begin/end
	void block_begin(drcuml_block &block);
	void block_end(drcuml_block &block);

	// get/set values
	void set_value(drccodeptr codebase, uint32_t mapvar, uint32_t newvalue);
	uint32_t get_value(drccodeptr codebase, uint32_t mapvar) const;
	uint32_t get_last_value(uint32_t mapvar);

private:
	struct map_entry
	{
		drccodeptr      codeptr;            // pointer to the relevant code
		uint32_t        mapvar;             // map variable id
		uint32_t        newval;             // value of the variable starting at codeptr
	};
	using map_entry_vector = std::vector<map_entry>;

	// internal state
	drc_cache &         m_cache;            // pointer to the cache
	uint64_t            m_uniquevalue;      // unique value used to find the table
	uint32_t            m_mapvalue[uml::MAPVAR_END - uml::MAPVAR_M0]; // array of current values
	map_entry_vector    m_entry_list;       // list of entries
};


// ======================> drc_label_list

typedef delegate<void (void *, drccodeptr)> drc_label_fixup_delegate;

// structure holding a live list of labels
class drc_label_list
{
public:
	// construction/destruction
	drc_label_list(drc_cache &cache);
	~drc_label_list();

	// block begin/end
	void block_begin(drcuml_block &block);
	void block_end(drcuml_block &block);

	// get/set values
	drccodeptr get_codeptr(uml::code_label label, drc_label_fixup_delegate const &fixup, void *param);
	void set_codeptr(uml::code_label label, drccodeptr codeptr);

private:
	struct label_entry
	{
		uml::code_label     label;          // the label specified
		drccodeptr          codeptr;        // pointer to the relevant code
	};
	using label_entry_list = std::list<label_entry>;

	struct label_fixup
	{
		label_entry *       label;          // the label in question
		drc_label_fixup_delegate callback;  // callback
	};
	using label_fixup_list = std::list<label_fixup>;

	// internal helpers
	void reset(bool fatal_on_leftovers);
	label_entry &find_or_allocate(uml::code_label label);
	void oob_callback(drccodeptr *codeptr, void *param1, void *param2);

	// internal state
	drc_cache &         m_cache;            // pointer to the cache
	label_entry_list    m_list;             // head of the live list
	label_fixup_list    m_fixup_list;       // list of pending oob fixups
	drc_oob_delegate    m_oob_callback_delegate; // pre-computed delegate
	label_entry_list    m_free_labels;
	label_fixup_list    m_free_fixups;
};


// ======================> resolved_member_function

struct resolved_member_function
{
	uintptr_t obj = uintptr_t(nullptr);
	uint8_t *func = nullptr;

	explicit operator bool() const noexcept
	{
		return bool(func);
	}

	template <typename C, typename F>
	void set(C &&instance, F &&mfp) noexcept
	{
		auto const [entrypoint, adjusted] = util::resolve_member_function(std::forward<F>(mfp), std::forward<C>(instance));
		obj = adjusted;
		func = reinterpret_cast<uint8_t *>(entrypoint);
	}
};


// ======================> resolved_memory_accessors

struct resolved_memory_accessors
{
	resolved_member_function read_byte;
	resolved_member_function read_byte_masked;
	resolved_member_function read_word;
	resolved_member_function read_word_masked;
	resolved_member_function read_dword;
	resolved_member_function read_dword_masked;
	resolved_member_function read_qword;
	resolved_member_function read_qword_masked;

	resolved_member_function write_byte;
	resolved_member_function write_byte_masked;
	resolved_member_function write_word;
	resolved_member_function write_word_masked;
	resolved_member_function write_dword;
	resolved_member_function write_dword_masked;
	resolved_member_function write_qword;
	resolved_member_function write_qword_masked;

	void set(address_space &space);
};

using resolved_memory_accessors_vector = std::vector<resolved_memory_accessors>;

} // namespace drc


#endif // MAME_CPU_DRCBEUT_H