1 // license:BSD-3-Clause
2 // copyright-holders:R. Belmont
3 /***************************************************************************
4 
5   Lapis ProColor Server 8*16 video card
6 
7   FsFF6001: DAC color # (seems to have the data bits perfectly reversed)
8   FsFF6003: DAC color write (not bitswapped)
9   FsFF6017: Mode (13 = 1bpp, 17 = 2bpp, 1b = 4bpp, 1e = 8bpp, 0a = 15bpp)
10   FsFF7000: Bit 2 is VBL IRQ enable/ack
11   FsFF7001: Bit 0 is VBL status
12 
13 ***************************************************************************/
14 
15 #include "emu.h"
16 #include "pds30_procolor816.h"
17 #include "screen.h"
18 
19 #define PROCOLOR816_SCREEN_NAME "cb264_screen"
20 #define PROCOLOR816_ROM_REGION  "cb264_rom"
21 
22 #define VRAM_SIZE   (0x200000)  // 2 megs?
23 
24 
25 ROM_START( procolor816 )
26 	ROM_REGION(0x8000, PROCOLOR816_ROM_REGION, 0)
CRC(ebef6168)27 	ROM_LOAD( "procolor_ver60590.bin", 0x000000, 0x008000, CRC(ebef6168) SHA1(e41ecc7d12fc13bc74f9223ca02920e8a7eb072b) )
28 ROM_END
29 
30 //**************************************************************************
31 //  GLOBAL VARIABLES
32 //**************************************************************************
33 
34 DEFINE_DEVICE_TYPE(PDS030_PROCOLOR816, nubus_procolor816_device, "pd3_pc16", "Lapis ProColor Server 8*16")
35 
36 
37 //-------------------------------------------------
38 //  device_add_mconfig - add device configuration
39 //-------------------------------------------------
40 
41 void nubus_procolor816_device::device_add_mconfig(machine_config &config)
42 {
43 	screen_device &screen(SCREEN(config, PROCOLOR816_SCREEN_NAME, SCREEN_TYPE_RASTER));
44 	screen.set_screen_update(FUNC(nubus_procolor816_device::screen_update));
45 	screen.set_raw(25175000, 800, 0, 640, 525, 0, 480);
46 	screen.set_size(1024, 768);
47 	screen.set_visarea(0, 640-1, 0, 480-1);
48 }
49 
50 //-------------------------------------------------
51 //  rom_region - device-specific ROM region
52 //-------------------------------------------------
53 
device_rom_region() const54 const tiny_rom_entry *nubus_procolor816_device::device_rom_region() const
55 {
56 	return ROM_NAME( procolor816 );
57 }
58 
59 //**************************************************************************
60 //  LIVE DEVICE
61 //**************************************************************************
62 
63 //-------------------------------------------------
64 //  nubus_procolor816_device - constructor
65 //-------------------------------------------------
66 
nubus_procolor816_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)67 nubus_procolor816_device::nubus_procolor816_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
68 	nubus_procolor816_device(mconfig, PDS030_PROCOLOR816, tag, owner, clock)
69 {
70 }
71 
nubus_procolor816_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)72 nubus_procolor816_device::nubus_procolor816_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
73 	device_t(mconfig, type, tag, owner, clock),
74 	device_video_interface(mconfig, *this),
75 	device_nubus_card_interface(mconfig, *this),
76 	m_vram32(nullptr), m_mode(0), m_vbl_disable(0), m_toggle(0), m_count(0), m_clutoffs(0), m_timer(nullptr)
77 {
78 	set_screen(*this, PROCOLOR816_SCREEN_NAME);
79 }
80 
81 //-------------------------------------------------
82 //  device_start - device-specific startup
83 //-------------------------------------------------
84 
device_start()85 void nubus_procolor816_device::device_start()
86 {
87 	uint32_t slotspace;
88 
89 	install_declaration_rom(this, PROCOLOR816_ROM_REGION);
90 
91 	slotspace = get_slotspace();
92 
93 //  printf("[procolor816 %p] slotspace = %x\n", this, slotspace);
94 
95 	m_vram.resize(VRAM_SIZE);
96 	m_vram32 = (uint32_t *)&m_vram[0];
97 
98 	nubus().install_device(slotspace, slotspace+VRAM_SIZE-1, read32s_delegate(*this, FUNC(nubus_procolor816_device::vram_r)), write32s_delegate(*this, FUNC(nubus_procolor816_device::vram_w)));
99 	nubus().install_device(slotspace+0x900000, slotspace+VRAM_SIZE-1+0x900000, read32s_delegate(*this, FUNC(nubus_procolor816_device::vram_r)), write32s_delegate(*this, FUNC(nubus_procolor816_device::vram_w)));
100 	nubus().install_device(slotspace+0xf00000, slotspace+0xff7fff, read32s_delegate(*this, FUNC(nubus_procolor816_device::procolor816_r)), write32s_delegate(*this, FUNC(nubus_procolor816_device::procolor816_w)));
101 
102 	m_timer = timer_alloc(0, nullptr);
103 	m_timer->adjust(screen().time_until_pos(479, 0), 0);
104 }
105 
106 //-------------------------------------------------
107 //  device_reset - device-specific reset
108 //-------------------------------------------------
109 
device_reset()110 void nubus_procolor816_device::device_reset()
111 {
112 	m_count = 0;
113 	m_clutoffs = 0;
114 	m_vbl_disable = 1;
115 	m_mode = 3;
116 	memset(&m_vram[0], 0, VRAM_SIZE);
117 	memset(m_palette, 0, sizeof(m_palette));
118 
119 	m_palette[0] = rgb_t(255, 255, 255);
120 	m_palette[0x80] = rgb_t(0, 0, 0);
121 }
122 
123 
device_timer(emu_timer & timer,device_timer_id tid,int param,void * ptr)124 void nubus_procolor816_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
125 {
126 	if (!m_vbl_disable)
127 	{
128 		raise_slot_irq();
129 	}
130 
131 	m_timer->adjust(screen().time_until_pos(479, 0), 0);
132 }
133 
134 /***************************************************************************
135 
136   CB264 section
137 
138 ***************************************************************************/
139 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)140 uint32_t nubus_procolor816_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
141 {
142 	uint8_t const *const vram = &m_vram[4];
143 
144 	switch (m_mode)
145 	{
146 		case 0: // 1 bpp?
147 			for (int y = 0; y < 480; y++)
148 			{
149 				uint32_t *scanline = &bitmap.pix(y);
150 				for (int x = 0; x < 640/8; x++)
151 				{
152 					uint8_t const pixels = vram[(y * 640/8) + (BYTE4_XOR_BE(x))];
153 
154 					*scanline++ = m_palette[(pixels&0x80)];
155 					*scanline++ = m_palette[((pixels<<1)&0x80)];
156 					*scanline++ = m_palette[((pixels<<2)&0x80)];
157 					*scanline++ = m_palette[((pixels<<3)&0x80)];
158 					*scanline++ = m_palette[((pixels<<4)&0x80)];
159 					*scanline++ = m_palette[((pixels<<5)&0x80)];
160 					*scanline++ = m_palette[((pixels<<6)&0x80)];
161 					*scanline++ = m_palette[((pixels<<7)&0x80)];
162 				}
163 			}
164 			break;
165 
166 		case 1: // 2 bpp
167 			for (int y = 0; y < 480; y++)
168 			{
169 				uint32_t *scanline = &bitmap.pix(y);
170 				for (int x = 0; x < 640/4; x++)
171 				{
172 					uint8_t const pixels = vram[(y * 640/4) + (BYTE4_XOR_BE(x))];
173 
174 					*scanline++ = m_palette[(pixels&0xc0)];
175 					*scanline++ = m_palette[((pixels<<2)&0xc0)];
176 					*scanline++ = m_palette[((pixels<<4)&0xc0)];
177 					*scanline++ = m_palette[((pixels<<6)&0xc0)];
178 				}
179 			}
180 			break;
181 
182 		case 2: // 4 bpp
183 			for (int y = 0; y < 480; y++)
184 			{
185 				uint32_t *scanline = &bitmap.pix(y);
186 				for (int x = 0; x < 640/2; x++)
187 				{
188 					uint8_t const pixels = vram[(y * 640/2) + (BYTE4_XOR_BE(x))];
189 
190 					*scanline++ = m_palette[(pixels&0xf0)];
191 					*scanline++ = m_palette[((pixels&0x0f)<<4)];
192 				}
193 			}
194 			break;
195 
196 		case 3: // 8 bpp
197 			for (int y = 0; y < 480; y++)
198 			{
199 				uint32_t *scanline = &bitmap.pix(y);
200 				for (int x = 0; x < 640; x++)
201 				{
202 					uint8_t const pixels = vram[(y * 640) + (BYTE4_XOR_BE(x))];
203 					*scanline++ = m_palette[pixels];
204 				}
205 			}
206 			break;
207 
208 		case 4: // 15 bpp
209 			{
210 				uint16_t const *const vram16 = (uint16_t *)&m_vram[0];
211 
212 				for (int y = 0; y < 480; y++)
213 				{
214 					uint32_t *scanline = &bitmap.pix(y);
215 					for (int x = 0; x < 640; x++)
216 					{
217 						uint16_t const pixels = vram16[(y * 640) + BYTE_XOR_BE(x)];
218 						*scanline++ = rgb_t(pal5bit((pixels>>10) & 0x1f), pal5bit((pixels>>5) & 0x1f), pal5bit(pixels & 0x1f));
219 					}
220 				}
221 			}
222 			break;
223 
224 		default:
225 			fatalerror("procolor816: unknown video mode %d\n", m_mode);
226 	}
227 	return 0;
228 }
229 
procolor816_w(offs_t offset,uint32_t data,uint32_t mem_mask)230 void nubus_procolor816_device::procolor816_w(offs_t offset, uint32_t data, uint32_t mem_mask)
231 {
232 	switch (offset)
233 	{
234 		case 0x3d805:           // mode
235 			if (mem_mask == 0xff)
236 			{
237 				switch (data & 0xff)
238 				{
239 					case 0x13:
240 						m_mode = 0;
241 						break;
242 
243 					case 0x17:
244 						m_mode = 1;
245 						break;
246 
247 					case 0x1b:
248 						m_mode = 2;
249 						break;
250 
251 					case 0x1e:
252 						m_mode = 3;
253 						break;
254 
255 					case 0x0a:
256 						m_mode = 4;
257 						break;
258 				}
259 			}
260 			break;
261 
262 		case 0x3d800:
263 			if (mem_mask == 0x00ff0000)
264 			{
265 		//          printf("%s %08x to DAC control\n", machine().describe_context().c_str(), data);
266 					m_clutoffs = bitswap<8>((data>>16)&0xff, 0, 1, 2, 3, 4, 5, 6, 7);
267 			}
268 			else if (mem_mask == 0x000000ff)
269 			{
270 					m_colors[m_count++] = (data & 0xff);
271 
272 					if (m_count == 3)
273 					{
274 //                        printf("%s RAMDAC: color %02x = %02x %02x %02x\n", machine().describe_context().c_str(), m_clutoffs, m_colors[0], m_colors[1], m_colors[2]);
275 						m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]);
276 						m_clutoffs++;
277 						if (m_clutoffs > 255)
278 						{
279 							m_clutoffs = 0;
280 						}
281 						m_count = 0;
282 					}
283 			}
284 			break;
285 
286 	case 0x3dc00:   // VBL control
287 			if (mem_mask == 0xff000000)
288 			{
289 				if (data & 0x04000000)
290 				{
291 					m_vbl_disable = 0;
292 					lower_slot_irq();
293 				}
294 				else
295 				{
296 					m_vbl_disable = 1;
297 				}
298 			}
299 			break;
300 
301 		default:
302 //            printf("%s procolor816_w: %08x @ %x, mask %08x\n", machine().describe_context().c_str(), data, offset, mem_mask);
303 			break;
304 	}
305 }
306 
procolor816_r(offs_t offset,uint32_t mem_mask)307 uint32_t nubus_procolor816_device::procolor816_r(offs_t offset, uint32_t mem_mask)
308 {
309 	if (offset == 0x3dc00)
310 	{
311 		m_toggle ^= 0xffffffff;
312 		return m_toggle;
313 	}
314 	else if (offset == 0x3d807)
315 	{
316 		return 0;
317 	}
318 	else
319 	{
320 //      printf("procolor816_r: @ %x, mask %08x [PC=%x]\n", offset, mem_mask, machine().device<cpu_device>("maincpu")->pc());
321 	}
322 
323 	return 0;
324 }
325 
vram_w(offs_t offset,uint32_t data,uint32_t mem_mask)326 void nubus_procolor816_device::vram_w(offs_t offset, uint32_t data, uint32_t mem_mask)
327 {
328 	COMBINE_DATA(&m_vram32[offset]);
329 }
330 
vram_r(offs_t offset,uint32_t mem_mask)331 uint32_t nubus_procolor816_device::vram_r(offs_t offset, uint32_t mem_mask)
332 {
333 	return m_vram32[offset];
334 }
335