1 // license:BSD-3-Clause
2 // copyright-holders:Carlos A. Lozano, Phil Stroffolino
3 /***************************************************************************
4 
5     video/contra.c
6 
7 ***************************************************************************/
8 
9 #include "emu.h"
10 #include "includes/contra.h"
11 
12 
13 /***************************************************************************
14 **
15 **  Contra has palette RAM, but it also has four lookup table PROMs
16 **
17 **  0   sprites #0
18 **  1   tiles   #0
19 **  2   sprites #1
20 **  3   tiles   #1
21 **
22 ***************************************************************************/
23 
contra_palette(palette_device & palette) const24 void contra_state::contra_palette(palette_device &palette) const
25 {
26 	uint8_t const *const color_prom = memregion("proms")->base();
27 
28 	for (int chip = 0; chip < 2; chip++)
29 	{
30 		for (int pal = 0; pal < 8; pal++)
31 		{
32 			int const clut = (chip << 1) | (pal & 1);
33 
34 			for (int i = 0; i < 0x100; i++)
35 			{
36 				uint8_t ctabentry;
37 
38 				if (((pal & 0x01) == 0) && (color_prom[(clut << 8) | i] == 0))
39 					ctabentry = 0;
40 				else
41 					ctabentry = (pal << 4) | (color_prom[(clut << 8) | i] & 0x0f);
42 
43 				palette.set_pen_indirect((chip << 11) | (pal << 8) | i, ctabentry);
44 			}
45 		}
46 	}
47 }
48 
49 
50 
51 /***************************************************************************
52 
53     Callbacks for the TileMap code
54 
55 ***************************************************************************/
56 
TILE_GET_INFO_MEMBER(contra_state::get_fg_tile_info)57 TILE_GET_INFO_MEMBER(contra_state::get_fg_tile_info)
58 {
59 	uint8_t ctrl_3 = m_k007121_1->ctrlram_r(3);
60 	uint8_t ctrl_4 = m_k007121_1->ctrlram_r(4);
61 	uint8_t ctrl_5 = m_k007121_1->ctrlram_r(5);
62 	uint8_t ctrl_6 = m_k007121_1->ctrlram_r(6);
63 	int attr = m_fg_cram[tile_index];
64 	int bit0 = (ctrl_5 >> 0) & 0x03;
65 	int bit1 = (ctrl_5 >> 2) & 0x03;
66 	int bit2 = (ctrl_5 >> 4) & 0x03;
67 	int bit3 = (ctrl_5 >> 6) & 0x03;
68 	int bank = ((attr & 0x80) >> 7) |
69 			((attr >> (bit0 + 2)) & 0x02) |
70 			((attr >> (bit1 + 1)) & 0x04) |
71 			((attr >> (bit2    )) & 0x08) |
72 			((attr >> (bit3 - 1)) & 0x10) |
73 			((ctrl_3 & 0x01) << 5);
74 	int mask = (ctrl_4 & 0xf0) >> 4;
75 
76 	bank = (bank & ~(mask << 1)) | ((ctrl_4 & mask) << 1);
77 
78 	tileinfo.set(0,
79 			m_fg_vram[tile_index] + bank * 256,
80 			((ctrl_6 & 0x30) * 2 + 16) + (attr & 7),
81 			0);
82 }
83 
TILE_GET_INFO_MEMBER(contra_state::get_bg_tile_info)84 TILE_GET_INFO_MEMBER(contra_state::get_bg_tile_info)
85 {
86 	uint8_t ctrl_3 = m_k007121_2->ctrlram_r(3);
87 	uint8_t ctrl_4 = m_k007121_2->ctrlram_r(4);
88 	uint8_t ctrl_5 = m_k007121_2->ctrlram_r(5);
89 	uint8_t ctrl_6 = m_k007121_2->ctrlram_r(6);
90 	int attr = m_bg_cram[tile_index];
91 	int bit0 = (ctrl_5 >> 0) & 0x03;
92 	int bit1 = (ctrl_5 >> 2) & 0x03;
93 	int bit2 = (ctrl_5 >> 4) & 0x03;
94 	int bit3 = (ctrl_5 >> 6) & 0x03;
95 	int bank = ((attr & 0x80) >> 7) |
96 			((attr >> (bit0 + 2)) & 0x02) |
97 			((attr >> (bit1 + 1)) & 0x04) |
98 			((attr >> (bit2    )) & 0x08) |
99 			((attr >> (bit3 - 1)) & 0x10) |
100 			((ctrl_3 & 0x01) << 5);
101 	int mask = (ctrl_4 & 0xf0) >> 4;
102 
103 	// 2009-12 FP: TO BE VERIFIED - old code used ctrl4 from chip 0?!?
104 	bank = (bank & ~(mask << 1)) | ((ctrl_4 & mask) << 1);
105 
106 	tileinfo.set(1,
107 			m_bg_vram[tile_index] + bank * 256,
108 			((ctrl_6 & 0x30) * 2 + 16) + (attr & 7),
109 			0);
110 }
111 
TILE_GET_INFO_MEMBER(contra_state::get_tx_tile_info)112 TILE_GET_INFO_MEMBER(contra_state::get_tx_tile_info)
113 {
114 	uint8_t ctrl_5 = m_k007121_1->ctrlram_r(5);
115 	uint8_t ctrl_6 = m_k007121_1->ctrlram_r(6);
116 	int attr = m_tx_cram[tile_index];
117 	int bit0 = (ctrl_5 >> 0) & 0x03;
118 	int bit1 = (ctrl_5 >> 2) & 0x03;
119 	int bit2 = (ctrl_5 >> 4) & 0x03;
120 	int bit3 = (ctrl_5 >> 6) & 0x03;
121 	int bank = ((attr & 0x80) >> 7) |
122 			((attr >> (bit0 + 2)) & 0x02) |
123 			((attr >> (bit1 + 1)) & 0x04) |
124 			((attr >> (bit2    )) & 0x08) |
125 			((attr >> (bit3 - 1)) & 0x10);
126 
127 	tileinfo.set(0,
128 			m_tx_vram[tile_index] + bank * 256,
129 			((ctrl_6 & 0x30) * 2 + 16) + (attr & 7),
130 			0);
131 }
132 
133 
134 /***************************************************************************
135 
136     Start the video hardware emulation.
137 
138 ***************************************************************************/
139 
video_start()140 void contra_state::video_start()
141 {
142 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(contra_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
143 	m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(contra_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
144 	m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(contra_state::get_tx_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
145 
146 	m_buffered_spriteram = std::make_unique<uint8_t[]>(0x800);
147 	m_buffered_spriteram_2 = std::make_unique<uint8_t[]>(0x800);
148 
149 	m_bg_clip = m_screen->visible_area();
150 	m_bg_clip.min_x += 40;
151 
152 	m_fg_clip = m_bg_clip;
153 
154 	m_tx_clip = m_screen->visible_area();
155 	m_tx_clip.max_x = 39;
156 	m_tx_clip.min_x = 0;
157 
158 	m_fg_tilemap->set_transparent_pen(0);
159 
160 	save_pointer(NAME(m_buffered_spriteram), 0x800);
161 	save_pointer(NAME(m_buffered_spriteram_2), 0x800);
162 }
163 
164 
165 /***************************************************************************
166 
167     Memory handlers
168 
169 ***************************************************************************/
170 
contra_fg_vram_w(offs_t offset,uint8_t data)171 void contra_state::contra_fg_vram_w(offs_t offset, uint8_t data)
172 {
173 	m_fg_vram[offset] = data;
174 	m_fg_tilemap->mark_tile_dirty(offset);
175 }
176 
contra_fg_cram_w(offs_t offset,uint8_t data)177 void contra_state::contra_fg_cram_w(offs_t offset, uint8_t data)
178 {
179 	m_fg_cram[offset] = data;
180 	m_fg_tilemap->mark_tile_dirty(offset);
181 }
182 
contra_bg_vram_w(offs_t offset,uint8_t data)183 void contra_state::contra_bg_vram_w(offs_t offset, uint8_t data)
184 {
185 	m_bg_vram[offset] = data;
186 	m_bg_tilemap->mark_tile_dirty(offset);
187 }
188 
contra_bg_cram_w(offs_t offset,uint8_t data)189 void contra_state::contra_bg_cram_w(offs_t offset, uint8_t data)
190 {
191 	m_bg_cram[offset] = data;
192 	m_bg_tilemap->mark_tile_dirty(offset);
193 }
194 
contra_text_vram_w(offs_t offset,uint8_t data)195 void contra_state::contra_text_vram_w(offs_t offset, uint8_t data)
196 {
197 	m_tx_vram[offset] = data;
198 	m_tx_tilemap->mark_tile_dirty(offset);
199 }
200 
contra_text_cram_w(offs_t offset,uint8_t data)201 void contra_state::contra_text_cram_w(offs_t offset, uint8_t data)
202 {
203 	m_tx_cram[offset] = data;
204 	m_tx_tilemap->mark_tile_dirty(offset);
205 }
206 
contra_K007121_ctrl_0_w(offs_t offset,uint8_t data)207 void contra_state::contra_K007121_ctrl_0_w(offs_t offset, uint8_t data)
208 {
209 	uint8_t ctrl_6 = m_k007121_1->ctrlram_r(6);
210 
211 	if (offset == 3)
212 	{
213 		if ((data & 0x8) == 0)
214 			memcpy(m_buffered_spriteram.get(), m_spriteram + 0x800, 0x800);
215 		else
216 			memcpy(m_buffered_spriteram.get(), m_spriteram, 0x800);
217 	}
218 
219 	if (offset == 6)
220 	{
221 		if (ctrl_6 != data)
222 			m_fg_tilemap->mark_all_dirty();
223 	}
224 
225 	if (offset == 7)
226 		m_fg_tilemap->set_flip((data & 0x08) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
227 
228 	m_k007121_1->ctrl_w(offset, data);
229 }
230 
contra_K007121_ctrl_1_w(offs_t offset,uint8_t data)231 void contra_state::contra_K007121_ctrl_1_w(offs_t offset, uint8_t data)
232 {
233 	uint8_t ctrl_6 = m_k007121_2->ctrlram_r(6);
234 
235 	if (offset == 3)
236 	{
237 		if ((data & 0x8) == 0)
238 			memcpy(m_buffered_spriteram_2.get(), m_spriteram_2 + 0x800, 0x800);
239 		else
240 			memcpy(m_buffered_spriteram_2.get(), m_spriteram_2 + 0x000, 0x800);
241 	}
242 	if (offset == 6)
243 	{
244 		if (ctrl_6 != data )
245 			m_bg_tilemap->mark_all_dirty();
246 	}
247 	if (offset == 7)
248 		m_bg_tilemap->set_flip((data & 0x08) ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
249 
250 	m_k007121_2->ctrl_w(offset, data);
251 }
252 
253 
254 
255 /***************************************************************************
256 
257     Display Refresh
258 
259 ***************************************************************************/
260 
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect,bitmap_ind8 & priority_bitmap,int bank)261 void contra_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect, bitmap_ind8 &priority_bitmap, int bank )
262 {
263 	k007121_device *k007121 = bank ? m_k007121_2 : m_k007121_1;
264 	int base_color = (k007121->ctrlram_r(6) & 0x30) * 2;
265 	const uint8_t *source;
266 
267 	if (bank == 0)
268 		source = m_buffered_spriteram.get();
269 	else
270 		source = m_buffered_spriteram_2.get();
271 
272 	k007121->sprites_draw(bitmap, cliprect, m_gfxdecode->gfx(bank), *m_palette, source, base_color, 40, 0, priority_bitmap, (uint32_t)-1);
273 }
274 
screen_update_contra(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)275 uint32_t contra_state::screen_update_contra(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
276 {
277 	uint8_t ctrl_1_0 = m_k007121_1->ctrlram_r(0);
278 	uint8_t ctrl_1_2 = m_k007121_1->ctrlram_r(2);
279 	uint8_t ctrl_2_0 = m_k007121_2->ctrlram_r(0);
280 	uint8_t ctrl_2_2 = m_k007121_2->ctrlram_r(2);
281 	rectangle bg_finalclip = m_bg_clip;
282 	rectangle fg_finalclip = m_fg_clip;
283 	rectangle tx_finalclip = m_tx_clip;
284 
285 	bg_finalclip &= cliprect;
286 	fg_finalclip &= cliprect;
287 	tx_finalclip &= cliprect;
288 
289 	m_fg_tilemap->set_scrollx(0, ctrl_1_0 - 40);
290 	m_fg_tilemap->set_scrolly(0, ctrl_1_2);
291 	m_bg_tilemap->set_scrollx(0, ctrl_2_0 - 40);
292 	m_bg_tilemap->set_scrolly(0, ctrl_2_2);
293 
294 	m_bg_tilemap->draw(screen, bitmap, bg_finalclip, 0 ,0);
295 	m_fg_tilemap->draw(screen, bitmap, fg_finalclip, 0 ,0);
296 	draw_sprites(bitmap,cliprect, screen.priority(), 0);
297 	draw_sprites(bitmap,cliprect, screen.priority(), 1);
298 	m_tx_tilemap->draw(screen, bitmap, tx_finalclip, 0 ,0);
299 	return 0;
300 }
301