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