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