summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/emumem_mud.cpp
blob: d1583b583666b0c6d7afcf75f785d0de03451f0c (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
// 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 emu::detail::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, emask;
	if(Endian == ENDIANNESS_BIG) {
		smask =  make_bitmask<uX>(8*sizeof(uX) - ((addrstart - m_addrstart) << (3 - AddrShift)));
		emask = ~make_bitmask<uX>(8*sizeof(uX) - ((addrend - m_addrend + 1) << (3 - AddrShift)));
	} else {
		smask = ~make_bitmask<uX>((addrstart - m_addrstart) << (3 - AddrShift));
		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], unitmask, 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 emu::detail::handler_entry_size<Width>::uX gumask, typename emu::detail::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) });
		}
		if(gumask & numask)
			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>;