1 // license:BSD-3-Clause
2 // copyright-holders:Mike Balfour, Aaron Giles
3 /***************************************************************************
4 
5     Atari Cloud 9 (prototype) hardware
6 
7 ***************************************************************************/
8 
9 #include "emu.h"
10 #include "includes/cloud9.h"
11 #include "video/resnet.h"
12 
13 
14 /*************************************
15  *
16  *  Video startup
17  *
18  *************************************/
19 
video_start()20 void cloud9_state::video_start()
21 {
22 	static const int resistances[3] = { 22000, 10000, 4700 };
23 
24 	/* allocate second bank of videoram */
25 	m_videoram = std::make_unique<uint8_t[]>(0x8000);
26 	membank("bank1")->set_base(m_videoram.get());
27 
28 	/* get pointers to our PROMs */
29 	m_syncprom = memregion("proms")->base() + 0x000;
30 	m_wpprom = memregion("proms")->base() + 0x200;
31 	m_priprom = memregion("proms")->base() + 0x300;
32 
33 	/* compute the color output resistor weights at startup */
34 	compute_resistor_weights(0, 255, -1.0,
35 			3,  resistances, m_rweights, 1000, 0,
36 			3,  resistances, m_gweights, 1000, 0,
37 			3,  resistances, m_bweights, 1000, 0);
38 
39 	/* allocate a bitmap for drawing sprites */
40 	m_screen->register_screen_bitmap(m_spritebitmap);
41 
42 	/* register for savestates */
43 	save_pointer(NAME(m_videoram), 0x8000);
44 	save_item(NAME(m_bitmode_addr));
45 }
46 
47 
48 
49 /*************************************
50  *
51  *  Palette RAM accesses
52  *
53  *************************************/
54 
cloud9_paletteram_w(offs_t offset,uint8_t data)55 void cloud9_state::cloud9_paletteram_w(offs_t offset, uint8_t data)
56 {
57 	int bit0, bit1, bit2;
58 	int r, g, b;
59 
60 	/* extract the raw RGB bits */
61 	r = (data & 0xe0) >> 5;
62 	g = (data & 0x1c) >> 2;
63 	b = ((data & 0x03) << 1) | ((offset & 0x40) >> 6);
64 
65 	/* red component (inverted) */
66 	bit0 = (~r >> 0) & 0x01;
67 	bit1 = (~r >> 1) & 0x01;
68 	bit2 = (~r >> 2) & 0x01;
69 	r = combine_weights(m_rweights, bit0, bit1, bit2);
70 
71 	/* green component (inverted) */
72 	bit0 = (~g >> 0) & 0x01;
73 	bit1 = (~g >> 1) & 0x01;
74 	bit2 = (~g >> 2) & 0x01;
75 	g = combine_weights(m_gweights, bit0, bit1, bit2);
76 
77 	/* blue component (inverted) */
78 	bit0 = (~b >> 0) & 0x01;
79 	bit1 = (~b >> 1) & 0x01;
80 	bit2 = (~b >> 2) & 0x01;
81 	b = combine_weights(m_bweights, bit0, bit1, bit2);
82 
83 	m_palette->set_pen_color(offset & 0x3f, rgb_t(r, g, b));
84 }
85 
86 
87 
88 /*************************************
89  *
90  *  Video RAM access via the write
91  *  protect PROM
92  *
93  *************************************/
94 
cloud9_write_vram(uint16_t addr,uint8_t data,uint8_t bitmd,uint8_t pixba)95 inline void cloud9_state::cloud9_write_vram( uint16_t addr, uint8_t data, uint8_t bitmd, uint8_t pixba )
96 {
97 	uint8_t *dest = &m_videoram[0x0000 | (addr & 0x3fff)];
98 	uint8_t *dest2 = &m_videoram[0x4000 | (addr & 0x3fff)];
99 	uint8_t promaddr = 0;
100 	uint8_t wpbits;
101 
102 	/*
103 	    Inputs to the write-protect PROM:
104 
105 	    Bit 7 = BITMD
106 	    Bit 6 = video_control[4]
107 	    Bit 5 = video_control[6]
108 	    Bit 4 = 1 if (A15-A12 != 4)
109 	    Bit 3 = !(A13 | A12 | A11)
110 	    Bit 2 = A9 & A10
111 	    Bit 1 = PIXB
112 	    Bit 0 = PIXA
113 	*/
114 	promaddr |= bitmd << 7;
115 	promaddr |= m_videolatch->q4_r() << 6;
116 	promaddr |= m_videolatch->q6_r() << 5;
117 	promaddr |= ((addr & 0xf000) != 0x4000) << 4;
118 	promaddr |= ((addr & 0x3800) == 0x0000) << 3;
119 	promaddr |= ((addr & 0x0600) == 0x0600) << 2;
120 	promaddr |= (pixba << 0);
121 
122 	/* look up the PROM result */
123 	wpbits = m_wpprom[promaddr];
124 
125 	/* write to the appropriate parts of VRAM depending on the result */
126 	if (!(wpbits & 1))
127 		dest2[0] = (dest2[0] & 0x0f) | (data & 0xf0);
128 	if (!(wpbits & 2))
129 		dest2[0] = (dest2[0] & 0xf0) | (data & 0x0f);
130 	if (!(wpbits & 4))
131 		dest[0] = (dest[0] & 0x0f) | (data & 0xf0);
132 	if (!(wpbits & 8))
133 		dest[0] = (dest[0] & 0xf0) | (data & 0x0f);
134 }
135 
136 
137 
138 /*************************************
139  *
140  *  Autoincrement control for bit mode
141  *
142  *************************************/
143 
bitmode_autoinc()144 inline void cloud9_state::bitmode_autoinc(  )
145 {
146 	/* auto increment in the x-direction if it's enabled */
147 	if (!m_videolatch->q0_r()) /* /AX */
148 		m_bitmode_addr[0]++;
149 
150 	/* auto increment in the y-direction if it's enabled */
151 	if (!m_videolatch->q1_r()) /* /AY */
152 		m_bitmode_addr[1]++;
153 }
154 
155 
156 
157 /*************************************
158  *
159  *  Standard video RAM access
160  *
161  *************************************/
162 
cloud9_videoram_w(offs_t offset,uint8_t data)163 void cloud9_state::cloud9_videoram_w(offs_t offset, uint8_t data)
164 {
165 	/* direct writes to VRAM go through the write protect PROM as well */
166 	cloud9_write_vram(offset, data, 0, 0);
167 }
168 
169 
170 
171 /*************************************
172  *
173  *  Bit mode video RAM access
174  *
175  *************************************/
176 
cloud9_bitmode_r()177 uint8_t cloud9_state::cloud9_bitmode_r()
178 {
179 	/* in bitmode, the address comes from the autoincrement latches */
180 	uint16_t addr = (m_bitmode_addr[1] << 6) | (m_bitmode_addr[0] >> 2);
181 
182 	/* the appropriate pixel is selected into the upper 4 bits */
183 	uint8_t result = m_videoram[((~m_bitmode_addr[0] & 2) << 13) | addr] << ((m_bitmode_addr[0] & 1) * 4);
184 
185 	/* autoincrement because /BITMD was selected */
186 	bitmode_autoinc();
187 
188 	/* the upper 4 bits of the data lines are not driven so make them all 1's */
189 	return (result >> 4) | 0xf0;
190 }
191 
192 
cloud9_bitmode_w(uint8_t data)193 void cloud9_state::cloud9_bitmode_w(uint8_t data)
194 {
195 	/* in bitmode, the address comes from the autoincrement latches */
196 	uint16_t addr = (m_bitmode_addr[1] << 6) | (m_bitmode_addr[0] >> 2);
197 
198 	/* the lower 4 bits of data are replicated to the upper 4 bits */
199 	data = (data & 0x0f) | (data << 4);
200 
201 	/* write through the generic VRAM routine, passing the low 2 X bits as PIXB/PIXA */
202 	cloud9_write_vram(addr, data, 1, m_bitmode_addr[0] & 3);
203 
204 	/* autoincrement because /BITMD was selected */
205 	bitmode_autoinc();
206 }
207 
208 
cloud9_bitmode_addr_w(offs_t offset,uint8_t data)209 void cloud9_state::cloud9_bitmode_addr_w(offs_t offset, uint8_t data)
210 {
211 	/* write through to video RAM and also to the addressing latches */
212 	cloud9_write_vram(offset, data, 0, 0);
213 	m_bitmode_addr[offset] = data;
214 }
215 
216 
217 
218 /*************************************
219  *
220  *  Video updating
221  *
222  *************************************/
223 
screen_update_cloud9(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)224 uint32_t cloud9_state::screen_update_cloud9(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
225 {
226 	uint8_t const *const spriteaddr = m_spriteram;
227 	int const flip = m_videolatch->q5_r() ? 0xff : 0x00;    /* PLAYER2 */
228 	pen_t const black = m_palette->black_pen();
229 
230 	/* draw the sprites */
231 	m_spritebitmap.fill(0x00, cliprect);
232 	for (int offs = 0; offs < 0x20; offs++)
233 		if (spriteaddr[offs + 0x00] != 0)
234 		{
235 			int const x = spriteaddr[offs + 0x60];
236 			int const y = 256 - 15 - spriteaddr[offs + 0x00];
237 			int const xflip = spriteaddr[offs + 0x40] & 0x80;
238 			int const yflip = spriteaddr[offs + 0x40] & 0x40;
239 			int const which = spriteaddr[offs + 0x20];
240 			int const color = 0;
241 
242 			m_gfxdecode->gfx(0)->transpen(m_spritebitmap,cliprect, which, color, xflip, yflip, x, y, 0);
243 			if (x >= 256 - 16)
244 				m_gfxdecode->gfx(0)->transpen(m_spritebitmap,cliprect, which, color, xflip, yflip, x - 256, y, 0);
245 		}
246 
247 	/* draw the bitmap to the screen, looping over Y */
248 	for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
249 	{
250 		uint16_t *const dst = &bitmap.pix(y);
251 
252 		/* if we're in the VBLANK region, just fill with black */
253 		if (~m_syncprom[y] & 2)
254 		{
255 			for (int x = cliprect.left(); x <= cliprect.right(); x++)
256 				dst[x] = black;
257 		}
258 
259 		/* non-VBLANK region: merge the sprites and the bitmap */
260 		else
261 		{
262 			uint16_t const *const mosrc = &m_spritebitmap.pix(y);
263 			int const effy = y ^ flip;
264 
265 			/* two videoram arrays */
266 			uint8_t const *const src[2]{ &m_videoram[0x4000 | (effy * 64)], &m_videoram[0x0000 | (effy * 64)] };
267 
268 			/* loop over X */
269 			for (int x = cliprect.left(); x <= cliprect.right(); x++)
270 			{
271 				/* if we're in the HBLANK region, just store black */
272 				if (x >= 256)
273 					dst[x] = black;
274 
275 				/* otherwise, process normally */
276 				else
277 				{
278 					int const effx = x ^ flip;
279 
280 					/* low 4 bits = left pixel, high 4 bits = right pixel */
281 					uint8_t pix = (src[(effx >> 1) & 1][effx / 4] >> ((~effx & 1) * 4)) & 0x0f;
282 					uint8_t const mopix = mosrc[x];
283 
284 					/* sprites have priority if sprite pixel != 0 or some other condition */
285 					if (mopix != 0)
286 						pix = mopix | 0x10;
287 
288 					/* the high bit is the bank select */
289 					pix |= m_videolatch->q7_r() << 5;
290 
291 					/* store the pixel value and also a priority value based on the topmost bit */
292 					dst[x] = pix;
293 				}
294 			}
295 		}
296 	}
297 	return 0;
298 }
299