1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /**********************************************************************
4 
5     Wang PC PM-001B Medium-Resolution Video Controller emulation
6 
7 **********************************************************************/
8 
9 /*
10 
11     TODO:
12 
13     - character clock
14     - blink
15 
16 */
17 
18 #include "emu.h"
19 #include "mvc.h"
20 
21 #include "screen.h"
22 
23 
24 
25 //**************************************************************************
26 //  MACROS/CONSTANTS
27 //**************************************************************************
28 
29 #define LOG 0
30 
31 #define OPTION_ID           0x15
32 
33 #define MC6845_TAG          "mc6845"
34 #define SCREEN_TAG          "screen"
35 
36 #define VIDEO_RAM_SIZE      0x800
37 #define CHAR_RAM_SIZE       0x1000
38 #define BITMAP_RAM_SIZE     0x4000
39 
40 #define OPTION_VRAM         BIT(m_option, 0)
41 #define OPTION_VSYNC        BIT(m_option, 3)
42 
43 #define ATTR_BLINK          BIT(attr, 0)
44 #define ATTR_REVERSE        BIT(attr, 1)
45 #define ATTR_BLANK          BIT(attr, 2)
46 #define ATTR_BOLD           BIT(attr, 3)
47 #define ATTR_OVERSCORE      BIT(attr, 4)
48 #define ATTR_UNDERSCORE     BIT(attr, 5)
49 #define ATTR_SUBSCRIPT      BIT(attr, 6)
50 #define ATTR_SUPERSCRIPT    BIT(attr, 7)
51 
52 static const rgb_t PALETTE_MVC[] =
53 {
54 	rgb_t::black(),
55 	rgb_t(0x00, 0x80, 0x00),
56 	rgb_t(0x00, 0xff, 0x00)
57 };
58 
59 
60 
61 //**************************************************************************
62 //  DEVICE DEFINITIONS
63 //**************************************************************************
64 
65 DEFINE_DEVICE_TYPE(WANGPC_MVC, wangpc_mvc_device, "wangpc_mvc", "Wang PC Medium Resolution Video Card")
66 
67 
68 //-------------------------------------------------
69 //  mc6845
70 //-------------------------------------------------
71 
MC6845_UPDATE_ROW(wangpc_mvc_device::crtc_update_row)72 MC6845_UPDATE_ROW( wangpc_mvc_device::crtc_update_row )
73 {
74 	for (int sx = 0; sx < 50; sx++)
75 	{
76 		offs_t const addr = (y * 50) + sx;
77 		uint16_t data = m_bitmap_ram[addr];
78 
79 		for (int bit = 0; bit < 16; bit++)
80 		{
81 			int const x = (sx * 16) + bit;
82 			int const color = BIT(data, 15) && de;
83 
84 			bitmap.pix(vbp + y, hbp + x) = PALETTE_MVC[color];
85 
86 			data <<= 1;
87 		}
88 	}
89 
90 	for (int column = 0; column < x_count; column++)
91 	{
92 		uint16_t const code = m_video_ram[((ma + column) & 0x7ff)];
93 		uint8_t const attr = code & 0xff;
94 
95 		uint8_t new_ra = ra + 1;
96 
97 		if (ATTR_SUPERSCRIPT)
98 		{
99 			new_ra = ra + 3;
100 		}
101 		else if (ATTR_SUBSCRIPT)
102 		{
103 			new_ra = ra;
104 		}
105 
106 		offs_t const addr = ((code >> 8) << 4) | (new_ra & 0x0f);
107 		uint16_t data = m_char_ram[addr & 0xfff];
108 
109 		if ((column == cursor_x) || (!ra && ATTR_OVERSCORE) || ((ra == 9) && ATTR_UNDERSCORE))
110 		{
111 			data = 0xffff;
112 		}
113 
114 		for (int bit = 0; bit < 10; bit++)
115 		{
116 			int const x = (column * 10) + bit;
117 			int color = ((BIT(data, 9) & ~ATTR_BLANK) ^ ATTR_REVERSE);
118 
119 			if ((color | bitmap.pix(vbp + y, hbp + x)) & ATTR_BOLD)
120 				color = 2;
121 			if (color)
122 				bitmap.pix(vbp + y, hbp + x) = de ? PALETTE_MVC[color] : rgb_t::black();
123 
124 			data <<= 1;
125 		}
126 	}
127 }
128 
WRITE_LINE_MEMBER(wangpc_mvc_device::vsync_w)129 WRITE_LINE_MEMBER( wangpc_mvc_device::vsync_w )
130 {
131 	if (OPTION_VSYNC && state)
132 	{
133 		set_irq(ASSERT_LINE);
134 	}
135 }
136 
137 //-------------------------------------------------
138 //  machine_config( wangpc_mvc )
139 //-------------------------------------------------
140 
device_add_mconfig(machine_config & config)141 void wangpc_mvc_device::device_add_mconfig(machine_config &config)
142 {
143 	screen_device &screen(SCREEN(config, SCREEN_TAG, SCREEN_TYPE_RASTER));
144 	screen.set_screen_update(MC6845_TAG, FUNC(mc6845_device::screen_update));
145 	screen.set_size(80*10, 25*12);
146 	screen.set_visarea(0, 80*10-1, 0, 25*12-1);
147 	screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500));
148 	screen.set_refresh_hz(60);
149 
150 	MC6845_1(config, m_crtc, XTAL(14'318'181)/16);
151 	m_crtc->set_screen(SCREEN_TAG);
152 	m_crtc->set_show_border_area(true);
153 	m_crtc->set_char_width(10);
154 	m_crtc->set_update_row_callback(FUNC(wangpc_mvc_device::crtc_update_row));
155 	m_crtc->out_vsync_callback().set(FUNC(wangpc_mvc_device::vsync_w));
156 }
157 
158 
159 
160 //**************************************************************************
161 //  INLINE HELPERS
162 //**************************************************************************
163 
164 //-------------------------------------------------
165 //  set_irq -
166 //-------------------------------------------------
167 
set_irq(int state)168 inline void wangpc_mvc_device::set_irq(int state)
169 {
170 	m_irq = state;
171 
172 	m_bus->irq3_w(m_irq);
173 }
174 
175 
176 
177 //**************************************************************************
178 //  LIVE DEVICE
179 //**************************************************************************
180 
181 //-------------------------------------------------
182 //  wangpc_mvc_device - constructor
183 //-------------------------------------------------
184 
wangpc_mvc_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)185 wangpc_mvc_device::wangpc_mvc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
186 	device_t(mconfig, WANGPC_MVC, tag, owner, clock),
187 	device_wangpcbus_card_interface(mconfig, *this),
188 	m_crtc(*this, MC6845_TAG),
189 	m_video_ram(*this, "video_ram"),
190 	m_char_ram(*this, "char_ram"),
191 	m_bitmap_ram(*this, "bitmap_ram"),
192 	m_option(0),
193 	m_irq(CLEAR_LINE)
194 {
195 }
196 
197 
198 //-------------------------------------------------
199 //  device_start - device-specific startup
200 //-------------------------------------------------
201 
device_start()202 void wangpc_mvc_device::device_start()
203 {
204 	// allocate memory
205 	m_video_ram.allocate(VIDEO_RAM_SIZE);
206 	m_char_ram.allocate(CHAR_RAM_SIZE);
207 	m_bitmap_ram.allocate(BITMAP_RAM_SIZE);
208 
209 	// state saving
210 	save_item(NAME(m_option));
211 	save_item(NAME(m_irq));
212 }
213 
214 
215 //-------------------------------------------------
216 //  device_reset - device-specific reset
217 //-------------------------------------------------
218 
device_reset()219 void wangpc_mvc_device::device_reset()
220 {
221 	m_option = 0;
222 
223 	set_irq(CLEAR_LINE);
224 }
225 
226 
227 //-------------------------------------------------
228 //  wangpcbus_mrdc_r - memory read
229 //-------------------------------------------------
230 
wangpcbus_mrdc_r(offs_t offset,uint16_t mem_mask)231 uint16_t wangpc_mvc_device::wangpcbus_mrdc_r(offs_t offset, uint16_t mem_mask)
232 {
233 	uint16_t data = 0xffff;
234 
235 	if (OPTION_VRAM)
236 	{
237 		if (offset >= 0xe0000/2 && offset < 0xe8000/2)
238 		{
239 			data = m_bitmap_ram[offset & 0x3fff];
240 		}
241 		else if (offset >= 0xf0000/2 && offset < 0xf1000/2)
242 		{
243 			data = m_video_ram[offset & 0x7ff];
244 		}
245 		else if (offset >= 0xf2000/2 && offset < 0xf4000/2)
246 		{
247 			data = m_char_ram[offset & 0xfff];
248 		}
249 	}
250 
251 	return data;
252 }
253 
254 
255 //-------------------------------------------------
256 //  wangpcbus_amwc_w - memory write
257 //-------------------------------------------------
258 
wangpcbus_amwc_w(offs_t offset,uint16_t mem_mask,uint16_t data)259 void wangpc_mvc_device::wangpcbus_amwc_w(offs_t offset, uint16_t mem_mask, uint16_t data)
260 {
261 	if (OPTION_VRAM)
262 	{
263 		if (offset >= 0xe0000/2 && offset < 0xe8000/2)
264 		{
265 			m_bitmap_ram[offset & 0x3fff] = data;
266 		}
267 		else if (offset >= 0xf0000/2 && offset < 0xf1000/2)
268 		{
269 			m_video_ram[offset & 0x7ff] = data;
270 		}
271 		else if (offset >= 0xf2000/2 && offset < 0xf4000/2)
272 		{
273 			m_char_ram[offset & 0xfff] = data;
274 		}
275 	}
276 }
277 
278 
279 //-------------------------------------------------
280 //  wangpcbus_iorc_r - I/O read
281 //-------------------------------------------------
282 
wangpcbus_iorc_r(offs_t offset,uint16_t mem_mask)283 uint16_t wangpc_mvc_device::wangpcbus_iorc_r(offs_t offset, uint16_t mem_mask)
284 {
285 	uint16_t data = 0xffff;
286 
287 	if (sad(offset))
288 	{
289 		switch (offset & 0x7f)
290 		{
291 		case 0xfe/2:
292 			data = 0xff00 | (m_irq << 7) | OPTION_ID;
293 
294 			set_irq(CLEAR_LINE);
295 			break;
296 		}
297 	}
298 
299 	return data;
300 }
301 
302 
303 //-------------------------------------------------
304 //  wangpcbus_aiowc_w - I/O write
305 //-------------------------------------------------
306 
wangpcbus_aiowc_w(offs_t offset,uint16_t mem_mask,uint16_t data)307 void wangpc_mvc_device::wangpcbus_aiowc_w(offs_t offset, uint16_t mem_mask, uint16_t data)
308 {
309 	if (sad(offset) && ACCESSING_BITS_0_7)
310 	{
311 		switch (offset & 0x7f)
312 		{
313 		case 0x00/2:
314 			m_crtc->address_w(data & 0xff);
315 			break;
316 
317 		case 0x02/2:
318 			m_crtc->register_w(data & 0xff);
319 			break;
320 
321 		case 0x10/2:
322 		case 0x12/2:
323 			if (LOG) logerror("MVC option %02x\n", data & 0xff);
324 
325 			m_option = data & 0xff;
326 			break;
327 		}
328 	}
329 }
330