1 // license:BSD-3-Clause
2 // copyright-holders:Wilbert Pol
3 /***************************************************************************
4 
5     IBM PC junior
6     Tandy 1000 Graphics Adapter (T1T) section
7 
8     Note that in the IBM PC Junior world, the term 'vga' is not the 'vga' that
9     most people think of
10 
11 ***************************************************************************/
12 
13 #include "emu.h"
14 #include "pc_t1t.h"
15 
16 #include "machine/ram.h"
17 #include "screen.h"
18 
19 
20 enum
21 {
22 	T1000_TEXT_INTEN = 0,
23 	T1000_TEXT_BLINK,
24 	T1000_GFX_1BPP,
25 	T1000_GFX_2BPP,
26 	T1000_GFX_4BPP,
27 	T1000_GFX_2BPP_TGA,
28 	PCJX_TEXT,
29 	PCJR_GFX_2BPP_HIGH
30 };
31 
32 
33 DEFINE_DEVICE_TYPE(PCVIDEO_T1000, pcvideo_t1000_device, "tandy_1000_graphics", "Tandy 1000 Graphics Adapter")
34 DEFINE_DEVICE_TYPE(PCVIDEO_PCJR,  pcvideo_pcjr_device,  "pcjr_graphics",       "PC Jr Graphics Adapter")
35 
pc_t1t_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)36 pc_t1t_device::pc_t1t_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
37 	device_t(mconfig, type, tag, owner, clock),
38 	device_video_interface(mconfig, *this),
39 	m_mc6845(*this, T1000_MC6845_NAME),
40 	m_mode_control(0),
41 	m_color_select(0),
42 	m_status(0),
43 	m_bank(0),
44 	m_pc_framecnt(0),
45 	m_displayram(nullptr),
46 	m_chr_gen(nullptr),
47 	m_chr_size(0),
48 	m_ra_offset(0),
49 	m_address_data_ff(0),
50 	m_update_row_type(-1),
51 	m_display_enable(0),
52 	m_vsync(0),
53 	m_palette_base(0),
54 	m_palette(*this,"palette"),
55 	m_ram(*this, ":" RAM_TAG),
56 	m_vram(*this, "vram")
57 {
58 }
59 
pcvideo_t1000_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)60 pcvideo_t1000_device::pcvideo_t1000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
61 	: pc_t1t_device(mconfig, PCVIDEO_T1000, tag, owner, clock)
62 {
63 }
64 
pcvideo_pcjr_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)65 pcvideo_pcjr_device::pcvideo_pcjr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
66 	: pc_t1t_device(mconfig, PCVIDEO_PCJR, tag, owner, clock),
67 	m_pic8259(*this, ":pic8259"),
68 	m_jxkanji(nullptr)
69 {
70 }
71 
72 
device_start()73 void pcvideo_t1000_device::device_start()
74 {
75 	if(!m_ram->started())
76 		throw device_missing_dependencies();
77 	m_chr_gen = machine().root_device().memregion("gfx1")->base();
78 	m_bank = 0;
79 	m_chr_size = 1;
80 	m_ra_offset = 256;
81 	m_vram->space(0).install_ram(0, 128*1024 - 1, m_ram->pointer());
82 }
83 
84 
device_start()85 void pcvideo_pcjr_device::device_start()
86 {
87 	if(!m_ram->started())
88 		throw device_missing_dependencies();
89 	m_chr_gen = machine().root_device().memregion("gfx1")->base();
90 	m_bank = 0;
91 	m_mode_control = 0x08;
92 	m_chr_size = 8;
93 	m_ra_offset = 1;
94 	if(!strncmp(machine().system().name, "ibmpcjx", 7))
95 	{
96 		m_jxkanji = machine().root_device().memregion("kanji")->base();
97 		m_vram->space(0).install_ram(0, 128*1024 - 1, memshare(":vram")->ptr()); // TODO: fix when this is really understood
98 	}
99 	else
100 	{
101 		m_jxkanji = nullptr;
102 		m_vram->space(0).install_ram(0, 128*1024 - 1, m_ram->pointer());
103 	}
104 }
105 
106 
107 /***************************************************************************
108 
109     Static declarations
110 
111 ***************************************************************************/
112 
vram_map(address_map & map)113 void pc_t1t_device::vram_map(address_map &map)
114 {
115 	map.unmap_value_high();
116 	map(0x20000, 0x3ffff).noprw();
117 }
118 
device_add_mconfig(machine_config & config)119 void pcvideo_t1000_device::device_add_mconfig(machine_config &config)
120 {
121 	screen_device &screen(SCREEN(config, T1000_SCREEN_NAME, SCREEN_TYPE_RASTER));
122 	screen.set_raw(XTAL(14'318'181),912,0,640,262,0,200);
123 	screen.set_screen_update(T1000_MC6845_NAME, FUNC(mc6845_device::screen_update));
124 
125 	PALETTE(config, m_palette, FUNC(pcvideo_t1000_device::pcjr_palette), 32);
126 
127 	MC6845(config, m_mc6845, XTAL(14'318'181)/8);
128 	m_mc6845->set_screen(T1000_SCREEN_NAME);
129 	m_mc6845->set_show_border_area(false);
130 	m_mc6845->set_char_width(8);
131 	m_mc6845->set_update_row_callback(FUNC(pc_t1t_device::crtc_update_row));
132 	m_mc6845->out_de_callback().set(FUNC(pc_t1t_device::t1000_de_changed));
133 	m_mc6845->out_vsync_callback().set(FUNC(pcvideo_t1000_device::t1000_vsync_changed));
134 
135 	ADDRESS_MAP_BANK(config, m_vram).set_map(&pc_t1t_device::vram_map).set_options(ENDIANNESS_LITTLE, 8, 18, 0x4000);
136 }
137 
138 
device_add_mconfig(machine_config & config)139 void pcvideo_pcjr_device::device_add_mconfig(machine_config &config)
140 {
141 	screen_device &screen(SCREEN(config, T1000_SCREEN_NAME, SCREEN_TYPE_RASTER));
142 	screen.set_raw(XTAL(14'318'181), 912, 0, 640, 262, 0, 200);
143 	screen.set_screen_update(T1000_MC6845_NAME, FUNC(mc6845_device::screen_update));
144 
145 	PALETTE(config, m_palette, FUNC(pcvideo_pcjr_device::pcjr_palette), 32);
146 
147 	MC6845(config, m_mc6845, XTAL(14'318'181)/16);
148 	m_mc6845->set_screen(T1000_SCREEN_NAME);
149 	m_mc6845->set_show_border_area(false);
150 	m_mc6845->set_char_width(8);
151 	m_mc6845->set_update_row_callback(FUNC(pcvideo_pcjr_device::crtc_update_row));
152 	m_mc6845->out_de_callback().set(FUNC(pc_t1t_device::t1000_de_changed));
153 	m_mc6845->out_vsync_callback().set(FUNC(pcvideo_pcjr_device::pcjr_vsync_changed));
154 
155 	ADDRESS_MAP_BANK(config, m_vram).set_map(&pc_t1t_device::vram_map).set_options(ENDIANNESS_LITTLE, 8, 18, 0x4000);
156 }
157 
158 
159 /***************************************************************************
160 
161     Methods
162 
163 ***************************************************************************/
164 
165 /* Initialise the cga palette */
pcjr_palette(palette_device & palette) const166 void pc_t1t_device::pcjr_palette(palette_device &palette) const
167 {
168 	static constexpr rgb_t tga_palette[16] =
169 	{
170 		{ 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0xaa }, { 0x00, 0xaa, 0x00 }, { 0x00, 0xaa, 0xaa },
171 		{ 0xaa, 0x00, 0x00 }, { 0xaa, 0x00, 0xaa }, { 0xaa, 0x55, 0x00 }, { 0xaa, 0xaa, 0xaa },
172 		{ 0x55, 0x55, 0x55 }, { 0x55, 0x55, 0xff }, { 0x55, 0xff, 0x55 }, { 0x55, 0xff, 0xff },
173 		{ 0xff, 0x55, 0x55 }, { 0xff, 0x55, 0xff }, { 0xff, 0xff, 0x55 }, { 0xff, 0xff, 0xff }
174 	};
175 
176 	// colors
177 	for (int i = 0; i < 16; i++)
178 		palette.set_pen_color(i, tga_palette[i]);
179 
180 	/* b/w mode shades */
181 	for (int i = 0; i < 16; i++)
182 		palette.set_pen_color(16+i, pal4bit(i), pal4bit(i), pal4bit(i));
183 }
184 
185 
MC6845_UPDATE_ROW(pc_t1t_device::t1000_text_inten_update_row)186 MC6845_UPDATE_ROW( pc_t1t_device::t1000_text_inten_update_row )
187 {
188 	rgb_t const *const palette = m_palette->palette()->entry_list_raw();
189 	uint32_t *p = &bitmap.pix(y);
190 
191 	if ( y == 0 ) logerror("t1000_text_inten_update_row\n");
192 	for (int i = 0; i < x_count; i++)
193 	{
194 		uint16_t offset = ( ( ma + i ) << 1 ) & 0x3fff;
195 		uint8_t chr = m_displayram[ offset ];
196 		uint8_t attr = m_displayram[ offset +1 ];
197 		uint8_t data = m_chr_gen[ chr * m_chr_size + ra * m_ra_offset ];
198 		uint16_t fg = m_palette_base + ( attr & 0x0F );
199 		uint16_t bg = m_palette_base + ( ( attr >> 4 ) & 0x07 );
200 
201 		if ( i == cursor_x && ( m_pc_framecnt & 0x08 ) )
202 		{
203 			data = 0xFF;
204 		}
205 
206 		*p++ = palette[BIT(data, 7) ? fg : bg];
207 		*p++ = palette[BIT(data, 6) ? fg : bg];
208 		*p++ = palette[BIT(data, 5) ? fg : bg];
209 		*p++ = palette[BIT(data, 4) ? fg : bg];
210 		*p++ = palette[BIT(data, 3) ? fg : bg];
211 		*p++ = palette[BIT(data, 2) ? fg : bg];
212 		*p++ = palette[BIT(data, 1) ? fg : bg];
213 		*p++ = palette[BIT(data, 0) ? fg : bg];
214 	}
215 }
216 
217 
MC6845_UPDATE_ROW(pc_t1t_device::t1000_text_blink_update_row)218 MC6845_UPDATE_ROW( pc_t1t_device::t1000_text_blink_update_row )
219 {
220 	rgb_t const *const palette = m_palette->palette()->entry_list_raw();
221 	uint32_t *p = &bitmap.pix(y);
222 
223 	for (int i = 0; i < x_count; i++)
224 	{
225 		uint16_t offset = ( ( ma + i ) << 1 ) & 0x3fff;
226 		uint8_t chr = m_displayram[ offset ];
227 		uint8_t attr = m_displayram[ offset +1 ];
228 		uint8_t data = m_chr_gen[ chr * m_chr_size + ra * m_ra_offset ];
229 		uint16_t fg = m_palette_base + ( attr & 0x0F );
230 		uint16_t bg = m_palette_base + ( ( attr >> 4 ) & 0x07 );
231 
232 		if ( i == cursor_x )
233 		{
234 			if ( m_pc_framecnt & 0x08 )
235 			{
236 				data = 0xFF;
237 			}
238 		}
239 		else
240 		{
241 			if ( ( attr & 0x80 ) && ( m_pc_framecnt & 0x10 ) )
242 			{
243 				data = 0x00;
244 			}
245 		}
246 
247 		*p++ = palette[BIT(data, 7) ? fg : bg];
248 		*p++ = palette[BIT(data, 6) ? fg : bg];
249 		*p++ = palette[BIT(data, 5) ? fg : bg];
250 		*p++ = palette[BIT(data, 4) ? fg : bg];
251 		*p++ = palette[BIT(data, 3) ? fg : bg];
252 		*p++ = palette[BIT(data, 2) ? fg : bg];
253 		*p++ = palette[BIT(data, 1) ? fg : bg];
254 		*p++ = palette[BIT(data, 0) ? fg : bg];
255 	}
256 }
257 
MC6845_UPDATE_ROW(pcvideo_pcjr_device::pcjx_text_update_row)258 MC6845_UPDATE_ROW( pcvideo_pcjr_device::pcjx_text_update_row )
259 {
260 	rgb_t const *const palette = m_palette->palette()->entry_list_raw();
261 	uint32_t *p = &bitmap.pix(y);
262 
263 	for (int i = 0; i < x_count; i++)
264 	{
265 		uint16_t offset = ( ( ma + i ) << 1 ) & 0x3fff;
266 		uint8_t chr = m_displayram[ offset ];
267 		uint8_t attr = m_displayram[ offset +1 ];
268 		uint16_t fg = m_palette_base + ( attr & 0x07 );
269 		uint16_t bg = m_palette_base + ( ( attr >> 4 ) & 0x07 );
270 		uint16_t code = chr & 0x1f;
271 		if((attr & 0x88) == 0x88)
272 		{
273 			code = m_displayram[ offset - 2 ] & 0x1f;
274 			code = (code << 8) + chr;
275 		}
276 		else if(attr & 0x80)
277 			code = (code << 8) + m_displayram[ offset + 2 ];
278 		else
279 			code = chr;
280 
281 		uint8_t data;
282 		if(ra < 16)
283 			data = m_jxkanji[code * 16 * 2 + (ra * 2) + ((attr & 8)?1:0)];
284 		else
285 			data = ((i == cursor_x) && (m_pc_framecnt & 8)) ? 0xff: 0;
286 
287 		*p++ = palette[BIT(data, 7) ? fg : bg];
288 		*p++ = palette[BIT(data, 6) ? fg : bg];
289 		*p++ = palette[BIT(data, 5) ? fg : bg];
290 		*p++ = palette[BIT(data, 4) ? fg : bg];
291 		*p++ = palette[BIT(data, 3) ? fg : bg];
292 		*p++ = palette[BIT(data, 2) ? fg : bg];
293 		*p++ = palette[BIT(data, 1) ? fg : bg];
294 		*p++ = palette[BIT(data, 0) ? fg : bg];
295 	}
296 }
297 
MC6845_UPDATE_ROW(pc_t1t_device::t1000_gfx_4bpp_update_row)298 MC6845_UPDATE_ROW( pc_t1t_device::t1000_gfx_4bpp_update_row )
299 {
300 	rgb_t const *const palette = m_palette->palette()->entry_list_raw();
301 	uint32_t *p = &bitmap.pix(y);
302 	uint8_t const *const vid = m_displayram + ( ra << 13 );
303 
304 	for (int i = 0; i < x_count; i++)
305 	{
306 		uint16_t offset = ( ( ma + i ) << 1 ) & 0x1fff;
307 		uint8_t data = vid[offset];
308 
309 		*p++ = palette[m_palette_base + m_reg.data[0x10 | (data >> 4)]];
310 		*p++ = palette[m_palette_base + m_reg.data[0x10 | (data >> 4)]];
311 		*p++ = palette[m_palette_base + m_reg.data[0x10 | (data & 0x0f)]];
312 		*p++ = palette[m_palette_base + m_reg.data[0x10 | (data & 0x0f)]];
313 
314 		data = vid[offset + 1];
315 
316 		*p++ = palette[m_palette_base + m_reg.data[0x10 | (data >> 4)]];
317 		*p++ = palette[m_palette_base + m_reg.data[0x10 | (data >> 4)]];
318 		*p++ = palette[m_palette_base + m_reg.data[0x10 | (data & 0x0f)]];
319 		*p++ = palette[m_palette_base + m_reg.data[0x10 | (data & 0x0f)]];
320 	}
321 }
322 
323 
MC6845_UPDATE_ROW(pc_t1t_device::t1000_gfx_2bpp_update_row)324 MC6845_UPDATE_ROW( pc_t1t_device::t1000_gfx_2bpp_update_row )
325 {
326 	rgb_t const *const palette = m_palette->palette()->entry_list_raw();
327 	uint32_t *p = &bitmap.pix(y);
328 	uint8_t const *const vid = m_displayram + ( ra << 13 );
329 
330 	for (int i = 0; i < x_count; i++)
331 	{
332 		uint16_t offset = ( ( ma + i ) << 1 ) & 0x1fff;
333 		uint8_t data = vid[offset];
334 
335 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data >> 6) & 0x03)]];
336 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data >> 4) & 0x03)]];
337 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data >> 2) & 0x03)]];
338 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data >> 0) & 0x03)]];
339 
340 		data = vid[offset + 1];
341 
342 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data >> 6) & 0x03)]];
343 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data >> 4) & 0x03)]];
344 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data >> 2) & 0x03)]];
345 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data >> 0) & 0x03)]];
346 	}
347 }
348 
349 
MC6845_UPDATE_ROW(pcvideo_pcjr_device::pcjr_gfx_2bpp_high_update_row)350 MC6845_UPDATE_ROW( pcvideo_pcjr_device::pcjr_gfx_2bpp_high_update_row )
351 {
352 	rgb_t const *const palette = m_palette->palette()->entry_list_raw();
353 	uint32_t *p = &bitmap.pix(y);
354 	uint8_t const *const vid = m_displayram + ( ra << 13 );
355 
356 	for (int i = 0; i < x_count; i++)
357 	{
358 		uint16_t offset = ( ( ma + i ) << 1 ) & 0x1fff;
359 		uint8_t data0 = vid[offset];
360 		uint8_t data1 = vid[offset + 1];
361 
362 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data0 >> 7) & 0x01) | ((data1 >> 6) & 0x02)]];
363 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data0 >> 6) & 0x01) | ((data1 >> 5) & 0x02)]];
364 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data0 >> 5) & 0x01) | ((data1 >> 4) & 0x02)]];
365 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data0 >> 4) & 0x01) | ((data1 >> 3) & 0x02)]];
366 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data0 >> 3) & 0x01) | ((data1 >> 2) & 0x02)]];
367 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data0 >> 2) & 0x01) | ((data1 >> 1) & 0x02)]];
368 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data0 >> 1) & 0x01) | ((data1 >> 0) & 0x02)]];
369 		*p++ = palette[m_palette_base + m_reg.data[0x10 | ((data0 >> 0) & 0x01) | ((data1 << 1) & 0x02)]];
370 	}
371 }
372 
373 
MC6845_UPDATE_ROW(pc_t1t_device::t1000_gfx_2bpp_tga_update_row)374 MC6845_UPDATE_ROW( pc_t1t_device::t1000_gfx_2bpp_tga_update_row )
375 {
376 	rgb_t const *const palette = m_palette->palette()->entry_list_raw();
377 	uint32_t *p = &bitmap.pix(y);
378 	uint8_t const *const vid = m_displayram + ( ra << 13 );
379 
380 	if (y == 0) logerror("t1000_gfx_2bpp_tga_update_row\n");
381 	for (int i = 0; i < x_count; i++)
382 	{
383 		uint16_t offset = ( ( ma + i ) << 1 ) & 0x1fff;
384 		uint8_t data = vid[offset];
385 		uint8_t data2 = vid[offset + 1] << 1;
386 
387 		*p++ = palette[m_reg.data[0x10 | (((data2 & 0x100) | (data & 0x80)) >> 7)]];
388 		*p++ = palette[m_reg.data[0x10 | (((data2 & 0x080) | (data & 0x40)) >> 6)]];
389 		*p++ = palette[m_reg.data[0x10 | (((data2 & 0x040) | (data & 0x20)) >> 5)]];
390 		*p++ = palette[m_reg.data[0x10 | (((data2 & 0x020) | (data & 0x10)) >> 4)]];
391 
392 		*p++ = palette[m_reg.data[0x10 | (((data2 & 0x010) | (data & 0x08)) >> 3)]];
393 		*p++ = palette[m_reg.data[0x10 | (((data2 & 0x008) | (data & 0x04)) >> 2)]];
394 		*p++ = palette[m_reg.data[0x10 | (((data2 & 0x004) | (data & 0x02)) >> 1)]];
395 		*p++ = palette[m_reg.data[0x10 | (((data2 & 0x002) | (data & 0x01)) >> 0)]];
396 	}
397 }
398 
399 
MC6845_UPDATE_ROW(pc_t1t_device::t1000_gfx_1bpp_update_row)400 MC6845_UPDATE_ROW( pc_t1t_device::t1000_gfx_1bpp_update_row )
401 {
402 	rgb_t const *const palette = m_palette->palette()->entry_list_raw();
403 	uint32_t *p = &bitmap.pix(y);
404 	uint8_t const *const vid = m_displayram + ( ra << 13 );
405 	uint8_t fg = m_palette_base + m_reg.data[0x11];
406 	uint8_t bg = m_palette_base + m_reg.data[0x10];
407 
408 	if (y == 0) logerror("t1000_gfx_1bpp_update_row\n");
409 	for (int i = 0; i < x_count; i++)
410 	{
411 		uint16_t offset = ( ( ma + i ) << 1 ) & 0x1fff;
412 		uint8_t data = vid[offset];
413 
414 		*p++ = palette[BIT(data, 7) ? fg : bg];
415 		*p++ = palette[BIT(data, 6) ? fg : bg];
416 		*p++ = palette[BIT(data, 5) ? fg : bg];
417 		*p++ = palette[BIT(data, 4) ? fg : bg];
418 		*p++ = palette[BIT(data, 3) ? fg : bg];
419 		*p++ = palette[BIT(data, 2) ? fg : bg];
420 		*p++ = palette[BIT(data, 1) ? fg : bg];
421 		*p++ = palette[BIT(data, 0) ? fg : bg];
422 
423 		data = vid[offset + 1];
424 
425 		*p++ = palette[BIT(data, 7) ? fg : bg];
426 		*p++ = palette[BIT(data, 6) ? fg : bg];
427 		*p++ = palette[BIT(data, 5) ? fg : bg];
428 		*p++ = palette[BIT(data, 4) ? fg : bg];
429 		*p++ = palette[BIT(data, 3) ? fg : bg];
430 		*p++ = palette[BIT(data, 2) ? fg : bg];
431 		*p++ = palette[BIT(data, 1) ? fg : bg];
432 		*p++ = palette[BIT(data, 0) ? fg : bg];
433 	}
434 }
435 
MC6845_UPDATE_ROW(pc_t1t_device::crtc_update_row)436 MC6845_UPDATE_ROW( pc_t1t_device::crtc_update_row )
437 {
438 	if (m_update_row_type == -1)
439 		return;
440 
441 	switch (m_update_row_type)
442 	{
443 		case T1000_TEXT_INTEN:
444 			t1000_text_inten_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp);
445 			break;
446 		case T1000_TEXT_BLINK:
447 			t1000_text_blink_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp);
448 			break;
449 		case T1000_GFX_1BPP:
450 			t1000_gfx_1bpp_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp);
451 			break;
452 		case T1000_GFX_2BPP:
453 			t1000_gfx_2bpp_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp);
454 			break;
455 		case T1000_GFX_2BPP_TGA:
456 			t1000_gfx_2bpp_tga_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp);
457 			break;
458 		case T1000_GFX_4BPP:
459 			t1000_gfx_4bpp_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp);
460 			break;
461 	}
462 }
463 
464 
MC6845_UPDATE_ROW(pcvideo_pcjr_device::crtc_update_row)465 MC6845_UPDATE_ROW( pcvideo_pcjr_device::crtc_update_row )
466 {
467 	if (m_update_row_type == -1)
468 		return;
469 
470 	switch (m_update_row_type)
471 	{
472 		case PCJX_TEXT:
473 			pcjx_text_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp);
474 			break;
475 		case PCJR_GFX_2BPP_HIGH:
476 			pcjr_gfx_2bpp_high_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp);
477 			break;
478 		default:
479 			pc_t1t_device::crtc_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp);
480 			break;
481 	}
482 }
483 
484 
mode_switch()485 void pcvideo_t1000_device::mode_switch()
486 {
487 	switch( m_mode_control & 0x3B )
488 	{
489 	case 0x08: case 0x09:
490 		m_update_row_type = T1000_TEXT_INTEN;
491 		break;
492 	case 0x28: case 0x29:
493 		m_update_row_type = T1000_TEXT_BLINK;
494 		break;
495 	case 0x0A: case 0x0B: case 0x2A: case 0x2B:
496 		switch( m_bank & 0xc0 )
497 		{
498 		case 0x00:
499 		case 0x40:
500 			//logerror("t1t_gfx_2bpp - 1\n");
501 			m_update_row_type = T1000_GFX_2BPP;
502 			if ( m_color_select )
503 			{
504 				m_reg.data[0x10] = 0x00;
505 				m_reg.data[0x11] = 0x0B;
506 				m_reg.data[0x12] = 0x0D;
507 				m_reg.data[0x13] = 0x0F;
508 			}
509 			else
510 			{
511 				m_reg.data[0x10] = 0x00;
512 				m_reg.data[0x11] = 0x0A;
513 				m_reg.data[0x12] = 0x0C;
514 				m_reg.data[0x13] = 0x0E;
515 			}
516 			break;
517 		case 0x80:
518 		case 0xc0:
519 			//logerror("t1t_gfx_4bpp\n");
520 			m_update_row_type = T1000_GFX_4BPP;
521 			break;
522 		}
523 		break;
524 	case 0x18: case 0x19: case 0x1A: case 0x1B:
525 	case 0x38: case 0x39: case 0x3A: case 0x3B:
526 		switch( m_bank & 0xc0 )
527 		{
528 		case 0x00:
529 		case 0x40:
530 			//logerror("t1t_gfx_1bpp\n");
531 			m_update_row_type = T1000_GFX_1BPP;
532 			break;
533 		case 0x80:
534 		case 0xc0:
535 			//logerror("t1t_gfx_2bpp - 2\n");
536 			m_update_row_type = T1000_GFX_2BPP_TGA;
537 			break;
538 		}
539 		break;
540 	default:
541 		m_update_row_type = -1;
542 		break;
543 	}
544 }
545 
546 
547 /* mode control 1 ( m_reg.data[0] ) */
548 /* bit0 - 0 = low bandwidth, 1 = high bandwidth */
549 /* bit1 - 0 = alpha, 1 = graphics */
550 /* bit2 - 0 = color, 1 = b/w */
551 /* bit3 - 0 = video disable, 1 = video enable */
552 /* bit4 - 1 = 16 color graphics */
553 /* mode control 2 ( m_reg.data[3] ) */
554 /* bit1 - 1 = enable blink */
555 /* bit3 - 1 = 2 color graphics */
556 
pc_pcjr_mode_switch()557 void pcvideo_pcjr_device::pc_pcjr_mode_switch()
558 {
559 	switch( m_reg.data[0] & 0x1A )
560 	{
561 	case 0x08:      /* 01x0x */
562 		if(m_jxkanji)
563 		{
564 			m_update_row_type = PCJX_TEXT;
565 			break;
566 		}
567 		if ( m_reg.data[3] & 0x02 )
568 		{
569 			m_update_row_type = T1000_TEXT_BLINK;
570 		}
571 		else
572 		{
573 			m_update_row_type = T1000_TEXT_INTEN;
574 		}
575 		break;
576 	case 0x0A:      /* 01x1x */
577 		/* By default use medium resolution mode */
578 		m_update_row_type = T1000_GFX_2BPP;
579 
580 		/* Check for high resolution mode */
581 		if ( ( m_bank & 0xc0 ) == 0xc0 )
582 			m_update_row_type = PCJR_GFX_2BPP_HIGH;
583 
584 		/* Check for 640x200 b/w 2 shades mode */
585 		if ( ( m_reg.data[0] & 0x04 ) && ( m_reg.data[3] & 0x08 ) )
586 		{
587 			m_update_row_type = T1000_GFX_1BPP;
588 		}
589 		break;
590 	case 0x18:      /* 11x0x - invalid?? */
591 		m_update_row_type = -1;
592 		break;
593 	case 0x1A:      /* 11x1x */
594 		m_update_row_type = T1000_GFX_4BPP;
595 		break;
596 	default:
597 		m_update_row_type = -1;
598 		break;
599 	}
600 
601 	/* Determine mc6845 input clock */
602 	if ( m_reg.data[0] & 0x01 )
603 	{
604 		m_mc6845->set_unscaled_clock( XTAL(14'318'181)/8 );
605 	}
606 	else
607 	{
608 		m_mc6845->set_unscaled_clock( XTAL(14'318'181)/16 );
609 	}
610 
611 	/* color or b/w? */
612 	m_palette_base = ( m_reg.data[0] & 0x04 ) ? 16 : 0;
613 }
614 
615 
616 /*
617  * 3d8 rW   T1T mode control register (see #P138)
618  */
mode_control_w(int data)619 void pcvideo_t1000_device::mode_control_w(int data)
620 {
621 	m_mode_control = data;
622 
623 	mode_switch();
624 }
625 
mode_control_r()626 int pc_t1t_device::mode_control_r()
627 {
628 	int data = m_mode_control;
629 	return data;
630 }
631 
632 /*
633  * 3d9 ?W   color select register on color adapter
634  */
color_select_w(int data)635 void pc_t1t_device::color_select_w(int data)
636 {
637 	if (m_color_select == data)
638 		return;
639 	m_color_select = data;
640 }
641 
color_select_r()642 int pc_t1t_device::color_select_r()
643 {
644 	int data = m_color_select;
645 	return data;
646 }
647 
648 /*  Bitfields for T1T status register:
649  *  Bit(s)  Description (Table P179)
650  *  7-6 not used
651  *  5-4 color EGA, color ET4000: diagnose video display feedback, select
652  *      from color plane enable
653  *  4   holds current dot being displayed
654  *  3   in vertical retrace
655  *  2   (CGA,color EGA) light pen switch is off
656  *      (MCGA,color ET4000) reserved (0)
657  *  1   (CGA,color EGA) positive edge from light pen has set trigger
658  *      (MCGA,color ET4000) reserved (0)
659  *  0   display enabled
660  *      =0  do not use memory
661  *      =1  memory access without interfering with display
662  *      (Genoa SuperEGA) horizontal or vertical retrace
663  */
status_r()664 int pc_t1t_device::status_r()
665 {
666 	int data = m_vsync | m_status | m_display_enable;
667 	/* HACK HACK HACK */
668 	data |= ( m_display_enable ? 0x10 : 0x00 );
669 	/* end HACK */
670 	return data;
671 }
672 
673 /*
674  * 3db -W   light pen strobe reset (on any value)
675  */
lightpen_strobe_w(int data)676 void pc_t1t_device::lightpen_strobe_w(int data)
677 {
678 //  pc_port[0x3db] = data;
679 }
680 
681 
682 /*
683  * 3da -W   (mono EGA/mono VGA) feature control register
684  *          (see PORT 03DAh-W for details; VGA, see PORT 03CAh-R)
685  */
vga_index_w(int data)686 void pc_t1t_device::vga_index_w(int data)
687 {
688 	m_reg.index = data;
689 }
690 
vga_data_w(int data)691 void pcvideo_t1000_device::vga_data_w(int data)
692 {
693 	m_reg.data[m_reg.index] = data;
694 
695 	switch (m_reg.index)
696 	{
697 		case 0x00: /* mode control 1 */
698 			break;
699 		case 0x01: /* palette mask (bits 3-0) */
700 			break;
701 		case 0x02: /* border color (bits 3-0) */
702 			break;
703 		case 0x03: /* mode control 2 */
704 			break;
705 		case 0x04: /* reset register */
706 			break;
707 		/* palette array */
708 		case 0x10: case 0x11: case 0x12: case 0x13:
709 		case 0x14: case 0x15: case 0x16: case 0x17:
710 		case 0x18: case 0x19: case 0x1a: case 0x1b:
711 		case 0x1c: case 0x1d: case 0x1e: case 0x1f:
712 			m_reg.data[m_reg.index] = data & 0x0F;
713 			break;
714 	}
715 }
716 
717 
pc_pcjr_vga_data_w(int data)718 void pcvideo_pcjr_device::pc_pcjr_vga_data_w(int data)
719 {
720 	m_reg.data[m_reg.index] = data;
721 
722 	switch (m_reg.index)
723 	{
724 		case 0x00:  /* mode control 1 */
725 					/* bit0 - 0 = low bandwidth, 1 = high bandwidth */
726 					/* bit1 - 0 = alpha, 1 = graphics */
727 					/* bit2 - 0 = color, 1 = b/w */
728 					/* bit3 - 0 = video disable, 1 = video enable */
729 					/* bit4 - 1 = 16 color graphics */
730 			pc_pcjr_mode_switch();
731 			break;
732 		case 0x01:  /* palette mask (bits 3-0) */
733 			break;
734 		case 0x02:  /* border color (bits 3-0) */
735 			break;
736 		case 0x03:  /* mode control 2 */
737 					/* bit1 - 1 = enable blink */
738 					/* bit3 - 1 = 2 color graphics */
739 			pc_pcjr_mode_switch();
740 			break;
741 		case 0x04:  /* reset register */
742 			break;
743 					/* palette array */
744 		case 0x10: case 0x11: case 0x12: case 0x13:
745 		case 0x14: case 0x15: case 0x16: case 0x17:
746 		case 0x18: case 0x19: case 0x1a: case 0x1b:
747 		case 0x1c: case 0x1d: case 0x1e: case 0x1f:
748 			m_reg.data[m_reg.index] = data & 0x0F;
749 			break;
750 	}
751 }
752 
753 
vga_data_r()754 int pc_t1t_device::vga_data_r()
755 {
756 	int data = m_reg.data[m_reg.index];
757 
758 	switch (m_reg.index)
759 	{
760 		case 0x00: /* mode control 1 */
761 			break;
762 		case 0x01: /* palette mask (bits 3-0) */
763 			break;
764 		case 0x02: /* border color (bits 3-0) */
765 			break;
766 		case 0x03: /* mode control 2 */
767 			break;
768 		case 0x04: /* reset register */
769 			break;
770 		/* palette array */
771 		case 0x10: case 0x11: case 0x12: case 0x13:
772 		case 0x14: case 0x15: case 0x16: case 0x17:
773 		case 0x18: case 0x19: case 0x1a: case 0x1b:
774 		case 0x1c: case 0x1d: case 0x1e: case 0x1f:
775 			break;
776 	}
777 	return data;
778 }
779 
780 /*
781  * 3df RW   display bank, access bank, mode
782  * bit 0-2  Identifies the page of main memory being displayed in units of 16K.
783  *          0: 0K, 1: 16K...7: 112K. In 32K modes (bits 6-7 = 2) only 0,2,4 and
784  *          6 are valid, as the next page will also be used.
785  *     3-5  Identifies the page of main memory that can be read/written at B8000h
786  *          in units of 16K. 0: 0K, 1: 16K...7: 112K. In 32K modes (bits 6-7 = 2)
787  *          only 0,2,4 and 6 are valid, as the next page will also be used.
788  *     6-7  Display mode. 0: Text, 1: 16K graphics mode (4,5,6,8)
789  *          2: 32K graphics mode (9,Ah)
790  */
bank_w(int data)791 void pcvideo_t1000_device::bank_w(int data)
792 {
793 	int dram, vram;
794 	if ((data&0xc0)==0xc0) /* needed for lemmings */
795 	{
796 		dram = (m_bank & 0x06);// | ((m_bank & 0x1800) >> 8);
797 		vram = ((m_bank & 0x30) >> 3);// | ((m_bank & 0x6000) >> 10);
798 	}
799 	else
800 	{
801 		dram = (m_bank & 0x07);// | ((m_bank & 0x1800) >> 8);
802 		vram = ((m_bank & 0x38) >> 3);// | ((m_bank & 0x6000) >> 10);
803 	}
804 	m_displayram = m_ram->pointer() + (dram << 14);
805 	if(m_disable)
806 		return;
807 	m_vram->set_bank(vram);
808 	if((m_bank & 0xc0) != (data & 0xc0))
809 		mode_switch();
810 }
811 
812 
pc_pcjr_bank_w(int data)813 void pcvideo_pcjr_device::pc_pcjr_bank_w(int data)
814 {
815 	int dram, vram;
816 	m_bank = data;
817 	/* it seems the video ram is mapped to the last 128K of main memory */
818 	if ((data&0xc0)==0xc0) /* needed for lemmings */
819 	{
820 		dram = (data & 0x06);
821 		vram = (data & 0x30) >> 3;
822 	}
823 	else
824 	{
825 		dram = (data & 0x07);
826 		vram = (data & 0x38) >> 3;
827 	}
828 	m_vram->set_bank(vram);
829 	m_displayram = m_ram->pointer() + (dram << 14);
830 	if((m_bank & 0xc0) != (data & 0xc0))
831 		pc_pcjr_mode_switch();
832 }
833 
pc_pcjx_bank_w(int data)834 void pcvideo_pcjr_device::pc_pcjx_bank_w(int data)
835 {
836 	int dram, vram;
837 	m_bank = data;
838 	if ((data&0xc0)==0xc0) /* needed for lemmings */
839 	{
840 		dram = (data & 0x06);
841 		vram = (data & 0x30) >> 3;
842 	}
843 	else
844 	{
845 		dram = (data & 0x07);
846 		vram = (data & 0x38) >> 3;
847 	}
848 	m_vram->set_bank(vram);
849 	/* this certainly isn't correct but otherwise the memory test stomps on the vram */
850 	m_displayram = (uint8_t *)memshare(":vram")->ptr() + (dram << 14);
851 	if((m_bank & 0xc0) != (data & 0xc0))
852 		pc_pcjr_mode_switch();
853 }
854 
bank_r()855 int pc_t1t_device::bank_r()
856 {
857 	return m_bank;
858 }
859 
860 /*************************************************************************
861  *
862  *      T1T
863  *      Tandy 1000 / PCjr
864  *
865  *************************************************************************/
866 
write(offs_t offset,uint8_t data)867 void pcvideo_t1000_device::write(offs_t offset, uint8_t data)
868 {
869 	switch( offset )
870 	{
871 		case 0: case 2: case 4: case 6:
872 			m_mc6845->address_w(data);
873 			break;
874 		case 1: case 3: case 5: case 7:
875 			m_mc6845->register_w(data);
876 			break;
877 		case 8:
878 			mode_control_w(data);
879 			break;
880 		case 9:
881 			color_select_w(data);
882 			break;
883 		case 10:
884 			vga_index_w(data);
885 			break;
886 		case 11:
887 			lightpen_strobe_w(data);
888 			break;
889 		case 12:
890 			break;
891 		case 13:
892 			m_bank = (data << 8) | (m_bank & 0xff);
893 			bank_w(m_bank);
894 			break;
895 		case 14:
896 			vga_data_w(data);
897 			break;
898 		case 15:
899 			m_bank = (m_bank & 0xff00) | data;
900 			bank_w(data);
901 			break;
902 	}
903 }
904 
write(offs_t offset,uint8_t data)905 void pcvideo_pcjr_device::write(offs_t offset, uint8_t data)
906 {
907 	switch( offset )
908 	{
909 		case 0: case 4:
910 			m_mc6845->address_w(data);
911 			break;
912 		case 1: case 5:
913 			m_mc6845->register_w(data);
914 			break;
915 		case 10:
916 			if ( m_address_data_ff & 0x01 )
917 			{
918 				pc_pcjr_vga_data_w( data );
919 			}
920 			else
921 			{
922 				vga_index_w( data );
923 			}
924 			m_address_data_ff ^= 0x01;
925 			break;
926 		case 11:
927 			lightpen_strobe_w(data);
928 			break;
929 		case 12:
930 			break;
931 		case 15:
932 			if(m_jxkanji)
933 				pc_pcjx_bank_w(data);
934 			else
935 				pc_pcjr_bank_w(data);
936 			break;
937 
938 		default:
939 			break;
940 	}
941 }
942 
943 
read(offs_t offset)944 uint8_t pc_t1t_device::read(offs_t offset)
945 {
946 	int             data = 0xff;
947 
948 	switch( offset )
949 	{
950 		case 0: case 2: case 4: case 6:
951 			/* return last written mc6845 address value here? */
952 			break;
953 
954 		case 1: case 3: case 5: case 7:
955 			data = m_mc6845->register_r();
956 			break;
957 
958 		case 8:
959 			data = mode_control_r();
960 			break;
961 
962 		case 9:
963 			data = color_select_r();
964 			break;
965 
966 		case 10:
967 			m_address_data_ff = 0;
968 			data = status_r();
969 			break;
970 
971 		case 11:
972 			/* -W lightpen strobe reset */
973 			break;
974 
975 		case 12:
976 		case 13:
977 			break;
978 
979 		case 14:
980 			data = vga_data_r();
981 			break;
982 
983 		case 15:
984 			data = bank_r();
985 			break;
986 	}
987 	return data;
988 }
989 
WRITE_LINE_MEMBER(pc_t1t_device::t1000_de_changed)990 WRITE_LINE_MEMBER( pc_t1t_device::t1000_de_changed )
991 {
992 	m_display_enable = state ? 1 : 0;
993 }
994 
995 
WRITE_LINE_MEMBER(pcvideo_t1000_device::t1000_vsync_changed)996 WRITE_LINE_MEMBER( pcvideo_t1000_device::t1000_vsync_changed )
997 {
998 	m_vsync = state ? 8 : 0;
999 	if ( state )
1000 	{
1001 		m_pc_framecnt++;
1002 	}
1003 }
1004 
WRITE_LINE_MEMBER(pcvideo_t1000_device::disable_w)1005 WRITE_LINE_MEMBER( pcvideo_t1000_device::disable_w )
1006 {
1007 	if(state)
1008 		m_vram->set_bank(8);
1009 	else
1010 		bank_w(m_bank);
1011 	m_disable = state ? true : false;
1012 }
1013 
WRITE_LINE_MEMBER(pcvideo_pcjr_device::pcjr_vsync_changed)1014 WRITE_LINE_MEMBER( pcvideo_pcjr_device::pcjr_vsync_changed )
1015 {
1016 	m_vsync = state ? 8 : 0;
1017 	if ( state )
1018 	{
1019 		m_pc_framecnt++;
1020 	}
1021 	m_pic8259->ir5_w(state);
1022 }
1023