summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/alto2/a2roms.cpp
blob: 7eab1e342122f6cc0ba06cf78b2699a28db50fa8 (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
// license:BSD-3-Clause
// copyright-holders:Juergen Buchmueller
/*****************************************************************************
 *
 *   Xerox AltoII PROM loading and decoding
 *
 *****************************************************************************/
#include "emu.h"
#include "alto2cpu.h"
#include "a2roms.h"

#define DEBUG_PROM_LOAD     0   //!< define to 1 to dump PROMs after loading

/**
 * @brief return number of 1 bits in a 32 bit value
 *
 * 32-bit recursive reduction using SWAR,
 * but first step is mapping 2-bit values
 * into sum of 2 1-bit values in sneaky way.
 */
static uint32_t ones_u32(uint32_t val)
{
	val -= ((val >> 1) & 0x55555555);
	val = (((val >> 2) & 0x33333333) + (val & 0x33333333));
	val = (((val >> 4) + val) & 0x0f0f0f0f);
	val += (val >> 8);
	val += (val >> 16);
	return val & 0x3f;
}

/**
 * @brief return the log2 of an integer value
 */
static uint32_t log2_u32(uint32_t val)
{
	val |= (val >> 1);
	val |= (val >> 2);
	val |= (val >> 4);
	val |= (val >> 8);
	val |= (val >> 16);
	return ones_u32(val >> 1);
}

/**
 * @brief map a number of data or address lines using a lookup table
 *
 * @param map pointer to an array of values, or nullptr for default
 * @param lines number of data or address lines
 * @param val value to map
 * @result returns the remapped value, or just val, if map was nullptr
 */
static uint32_t map_lines(const uint8_t *map, int lines, uint32_t val)
{
	if (nullptr == map)
		return val;

	uint32_t res = 0;
	for (int i = 0; i < lines; i++)
		if (val & (1 << i))
			res |= 1 << map[i];
	return res;
}

/**
 * @brief write to a ROM base + address of type 'type', ANDing with and, ORing with or
 *
 * @param base ROM base address in memory
 * @param type one of 1 for uint8_t, 2 for uint16_t, 4 for uint32_t
 * @param addr address offset into base
 * @param dand value to AND to contents before XORing
 * @param dxor value to XOR before writing back
 */
static void write_type_and_xor(void *base, int type, uint32_t addr, uint32_t dand, uint32_t dxor)
{
	switch (type) {
	case sizeof(uint8_t):
		{
			uint8_t *base8 = reinterpret_cast<uint8_t *>(base);
			base8[addr] = (base8[addr] & dand) ^ dxor;
		}
		break;
	case sizeof(uint16_t):
		{
			uint16_t *base16 = reinterpret_cast<uint16_t *>(base);
			base16[addr] = (base16[addr] & dand) ^ dxor;
		}
		break;
	case sizeof(uint32_t):
		{
			uint32_t *base32 = reinterpret_cast<uint32_t *>(base);
			base32[addr] = (base32[addr] & dand) ^ dxor;
		}
		break;
	default:
		fatalerror("write_type_and_xor() invalid type size (%d) in ROM definitions\n", type);
	}
}

/**
 * @brief load a PROM from a (list of) source region(s) shifting, swapping and inverting address and data bits
 * @param prom PROM loading definition
 * @param src source ROM region where to load data from
 * @param pages number of pages of definitions
 * @param segments number of segments in one page of the result
 * @return pointer to the newly allocated memory filled with source bits
 */
uint8_t* prom_load(running_machine& machine, const prom_load_t* prom, const uint8_t* src, int pages, int segments)
{
	void* array = nullptr;
	size_t type = prom->type;
	size_t size = prom->size;
#if DEBUG_PROM_LOAD
	uint8_t width = prom->width;
#endif

	switch (type) {
	case sizeof(uint8_t):
		array = auto_alloc_array(machine, uint8_t, pages * size);
		break;
	case sizeof(uint16_t):
		array = auto_alloc_array(machine, uint16_t, pages * size);
		break;
	case sizeof(uint32_t):
		array = auto_alloc_array(machine, uint32_t, pages * size);
		break;
	}

	uint8_t* base = reinterpret_cast<uint8_t*>(array);
	for (int page = 0; page < pages; page++)
	{
		uint8_t* dst = base + (prom->type * prom->size * page);
		for (int segment = 0; segment < segments; segment++, prom++)
		{
			for (uint32_t src_addr = 0; src_addr < prom->size; src_addr++)
			{
				// map destination address lines
				uint32_t dst_addr = map_lines(prom->amap, log2_u32(prom->size) + 1, src_addr);
				// fetch data bits
				uint32_t data = src[src_addr ^ prom->axor] ^ prom->dxor;
				// mask width bits
				data = data & ((1 << prom->width) - 1);
				// map destination data lines
				data = map_lines(prom->dmap, prom->width, data);
				// shift to destination position
				data = data << prom->shift;
				// and destination width dand then xor data
				write_type_and_xor(dst, prom->type, dst_addr, prom->dand, data);
			}
			src += prom->size;
		}
	}

#if DEBUG_PROM_LOAD
	switch (type) {
	case sizeof(uint8_t):
		{
			uint8_t* data = reinterpret_cast<uint8_t*>(array);
			for (int addr = 0; addr < pages*size; addr++) {
				if (0 == (addr % 16))
					printf("%04x:", addr);
				if (width <= 4)
					printf(" %x", data[addr]);
				else
					printf(" %02x", data[addr]);
				if (15 == (addr % 16))
					printf("\n");
			}
		}
		break;
	case sizeof(uint16_t):
		{
			uint16_t* data = reinterpret_cast<uint16_t*>(array);
			for (int addr = 0; addr < pages*size; addr++) {
				if (0 == (addr % 8))
					printf("%04x:", addr);
				printf(" %04x", data[addr]);
				if (7 == (addr % 8))
					printf("\n");
			}
		}
		break;
	case sizeof(uint32_t):
		{
			uint32_t* data = reinterpret_cast<uint32_t*>(array);
			for (int addr = 0; addr < pages*size; addr++) {
				if (0 == (addr % 4))
					printf("%04x:", addr);
				printf(" %08x", data[addr]);
				if (3 == (addr % 4))
					printf("\n");
			}
		}
		break;
	}
#endif
	return reinterpret_cast<uint8_t *>(array);
}