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