1 /*****************************************************************************
2 
3 	Irem M90 system.  There is 1 video chip - NANAO GA-25, it produces
4 	2 tilemaps and sprites.  16 control bytes:
5 
6 	0:  Playfield 1 X scroll
7 	2:  Playfield 1 Y scroll
8 	4:  Playfield 2 X scroll
9 	6:  Playfield 2 Y scroll
10 	8:  Bit 0x01 - unknown (set by hasamu)
11 	10: Playfield 1 control
12 		Bits0x03 - Playfield 1 VRAM base
13  		Bit 0x04 - Playfield 1 width (0 is 64 tiles, 0x4 is 128 tiles)
14 		Bit 0x10 - Playfield 1 disable
15 		Bit 0x20 - Playfield 1 rowscroll enable
16 	12: Playfield 2 control
17 		Bits0x03 - Playfield 2 VRAM base
18  		Bit 0x04 - Playfield 2 width (0 is 64 tiles, 0x4 is 128 tiles)
19 		Bit 0x10 - Playfield 2 disable
20 		Bit 0x20 - Playfield 2 rowscroll enable
21 	    Bits0x03 - Sprite/Tile Priority (related to sprite color)
22 
23 	Emulation by Bryan McPhail, mish@tendril.co.uk, thanks to Chris Hardy!
24 
25 *****************************************************************************/
26 
27 #include "driver.h"
28 #include "vidhrdw/generic.h"
29 #include "state.h"
30 
31 static unsigned char *m90_spriteram;
32 unsigned char *m90_video_data;
33 static struct tilemap *pf1_layer,*pf2_layer,*pf1_wide_layer,*pf2_wide_layer;
34 static int m90_video_control_data[16];
35 
get_tile_info(int tile_index,int layer,int page_mask)36 static void get_tile_info(int tile_index,int layer,int page_mask)
37 {
38 	int tile,color;
39 	tile_index = 4*tile_index + ((m90_video_control_data[0xa+2*layer] & page_mask)*0x4000);
40 
41 	tile=m90_video_data[tile_index]+(m90_video_data[tile_index+1]<<8);
42 	color=m90_video_data[tile_index+2];
43 	SET_TILE_INFO(
44 			0,
45 			tile,
46 			color&0xf,
47 			TILE_FLIPYX((color & 0xc0) >> 6))
48 	tile_info.priority = (color & 0x30) ? 1 : 0;
49 }
50 
51 
get_pf1_tile_info(int tile_index)52 static void get_pf1_tile_info (int tile_index) { get_tile_info(tile_index,0,3); }
get_pf1w_tile_info(int tile_index)53 static void get_pf1w_tile_info(int tile_index) { get_tile_info(tile_index,0,2); }
get_pf2_tile_info(int tile_index)54 static void get_pf2_tile_info (int tile_index) { get_tile_info(tile_index,1,3); }
get_pf2w_tile_info(int tile_index)55 static void get_pf2w_tile_info(int tile_index) { get_tile_info(tile_index,1,2); }
56 
57 
VIDEO_START(m90)58 VIDEO_START( m90 )
59 {
60 	pf1_layer =      tilemap_create(get_pf1_tile_info, tilemap_scan_rows,TILEMAP_TRANSPARENT,8,8,64,64);
61 	pf1_wide_layer = tilemap_create(get_pf1w_tile_info,tilemap_scan_rows,TILEMAP_TRANSPARENT,8,8,128,64);
62 	pf2_layer =      tilemap_create(get_pf2_tile_info, tilemap_scan_rows,TILEMAP_OPAQUE,8,8,64,64);
63 	pf2_wide_layer = tilemap_create(get_pf2w_tile_info,tilemap_scan_rows,TILEMAP_OPAQUE,8,8,128,64);
64 
65 	if (!pf1_layer || !pf1_wide_layer || !pf2_layer || !pf2_wide_layer)
66 		return 1;
67 
68 	tilemap_set_transparent_pen(pf1_layer,0);
69 	tilemap_set_transparent_pen(pf1_wide_layer,0);
70 
71 	state_save_register_UINT32("video", 0, "m90_video_control_data", (UINT32*) m90_video_control_data, 16);
72 
73 	return 0;
74 }
75 
m90_drawsprites(struct mame_bitmap * bitmap,const struct rectangle * cliprect)76 static void m90_drawsprites(struct mame_bitmap *bitmap,const struct rectangle *cliprect)
77 {
78 	int offs;
79 
80 	for (offs = 0x1f2;offs >= 0;offs -= 6)
81 	{
82 		int x,y,sprite,colour,fx,fy,y_multi,i;
83 
84 		sprite = (m90_spriteram[offs+2] | (m90_spriteram[offs+3]<<8));
85 		colour = (m90_spriteram[offs+1] >> 1) & 0x0f;
86 
87 		y = m90_spriteram[offs+0] | ((m90_spriteram[offs+1] & 0x01) << 8);
88 		x = m90_spriteram[offs+4] | ((m90_spriteram[offs+5] & 0x01) << 8);
89 
90 		x = x - 16;
91 		y = 512 - y;
92 
93 		fx = m90_spriteram[offs+5] & 0x02;
94 		fy = m90_spriteram[offs+1] & 0x80;
95 
96 		y_multi = 1 << ((m90_spriteram[offs+1] & 0x60) >> 5);
97 		y -= 16 * y_multi;
98 
99 		for (i = 0;i < y_multi;i++)
100 			if (m90_video_control_data[0xe] & 0x01)
101 			    pdrawgfx(bitmap,Machine->gfx[1],
102 					sprite + (fy ? y_multi-1 - i : i),
103 					colour,
104 					fx,fy,
105 					x,y+i*16,
106 					cliprect,TRANSPARENCY_PEN,0,
107 					(colour & 0x08) ? 0x00 : 0x02);
108 			else if (m90_video_control_data[0xe] & 0x02)
109 				pdrawgfx(bitmap,Machine->gfx[1],
110 					sprite + (fy ? y_multi-1 - i : i),
111 					colour,
112 					fx,fy,
113 					x,y+i*16,
114 					cliprect,TRANSPARENCY_PEN,0,
115 					((colour & 0x0c)==0x0c) ? 0x00 : 0x02);
116 			else
117 				pdrawgfx(bitmap,Machine->gfx[1],
118 					sprite + (fy ? y_multi-1 - i : i),
119 					colour,
120 					fx,fy,
121 					x,y+i*16,
122 					cliprect,TRANSPARENCY_PEN,0,
123 					0x02);
124 	}
125 }
126 
127 #if 0
128 static void bootleg_drawsprites(struct mame_bitmap *bitmap,const struct rectangle *cliprect)
129 {
130 	int offs;
131 
132 	for (offs = 0x0;offs <0x800-8;offs+= 8) {
133 		int x,y,sprite,colour,fx,fy;
134 
135 		if (/*spriteram[offs+0]==0x78 &&*/ spriteram[offs+1]==0x7f) continue;
136 
137 		y=(spriteram[offs+0] | (spriteram[offs+1]<<8))&0x1ff;
138 		x=(spriteram[offs+6] | (spriteram[offs+7]<<8))&0x1ff;
139 
140 		x = x - /*64 -*/ 16;
141 		y = 256 - /*32 -*/ y;
142 
143 	    sprite=(spriteram[offs+2] | (spriteram[offs+3]<<8));
144 		colour=(spriteram[offs+5]>>1)&0xf;
145 
146 		fx=spriteram[offs+5]&1;
147 		fy=0;/*spriteram[offs+5]&2;*/
148 
149 		drawgfx(bitmap,Machine->gfx[1],
150 				sprite&0x1fff,
151 				colour,
152 				fx,fy,
153 				x,y,
154 				cliprect,TRANSPARENCY_PEN,0);
155 	}
156 }
157 #endif
158 
WRITE_HANDLER(m90_video_control_w)159 WRITE_HANDLER( m90_video_control_w )
160 {
161 	m90_video_control_data[offset]=data;
162 }
163 
164 
markdirty(struct tilemap * tilemap,int page,offs_t offset)165 static void markdirty(struct tilemap *tilemap,int page,offs_t offset)
166 {
167 	offset -= page * 0x4000;
168 
169 	if (offset >= 0 && offset < 0x4000)
170 		tilemap_mark_tile_dirty(tilemap,offset/4);
171 }
172 
173 
WRITE_HANDLER(m90_video_w)174 WRITE_HANDLER( m90_video_w )
175 {
176 	m90_video_data[offset] = data;
177 
178 	markdirty(pf1_layer,     m90_video_control_data[0xa] & 0x3,offset);
179 	markdirty(pf1_wide_layer,m90_video_control_data[0xa] & 0x2,offset);
180 	markdirty(pf2_layer,     m90_video_control_data[0xc] & 0x3,offset);
181 	markdirty(pf2_wide_layer,m90_video_control_data[0xc] & 0x2,offset);
182 }
183 
VIDEO_UPDATE(m90)184 VIDEO_UPDATE( m90 )
185 {
186 	static int last_pf1,last_pf2;
187 	int pf1_base = m90_video_control_data[0xa] & 0x3;
188 	int pf2_base = m90_video_control_data[0xc] & 0x3;
189 	int i,pf1_enable,pf2_enable, video_enable;
190 
191     if (m90_video_control_data[0xe]&0x04) video_enable=0; else video_enable=1;
192 	if (m90_video_control_data[0xa]&0x10) pf1_enable=0; else pf1_enable=1;
193 	if (m90_video_control_data[0xc]&0x10) pf2_enable=0; else pf2_enable=1;
194 /*	tilemap_set_enable(pf1_layer,pf1_enable);*/
195 /*	tilemap_set_enable(pf2_layer,pf2_enable);*/
196 /*	tilemap_set_enable(pf1_wide_layer,pf1_enable);*/
197 /*	tilemap_set_enable(pf2_wide_layer,pf2_enable);*/
198 
199 	/* Dirty tilemaps if VRAM base changes */
200 	if (pf1_base!=last_pf1)
201 	{
202 		tilemap_mark_all_tiles_dirty(pf1_layer);
203 		tilemap_mark_all_tiles_dirty(pf1_wide_layer);
204 	}
205 	if (pf2_base!=last_pf2)
206 	{
207 		tilemap_mark_all_tiles_dirty(pf2_layer);
208 		tilemap_mark_all_tiles_dirty(pf2_wide_layer);
209 	}
210 	last_pf1=pf1_base;
211 	last_pf2=pf2_base;
212 
213 	m90_spriteram=m90_video_data+0xee00;
214 
215 	/* Setup scrolling */
216 	if (m90_video_control_data[0xa]&0x20)
217 	{
218 		tilemap_set_scroll_rows(pf1_layer,512);
219 		tilemap_set_scroll_rows(pf1_wide_layer,512);
220 		for (i=0; i<1024; i+=2)
221 			tilemap_set_scrollx( pf1_layer,i/2, (m90_video_data[0xf000+i]+(m90_video_data[0xf001+i]<<8))+2);
222 		for (i=0; i<1024; i+=2)
223 			tilemap_set_scrollx( pf1_wide_layer,i/2, (m90_video_data[0xf000+i]+(m90_video_data[0xf001+i]<<8))+256+2);
224 	}
225 	else
226 	{
227 		tilemap_set_scroll_rows(pf1_layer,1);
228 		tilemap_set_scroll_rows(pf1_wide_layer,1);
229 		tilemap_set_scrollx( pf1_layer,0, (m90_video_control_data[3]<<8)+m90_video_control_data[2]+2);
230 		tilemap_set_scrollx( pf1_wide_layer,0, (m90_video_control_data[3]<<8)+m90_video_control_data[2]+256+2);
231 	}
232 
233 	/* Setup scrolling */
234 	if (m90_video_control_data[0xc]&0x20) {
235 		tilemap_set_scroll_rows(pf2_layer,512);
236 		tilemap_set_scroll_rows(pf2_wide_layer,512);
237 		for (i=0; i<1024; i+=2)
238 			tilemap_set_scrollx( pf2_layer,i/2, (m90_video_data[0xf400+i]+(m90_video_data[0xf401+i]<<8))-2);
239 		for (i=0; i<1024; i+=2)
240 			tilemap_set_scrollx( pf2_wide_layer,i/2, (m90_video_data[0xf400+i]+(m90_video_data[0xf401+i]<<8))+256-2);
241 	} else {
242 		tilemap_set_scroll_rows(pf2_layer,1);
243 		tilemap_set_scroll_rows(pf2_wide_layer,1);
244 		tilemap_set_scrollx( pf2_layer,0, (m90_video_control_data[7]<<8)+m90_video_control_data[6]-2);
245 		tilemap_set_scrollx( pf2_wide_layer,0, (m90_video_control_data[7]<<8)+m90_video_control_data[6]+256-2 );
246 	}
247 
248 	fillbitmap(priority_bitmap,0,cliprect);
249 
250 	if (video_enable) {
251 		if (!pf2_enable)
252 			fillbitmap(bitmap,Machine->pens[0],cliprect);
253 
254 
255 		if (pf2_enable)
256 		{
257 			// use the playfield 2 y-offset table for each scanline
258 			if (m90_video_control_data[0xc] & 0x40) {
259 
260 				int line;
261 				struct rectangle clip;
262 				clip.min_x = cliprect->min_x;
263 				clip.max_x = cliprect->max_x;
264 
265 				for(line = 0; line < 1024; line+=2)
266 				{
267 					clip.min_y = clip.max_y = line / 2;
268 
269 					if (m90_video_control_data[0xc] & 0x4) {
270 						tilemap_set_scrolly(pf2_wide_layer, 0,(m90_video_control_data[5]<<8)+m90_video_control_data[4] + (m90_video_data[0xfc00+line]+(m90_video_data[0xfc01+line]<<8))+128);
271                         tilemap_draw(bitmap,&clip,pf2_wide_layer,0,0);
272 						tilemap_draw(bitmap,&clip,pf2_wide_layer,1,1);
273 					} else {
274 						tilemap_set_scrolly(pf2_layer, 0,(m90_video_control_data[5]<<8)+m90_video_control_data[4] + (m90_video_data[0xfc00+line]+(m90_video_data[0xfc01+line]<<8))+128);
275 						tilemap_draw(bitmap,&clip,pf2_layer,0,0);
276 						tilemap_draw(bitmap,&clip,pf2_layer,1,1);
277 					}
278 				}
279 			}
280 			else
281 			{
282 				if (m90_video_control_data[0xc] & 0x4) {
283 					tilemap_set_scrolly( pf2_wide_layer,0,(m90_video_control_data[5]<<8)+m90_video_control_data[4] );
284 					tilemap_draw(bitmap,cliprect,pf2_wide_layer,0,0);
285 					tilemap_draw(bitmap,cliprect,pf2_wide_layer,1,1);
286 				} else {
287 					tilemap_set_scrolly( pf2_layer,0,(m90_video_control_data[5]<<8)+m90_video_control_data[4] );
288 					tilemap_draw(bitmap,cliprect,pf2_layer,0,0);
289 					tilemap_draw(bitmap,cliprect,pf2_layer,1,1);
290 				}
291 			}
292 		}
293 
294 		if (pf1_enable)
295 		{
296 			// use the playfield 1 y-offset table for each scanline
297 			if (m90_video_control_data[0xa] & 0x40) {
298 
299 				int line;
300 				struct rectangle clip;
301 				clip.min_x = cliprect->min_x;
302 				clip.max_x = cliprect->max_x;
303 
304 				for(line = 0; line < 1024; line+=2)
305 				{
306 					clip.min_y = clip.max_y = line / 2;
307 
308 					if (m90_video_control_data[0xa] & 0x4) {
309                         tilemap_set_scrolly(pf1_wide_layer, 0,(m90_video_control_data[1]<<8)+m90_video_control_data[0] + (m90_video_data[0xf800+line]+(m90_video_data[0xf801+line]<<8))+128);
310 						tilemap_draw(bitmap,&clip,pf1_wide_layer,0,0);
311 						tilemap_draw(bitmap,&clip,pf1_wide_layer,1,1);
312 					} else {
313                         tilemap_set_scrolly(pf1_layer, 0,(m90_video_control_data[1]<<8)+m90_video_control_data[0] + (m90_video_data[0xf800+line]+(m90_video_data[0xf801+line]<<8))+128);
314 						tilemap_draw(bitmap,&clip,pf1_layer,0,0);
315 						tilemap_draw(bitmap,&clip,pf1_layer,1,1);
316 					}
317 				}
318 			}
319 			else
320 			{
321 				if (m90_video_control_data[0xa] & 0x4) {
322 					tilemap_set_scrolly( pf1_wide_layer,0,(m90_video_control_data[1]<<8)+m90_video_control_data[0] );
323 					tilemap_draw(bitmap,cliprect,pf1_wide_layer,0,0);
324 					tilemap_draw(bitmap,cliprect,pf1_wide_layer,1,1);
325 				} else {
326 					tilemap_set_scrolly( pf1_layer,0,(m90_video_control_data[1]<<8)+m90_video_control_data[0] );
327 					tilemap_draw(bitmap,cliprect,pf1_layer,0,0);
328 					tilemap_draw(bitmap,cliprect,pf1_layer,1,1);
329 				}
330 			}
331 		}
332 
333 	    m90_drawsprites(bitmap,cliprect);
334 
335 	} else {
336 		fillbitmap(bitmap,get_black_pen(),cliprect);
337 	}
338 
339 }
340