summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/emumem_mud.cpp
blob: 8279eea5635953f839192b3e03bdf569186527bf (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
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert

#include "emu.h"
#include "emumem_mud.h"

template<typename T> static u8 mask_to_ukey(T mask);

template<> u8 mask_to_ukey<u16>(u16 mask)
{
	return
		(mask & 0xff00 ? 0x02 : 0x00) |
		(mask & 0x00ff ? 0x01 : 0x00);
}

template<> u8 mask_to_ukey<u32>(u32 mask)
{
	return
		(mask & 0xff000000 ? 0x08 : 0x00) |
		(mask & 0x00ff0000 ? 0x04 : 0x00) |
		(mask & 0x0000ff00 ? 0x02 : 0x00) |
		(mask & 0x000000ff ? 0x01 : 0x00);
}

template<> u8 mask_to_ukey<u64>(u64 mask)
{
	return
		(mask & 0xff00000000000000 ? 0x80 : 0x00) |
		(mask & 0x00ff000000000000 ? 0x40 : 0x00) |
		(mask & 0x0000ff0000000000 ? 0x20 : 0x00) |
		(mask & 0x000000ff00000000 ? 0x10 : 0x00) |
		(mask & 0x00000000ff000000 ? 0x08 : 0x00) |
		(mask & 0x0000000000ff0000 ? 0x04 : 0x00) |
		(mask & 0x000000000000ff00 ? 0x02 : 0x00) |
		(mask & 0x00000000000000ff ? 0x01 : 0x00);
}

template<int Width, int AddrShift, int Endian> memory_units_descriptor<Width, AddrShift, Endian>::memory_units_descriptor(u8 access_width, u8 access_endian, handler_entry *handler, offs_t addrstart, offs_t addrend, offs_t mask, typename handler_entry_size<Width>::uX unitmask, int cswidth) : m_handler(handler), m_access_width(access_width), m_access_endian(access_endian)
{
	constexpr u32 NATIVE_MASK = Width + AddrShift >= 0 ? make_bitmask<u32>(Width + AddrShift) : 0;
	u32 bits_per_access = 8 << access_width;

	// Compute the real base addresses
	m_addrstart = addrstart & ~NATIVE_MASK;
	m_addrend = addrend & ~NATIVE_MASK;


	// Compute the masks and the keys
	std::array<uX, 4> umasks;
	umasks.fill(unitmask);

	uX smask = ~make_bitmask<uX>((addrstart - m_addrstart) << (3 - AddrShift));
	uX emask =  make_bitmask<uX>((addrend - m_addrend + 1) << (3 - AddrShift));

	umasks[handler_entry::START]                    &= smask;
	umasks[handler_entry::END]                      &= emask;
	umasks[handler_entry::START|handler_entry::END] &= smask | emask;

	for(u32 i=0; i<4; i++)
		m_keymap[i] = mask_to_ukey<uX>(umasks[i]);


	// Compute the shift
	uX dmask = make_bitmask<uX>(bits_per_access);
	u32 active_count = 0;
	for(u32 i=0; i != 8 << Width; i += bits_per_access)
		if(unitmask & (dmask << i))
			active_count ++;
	u32 active_count_log = active_count == 1 ? 0 : active_count == 2 ? 1 : active_count == 4 ? 2 : active_count == 8 ? 3 : 0xff;
	if(active_count_log == 0xff)
		abort();
	s8 base_shift = Width - access_width - active_count_log;
	s8 shift = base_shift + access_width + AddrShift;


	// Build the handler characteristics
	m_handler_start = shift < 0 ? addrstart << -shift : addrstart >> shift;
	m_handler_mask = shift < 0 ? (mask << -shift) | make_bitmask<offs_t>(-shift) : mask >> shift;

	for(u32 i=0; i<4; i++)
		if(m_entries_for_key.find(m_keymap[i]) == m_entries_for_key.end())
			generate(m_keymap[i], umasks[i], cswidth, bits_per_access, base_shift, shift, active_count);
}

template<int Width, int AddrShift, int Endian> void memory_units_descriptor<Width, AddrShift, Endian>::generate(u8 ukey, typename handler_entry_size<Width>::uX umask, u32 cswidth, u32 bits_per_access, u8 base_shift, s8 shift, u32 active_count)
{
	auto &entries = m_entries_for_key[ukey];
	
	// Compute the selection masks
	if(!cswidth)
		cswidth = bits_per_access;

	uX csmask = make_bitmask<uX>(cswidth);
	uX dmask = make_bitmask<uX>(bits_per_access);

	u32 offset = 0;

	for(u32 i=0; i != 8 << Width; i += bits_per_access) {
		uX numask = dmask << i;
		if(umask & numask) {
			uX amask = csmask << (i & ~(cswidth - 1));
			entries.emplace_back(entry{ amask, numask, shift, u8(i), u8(Endian == ENDIANNESS_BIG ? active_count - 1 - offset : offset) });
			offset ++;
		}
	}
}

template class memory_units_descriptor<1,  3, ENDIANNESS_LITTLE>;
template class memory_units_descriptor<1,  3, ENDIANNESS_BIG>;
template class memory_units_descriptor<1,  0, ENDIANNESS_LITTLE>;
template class memory_units_descriptor<1,  0, ENDIANNESS_BIG>;
template class memory_units_descriptor<1, -1, ENDIANNESS_LITTLE>;
template class memory_units_descriptor<1, -1, ENDIANNESS_BIG>;
template class memory_units_descriptor<2,  0, ENDIANNESS_LITTLE>;
template class memory_units_descriptor<2,  0, ENDIANNESS_BIG>;
template class memory_units_descriptor<2, -1, ENDIANNESS_LITTLE>;
template class memory_units_descriptor<2, -1, ENDIANNESS_BIG>;
template class memory_units_descriptor<2, -2, ENDIANNESS_LITTLE>;
template class memory_units_descriptor<2, -2, ENDIANNESS_BIG>;
template class memory_units_descriptor<3,  0, ENDIANNESS_LITTLE>;
template class memory_units_descriptor<3,  0, ENDIANNESS_BIG>;
template class memory_units_descriptor<3, -1, ENDIANNESS_LITTLE>;
template class memory_units_descriptor<3, -1, ENDIANNESS_BIG>;
template class memory_units_descriptor<3, -2, ENDIANNESS_LITTLE>;
template class memory_units_descriptor<3, -2, ENDIANNESS_BIG>;
template class memory_units_descriptor<3, -3, ENDIANNESS_LITTLE>;
template class memory_units_descriptor<3, -3, ENDIANNESS_BIG>;