1 // license:BSD-3-Clause
2 // copyright-holders:Robbbert
3 /* Super80.c written by Robbbert, 2005-2010. See the driver source for documentation. */
4 
5 
6 
7 #include "emu.h"
8 #include "includes/super80.h"
9 
10 
11 
12 /**************************** PALETTES for super80m and super80v ******************************************/
13 
super80m_palette(palette_device & palette) const14 void super80_state::super80m_palette(palette_device &palette) const
15 {
16 	// RGB
17 	palette.set_pen_color( 0, rgb_t(0x00, 0x00, 0x00));   //  0 Black
18 	palette.set_pen_color( 1, rgb_t(0x00, 0x00, 0x00));   //  1 Black
19 	palette.set_pen_color( 2, rgb_t(0x00, 0x00, 0x7f));   //  2 Blue
20 	palette.set_pen_color( 3, rgb_t(0x00, 0x00, 0xff));   //  3 Light Blue
21 	palette.set_pen_color( 4, rgb_t(0x00, 0x7f, 0x00));   //  4 Green
22 	palette.set_pen_color( 5, rgb_t(0x00, 0xff, 0x00));   //  5 Bright Green
23 	palette.set_pen_color( 6, rgb_t(0x00, 0x7f, 0x7f));   //  6 Cyan
24 	palette.set_pen_color( 7, rgb_t(0x00, 0xff, 0xff));   //  7 Turquoise
25 	palette.set_pen_color( 8, rgb_t(0x7f, 0x00, 0x00));   //  8 Dark Red
26 	palette.set_pen_color( 9, rgb_t(0xff, 0x00, 0x00));   //  9 Red
27 	palette.set_pen_color(10, rgb_t(0x7f, 0x00, 0x7f));   // 10 Purple
28 	palette.set_pen_color(11, rgb_t(0xff, 0x00, 0xff));   // 11 Magenta
29 	palette.set_pen_color(12, rgb_t(0x7f, 0x7f, 0x00));   // 12 Lime
30 	palette.set_pen_color(13, rgb_t(0xff, 0xff, 0x00));   // 13 Yellow
31 	palette.set_pen_color(14, rgb_t(0xbf, 0xbf, 0xbf));   // 14 Off White
32 	palette.set_pen_color(15, rgb_t(0xff, 0xff, 0xff));   // 15 White
33 	// Composite
34 	palette.set_pen_color(16, rgb_t(0x00, 0x00, 0x00));   //  0 Black
35 	palette.set_pen_color(17, rgb_t(0x80, 0x80, 0x80));   //  1 Grey
36 	palette.set_pen_color(18, rgb_t(0x00, 0x00, 0xff));   //  2 Blue
37 	palette.set_pen_color(19, rgb_t(0xff, 0xff, 0x80));   //  3 Light Yellow
38 	palette.set_pen_color(20, rgb_t(0x00, 0xff, 0x00));   //  4 Green
39 	palette.set_pen_color(21, rgb_t(0xff, 0x80, 0xff));   //  5 Light Magenta
40 	palette.set_pen_color(22, rgb_t(0x00, 0xff, 0xff));   //  6 Cyan
41 	palette.set_pen_color(23, rgb_t(0xff, 0x40, 0x40));   //  7 Light Red
42 	palette.set_pen_color(24, rgb_t(0xff, 0x00, 0x00));   //  8 Red
43 	palette.set_pen_color(25, rgb_t(0x00, 0x80, 0x80));   //  9 Dark Cyan
44 	palette.set_pen_color(26, rgb_t(0xff, 0x00, 0xff));   // 10 Magenta
45 	palette.set_pen_color(27, rgb_t(0x80, 0xff, 0x80));   // 11 Light Green
46 	palette.set_pen_color(28, rgb_t(0xff, 0xff, 0x00));   // 12 Yellow
47 	palette.set_pen_color(29, rgb_t(0x00, 0x00, 0x80));   // 13 Dark Blue
48 	palette.set_pen_color(30, rgb_t(0xff, 0xff, 0xff));   // 14 White
49 	palette.set_pen_color(31, rgb_t(0x00, 0x00, 0x00));   // 15 Black
50 }
51 
52 
53 
screen_vblank_super80m(bool state)54 void super80_state::screen_vblank_super80m(bool state)
55 {
56 	// rising edge
57 	if (state)
58 	{
59 		// if we chose another palette or colour mode, enable it
60 		m_palette_index = (m_io_config->read() & 0x60) ? 0 : 16;
61 	}
62 }
63 
screen_update_super80(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)64 uint32_t super80_state::screen_update_super80(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
65 {
66 	address_space& program = m_maincpu->space(AS_PROGRAM);
67 
68 	m_cass_led = BIT(m_portf0, 5);
69 
70 	const uint8_t options = m_io_config->read();
71 	bool screen_on = BIT(m_portf0, 2) || !BIT(options, 2);    // bit 2 of port F0 is high, OR user turned on config switch
72 
73 	uint8_t fg = 0;
74 	if (screen_on)
75 	{
76 		if (BIT(options, 5))
77 			fg = 15;    // b&w
78 		else
79 			fg = 5;     // green
80 	}
81 
82 	uint16_t sy = 0;
83 	uint16_t ma = m_vidpg;
84 	for (uint8_t y = 0; y < 16; y++)
85 	{
86 		for (uint8_t ra = 0; ra < 10; ra++)
87 		{
88 			uint16_t *p = &bitmap.pix(sy++);
89 
90 			for (uint16_t x = 0; x < 32; x++)    // done this way to avoid x overflowing on page FF
91 			{
92 				uint8_t chr = 32;
93 				if (screen_on)
94 				{
95 					chr = program.read_byte(ma | x) & 0x7f;
96 					if ((chr >= 0x61) && (chr <= 0x7a))
97 						chr &= 0x1f;
98 					else
99 						chr &= 0x3f;
100 				}
101 
102 				// get pattern of pixels for that character scanline
103 				const uint8_t gfx = m_p_chargen[(chr<<4) | ((ra & 8) >> 3) | ((ra & 7) << 1)];
104 
105 				// Display a scanline of a character
106 				*p++ = BIT(gfx, 7) ? fg : 0;
107 				*p++ = BIT(gfx, 6) ? fg : 0;
108 				*p++ = BIT(gfx, 5) ? fg : 0;
109 				*p++ = BIT(gfx, 4) ? fg : 0;
110 				*p++ = BIT(gfx, 3) ? fg : 0;
111 				*p++ = BIT(gfx, 2) ? fg : 0;
112 				*p++ = BIT(gfx, 1) ? fg : 0;
113 				*p++ = BIT(gfx, 0) ? fg : 0;
114 			}
115 		}
116 		ma += 32;
117 	}
118 	return 0;
119 }
120 
screen_update_super80d(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)121 uint32_t super80_state::screen_update_super80d(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
122 {
123 	address_space& program = m_maincpu->space(AS_PROGRAM);
124 	m_cass_led = BIT(m_portf0, 5);
125 
126 	const uint8_t options = m_io_config->read();
127 	bool screen_on = BIT(m_portf0, 2) || !BIT(options, 2); // bit 2 of port F0 is high, OR user turned on config switch
128 
129 	uint8_t fg = 0;
130 	if (screen_on)
131 	{
132 		if (BIT(options, 5))
133 			fg = 15;    // b&w
134 		else
135 			fg = 5;     // green
136 	}
137 
138 	uint16_t sy = 0;
139 	uint16_t ma = m_vidpg;
140 	for (uint8_t y = 0; y < 16; y++)
141 	{
142 		for (uint8_t ra = 0; ra < 10; ra++)
143 		{
144 			uint16_t *p = &bitmap.pix(sy++);
145 
146 			for (uint16_t x = 0; x < 32; x++)
147 			{
148 				uint8_t chr = 32;
149 				if (screen_on)
150 					chr = program.read_byte(ma | x);
151 
152 				// get pattern of pixels for that character scanline
153 				const uint8_t gfx = m_p_chargen[((chr & 0x7f)<<4) | ((ra & 8) >> 3) | ((ra & 7) << 1)] ^ ((chr & 0x80) ? 0xff : 0);
154 
155 				// Display a scanline of a character
156 				*p++ = BIT(gfx, 7) ? fg : 0;
157 				*p++ = BIT(gfx, 6) ? fg : 0;
158 				*p++ = BIT(gfx, 5) ? fg : 0;
159 				*p++ = BIT(gfx, 4) ? fg : 0;
160 				*p++ = BIT(gfx, 3) ? fg : 0;
161 				*p++ = BIT(gfx, 2) ? fg : 0;
162 				*p++ = BIT(gfx, 1) ? fg : 0;
163 				*p++ = BIT(gfx, 0) ? fg : 0;
164 			}
165 		}
166 		ma+=32;
167 	}
168 	return 0;
169 }
170 
screen_update_super80e(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)171 uint32_t super80_state::screen_update_super80e(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
172 {
173 	address_space& program = m_maincpu->space(AS_PROGRAM);
174 	m_cass_led = BIT(m_portf0, 5);
175 
176 	const uint8_t options = m_io_config->read();
177 	bool screen_on = BIT(m_portf0, 2) || !BIT(options, 2); // bit 2 of port F0 is high, OR user turned on config switch
178 
179 	uint8_t fg = 0;
180 	if (screen_on)
181 	{
182 		if (BIT(options, 5))
183 			fg = 15;    // b&w
184 		else
185 			fg = 5;     // green
186 	}
187 
188 	uint16_t sy = 0;
189 	uint16_t ma = m_vidpg;
190 	for (uint8_t y = 0; y < 16; y++)
191 	{
192 		for (uint8_t ra = 0; ra < 10; ra++)
193 		{
194 			uint16_t *p = &bitmap.pix(sy++);
195 
196 			for (uint16_t x = 0; x < 32; x++)
197 			{
198 				uint8_t chr = 32;
199 				if (screen_on)
200 					chr = program.read_byte(ma | x);
201 
202 				// get pattern of pixels for that character scanline
203 				const uint8_t gfx = m_p_chargen[(chr<<4) | ((ra & 8) >> 3) | ((ra & 7) << 1)];
204 
205 				// Display a scanline of a character
206 				*p++ = BIT(gfx, 7) ? fg : 0;
207 				*p++ = BIT(gfx, 6) ? fg : 0;
208 				*p++ = BIT(gfx, 5) ? fg : 0;
209 				*p++ = BIT(gfx, 4) ? fg : 0;
210 				*p++ = BIT(gfx, 3) ? fg : 0;
211 				*p++ = BIT(gfx, 2) ? fg : 0;
212 				*p++ = BIT(gfx, 1) ? fg : 0;
213 				*p++ = BIT(gfx, 0) ? fg : 0;
214 			}
215 		}
216 		ma+=32;
217 	}
218 	return 0;
219 }
220 
screen_update_super80m(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)221 uint32_t super80_state::screen_update_super80m(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
222 {
223 	address_space& program = m_maincpu->space(AS_PROGRAM);
224 	m_cass_led = BIT(m_portf0, 5);
225 
226 	const uint8_t options = m_io_config->read();
227 
228 	// get selected character generator
229 	const bool cgen = m_current_charset ^ BIT(options, 4); // bit 0 of port F1 and cgen config switch
230 
231 	const bool screen_on = BIT(m_portf0, 2) || !BIT(options, 2); // bit 2 of port F0 is high, OR user turned on config switch
232 
233 	uint8_t fg = 0;
234 	if (screen_on)
235 	{
236 		if (BIT(options, 5))
237 			fg = 15;    // b&w
238 		else
239 			fg = 5;     // green
240 	}
241 
242 	uint16_t sy = 0;
243 	uint16_t ma = m_vidpg;
244 	for (uint8_t y = 0; y < 16; y++)
245 	{
246 		for (uint8_t ra = 0; ra < 10; ra++)
247 		{
248 			uint16_t *p = &bitmap.pix(sy++);
249 
250 			for (uint16_t x = 0; x < 32; x++)
251 			{
252 				uint8_t chr = 32;
253 				if (screen_on)
254 					chr = program.read_byte(ma | x);
255 
256 				uint8_t bg = 0;
257 				if (!(options & 0x40))
258 				{
259 					const uint8_t col = program.read_byte(0xfe00 | ma | x); // byte of colour to display
260 					fg = m_palette_index + (col & 0x0f);
261 					bg = m_palette_index + (col >> 4);
262 				}
263 
264 				// get pattern of pixels for that character scanline
265 				uint8_t gfx;
266 				if (cgen)
267 					gfx = m_p_chargen[(chr<<4) | ((ra & 8) >> 3) | ((ra & 7) << 1)];
268 				else
269 					gfx = m_p_chargen[0x1000 | ((chr & 0x7f)<<4) | ((ra & 8) >> 3) | ((ra & 7) << 1)] ^ ((chr & 0x80) ? 0xff : 0);
270 
271 				// Display a scanline of a character
272 				*p++ = BIT(gfx, 7) ? fg : bg;
273 				*p++ = BIT(gfx, 6) ? fg : bg;
274 				*p++ = BIT(gfx, 5) ? fg : bg;
275 				*p++ = BIT(gfx, 4) ? fg : bg;
276 				*p++ = BIT(gfx, 3) ? fg : bg;
277 				*p++ = BIT(gfx, 2) ? fg : bg;
278 				*p++ = BIT(gfx, 1) ? fg : bg;
279 				*p++ = BIT(gfx, 0) ? fg : bg;
280 			}
281 		}
282 		ma+=32;
283 	}
284 	return 0;
285 }
286 
287 
288 /**************************** I/O PORTS *****************************************************************/
289 
portf1_w(u8 data)290 void super80_state::portf1_w(u8 data)
291 {
292 	m_vidpg = (data & 0xfe) << 8;
293 	m_current_charset = BIT(data, 0);
294 }
295 
296 /*---------------------------------------------------------------
297 
298     Super-80R and Super-80V
299 
300 ---------------------------------------------------------------*/
301 
302 // we place videoram at 0x0000, colour ram at 0x1000, pcg at 0x2000
low_r(offs_t offset)303 u8 super80r_state::low_r(offs_t offset)
304 {
305 	return m_vram[offset];
306 }
307 
low_w(offs_t offset,u8 data)308 void super80r_state::low_w(offs_t offset, u8 data)
309 {
310 	m_vram[offset] = data; // video
311 }
312 
high_r(offs_t offset)313 u8 super80r_state::high_r(offs_t offset)
314 {
315 	return m_vram[offset+0x0800]; // video
316 }
317 
high_w(offs_t offset,u8 data)318 void super80r_state::high_w(offs_t offset, u8 data)
319 {
320 	m_vram[offset+0x0800] = data; // video
321 	m_vram[offset+0x2800] = data; // pcg
322 }
323 
low_r(offs_t offset)324 u8 super80v_state::low_r(offs_t offset)
325 {
326 	if (BIT(m_portf0, 2))
327 		return m_vram[offset]; // video
328 	else
329 		return m_vram[offset+0x1000]; // colour
330 }
331 
low_w(offs_t offset,u8 data)332 void super80v_state::low_w(offs_t offset, u8 data)
333 {
334 	if (BIT(m_portf0, 2))
335 		m_vram[offset] = data; // video
336 	else
337 		m_vram[offset+0x1000] = data; // colour
338 }
339 
high_r(offs_t offset)340 u8 super80v_state::high_r(offs_t offset)
341 {
342 	if (!BIT(m_portf0, 2))
343 		return m_vram[offset+0x1800]; // colour
344 	else
345 	if (BIT(m_portf0, 4))
346 		return m_vram[offset+0x0800]; // video
347 	else
348 		return m_p_chargen[offset]; // char rom
349 }
350 
high_w(offs_t offset,u8 data)351 void super80v_state::high_w(offs_t offset, u8 data)
352 {
353 	if (!BIT(m_portf0, 2))
354 		m_vram[offset+0x1800] = data; // colour
355 	else
356 	{
357 		m_vram[offset+0x0800] = data; // video
358 
359 		if (BIT(m_portf0, 4))
360 			m_vram[offset+0x2800] = data; // pcg
361 	}
362 }
363 
screen_update_super80v(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)364 uint32_t super80v_state::screen_update_super80v(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
365 {
366 	m_s_options = m_io_config->read();
367 	m_cass_led = BIT(m_portf0, 5);
368 	m_crtc->screen_update(screen, bitmap, cliprect);
369 	return 0;
370 }
371 
MC6845_UPDATE_ROW(super80v_state::crtc_update_row)372 MC6845_UPDATE_ROW( super80v_state::crtc_update_row )
373 {
374 	const rgb_t *palette = m_palette->palette()->entry_list_raw();
375 	uint32_t *p = &bitmap.pix(y);
376 
377 	for (uint16_t x = 0; x < x_count; x++)               // for each character
378 	{
379 		uint8_t inv = 0;
380 		if (x == cursor_x) inv=0xff;
381 		const uint16_t mem = (ma + x) & 0xfff;
382 		uint8_t chr = m_vram[mem];
383 
384 		/* get colour or b&w */
385 		uint8_t fg = 5;            // green
386 		if ((m_s_options & 0x60) == 0x60)
387 			fg = 15;       // b&w
388 
389 		uint8_t bg = 0;
390 		if (~m_s_options & 0x40)
391 		{
392 			const uint8_t col = m_vram[mem+0x1000];                 // byte of colour to display
393 			fg = m_palette_index + (col & 0x0f);
394 			bg = m_palette_index + (col >> 4);
395 		}
396 
397 		// if inverse mode, replace any pcgram chrs with inverse chrs
398 		if (!BIT(m_portf0, 4) && BIT(chr, 7))          // is it a high chr in inverse mode
399 		{
400 			inv ^= 0xff;                        // invert the chr
401 			chr &= 0x7f;                        // and drop bit 7
402 		}
403 
404 		// get pattern of pixels for that character scanline
405 		const uint8_t gfx = BIT(chr, 7)
406 			? m_vram[0x2000 | ((chr << 4) | ra)] ^ inv
407 			: m_p_chargen[((chr << 4) | ra)] ^ inv;
408 
409 		// Display a scanline of a character
410 		*p++ = palette[BIT(gfx, 7) ? fg : bg];
411 		*p++ = palette[BIT(gfx, 6) ? fg : bg];
412 		*p++ = palette[BIT(gfx, 5) ? fg : bg];
413 		*p++ = palette[BIT(gfx, 4) ? fg : bg];
414 		*p++ = palette[BIT(gfx, 3) ? fg : bg];
415 		*p++ = palette[BIT(gfx, 2) ? fg : bg];
416 		*p++ = palette[BIT(gfx, 1) ? fg : bg];
417 	}
418 }
419 
420 
421