1 // license:GPL-2.0+
2 // copyright-holders:Fabio Priuli, byuu, Nach
3 /***************************************************************************
4 
5     snescx4.c
6 
7     File to handle emulation of the SNES "CX4" add-on chip.
8 
9     Code based on original work by zsKnight, anomie and Nach.
10     This implementation is based on C++ "cx4*.cpp" by byuu
11     (up to date with source v 0.49).
12 
13 ***************************************************************************/
14 
15 #include "emu.h"
16 #include "machine/snescx4.h"
17 
18 static CX4 cx4;
19 
20 static uint16_t CX4_readw(uint16_t addr);
21 static uint32_t CX4_readl(uint16_t addr);
22 
23 static void CX4_writew(running_machine &machine, uint16_t addr, uint16_t data);
24 //static void CX4_writel(running_machine &machine, uint16_t addr, uint32_t data);
25 
26 static void CX4_C4DrawLine(int32_t X1, int32_t Y1, int16_t Z1, int32_t X2, int32_t Y2, int16_t Z2, uint8_t Color);
27 
28 #include "machine/cx4data.hxx"
29 #include "machine/cx4fn.hxx"
30 
CX4_ldr(uint8_t r)31 static uint32_t CX4_ldr(uint8_t r)
32 {
33 	uint16_t addr = 0x0080 + (r * 3);
34 	return (cx4.reg[addr + 0] <<  0)
35 			| (cx4.reg[addr + 1] <<  8)
36 			| (cx4.reg[addr + 2] << 16);
37 }
38 
CX4_str(uint8_t r,uint32_t data)39 static void CX4_str(uint8_t r, uint32_t data)
40 {
41 	uint16_t addr = 0x0080 + (r * 3);
42 	cx4.reg[addr + 0] = (data >>  0);
43 	cx4.reg[addr + 1] = (data >>  8);
44 	cx4.reg[addr + 2] = (data >> 16);
45 }
46 
CX4_mul(uint32_t x,uint32_t y,uint32_t * rl,uint32_t * rh)47 static void CX4_mul(uint32_t x, uint32_t y, uint32_t *rl, uint32_t *rh)
48 {
49 	int64_t rx = x & 0xffffff;
50 	int64_t ry = y & 0xffffff;
51 	if(rx & 0x800000)rx |= ~0x7fffff;
52 	if(ry & 0x800000)ry |= ~0x7fffff;
53 
54 	rx *= ry;
55 
56 	*rl = (rx)       & 0xffffff;
57 	*rh = (rx >> 24) & 0xffffff;
58 }
59 
CX4_sin(uint32_t rx)60 static uint32_t CX4_sin(uint32_t rx)
61 {
62 	cx4.r0 = rx & 0x1ff;
63 	if(cx4.r0 & 0x100)
64 	{
65 		cx4.r0 ^= 0x1ff;
66 	}
67 	if(cx4.r0 & 0x080)
68 	{
69 		cx4.r0 ^= 0x0ff;
70 	}
71 	if(rx & 0x100)
72 	{
73 		return CX4_sin_table[cx4.r0 + 0x80];
74 	}
75 	else
76 	{
77 		return CX4_sin_table[cx4.r0];
78 	}
79 }
80 
CX4_cos(uint32_t rx)81 static uint32_t CX4_cos(uint32_t rx)
82 {
83 	return CX4_sin(rx + 0x080);
84 }
85 
CX4_immediate_reg(uint32_t start)86 static void CX4_immediate_reg(uint32_t start)
87 {
88 	uint32_t i = 0;
89 	cx4.r0 = CX4_ldr(0);
90 	for(i = start; i < 48; i++)
91 	{
92 		if((cx4.r0 & 0x0fff) < 0x0c00)
93 		{
94 			cx4.ram[cx4.r0 & 0x0fff] = CX4_immediate_data[i];
95 		}
96 		cx4.r0++;
97 	}
98 	CX4_str(0, cx4.r0);
99 }
100 
CX4_transfer_data(running_machine & machine)101 static void CX4_transfer_data(running_machine &machine)
102 {
103 	uint32_t src;
104 	uint16_t dest, count;
105 	uint32_t i;
106 
107 	src   = (cx4.reg[0x40]) | (cx4.reg[0x41] << 8) | (cx4.reg[0x42] << 16);
108 	count = (cx4.reg[0x43]) | (cx4.reg[0x44] << 8);
109 	dest  = (cx4.reg[0x45]) | (cx4.reg[0x46] << 8);
110 
111 	address_space &space = machine.device<cpu_device>("maincpu")->space(AS_PROGRAM);
112 	for(i=0;i<count;i++)
113 	{
114 		CX4_write(machine, dest++, space.read_byte(src++));
115 	}
116 }
117 
118 #include "machine/cx4oam.hxx"
119 #include "machine/cx4ops.hxx"
120 
CX4_write(running_machine & machine,uint32_t addr,uint8_t data)121 void CX4_write(running_machine &machine, uint32_t addr, uint8_t data)
122 {
123 	addr &= 0x1fff;
124 
125 	if(addr < 0x0c00)
126 	{
127 		//ram
128 		cx4.ram[addr] = data;
129 		return;
130 	}
131 
132 	if(addr < 0x1f00)
133 	{
134 		//unmapped
135 		return;
136 	}
137 
138 	//command register
139 	cx4.reg[addr & 0xff] = data;
140 
141 	if(addr == 0x1f47)
142 	{
143 		//memory transfer
144 		CX4_transfer_data(machine);
145 		return;
146 	}
147 
148 	if(addr == 0x1f4f)
149 	{
150 		//c4 command
151 		if(cx4.reg[0x4d] == 0x0e && !(data & 0xc3))
152 		{
153 			//c4 test command
154 			cx4.reg[0x80] = data >> 2;
155 			return;
156 		}
157 
158 		switch(data)
159 		{
160 			case 0x00: CX4_op00(machine); break;
161 			case 0x01: CX4_op01(machine); break;
162 			case 0x05: CX4_op05(machine); break;
163 			case 0x0d: CX4_op0d(machine); break;
164 			case 0x10: CX4_op10(); break;
165 			case 0x13: CX4_op13(); break;
166 			case 0x15: CX4_op15(machine); break;
167 			case 0x1f: CX4_op1f(machine); break;
168 			case 0x22: CX4_op22(); break;
169 			case 0x25: CX4_op25(); break;
170 			case 0x2d: CX4_op2d(machine); break;
171 			case 0x40: CX4_op40(); break;
172 			case 0x54: CX4_op54(); break;
173 			case 0x5c: CX4_op5c(); break;
174 			case 0x5e: CX4_op5e(); break;
175 			case 0x60: CX4_op60(); break;
176 			case 0x62: CX4_op62(); break;
177 			case 0x64: CX4_op64(); break;
178 			case 0x66: CX4_op66(); break;
179 			case 0x68: CX4_op68(); break;
180 			case 0x6a: CX4_op6a(); break;
181 			case 0x6c: CX4_op6c(); break;
182 			case 0x6e: CX4_op6e(); break;
183 			case 0x70: CX4_op70(); break;
184 			case 0x72: CX4_op72(); break;
185 			case 0x74: CX4_op74(); break;
186 			case 0x76: CX4_op76(); break;
187 			case 0x78: CX4_op78(); break;
188 			case 0x7a: CX4_op7a(); break;
189 			case 0x7c: CX4_op7c(); break;
190 			case 0x89: CX4_op89(); break;
191 		}
192 	}
193 }
194 
195 #ifdef UNUSED_FUNCTION
CX4_writeb(running_machine & machine,uint16_t addr,uint8_t data)196 void CX4_writeb(running_machine &machine, uint16_t addr, uint8_t data)
197 {
198 	CX4_write(machine, addr,     data);
199 }
200 #endif
201 
CX4_writew(running_machine & machine,uint16_t addr,uint16_t data)202 static void CX4_writew(running_machine &machine, uint16_t addr, uint16_t data)
203 {
204 	CX4_write(machine, addr + 0, data >> 0);
205 	CX4_write(machine, addr + 1, data >> 8);
206 }
207 
208 #ifdef UNUSED_FUNCTION
CX4_writel(running_machine & machine,uint16_t addr,uint32_t data)209 void CX4_writel(running_machine &machine, uint16_t addr, uint32_t data)
210 {
211 	CX4_write(machine, addr + 0, data >>  0);
212 	CX4_write(machine, addr + 1, data >>  8);
213 	CX4_write(machine, addr + 2, data >> 16);
214 }
215 #endif
216 
CX4_read(uint32_t addr)217 uint8_t CX4_read(uint32_t addr)
218 {
219 	addr &= 0x1fff;
220 
221 	if(addr < 0x0c00)
222 	{
223 		return cx4.ram[addr];
224 	}
225 
226 	if(addr >= 0x1f00)
227 	{
228 		return cx4.reg[addr & 0xff];
229 	}
230 
231 	return 0xff;
232 }
233 
234 #ifdef UNUSED_FUNCTION
CX4_readb(uint16_t addr)235 uint8_t CX4_readb(uint16_t addr)
236 {
237 	return CX4_read(addr);
238 }
239 #endif
240 
CX4_readw(uint16_t addr)241 static uint16_t CX4_readw(uint16_t addr)
242 {
243 	return CX4_read(addr) | (CX4_read(addr + 1) << 8);
244 }
245 
CX4_readl(uint16_t addr)246 static uint32_t CX4_readl(uint16_t addr)
247 {
248 	return CX4_read(addr) | (CX4_read(addr + 1) << 8) | (CX4_read(addr + 2) << 16);
249 }
250 
251 #ifdef UNUSED_FUNCTION
CX4_reset()252 void CX4_reset()
253 {
254 	memset(cx4.ram, 0, 0x0c00);
255 	memset(cx4.reg, 0, 0x0100);
256 }
257 #endif
258