1 // license:BSD-3-Clause
2 // copyright-holders:R. Belmont
3 /***************************************************************************
4 
5   Apple 4*8 Graphics Card (model 630-0400) emulation
6   Apple 8*24 Graphics Card emulation (cards have the same framebuffer chip
7       w/different ROMs and RAMDACs, apparently)
8 
9 ***************************************************************************/
10 
11 #include "emu.h"
12 #include "nubus_48gc.h"
13 #include "screen.h"
14 
15 #include <algorithm>
16 
17 
18 #define VRAM_SIZE  (0x200000)  // 2 megs, maxed out
19 
20 #define GC48_SCREEN_NAME    "48gc_screen"
21 #define GC48_ROM_REGION     "48gc_rom"
22 
23 ROM_START( gc48 )
24 	ROM_REGION(0x8000, GC48_ROM_REGION, 0)
CRC(e283da91)25 	ROM_LOAD( "3410801.bin",  0x0000, 0x8000, CRC(e283da91) SHA1(4ae21d6d7bbaa6fc7aa301bee2b791ed33b1dcf9) )
26 ROM_END
27 
28 ROM_START( gc824 )
29 	ROM_REGION(0x8000, GC48_ROM_REGION, 0)
30 	ROM_LOAD( "3410868.bin",  0x000000, 0x008000, CRC(57f925fa) SHA1(4d3c0632711b7b31c8e0c5cfdd7ec1904f178336) ) /* Label: "341-0868 // (C)APPLE COMPUTER // INC. 1986-1991 // ALL RIGHTS // RESERVED    W5" */
31 ROM_END
32 
33 //**************************************************************************
34 //  GLOBAL VARIABLES
35 //**************************************************************************
36 
37 DEFINE_DEVICE_TYPE(NUBUS_48GC,  nubus_48gc_device,  "nb_48gc",  "Apple 4*8 video card")
38 DEFINE_DEVICE_TYPE(NUBUS_824GC, nubus_824gc_device, "nb_824gc", "Apple 8*24 video card")
39 
40 
41 //-------------------------------------------------
42 //  device_add_mconfig - add device configuration
43 //-------------------------------------------------
44 
45 void jmfb_device::device_add_mconfig(machine_config &config)
46 {
47 	screen_device &screen(SCREEN(config, GC48_SCREEN_NAME, SCREEN_TYPE_RASTER));
48 	screen.set_screen_update(FUNC(jmfb_device::screen_update));
49 	screen.set_raw(25175000, 800, 0, 640, 525, 0, 480);
50 //  screen.set_size(1152, 870);
51 //  screen.set_visarea(0, 1152-1, 0, 870-1);
52 //  screen.set_refresh_hz(75);
53 //  screen.set_vblank_time(ATTOSECONDS_IN_USEC(1260));
54 }
55 
56 //-------------------------------------------------
57 //  rom_region - device-specific ROM region
58 //-------------------------------------------------
59 
device_rom_region() const60 const tiny_rom_entry *jmfb_device::device_rom_region() const
61 {
62 	return ROM_NAME( gc48 );
63 }
64 
device_rom_region() const65 const tiny_rom_entry *nubus_824gc_device::device_rom_region() const
66 {
67 	return ROM_NAME( gc824 );
68 }
69 
70 //**************************************************************************
71 //  LIVE DEVICE
72 //**************************************************************************
73 
74 //-------------------------------------------------
75 //  jmfb_device - constructor
76 //-------------------------------------------------
77 
jmfb_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock,bool is824)78 jmfb_device::jmfb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool is824) :
79 	device_t(mconfig, type, tag, owner, clock),
80 	device_video_interface(mconfig, *this),
81 	device_nubus_card_interface(mconfig, *this),
82 	m_screen(nullptr), m_timer(nullptr), m_mode(0), m_vbl_disable(0), m_toggle(0), m_stride(0), m_base(0), m_count(0), m_clutoffs(0), m_xres(0), m_yres(0),
83 	m_is824(is824)
84 {
85 	set_screen(*this, GC48_SCREEN_NAME);
86 }
87 
nubus_48gc_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)88 nubus_48gc_device::nubus_48gc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
89 	jmfb_device(mconfig, NUBUS_48GC, tag, owner, clock, false)
90 {
91 }
92 
nubus_824gc_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)93 nubus_824gc_device::nubus_824gc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
94 	jmfb_device(mconfig, NUBUS_824GC, tag, owner, clock, true)
95 {
96 }
97 
98 //-------------------------------------------------
99 //  device_start - device-specific startup
100 //-------------------------------------------------
101 
device_start()102 void jmfb_device::device_start()
103 {
104 	uint32_t slotspace;
105 
106 	install_declaration_rom(this, GC48_ROM_REGION);
107 
108 	slotspace = get_slotspace();
109 
110 //  printf("[JMFB %p] slotspace = %x\n", this, slotspace);
111 
112 	m_vram.resize(VRAM_SIZE);
113 	install_bank(slotspace, slotspace+VRAM_SIZE-1, "bank_48gc", &m_vram[0]);
114 
115 	nubus().install_device(slotspace+0x200000, slotspace+0x2003ff, read32s_delegate(*this, FUNC(jmfb_device::mac_48gc_r)), write32s_delegate(*this, FUNC(jmfb_device::mac_48gc_w)));
116 
117 	m_timer = timer_alloc(0, nullptr);
118 	m_screen = nullptr;    // can we look this up now?
119 }
120 
121 //-------------------------------------------------
122 //  device_reset - device-specific reset
123 //-------------------------------------------------
124 
device_reset()125 void jmfb_device::device_reset()
126 {
127 	m_toggle = 0;
128 	m_clutoffs = 0;
129 	m_count = 0;
130 	m_vbl_disable = 1;
131 	m_stride = 80;
132 	m_base = 0;
133 	m_xres = 640;
134 	m_yres = 480;
135 	m_mode = 0;
136 	memset(&m_vram[0], 0, VRAM_SIZE);
137 	memset(m_palette, 0, sizeof(m_palette));
138 }
139 
140 /***************************************************************************
141 
142   Apple 4*8 Graphics Card section
143 
144 ***************************************************************************/
145 
device_timer(emu_timer & timer,device_timer_id tid,int param,void * ptr)146 void jmfb_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
147 {
148 	if (!m_vbl_disable)
149 	{
150 		raise_slot_irq();
151 	}
152 
153 	m_timer->adjust(m_screen->time_until_pos(479, 0), 0);
154 }
155 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)156 uint32_t jmfb_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
157 {
158 	uint8_t const *const vram8 = &m_vram[0xa00];
159 
160 	// first time?  kick off the VBL timer
161 	if (!m_screen)
162 	{
163 		m_screen = &screen;
164 		m_timer->adjust(m_screen->time_until_pos(479, 0), 0);
165 	}
166 
167 	switch (m_mode)
168 	{
169 		case 0: // 1bpp
170 			for (int y = 0; y < m_yres; y++)
171 			{
172 				uint32_t *scanline = &bitmap.pix(y);
173 				for (int x = 0; x < m_xres/8; x++)
174 				{
175 					uint8_t const pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
176 
177 					*scanline++ = m_palette[BIT(pixels, 7)];
178 					*scanline++ = m_palette[BIT(pixels, 6)];
179 					*scanline++ = m_palette[BIT(pixels, 5)];
180 					*scanline++ = m_palette[BIT(pixels, 4)];
181 					*scanline++ = m_palette[BIT(pixels, 3)];
182 					*scanline++ = m_palette[BIT(pixels, 2)];
183 					*scanline++ = m_palette[BIT(pixels, 1)];
184 					*scanline++ = m_palette[BIT(pixels, 0)];
185 				}
186 			}
187 			break;
188 
189 		case 1: // 2bpp
190 			for (int y = 0; y < m_yres; y++)
191 			{
192 				uint32_t *scanline = &bitmap.pix(y);
193 				for (int x = 0; x < m_xres/4; x++)
194 				{
195 					uint8_t const pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
196 
197 					*scanline++ = m_palette[(pixels>>6)&0x3];
198 					*scanline++ = m_palette[(pixels>>4)&0x3];
199 					*scanline++ = m_palette[(pixels>>2)&0x3];
200 					*scanline++ = m_palette[pixels&3];
201 				}
202 			}
203 			break;
204 
205 		case 2: // 4 bpp
206 			for (int y = 0; y < m_yres; y++)
207 			{
208 				uint32_t *scanline = &bitmap.pix(y);
209 				for (int x = 0; x < m_xres/2; x++)
210 				{
211 					uint8_t const pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
212 
213 					*scanline++ = m_palette[(pixels>>4)&0xf];
214 					*scanline++ = m_palette[pixels&0xf];
215 				}
216 			}
217 			break;
218 
219 		case 3: // 8 bpp
220 			for (int y = 0; y < m_yres; y++)
221 			{
222 				uint32_t *scanline = &bitmap.pix(y);
223 				for (int x = 0; x < m_xres; x++)
224 				{
225 					uint8_t const pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
226 					*scanline++ = m_palette[pixels];
227 				}
228 			}
229 			break;
230 
231 		case 4: // 24 bpp
232 			for (int y = 0; y < m_yres; y++)
233 			{
234 				uint32_t const *base = (uint32_t *)&m_vram[y * m_stride];
235 				std::copy_n(base, m_xres, &bitmap.pix(y));
236 			}
237 			break;
238 	}
239 
240 	return 0;
241 }
242 
mac_48gc_w(offs_t offset,uint32_t data,uint32_t mem_mask)243 void jmfb_device::mac_48gc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
244 {
245 	COMBINE_DATA(&m_registers[offset&0xff]);
246 
247 	switch (offset)
248 	{
249 		case 0x8/4: // base
250 //          printf("%x to base\n", data);
251 			m_base = (data*2)<<4;
252 			break;
253 
254 		case 0xc/4: // stride
255 //          printf("%x to stride\n", data);
256 			// this value is in DWORDs for 1-8 bpp and, uhh, strange for 24bpp
257 			if (m_mode < 4)
258 			{
259 				m_stride = data*4;
260 			}
261 			else
262 			{
263 				m_stride = (data*32)/3;
264 			}
265 			break;
266 
267 		case 0x200/4:   // DAC control
268 //          printf("%08x to DAC control\n", data);
269 			if (m_is824)
270 			{
271 				m_clutoffs = data&0xff;
272 			}
273 			else
274 			{
275 				m_clutoffs = data>>24;
276 			}
277 			m_count = 0;
278 			break;
279 
280 		case 0x204/4:   // DAC data
281 			if (m_is824)
282 			{
283 				m_colors[m_count++] = data&0xff;
284 			}
285 			else
286 			{
287 				m_colors[m_count++] = data>>24;
288 			}
289 
290 			if (m_count == 3)
291 			{
292 //              printf("RAMDAC: color %d = %02x %02x %02x\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2]);
293 				m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]);
294 				m_clutoffs++;
295 				m_count = 0;
296 			}
297 			break;
298 
299 		case 0x208/4:   // mode control
300 			m_mode = (data>>3)&3;
301 			if (m_mode == 3)    // this can be 8 or 24 bpp
302 			{
303 				// check pixel format for 24bpp
304 				if (m_is824)
305 				{
306 					if (data & 2)
307 					{
308 						m_mode = 4; // 24bpp
309 					}
310 				}
311 				else
312 				{
313 					if (((data>>5)&3) == 0)
314 					{
315 						m_mode = 4; // 24bpp
316 					}
317 				}
318 			}
319 //          printf("%02x to mode (m_mode = %d)\n", data, m_mode);
320 			break;
321 
322 		case 0x13c/4:   // bit 1 = VBL disable (1=no interrupts)
323 			m_vbl_disable = (data & 2) ? 1 : 0;
324 			break;
325 
326 		case 0x148/4:   // write 1 here to clear interrupt
327 			if (data == 1)
328 			{
329 				lower_slot_irq();
330 			}
331 			break;
332 
333 		default:
334 			break;
335 	}
336 }
337 
mac_48gc_r(offs_t offset,uint32_t mem_mask)338 uint32_t jmfb_device::mac_48gc_r(offs_t offset, uint32_t mem_mask)
339 {
340 //  printf("%s 48gc_r: @ %x, mask %08x\n", machine().describe_context().c_str(), offset, mem_mask);
341 
342 	switch (offset)
343 	{
344 		case 0:
345 			return 0x0c00;  // sense 13" RGB for now
346 //          return 0x0000;  // sense "RGB Kong" monitor
347 
348 		case 0x1c0/4:
349 			m_toggle ^= 0xffffffff;
350 			return m_toggle;
351 	}
352 
353 	return 0;
354 }
355