1 // license:BSD-3-Clause
2 // copyright-holders:Eric Smith
3 /*
4  * mathbox.c: math box simulation (Battlezone/Red Baron/Tempest)
5  *
6  * Copyright Eric Smith
7  *
8  */
9 
10 #include "burnint.h"
11 #include "mathbox.h"
12 
13 
14 /* math box scratch registers */
15 static INT16 m_reg[16];
16 
17 /* math box result */
18 static INT16 m_result;
19 
20 
21 #define REG0 m_reg [0x00]
22 #define REG1 m_reg [0x01]
23 #define REG2 m_reg [0x02]
24 #define REG3 m_reg [0x03]
25 #define REG4 m_reg [0x04]
26 #define REG5 m_reg [0x05]
27 #define REG6 m_reg [0x06]
28 #define REG7 m_reg [0x07]
29 #define REG8 m_reg [0x08]
30 #define REG9 m_reg [0x09]
31 #define REGa m_reg [0x0a]
32 #define REGb m_reg [0x0b]
33 #define REGc m_reg [0x0c]
34 #define REGd m_reg [0x0d]
35 #define REGe m_reg [0x0e]
36 #define REGf m_reg [0x0f]
37 
mathbox_reset()38 void mathbox_reset()
39 {
40 	m_result = 0;
41 	memset(m_reg, 0, sizeof(m_reg));
42 }
43 
mathbox_scan(INT32 nAction,INT32 *)44 void mathbox_scan(INT32 nAction, INT32 *)
45 {
46 	SCAN_VAR(m_reg);
47 	SCAN_VAR(m_result);
48 }
49 
50 
mathbox_go_write(UINT8 offset,UINT8 data)51 void mathbox_go_write(UINT8 offset, UINT8 data)
52 {
53 	INT32 mb_temp = 0;  /* temp 32-bit multiply results */
54 	INT16 mb_q = 0;     /* temp used in division */
55 	INT32 msb = 0;
56 
57 	switch (offset)
58 	{
59 	case 0x00: m_result = REG0 = (REG0 & 0xff00) | data;        break;
60 	case 0x01: m_result = REG0 = (REG0 & 0x00ff) | (data << 8); break;
61 	case 0x02: m_result = REG1 = (REG1 & 0xff00) | data;        break;
62 	case 0x03: m_result = REG1 = (REG1 & 0x00ff) | (data << 8); break;
63 	case 0x04: m_result = REG2 = (REG2 & 0xff00) | data;        break;
64 	case 0x05: m_result = REG2 = (REG2 & 0x00ff) | (data << 8); break;
65 	case 0x06: m_result = REG3 = (REG3 & 0xff00) | data;        break;
66 	case 0x07: m_result = REG3 = (REG3 & 0x00ff) | (data << 8); break;
67 	case 0x08: m_result = REG4 = (REG4 & 0xff00) | data;        break;
68 	case 0x09: m_result = REG4 = (REG4 & 0x00ff) | (data << 8); break;
69 
70 	case 0x0a: m_result = REG5 = (REG5 & 0xff00) | data;        break;
71 		/* note: no function loads low part of REG5 without performing a computation */
72 
73 	case 0x0c: m_result = REG6 = data; break;
74 		/* note: no function loads high part of REG6 */
75 
76 	case 0x15: m_result = REG7 = (REG7 & 0xff00) | data;        break;
77 	case 0x16: m_result = REG7 = (REG7 & 0x00ff) | (data << 8); break;
78 
79 	case 0x1a: m_result = REG8 = (REG8 & 0xff00) | data;        break;
80 	case 0x1b: m_result = REG8 = (REG8 & 0x00ff) | (data << 8); break;
81 
82 	case 0x0d: m_result = REGa = (REGa & 0xff00) | data;        break;
83 	case 0x0e: m_result = REGa = (REGa & 0x00ff) | (data << 8); break;
84 	case 0x0f: m_result = REGb = (REGb & 0xff00) | data;        break;
85 	case 0x10: m_result = REGb = (REGb & 0x00ff) | (data << 8); break;
86 
87 	case 0x17: m_result = REG7; break;
88 	case 0x19: m_result = REG8; break;
89 	case 0x18: m_result = REG9; break;
90 
91 	case 0x0b:
92 
93 		REG5 = (REG5 & 0x00ff) | (data << 8);
94 
95 		REGf = (INT16)0xffff;
96 		REG4 -= REG2;
97 		REG5 -= REG3;
98 
99 	step_048:
100 
101 		mb_temp = ((INT32) REG0) * ((INT32) REG4);
102 		REGc = mb_temp >> 16;
103 		REGe = mb_temp & 0xffff;
104 
105 		mb_temp = ((INT32) -REG1) * ((INT32) REG5);
106 		REG7 = mb_temp >> 16;
107 		mb_q = mb_temp & 0xffff;
108 
109 		REG7 += REGc;
110 
111 		/* rounding */
112 		REGe = (REGe >> 1) & 0x7fff;
113 		REGc = (mb_q >> 1) & 0x7fff;
114 		mb_q = REGc + REGe;
115 		if (mb_q < 0)
116 			REG7++;
117 
118 		m_result = REG7;
119 
120 		if (REGf < 0)
121 			break;
122 
123 		REG7 += REG2;
124 
125 		/* fall into command 12 */
126 
127 	case 0x12:
128 		mb_temp = ((INT32) REG1) * ((INT32) REG4);
129 		REGc = mb_temp >> 16;
130 		REG9 = mb_temp & 0xffff;
131 
132 		mb_temp = ((INT32) REG0) * ((INT32) REG5);
133 		REG8 = mb_temp >> 16;
134 		mb_q = mb_temp & 0xffff;
135 
136 		REG8 += REGc;
137 
138 		/* rounding */
139 		REG9 = (REG9 >> 1) & 0x7fff;
140 		REGc = (mb_q >> 1) & 0x7fff;
141 		REG9 += REGc;
142 		if (REG9 < 0)
143 			REG8++;
144 		REG9 <<= 1;  /* why? only to get the desired load address? */
145 
146 		m_result = REG8;
147 
148 		if (REGf < 0)
149 			break;
150 
151 		REG8 += REG3;
152 
153 		REG9 &= 0xff00;
154 
155 		/* fall into command 13 */
156 
157 	case 0x13:
158 		REGc = REG9;
159 		mb_q = REG8;
160 		goto step_0bf;
161 
162 	case 0x14:
163 		REGc = REGa;
164 		mb_q = REGb;
165 
166 	step_0bf:
167 		REGe = REG7 ^ mb_q;  /* save sign of result */
168 		REGd = mb_q;
169 		if (mb_q >= 0)
170 			mb_q = REGc;
171 		else
172 		{
173 			REGd = - mb_q - 1;
174 			mb_q = - REGc - 1;
175 			if ((mb_q < 0) && ((mb_q + 1) < 0))
176 				REGd++;
177 			mb_q++;
178 		}
179 
180 	/* step 0c9: */
181 		/* REGc = abs (REG7) */
182 		if (REG7 >= 0)
183 			REGc = REG7;
184 		else
185 			REGc = -REG7;
186 
187 		REGf = REG6;  /* step counter */
188 
189 		do
190 		{
191 			REGd -= REGc;
192 			msb = ((mb_q & 0x8000) != 0);
193 			mb_q <<= 1;
194 			if (REGd >= 0)
195 				mb_q++;
196 			else
197 				REGd += REGc;
198 			REGd <<= 1;
199 			REGd += msb;
200 		}
201 		while (--REGf >= 0);
202 
203 		if (REGe >= 0)
204 			m_result = mb_q;
205 		else
206 			m_result = - mb_q;
207 		break;
208 
209 	case 0x11:
210 		REG5 = (REG5 & 0x00ff) | (data << 8);
211 		REGf = 0x0000;  /* do everything in one step */
212 		goto step_048;
213 		//break; // never reached
214 
215 	case 0x1c:
216 		/* window test? */
217 		REG5 = (REG5 & 0x00ff) | (data << 8);
218 		do
219 		{
220 			REGe = (REG4 + REG7) >> 1;
221 			REGf = (REG5 + REG8) >> 1;
222 			if ((REGb < REGe) && (REGf < REGe) && ((REGe + REGf) >= 0))
223 			{ REG7 = REGe; REG8 = REGf; }
224 			else
225 			{ REG4 = REGe; REG5 = REGf; }
226 		}
227 		while (--REG6 >= 0);
228 
229 		m_result = REG8;
230 		break;
231 
232 	case 0x1d:
233 		REG3 = (REG3 & 0x00ff) | (data << 8);
234 
235 		REG2 -= REG0;
236 		if (REG2 < 0)
237 			REG2 = -REG2;
238 
239 		REG3 -= REG1;
240 		if (REG3 < 0)
241 			REG3 = -REG3;
242 
243 		/* fall into command 1e */
244 
245 	case 0x1e:
246 		/* result = max (REG2, REG3) + 3/8 * min (REG2, REG3) */
247 		if (REG3 >= REG2)
248 		{ REGc = REG2; REGd = REG3; }
249 		else
250 		{ REGd = REG2; REGc = REG3; }
251 		REGc >>= 2;
252 		REGd += REGc;
253 		REGc >>= 1;
254 		m_result = REGd = (REGc + REGd);
255 		break;
256 
257 	case 0x1f:
258 		/* $$$ do some computation here (selftest? signature analysis? */
259 		break;
260 	}
261 }
262 
mathbox_status_read()263 UINT8 mathbox_status_read()
264 {
265 	return 0x00; /* always done! */
266 }
267 
mathbox_lo_read()268 UINT8 mathbox_lo_read()
269 {
270 	return m_result & 0xff;
271 }
272 
mathbox_hi_read()273 UINT8 mathbox_hi_read()
274 {
275 	return (m_result >> 8) & 0xff;
276 }
277