summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/video/oric.c
blob: 054515d1e92b14c14e58b451094d46619351b2b4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/***************************************************************************

    video/oric.c

    All graphic effects are supported including mid-line changes.
    There may be some small bugs.

    TODO:
    - speed up this code a bit?

***************************************************************************/

#include "includes/oric.h"

TIMER_CALLBACK_MEMBER(oric_state::oric_vh_timer_callback)
{
	/* update flash count */
	m_vh_state.flash_count++;
}

void oric_state::oric_vh_update_flash()
{
	/* flash active? */
	if (BIT(m_vh_state.text_attributes, 2))
	{
		/* yes */

		/* show or hide text? */
		if (BIT(m_vh_state.flash_count, 4))
		{
			/* hide */
			/* set foreground and background to be the same */
			m_vh_state.active_foreground_colour = m_vh_state.background_colour;
			m_vh_state.active_background_colour = m_vh_state.background_colour;
			return;
		}
	}


	/* show */
	m_vh_state.active_foreground_colour = m_vh_state.foreground_colour;
	m_vh_state.active_background_colour = m_vh_state.background_colour;
}

/* the alternate charset follows from the standard charset.
Each charset holds 128 chars with 8 bytes for each char.

The start address for the standard charset is dependant on the video mode */
void oric_state::oric_refresh_charset()
{
	/* alternate char set? */
	if (BIT(m_vh_state.text_attributes, 0))
	{
		/* yes */
		m_vh_state.char_data = m_vh_state.char_base + (128*8);
	}
	else
	{
		/* no */
		m_vh_state.char_data = m_vh_state.char_base;
	}
}

/* update video hardware state depending on the new attribute */
void oric_state::oric_vh_update_attribute(UINT8 c)
{
	/* attribute */
	UINT8 attribute = c & 0x03f;
	address_space &space = m_maincpu->space(AS_PROGRAM);

	switch ((attribute>>3) & 0x03)
	{
		case 0:
		{
			/* set foreground colour 00-07 = black,red,green,yellow,blue,magenta,cyan,white */
			m_vh_state.foreground_colour = attribute & 0x07;
			oric_vh_update_flash();
		}
		break;

		case 1:
		{
			m_vh_state.text_attributes = attribute & 0x07;

			oric_refresh_charset();

			/* text attributes */
			oric_vh_update_flash();
		}
		break;

		case 2:
		{
			/* set background colour */
			m_vh_state.background_colour = attribute & 0x07;
			oric_vh_update_flash();
		}
		break;

		case 3:
		{
			/* set video mode */
			m_vh_state.mode = attribute & 0x07;

			// a different charset base is used depending on the video mode
			// hires takes all the data from 0x0a000 through to about 0x0bf68,
			// so the charset is moved to 0x09800 */
			// text mode starts at 0x0bb80 and so the charset is in a different location
			if (BIT(m_vh_state.mode, 2))
			{
				/* set screen memory base and standard charset location for this mode */
				m_vh_state.read_addr = 0x0a000;
				if (m_ram)
					m_vh_state.char_base = m_ram + (offs_t)0x09800;
				else
					m_vh_state.char_base = (UINT8 *)space.get_read_ptr(0x09800);
			}
			else
			{
				/* set screen memory base and standard charset location for this mode */
				m_vh_state.read_addr = 0x0bb80;
				if (m_ram)
					m_vh_state.char_base = m_ram + (offs_t)0x0b400;
				else
					m_vh_state.char_base = (UINT8 *)space.get_read_ptr(0x0b400);
			}
			/* changing the mode also changes the position of the standard charset and alternative charset */
			oric_refresh_charset();
		}
		break;

		default:
			break;
	}
}


/* render 6-pixels using foreground and background colours specified */
/* used in hires and text mode */
void oric_state::oric_vh_render_6pixels(bitmap_ind16 &bitmap, int x, UINT8 y, UINT8 fg, UINT8 bg, UINT8 data, bool invert_flag)
{
	/* invert? */
	if (invert_flag)
	{
		fg ^=0x07;
		bg ^=0x07;
	}

	bitmap.pix16(y, x++) = BIT(data, 5) ? fg : bg;
	bitmap.pix16(y, x++) = BIT(data, 4) ? fg : bg;
	bitmap.pix16(y, x++) = BIT(data, 3) ? fg : bg;
	bitmap.pix16(y, x++) = BIT(data, 2) ? fg : bg;
	bitmap.pix16(y, x++) = BIT(data, 1) ? fg : bg;
	bitmap.pix16(y, x++) = BIT(data, 0) ? fg : bg;
}





/***************************************************************************
  oric_vh_screenrefresh
***************************************************************************/
UINT32 oric_state::screen_update_oric(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	UINT8 *RAM, y;
	offs_t byte_offset, read_addr_base;
	bool hires_active;
	address_space &space = m_maincpu->space(AS_PROGRAM);

	RAM = m_ram;

	/* set initial base */
	read_addr_base = m_vh_state.read_addr;

	/* is hires active? */
	hires_active = BIT(m_vh_state.mode, 2);

	for (y = 0; y < 224; y++)
	{
		int x = 0;

		/* foreground colour white */
		oric_vh_update_attribute(7);
		/* background colour black */
		oric_vh_update_attribute((1<<3));
		oric_vh_update_attribute((1<<4));

		for (byte_offset=0; byte_offset<40; byte_offset++)
		{
			UINT8 c;
			offs_t read_addr;

			/* after line 200 all rendering is done in text mode */
			if (y<200)
			{
				/* calculate fetch address based on current line and current mode */
				if (hires_active)
				{
					read_addr = read_addr_base + byte_offset + (offs_t)(y*40);
				}
				else
				{
					UINT8 char_line = y>>3;
					read_addr = read_addr_base + byte_offset + (offs_t)(char_line*40);
				}
			}
			else
			{
				UINT8 char_line = (y-200)>>3;
				read_addr = read_addr_base + byte_offset + (offs_t)(char_line*40);
			}

			/* fetch data */
			c = RAM ? RAM[read_addr] : space.read_byte(read_addr);

			/* if bits 6 and 5 are zero, the byte contains a serial attribute */
			if ((c & ((1 << 6) | (1 << 5))) == 0)
			{
				oric_vh_update_attribute(c);

				/* display background colour when attribute has been found */
				oric_vh_render_6pixels(bitmap, x, y, m_vh_state.active_foreground_colour, m_vh_state.active_background_colour, 0, (c & 0x080));

				if (y < 200)
				{
					/* is hires active? */
					hires_active = BIT(m_vh_state.mode, 2);
					read_addr_base = m_vh_state.read_addr;
				}
			}
			else
			{
				/* hires? */
				if (hires_active)
				{
					UINT8 pixel_data = c & 0x03f;
					/* plot hires pixels */
					oric_vh_render_6pixels(bitmap,x,y,m_vh_state.active_foreground_colour, m_vh_state.active_background_colour, pixel_data, BIT(c, 7));
				}
				else
				{
					UINT8 char_index, char_data, ch_line;

					char_index = (c & 0x07f);

					ch_line = y & 7;

					/* is double height set? */
					if (BIT(m_vh_state.text_attributes, 1))
					{
					/* if char line is even, top half of character is displayed else bottom half */
						UINT8 double_height_flag = BIT(y, 3);

						/* calculate line to fetch */
						ch_line = (ch_line>>1) + (double_height_flag<<2);
					}

					/* fetch pixel data for this char line */
					char_data = m_vh_state.char_data[(char_index<<3) | ch_line] & 0x03f;

					/* draw! */
					oric_vh_render_6pixels(bitmap,x,y,
						m_vh_state.active_foreground_colour,
						m_vh_state.active_background_colour, char_data, BIT(c, 7));
				}

			}

			x+=6;
		}

		/* after 200 lines have been drawn, force a change of the read address */
		/* there are 200 lines of hires/text mode, then 24 lines of text mode */
		/* the mode can't be changed in the last 24 lines. */
		if (y==199)
		{
			/* mode */
			read_addr_base = (offs_t)0x0bf68;
			hires_active = 0;
		}
	}
	return 0;
}


void oric_state::video_start()
{
	// initialise variables
	m_vh_state.active_foreground_colour = 0;
	m_vh_state.active_background_colour = 0;
	m_vh_state.foreground_colour = 0;
	m_vh_state.background_colour = 0;
	m_vh_state.mode = 0;
	m_vh_state.text_attributes = 0;
	m_vh_state.read_addr = 0;
	m_vh_state.char_data = 0;
	m_vh_state.char_base = 0;
	/* initialise flash timer */
	m_vh_state.flash_count = 0;
	machine().scheduler().timer_pulse(attotime::from_hz(50), timer_expired_delegate(FUNC(oric_state::oric_vh_timer_callback),this));
	/* mode */
	oric_vh_update_attribute((1<<3)|(1<<4));
}