1 // license:BSD-3-Clause
2 // copyright-holders:R. Belmont
3 /***************************************************************************
4
5 Apple Hi-Resolution Video Card emulation
6
7 RAMDAC: control at Fs0940e0, data at Fs0940e4
8 Fs090010 bit 16 is vbl status, bit 17 must be "1" for proper operation
9 Fs08000x are the control registers
10
11 ***************************************************************************/
12
13 #include "emu.h"
14 #include "nubus_m2hires.h"
15 #include "screen.h"
16
17 #define M2HIRES_SCREEN_NAME "m2hires_screen"
18 #define M2HIRES_ROM_REGION "m2hires_rom"
19
20 #define VRAM_SIZE (0x80000) // 512k max
21
22
23 ROM_START( m2hires )
24 ROM_REGION(0x2000, M2HIRES_ROM_REGION, 0)
CRC(ea6f7913)25 ROM_LOAD( "341-0660.bin", 0x0000, 0x2000, CRC(ea6f7913) SHA1(37c59f38ae34021d0cb86c2e76a598b7e6077c0d) )
26 ROM_END
27
28 //**************************************************************************
29 // GLOBAL VARIABLES
30 //**************************************************************************
31
32 DEFINE_DEVICE_TYPE(NUBUS_M2HIRES, nubus_m2hires_device, "nb_m2hr", "Macintosh II Hi-Resolution video card")
33
34
35 //-------------------------------------------------
36 // device_add_mconfig - add device configuration
37 //-------------------------------------------------
38
39 void nubus_m2hires_device::device_add_mconfig(machine_config &config)
40 {
41 screen_device &screen(SCREEN(config, M2HIRES_SCREEN_NAME, SCREEN_TYPE_RASTER));
42 screen.set_screen_update(FUNC(nubus_m2hires_device::screen_update));
43 screen.set_raw(25175000, 800, 0, 640, 525, 0, 480);
44 screen.set_size(1024, 768);
45 screen.set_visarea(0, 640-1, 0, 480-1);
46 }
47
48 //-------------------------------------------------
49 // rom_region - device-specific ROM region
50 //-------------------------------------------------
51
device_rom_region() const52 const tiny_rom_entry *nubus_m2hires_device::device_rom_region() const
53 {
54 return ROM_NAME( m2hires );
55 }
56
57 //**************************************************************************
58 // LIVE DEVICE
59 //**************************************************************************
60
61 //-------------------------------------------------
62 // nubus_m2hires_device - constructor
63 //-------------------------------------------------
64
nubus_m2hires_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)65 nubus_m2hires_device::nubus_m2hires_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
66 nubus_m2hires_device(mconfig, NUBUS_M2HIRES, tag, owner, clock)
67 {
68 }
69
nubus_m2hires_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)70 nubus_m2hires_device::nubus_m2hires_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
71 device_t(mconfig, type, tag, owner, clock),
72 device_video_interface(mconfig, *this),
73 device_nubus_card_interface(mconfig, *this),
74 m_vram32(nullptr), m_mode(0), m_vbl_disable(0), m_toggle(0), m_count(0), m_clutoffs(0), m_timer(nullptr)
75 {
76 set_screen(*this, M2HIRES_SCREEN_NAME);
77 }
78
79 //-------------------------------------------------
80 // device_start - device-specific startup
81 //-------------------------------------------------
82
device_start()83 void nubus_m2hires_device::device_start()
84 {
85 uint32_t slotspace;
86
87 install_declaration_rom(this, M2HIRES_ROM_REGION, true);
88
89 slotspace = get_slotspace();
90
91 // logerror("[m2hires %p] slotspace = %x\n", this, slotspace);
92
93 m_vram.resize(VRAM_SIZE);
94 m_vram32 = (uint32_t *)&m_vram[0];
95
96 nubus().install_device(slotspace, slotspace+VRAM_SIZE-1, read32s_delegate(*this, FUNC(nubus_m2hires_device::vram_r)), write32s_delegate(*this, FUNC(nubus_m2hires_device::vram_w)));
97 nubus().install_device(slotspace+0x900000, slotspace+VRAM_SIZE-1+0x900000, read32s_delegate(*this, FUNC(nubus_m2hires_device::vram_r)), write32s_delegate(*this, FUNC(nubus_m2hires_device::vram_w)));
98 nubus().install_device(slotspace+0x80000, slotspace+0xeffff, read32s_delegate(*this, FUNC(nubus_m2hires_device::m2hires_r)), write32s_delegate(*this, FUNC(nubus_m2hires_device::m2hires_w)));
99
100 m_timer = timer_alloc(0, nullptr);
101 m_timer->adjust(screen().time_until_pos(479, 0), 0);
102 }
103
104 //-------------------------------------------------
105 // device_reset - device-specific reset
106 //-------------------------------------------------
107
device_reset()108 void nubus_m2hires_device::device_reset()
109 {
110 m_count = 0;
111 m_clutoffs = 0;
112 m_vbl_disable = 1;
113 m_mode = 0;
114 memset(&m_vram[0], 0, VRAM_SIZE);
115 memset(m_palette, 0, sizeof(m_palette));
116
117 m_palette[0] = rgb_t(255, 255, 255);
118 m_palette[0x80] = rgb_t(0, 0, 0);
119 }
120
121
device_timer(emu_timer & timer,device_timer_id tid,int param,void * ptr)122 void nubus_m2hires_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
123 {
124 if (!m_vbl_disable)
125 {
126 raise_slot_irq();
127 }
128
129 m_timer->adjust(screen().time_until_pos(479, 0), 0);
130 }
131
132 /***************************************************************************
133
134 Spectrum 24 PDQ section
135
136 ***************************************************************************/
137
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)138 uint32_t nubus_m2hires_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
139 {
140 uint8_t const *const vram = &m_vram[0x20];
141
142 switch (m_mode)
143 {
144 case 0: // 1 bpp?
145 for (int y = 0; y < 480; y++)
146 {
147 uint32_t *scanline = &bitmap.pix(y);
148 for (int x = 0; x < 640/8; x++)
149 {
150 uint8_t const pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))];
151
152 *scanline++ = m_palette[BIT(pixels, 7)];
153 *scanline++ = m_palette[BIT(pixels, 6)];
154 *scanline++ = m_palette[BIT(pixels, 5)];
155 *scanline++ = m_palette[BIT(pixels, 4)];
156 *scanline++ = m_palette[BIT(pixels, 3)];
157 *scanline++ = m_palette[BIT(pixels, 2)];
158 *scanline++ = m_palette[BIT(pixels, 1)];
159 *scanline++ = m_palette[BIT(pixels, 0)];
160 }
161 }
162 break;
163
164 case 1: // 2 bpp
165 for (int y = 0; y < 480; y++)
166 {
167 uint32_t *scanline = &bitmap.pix(y);
168 for (int x = 0; x < 640/4; x++)
169 {
170 uint8_t const pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))];
171
172 *scanline++ = m_palette[((pixels>>6)&3)];
173 *scanline++ = m_palette[((pixels>>4)&3)];
174 *scanline++ = m_palette[((pixels>>2)&3)];
175 *scanline++ = m_palette[(pixels&3)];
176 }
177 }
178 break;
179
180 case 2: // 4 bpp
181 for (int y = 0; y < 480; y++)
182 {
183 uint32_t *scanline = &bitmap.pix(y);
184
185 for (int x = 0; x < 640/2; x++)
186 {
187 uint8_t const pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
188
189 *scanline++ = m_palette[((pixels&0xf0)>>4)];
190 *scanline++ = m_palette[(pixels&0xf)];
191 }
192 }
193 break;
194
195 case 3: // 8 bpp
196 for (int y = 0; y < 480; y++)
197 {
198 uint32_t *scanline = &bitmap.pix(y);
199
200 for (int x = 0; x < 640; x++)
201 {
202 uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
203 *scanline++ = m_palette[pixels];
204 }
205 }
206 break;
207
208 default:
209 fatalerror("m2hires: unknown video mode %d\n", m_mode);
210 }
211 return 0;
212 }
213
m2hires_w(offs_t offset,uint32_t data,uint32_t mem_mask)214 void nubus_m2hires_device::m2hires_w(offs_t offset, uint32_t data, uint32_t mem_mask)
215 {
216 data ^= 0xffffffff;
217
218 switch (offset)
219 {
220 case 1: // mode
221 switch (data)
222 {
223 case 0x20000000:
224 m_mode = 0;
225 break;
226
227 case 0x40000000:
228 m_mode = 1;
229 break;
230
231 case 0x80000000:
232 m_mode = 2;
233 break;
234
235 case 0x00010000:
236 m_mode = 3;
237 break;
238 }
239 break;
240
241 case 0x5038: // DAC control
242 // logerror("%08x to DAC control %s\n", data, machine().describe_context());
243 m_clutoffs = (data>>24)&0xff;
244 break;
245
246 case 0x5039: // DAC data
247 m_colors[m_count++] = (data>>24) & 0xff;
248
249 if (m_count == 3)
250 {
251 // logerror("RAMDAC: color %d = %02x %02x %02x %s\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], machine().describe_context() );
252 m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]);
253 m_clutoffs++;
254 if (m_clutoffs > 255)
255 {
256 m_clutoffs = 0;
257 }
258 m_count = 0;
259 }
260 break;
261
262 case 0x8000: // enable and ack VBL
263 m_vbl_disable = 0;
264 lower_slot_irq();
265 break;
266
267 case 0x8001: // disable VBL
268 m_vbl_disable = 1;
269 break;
270
271 default:
272 // logerror("m2hires_w: %08x @ %x, mask %08x %s\n", data, offset, mem_mask, machine().describe_context());
273 break;
274 }
275 }
276
m2hires_r(offs_t offset,uint32_t mem_mask)277 uint32_t nubus_m2hires_device::m2hires_r(offs_t offset, uint32_t mem_mask)
278 {
279 if (offset == 0x10010/4)
280 {
281 m_toggle ^= (1<<16);
282 return m_toggle | (1<<17); // bit 17 indicates a 4/8bpp capable ASIC apparently; the firmware won't enter those modes otherwise (although they show in the list)
283 }
284 /* else
285 {
286 logerror("m2hires_r: @ %x, mask %08x %s\n", offset, mem_mask, machine().describe_context());
287 }*/
288
289 return 0;
290 }
291
vram_w(offs_t offset,uint32_t data,uint32_t mem_mask)292 void nubus_m2hires_device::vram_w(offs_t offset, uint32_t data, uint32_t mem_mask)
293 {
294 data ^= 0xffffffff;
295 COMBINE_DATA(&m_vram32[offset]);
296 }
297
vram_r(offs_t offset,uint32_t mem_mask)298 uint32_t nubus_m2hires_device::vram_r(offs_t offset, uint32_t mem_mask)
299 {
300 return m_vram32[offset] ^ 0xffffffff;
301 }
302