summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/alto2/a2roms.cpp
blob: aa457024f7881050799ecc741959bfd66ef62322 (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
// license:BSD-3-Clause
// copyright-holders:Juergen Buchmueller
/*****************************************************************************
 *
 *   Xerox AltoII PROM loading and decoding
 *
 *****************************************************************************/
#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 ones_u32(UINT32 val)
{
		val -= ((val >> 1) & 0x55555555);
		val = (((val >> 2) & 0x33333333) + (val & 0x33333333));
		val = (((val >> 4) + val) & 0x0f0f0f0f);
		val += (val >> 8);
		val += (val >> 16);
		return (val & 0x0000003f);
}

/**
 * @brief return the log2 of an integer value
 */
static UINT32 log2_u32(UINT32 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 NULL 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 NULL
 */
static UINT32 map_lines(const UINT8 *map, int lines, UINT32 val)
{
	if (nullptr == map)
		return val;

	UINT32 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, 2 for UINT16, 4 for UINT32
 * @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 addr, UINT32 dand, UINT32 dxor)
{
	switch (type) {
	case sizeof(UINT8):
		{
			UINT8 *base8 = reinterpret_cast<UINT8 *>(base);
			base8[addr] = (base8[addr] & dand) ^ dxor;
		}
		break;
	case sizeof(UINT16):
		{
			UINT16 *base16 = reinterpret_cast<UINT16 *>(base);
			base16[addr] = (base16[addr] & dand) ^ dxor;
		}
		break;
	case sizeof(UINT32):
		{
			UINT32 *base32 = reinterpret_cast<UINT32 *>(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* prom_load(running_machine& machine, const prom_load_t* prom, const UINT8* src, int pages, int segments)
{
	void* array = nullptr;
	size_t type = prom->type;
	size_t size = prom->size;
#if DEBUG_PROM_LOAD
	UINT8 width = prom->width;
#endif

	switch (type) {
	case sizeof(UINT8):
		array = auto_alloc_array(machine, UINT8, pages * size);
		break;
	case sizeof(UINT16):
		array = auto_alloc_array(machine, UINT16, pages * size);
		break;
	case sizeof(UINT32):
		array = auto_alloc_array(machine, UINT32, pages * size);
		break;
	}

	UINT8* base = reinterpret_cast<UINT8*>(array);
	for (int page = 0; page < pages; page++)
	{
		UINT8* dst = base + (prom->type * prom->size * page);
		for (int segment = 0; segment < segments; segment++, prom++)
		{
			for (UINT32 src_addr = 0; src_addr < prom->size; src_addr++)
			{
				// map destination address lines
				UINT32 dst_addr = map_lines(prom->amap, log2_u32(prom->size) + 1, src_addr);
				// fetch data bits
				UINT32 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):
		{
			UINT8* data = reinterpret_cast<UINT8*>(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):
		{
			UINT16* data = reinterpret_cast<UINT16*>(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):
		{
			UINT32* data = reinterpret_cast<UINT32*>(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 *>(array);
}