1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles,Nicola Salmoria
3 /***************************************************************************
4
5 Art & Magic hardware
6
7 ***************************************************************************/
8
9 #include "emu.h"
10 #include "cpu/tms34010/tms34010.h"
11 #include "video/tlc34076.h"
12 #include "includes/artmagic.h"
13
14
15 #define INSTANT_BLIT 1
16
17
18 /*************************************
19 *
20 * Inlines
21 *
22 *************************************/
23
address_to_vram(offs_t * address)24 inline uint16_t *artmagic_state::address_to_vram(offs_t *address)
25 {
26 offs_t original = *address;
27 *address = (original & 0x001fffff) >> 4;
28 if (original < 0x001fffff)
29 return m_vram[0];
30 else if (original >= 0x00400000 && original < 0x005fffff)
31 return m_vram[1];
32 return nullptr;
33 }
34
35
36
37 /*************************************
38 *
39 * Video start
40 *
41 *************************************/
42
video_start()43 void artmagic_state::video_start()
44 {
45 save_item(NAME(m_xor));
46 save_item(NAME(m_is_stoneball));
47 save_item(NAME(m_blitter_data));
48 save_item(NAME(m_blitter_page));
49 }
50
51
52
53 /*************************************
54 *
55 * Shift register transfers
56 *
57 *************************************/
58
TMS340X0_TO_SHIFTREG_CB_MEMBER(artmagic_state::to_shiftreg)59 TMS340X0_TO_SHIFTREG_CB_MEMBER(artmagic_state::to_shiftreg)
60 {
61 uint16_t *vram = address_to_vram(&address);
62 if (vram)
63 memcpy(shiftreg, &vram[address], 0x400);
64 }
65
66
TMS340X0_FROM_SHIFTREG_CB_MEMBER(artmagic_state::from_shiftreg)67 TMS340X0_FROM_SHIFTREG_CB_MEMBER(artmagic_state::from_shiftreg)
68 {
69 uint16_t *vram = address_to_vram(&address);
70 if (vram)
71 memcpy(&vram[address], shiftreg, 0x400);
72 }
73
74
75
76 /*************************************
77 *
78 * Custom blitter
79 *
80 *************************************/
81
execute_blit()82 void artmagic_state::execute_blit()
83 {
84 uint16_t *dest = m_vram[m_blitter_page ^ 1];
85 int offset = ((m_blitter_data[1] & 0xff) << 16) | m_blitter_data[0];
86 int color = (m_blitter_data[1] >> 4) & 0xf0;
87 int x = (int16_t)m_blitter_data[2];
88 int y = (int16_t)m_blitter_data[3];
89 int maskx = m_blitter_data[6] & 0xff;
90 int masky = m_blitter_data[6] >> 8;
91 int w = ((m_blitter_data[7] & 0xff) + 1) * 4;
92 int h = (m_blitter_data[7] >> 8) + 1;
93 int i, j, sx, sy, last;
94
95 #if 0
96 {
97 static uint32_t hit_list[50000];
98 static int hit_index;
99 static FILE *f;
100
101 logerror("%s:Blit from %06X to (%d,%d) %dx%d -- %04X %04X %04X %04X %04X %04X %04X %04X\n",
102 machine().describe_context(), offset, x, y, w, h,
103 m_blitter_data[0], m_blitter_data[1],
104 m_blitter_data[2], m_blitter_data[3],
105 m_blitter_data[4], m_blitter_data[5],
106 m_blitter_data[6], m_blitter_data[7]);
107
108 if (!f) f = fopen("artmagic.log", "w");
109
110 for (i = 0; i < hit_index; i++)
111 if (hit_list[i] == offset)
112 break;
113 if (i == hit_index)
114 {
115 int tempoffs = offset;
116 hit_list[hit_index++] = offset;
117
118 fprintf(f, "----------------------\n"
119 "%s:Blit from %06X to (%d,%d) %dx%d -- %04X %04X %04X %04X %04X %04X %04X %04X\n",
120 machine().describe_context(), offset, x, y, w, h,
121 m_blitter_data[0], m_blitter_data[1],
122 m_blitter_data[2], m_blitter_data[3],
123 m_blitter_data[4], m_blitter_data[5],
124 m_blitter_data[6], m_blitter_data[7]);
125
126 fprintf(f, "\t");
127 for (i = 0; i < h; i++)
128 {
129 for (j = 0; j < w; j += 4)
130 fprintf(f, "%04X ", m_blitter_base[tempoffs++]);
131 fprintf(f, "\n\t");
132 }
133 fprintf(f, "\n\t");
134 tempoffs = offset;
135 for (i = 0; i < h; i++)
136 {
137 last = 0;
138 if (i == 0) /* first line */
139 {
140 /* ultennis, stonebal */
141 last ^= (m_blitter_data[7] & 0x0001);
142 if (m_is_stoneball)
143 last ^= ((m_blitter_data[0] & 0x0020) >> 3);
144 else /* ultennis */
145 last ^= ((m_blitter_data[0] & 0x0040) >> 4);
146
147 /* cheesech */
148 last ^= ((m_blitter_data[7] & 0x0400) >> 9);
149 last ^= ((m_blitter_data[0] & 0x2000) >> 10);
150 }
151 else /* following lines */
152 {
153 int val = m_blitter_base[tempoffs];
154
155 /* ultennis, stonebal */
156 last ^= 4;
157 last ^= ((val & 0x0400) >> 8);
158 last ^= ((val & 0x5000) >> 12);
159
160 /* cheesech */
161 last ^= 8;
162 last ^= ((val & 0x0800) >> 8);
163 last ^= ((val & 0xa000) >> 12);
164 }
165
166 for (j = 0; j < w; j += 4)
167 {
168 static const char hex[] = ".123456789ABCDEF";
169 int val = m_blitter_base[tempoffs++];
170 int p1, p2, p3, p4;
171 p1 = last = ((val ^ m_xor[last]) >> 0) & 0xf;
172 p2 = last = ((val ^ m_xor[last]) >> 4) & 0xf;
173 p3 = last = ((val ^ m_xor[last]) >> 8) & 0xf;
174 p4 = last = ((val ^ m_xor[last]) >> 12) & 0xf;
175 fprintf(f, "%c%c%c%c ", hex[p1], hex[p2], hex[p3], hex[p4]);
176 }
177 fprintf(f, "\n\t");
178 }
179 fprintf(f, "\n");
180 }
181 }
182 #endif
183
184 g_profiler.start(PROFILER_VIDEO);
185
186 last = 0;
187 sy = y;
188 for (i = 0; i < h; i++)
189 {
190 if ((i & 1) || !((masky << ((i/2) & 7)) & 0x80))
191 {
192 if (sy >= 0 && sy < 256)
193 {
194 int tsy = sy * 0x200;
195 sx = x;
196
197 /* The first pixel of every line doesn't have a previous pixel
198 to depend on, so it takes the "feed" from other bits.
199 The very first pixel blitted is also treated differently.
200
201 ultennis/stonebal use a different encryption from cheesech,
202 however the former only need to set bits 0 and 2 of the
203 feed (the others are irrelevant), while the latter only
204 bits 1 and 3, so I can handle both at the same time.
205 */
206 last = 0;
207 if (i == 0) /* first line */
208 {
209 /* ultennis, stonebal */
210 last ^= (m_blitter_data[7] & 0x0001);
211 if (m_is_stoneball)
212 last ^= ((m_blitter_data[0] & 0x0020) >> 3);
213 else /* ultennis */
214 last ^= (((m_blitter_data[0] + 1) & 0x0040) >> 4);
215
216 /* cheesech */
217 last ^= ((m_blitter_data[7] & 0x0400) >> 9);
218 last ^= ((m_blitter_data[0] & 0x2000) >> 10);
219 }
220 else /* following lines */
221 {
222 int val = m_blitter_base[offset & m_blitter_base.mask()];
223
224 /* ultennis, stonebal */
225 last ^= 4;
226 last ^= ((val & 0x0400) >> 8);
227 last ^= ((val & 0x5000) >> 12);
228
229 /* cheesech */
230 last ^= 8;
231 last ^= ((val & 0x0800) >> 8);
232 last ^= ((val & 0xa000) >> 12);
233 }
234
235 for (j = 0; j < w; j += 4)
236 {
237 uint16_t val = m_blitter_base[(offset + j/4) & m_blitter_base.mask()];
238 if (sx < 508)
239 {
240 if (h == 1 && m_is_stoneball)
241 last = ((val) >> 0) & 0xf;
242 else
243 last = ((val ^ m_xor[last]) >> 0) & 0xf;
244 if (!((maskx << ((j/2) & 7)) & 0x80))
245 {
246 if (last && sx >= 0 && sx < 512)
247 dest[tsy + sx] = color | (last);
248 sx++;
249 }
250
251 if (h == 1 && m_is_stoneball)
252 last = ((val) >> 4) & 0xf;
253 else
254 last = ((val ^ m_xor[last]) >> 4) & 0xf;
255 {
256 if (last && sx >= 0 && sx < 512)
257 dest[tsy + sx] = color | (last);
258 sx++;
259 }
260
261 if (h == 1 && m_is_stoneball)
262 last = ((val) >> 8) & 0xf;
263 else
264 last = ((val ^ m_xor[last]) >> 8) & 0xf;
265 if (!((maskx << ((j/2) & 7)) & 0x40))
266 {
267 if (last && sx >= 0 && sx < 512)
268 dest[tsy + sx] = color | (last);
269 sx++;
270 }
271
272 if (h == 1 && m_is_stoneball)
273 last = ((val) >> 12) & 0xf;
274 else
275 last = ((val ^ m_xor[last]) >> 12) & 0xf;
276 {
277 if (last && sx >= 0 && sx < 512)
278 dest[tsy + sx] = color | (last);
279 sx++;
280 }
281 }
282 }
283 }
284 sy++;
285 }
286 offset += w/4;
287 }
288
289 g_profiler.stop();
290
291 #if (!INSTANT_BLIT)
292 m_blitter_busy_until = machine.time() + attotime::from_nsec(w*h*20);
293 #endif
294 }
295
296
blitter_r()297 uint16_t artmagic_state::blitter_r()
298 {
299 /*
300 bit 1 is a busy flag; loops tightly if clear
301 bit 2 is tested in a similar fashion
302 bit 4 reflects the page
303 */
304 uint16_t result = 0xffef | (m_blitter_page << 4);
305 #if (!INSTANT_BLIT)
306 if (attotime_compare(machine().time(), m_blitter_busy_until) < 0)
307 result ^= 6;
308 #endif
309 return result;
310 }
311
312
blitter_w(offs_t offset,uint16_t data,uint16_t mem_mask)313 void artmagic_state::blitter_w(offs_t offset, uint16_t data, uint16_t mem_mask)
314 {
315 COMBINE_DATA(&m_blitter_data[offset]);
316
317 /* offset 3 triggers the blit */
318 if (offset == 3)
319 execute_blit();
320
321 /* offset 4 contains the target page */
322 else if (offset == 4)
323 m_blitter_page = (data >> 1) & 1;
324 }
325
326
327
328 /*************************************
329 *
330 * Video update
331 *
332 *************************************/
333
TMS340X0_SCANLINE_RGB32_CB_MEMBER(artmagic_state::scanline)334 TMS340X0_SCANLINE_RGB32_CB_MEMBER(artmagic_state::scanline)
335 {
336 offs_t offset = (params->rowaddr << 12) & 0x7ff000;
337 uint16_t const *vram = address_to_vram(&offset);
338 uint32_t *const dest = &bitmap.pix(scanline);
339 pen_t const *const pens = m_tlc34076->pens();
340 int coladdr = params->coladdr << 1;
341
342 vram += offset;
343 for (int x = params->heblnk; x < params->hsblnk; x++)
344 dest[x] = pens[vram[coladdr++ & 0x1ff] & 0xff];
345 }
346