machine/mv_sonora.cpp: Sonora/Ardbeg use an external pixel clock (PDM does not). Also fixed monochrome mode. [R. Belmont]

apple/omega.cpp: Add "Omega" programmable PLL chip to generate the pixel clock for LC III/LC 520/LC 550. [R. Belmont]
This commit is contained in:
arbee 2024-06-19 11:41:50 -04:00
parent f443505d3c
commit a7738bb241
6 changed files with 223 additions and 9 deletions

View File

@ -5,6 +5,11 @@
Mac video support, "Sonora" edition
Supports 5 different modelines at up to 16bpp
The original Sonora ASIC and its follow-on Ardbeg require an
external pixel clock source, while the version used in the PDM
machines has an internal clock source that automatically is set
appropriately for the video mode.
*********************************************************************/
#include "emu.h"
@ -13,11 +18,11 @@
DEFINE_DEVICE_TYPE(MAC_VIDEO_SONORA, mac_video_sonora_device, "mv_sonora", "Mac Sonora video support")
const mac_video_sonora_device::modeline mac_video_sonora_device::modelines[5] = {
{ 0x02, "512x384 12\" RGB", 15667200, 640, 16, 32, 80, 407, 1, 3, 19, true },
{ 0x06, "640x480 13\" RGB", 31334400, 896, 80, 64, 112, 525, 3, 3, 39, true },
{ 0x01, "640x870 15\" Portrait", 57283200, 832, 32, 80, 80, 918, 3, 3, 42, false },
{ 0x09, "832x624 16\" RGB", 57283200, 1152, 32, 64, 224, 667, 1, 3, 39, false },
{ 0x0b, "640x480 VGA", 25175000, 800, 16, 96, 48, 525, 10, 2, 33, false },
{ 0x02, "512x384 12\" RGB", 15667200, 640, 16, 32, 80, 407, 1, 3, 19, true, false },
{ 0x06, "640x480 13\" RGB", 31334400, 896, 80, 64, 112, 525, 3, 3, 39, true, false },
{ 0x01, "640x870 15\" Portrait", 57283200, 832, 32, 80, 80, 918, 3, 3, 42, false, true },
{ 0x09, "832x624 16\" RGB", 57283200, 1152, 32, 64, 224, 667, 1, 3, 39, false, false },
{ 0x0b, "640x480 VGA", 25175000, 800, 16, 96, 48, 525, 10, 2, 33, false, false },
};
mac_video_sonora_device::mac_video_sonora_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
@ -26,6 +31,7 @@ mac_video_sonora_device::mac_video_sonora_device(const machine_config &mconfig,
m_palette(*this, "palette"),
m_monitor_config(*this, "monitor"),
m_screen_vblank(*this),
m_isPDM(false),
m_is32bit(false)
{
}
@ -272,7 +278,11 @@ void mac_video_sonora_device::vctrl_w(offs_t offset, uint8_t data)
if(m_modeline_id != -1 && m_modeline_id != prev_modeline) {
const modeline &m = modelines[m_modeline_id];
rectangle visarea(0, m.htot - m.hfp - m.hs - m.hbp - 1, 0, m.vtot - m.vfp - m.vs - m.vbp - 1);
m_screen->configure(m.htot, m.vtot, visarea, attotime::from_ticks(m.htot*m.vtot, m.dotclock).as_attoseconds());
if (m_isPDM) {
m_screen->configure(m.htot, m.vtot, visarea, attotime::from_ticks(m.htot*m.vtot, m.dotclock).as_attoseconds());
} else {
m_screen->configure(m.htot, m.vtot, visarea, attotime::from_ticks(m.htot * m.vtot, m_extPixelClock).as_attoseconds());
}
}
break;
}
@ -305,7 +315,7 @@ uint8_t mac_video_sonora_device::dac_r(offs_t offset)
return m_pal_control;
default:
logerror("dac_r %x\n", offset);
// logerror("dac_r %x\n", offset);
return 0;
}
}
@ -322,7 +332,18 @@ void mac_video_sonora_device::dac_w(offs_t offset, uint8_t data)
switch(m_pal_idx) {
case 0: m_palette->set_pen_red_level(m_pal_address, data); break;
case 1: m_palette->set_pen_green_level(m_pal_address, data); break;
case 2: m_palette->set_pen_blue_level(m_pal_address, data); break;
case 2:
// monochrome monitors use the blue line as the video, so duplicate blue to all 3 primaries
if (modelines[m_modeline_id].monochrome) {
m_palette->set_pen_red_level(m_pal_address, data);
m_palette->set_pen_green_level(m_pal_address, data);
m_palette->set_pen_blue_level(m_pal_address, data);
}
else
{
m_palette->set_pen_blue_level(m_pal_address, data);
}
break;
}
m_pal_idx ++;
if(m_pal_idx == 3) {

View File

@ -33,6 +33,8 @@ public:
void set_vram_base(const uint64_t *vram) { m_vram = vram; }
void set_vram_offset(uint32_t offset) { m_vram_offset = offset; }
void set_32bit() { m_is32bit = true; }
void set_PDM() { m_isPDM = true; }
void set_pixel_clock(uint32_t pclk) { m_extPixelClock = pclk; }
protected:
virtual void device_start() override;
@ -48,6 +50,7 @@ private:
uint32_t htot, hfp, hs, hbp;
uint32_t vtot, vfp, vs, vbp;
bool supports_16bpp;
bool monochrome;
};
static const modeline modelines[5];
@ -58,10 +61,11 @@ private:
devcb_write_line m_screen_vblank;
const uint64_t *m_vram;
uint32_t m_vram_offset;
uint32_t m_vram_offset, m_extPixelClock;
uint8_t m_mode, m_depth, m_monitor_id, m_vtest;
uint8_t m_pal_address, m_pal_idx, m_pal_control, m_pal_colkey;
int m_modeline_id;
bool m_isPDM;
bool m_is32bit;
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);

View File

@ -23,6 +23,7 @@
#include "macadb.h"
#include "macscsi.h"
#include "mactoolbox.h"
#include "omega.h"
#include "sonora.h"
#include "bus/nscsi/cd.h"
@ -57,6 +58,7 @@ public:
m_ram(*this, RAM_TAG),
m_sonora(*this, "sonora"),
m_dfac(*this, "dfac"),
m_omega(*this, "omega"),
m_scsibus1(*this, "scsi"),
m_ncr5380(*this, "scsi:7:ncr5380"),
m_scsihelp(*this, "scsihelp"),
@ -83,6 +85,7 @@ private:
required_device<ram_device> m_ram;
required_device<sonora_device> m_sonora;
optional_device<dfac_device> m_dfac;
required_device<omega_device> m_omega;
required_device<nscsi_bus_device> m_scsibus1;
required_device<ncr5380_device> m_ncr5380;
required_device<mac_scsi_helper_device> m_scsihelp;
@ -298,6 +301,9 @@ void macvail_state::maclc3_base(machine_config &config)
m_dfac->add_route(0, "lspeaker", 1.0);
m_dfac->add_route(1, "rspeaker", 1.0);
APPLE_OMEGA(config, m_omega, 31.3344_MHz_XTAL);
m_omega->pclock_changed().set(m_sonora, FUNC(sonora_device::pixel_clock_w));
SONORA(config, m_sonora, C15M);
m_sonora->set_maincpu_tag("maincpu");
m_sonora->set_rom_tag("bootrom");
@ -324,8 +330,11 @@ void macvail_state::maclc3(machine_config &config)
m_egret->set_default_bios_tag("341s0851");
m_egret->reset_callback().set(FUNC(macvail_state::cuda_reset_w));
m_egret->dfac_scl_callback().set(m_dfac, FUNC(dfac_device::clock_write));
m_egret->dfac_scl_callback().append(m_omega, FUNC(omega_device::clock_write));
m_egret->dfac_sda_callback().set(m_dfac, FUNC(dfac_device::data_write));
m_egret->dfac_sda_callback().append(m_omega, FUNC(omega_device::data_write));
m_egret->dfac_latch_callback().set(m_dfac, FUNC(dfac_device::latch_write));
m_egret->dfac_latch_callback().append(m_omega, FUNC(omega_device::latch_write));
m_egret->linechange_callback().set(m_macadb, FUNC(macadb_device::adb_linechange_w));
m_egret->via_clock_callback().set(m_sonora, FUNC(sonora_device::cb1_w));
m_egret->via_data_callback().set(m_sonora, FUNC(sonora_device::cb2_w));
@ -356,6 +365,9 @@ void macvail_state::maclc520(machine_config &config)
m_cuda->linechange_callback().set(m_macadb, FUNC(macadb_device::adb_linechange_w));
m_cuda->via_clock_callback().set(m_sonora, FUNC(sonora_device::cb1_w));
m_cuda->via_data_callback().set(m_sonora, FUNC(sonora_device::cb2_w));
m_cuda->iic_scl_callback().set(m_omega, FUNC(omega_device::clock_write));
m_cuda->iic_sda_callback().set(m_omega, FUNC(omega_device::data_write));
m_cuda->dfac_latch_callback().set(m_omega, FUNC(omega_device::latch_write));
m_macadb->adb_data_callback().set(m_cuda, FUNC(cuda_device::set_adb_line));
config.set_perfect_quantum(m_maincpu);

141
src/mame/apple/omega.cpp Normal file
View File

@ -0,0 +1,141 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/***************************************************************************
omega.cpp - Apple PLL clock synthesizer, used with Sonora and Ardbeg
based machines to generate the system clock and video dot clock.
Omega is intended to share the 3-wire clock/data/latch serial bus
with DFAC. On the rising edge of the latch, it takes note of the
next 16 bits. The first 7 are the N parameter, the next 7 bits are
the D parameter, and the final 2 are the P parameter. The actual
formula is identical to the Gazelle chip and the Sierra Semiconductor
SC11412.
Pixel clock = (31.3344 MHz * (N / D)) / P;
________________________
/ 4 3 2 1 28 27 26 |
| * |
| 5 25 |
| 6 344S1060-A N 24 |
| 7 23 |
| 8 (C)1991 APPLE 22 |
| 9 21 |
| 10 20 |
| 11 19 |
|____12_13_14_15_16_17_18__|
1, 7, 13, 16, 19, 20 = DGND, digital ground
2, 28 = AGND, analog ground
3 = DOTFLTR, filter for the DOTCLK output
4, 26 = AVDD, analog +5 volt supply (connected to VDD in LC 520)
5 - OESYSCLK - 1 to enable the SYSCLK output on pin 15
6 - OEALL - 1 to enable both the pixel and system clocks?
8 - SLATCH - serial latch
9 - SDATA - serial data
10 - SCLK - serial bit clock
11, 14, 17, 23 = VDD, main +5 volt supply
12 - DOTCLK - video dot clock output
15 - SYSCLK - system clock output
18 - C32M - outputs a mirror of the reference crystal clock
21 - XTALOUT
22 - XTALIN - connect the 31.3344 MHz reference crystal between XTALIN and XTALOUT
24 - S1 - selects one of the canned system clock freqencies (24 is VDD, 25 is GND in LC III = 25 MHz)
25 - S0 - " " " " " " " "
27 - SYSFLTR - filter for the SYSCLK output
SYSFLTR and DOTFLTR are connected like this:
604 ohms? 0.1uF
(pin 3 or 27) ----/\/\/\----||-----|
| |-----GND
|---||-------------|
0.002uF
***************************************************************************/
#include "emu.h"
#include "omega.h"
#define VERBOSE (0)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(APPLE_OMEGA, omega_device, "aplomega", "Apple Omega PLL Clock Synthesizer")
omega_device::omega_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, APPLE_OMEGA, tag, owner, clock),
m_write_pclock(*this),
m_data(false),
m_clock(false),
m_latch(false),
m_latch_byte(0),
m_N(0),
m_D(0),
m_P(0),
m_bit(0)
{
}
void omega_device::device_start()
{
save_item(NAME(m_clock));
save_item(NAME(m_data));
save_item(NAME(m_latch));
save_item(NAME(m_latch_byte));
save_item(NAME(m_N));
save_item(NAME(m_D));
save_item(NAME(m_P));
save_item(NAME(m_bit));
}
void omega_device::clock_write(int state)
{
// take a bit on the rising edge of SCL
if (state && !m_clock)
{
m_latch_byte <<= 1;
m_latch_byte |= m_data & 1;
switch (m_bit)
{
case 6:
m_N = m_latch_byte;
m_latch_byte = 0;
break;
case 13:
m_D = m_latch_byte;
m_latch_byte = 0;
break;
case 15:
m_P = m_latch_byte & 3;
const u32 pclock = (u32)(31334400.0f * ((double)m_N / (double)m_D)) / (double)m_P;
m_write_pclock(pclock);
LOG("%s: N = %d, D = %d, P = %d, pixel clock = %d\n", tag(), m_N, m_D, m_P, pclock);
break;
}
m_bit++;
}
m_clock = state;
}
void omega_device::latch_write(int state)
{
// start counting bits on the falling edge of the latch
if (state && !m_latch)
{
LOG("%s: latch rising edge, resetting bit count\n", tag());
m_bit = 0;
m_latch_byte = 0;
}
m_latch = state;
}

34
src/mame/apple/omega.h Normal file
View File

@ -0,0 +1,34 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
#ifndef MAME_APPLE_OMEGA_H
#define MAME_APPLE_OMEGA_H
#pragma once
class omega_device : public device_t
{
public:
omega_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto pclock_changed() { return m_write_pclock.bind(); }
// Omega uses the same 3-wire serial interface as DFAC, and is intended
// to share the bus with DFAC.
void data_write(int state) { m_data = state; }
void clock_write(int state);
void latch_write(int state);
protected:
// device_r overrides
virtual void device_start() override;
private:
devcb_write32 m_write_pclock;
bool m_data, m_clock, m_latch;
u8 m_latch_byte, m_N, m_D, m_P;
u32 m_bit;
};
DECLARE_DEVICE_TYPE(APPLE_OMEGA, omega_device)
#endif // MAME_APPLE_OMEGA_H

View File

@ -43,6 +43,8 @@ public:
template <u8 mask> void slot_irq_w(int state);
void scc_irq_w(int state);
void pixel_clock_w(u32 pclk) { m_video->set_pixel_clock(pclk); }
protected:
// device-level overrides
virtual void device_start() override;