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