summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine
diff options
context:
space:
mode:
author Olivier Galibert <galibert@pobox.com>2022-06-14 10:50:20 +0200
committer Olivier Galibert <galibert@pobox.com>2022-06-14 12:07:55 +0200
commite76d23fc73a4ebb66959dc7b7c7f79ad6b0dcde1 (patch)
treed0bec988955f924167dac1fade448c8d2347406c /src/devices/machine
parent58650bd6812a92dfcfd8fa5bc6e225b34d4aa479 (diff)
saa7191: Move to devices/machine too
Diffstat (limited to 'src/devices/machine')
-rw-r--r--src/devices/machine/saa7191.cpp222
-rw-r--r--src/devices/machine/saa7191.h172
2 files changed, 394 insertions, 0 deletions
diff --git a/src/devices/machine/saa7191.cpp b/src/devices/machine/saa7191.cpp
new file mode 100644
index 00000000000..a879506e84b
--- /dev/null
+++ b/src/devices/machine/saa7191.cpp
@@ -0,0 +1,222 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/*********************************************************************
+
+ saa7191.cpp
+
+ Philips SAA7191B Digital Multistandard Colour Decoder (DMSD)
+
+ TODO:
+ - Actual functionality
+
+*********************************************************************/
+
+#include "emu.h"
+#include "saa7191.h"
+
+#define LOG_UNKNOWN (1 << 0)
+#define LOG_READS (1 << 1)
+#define LOG_WRITES (1 << 2)
+#define LOG_ERRORS (1 << 3)
+#define LOG_I2C_IGNORES (1 << 4)
+#define LOG_DEFAULT (LOG_READS | LOG_WRITES | LOG_ERRORS | LOG_I2C_IGNORES | LOG_UNKNOWN)
+
+#define VERBOSE (LOG_DEFAULT)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(SAA7191, saa7191_device, "saa7191", "Philips SAA7191 DMSD")
+
+saa7191_device::saa7191_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SAA7191, tag, owner, clock)
+ , m_chr_in(*this)
+ , m_cvbs_in(*this)
+ , m_y_out(*this)
+ , m_uv_out(*this)
+ , m_hs_out(*this)
+ , m_vs_out(*this)
+{
+}
+
+void saa7191_device::device_start()
+{
+ save_item(NAME(m_status));
+ save_item(NAME(m_regs));
+ save_item(NAME(m_i2c_write_addr));
+ save_item(NAME(m_i2c_read_addr));
+ save_item(NAME(m_i2c_subaddr));
+ save_item(NAME(m_i2c_state));
+
+ m_chr_in.resolve_safe(0);
+ m_cvbs_in.resolve_safe(0);
+
+ m_y_out.resolve_safe();
+ m_uv_out.resolve_safe();
+ m_hs_out.resolve_safe();
+ m_vs_out.resolve_safe();
+}
+
+void saa7191_device::device_reset()
+{
+ m_status = 0;
+ memset(m_regs, 0, sizeof(uint8_t) * REG_COUNT);
+
+ m_i2c_write_addr = 0x8a;
+ m_i2c_read_addr = 0x8b;
+ m_i2c_subaddr = 0x00;
+ m_i2c_state = I2C_STATE_IDLE;
+}
+
+void saa7191_device::i2c_data_w(uint8_t data)
+{
+ switch (m_i2c_state)
+ {
+ case I2C_STATE_IDLE:
+ if (data == m_i2c_write_addr)
+ m_i2c_state = I2C_STATE_SUBADDR_WRITE;
+ else if (data == m_i2c_read_addr)
+ m_i2c_state = I2C_STATE_SUBADDR_READ;
+ else
+ LOGMASKED(LOG_I2C_IGNORES, "I2C idle, address %02x ignored (mine are R:%02x/W:%02x)\n", data, m_i2c_read_addr, m_i2c_write_addr);
+ break;
+ case I2C_STATE_SUBADDR_WRITE:
+ m_i2c_subaddr = data;
+ m_i2c_state = I2C_STATE_DATA_WRITE;
+ break;
+ case I2C_STATE_SUBADDR_READ:
+ m_i2c_subaddr = data;
+ m_i2c_state = I2C_STATE_DATA_READ;
+ break;
+ case I2C_STATE_DATA_WRITE:
+ reg_w(data);
+ m_i2c_subaddr = (m_i2c_subaddr + 1) % REG_COUNT;
+ break;
+ case I2C_STATE_DATA_READ:
+ LOGMASKED(LOG_ERRORS, "I2C is expecting a data read, but data was written, returning to idle\n");
+ m_i2c_state = I2C_STATE_IDLE;
+ break;
+ default:
+ LOGMASKED(LOG_ERRORS, "Unknown I2C state %d, returning to idle\n", m_i2c_state);
+ m_i2c_state = I2C_STATE_IDLE;
+ break;
+ }
+}
+
+uint8_t saa7191_device::i2c_data_r()
+{
+ if (m_i2c_state != I2C_STATE_DATA_READ)
+ {
+ LOGMASKED(LOG_ERRORS, "i2c_data_r called, but we are in state %d and not expecting a data read, returning to idle\n", m_i2c_state);
+ m_i2c_state = I2C_STATE_IDLE;
+ return 0;
+ }
+ if (m_i2c_subaddr == 0x01)
+ {
+ LOGMASKED(LOG_READS, "i2c_data_r: Status = %02x\n", m_status);
+ m_i2c_subaddr = (m_i2c_subaddr + 1) % REG_COUNT;
+ return m_status;
+ }
+ LOGMASKED(LOG_UNKNOWN, "i2c_data_r: Unknown Sub-Address %02x, returning 0\n", m_i2c_subaddr);
+ m_i2c_subaddr = (m_i2c_subaddr + 1) % REG_COUNT;
+ return 0;
+}
+
+WRITE_LINE_MEMBER(saa7191_device::i2c_stop_w)
+{
+ if (state)
+ m_i2c_state = I2C_STATE_IDLE;
+}
+
+WRITE_LINE_MEMBER(saa7191_device::iicsa_w)
+{
+ m_i2c_write_addr = state ? 0x8e : 0x8a;
+ m_i2c_read_addr = m_i2c_write_addr | 1;
+}
+
+void saa7191_device::reg_w(uint8_t data)
+{
+ if (m_i2c_subaddr < REG_COUNT)
+ {
+ m_regs[m_i2c_subaddr] = data;
+ }
+
+ switch (m_i2c_subaddr)
+ {
+ case REG_IDEL:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Increment delay = %02x\n", data);
+ break;
+ case REG_HSYB:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync begin, 50Hz = %02x\n", data);
+ break;
+ case REG_HSYS:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync stop, 50Hz = %02x\n", data);
+ break;
+ case REG_HCLB:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H clamp begin, 50Hz = %02x\n", data);
+ break;
+ case REG_HCLS:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H clamp stop, 50Hz = %02x\n", data);
+ break;
+ case REG_HPHI:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync after PHI1, 50Hz = %02x\n", data);
+ break;
+ case REG_LUMC:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Luminance control = %02x\n", data);
+ break;
+ case REG_HUEC:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Hue control = %02x\n", data);
+ break;
+ case REG_CKTQ:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Colour killer threshold QAM = %02x\n", data);
+ break;
+ case REG_CKTS:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Colour killer threshold SECAM = %02x\n", data);
+ break;
+ case REG_PLSE:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: PAL switch sensitivity = %02x\n", data);
+ break;
+ case REG_SESE:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: SECAM switch sensitivity = %02x\n", data);
+ break;
+ case REG_GAIN:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Chroma gain control settings = %02x\n", data);
+ break;
+ case REG_STDC:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Standard/mode control = %02x\n", data);
+ break;
+ case REG_IOCK:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: I/O and clock control = %02x\n", data);
+ break;
+ case REG_CTL1:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Control #1 = %02x\n", data);
+ break;
+ case REG_CTL2:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Control #2 = %02x\n", data);
+ break;
+ case REG_CHCV:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Chroma gain reference = %02x\n", data);
+ break;
+ case REG_HS6B:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync begin, 60Hz = %02x\n", data);
+ break;
+ case REG_HS6S:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync stop, 60Hz = %02x\n", data);
+ break;
+ case REG_HC6B:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H clamp begin, 60Hz = %02x\n", data);
+ break;
+ case REG_HC6S:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H clamp stop, 60Hz = %02x\n", data);
+ break;
+ case REG_HP6I:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: H sync after PHI1, 60Hz = %02x\n", data);
+ break;
+ default:
+ LOGMASKED(LOG_WRITES, "i2c_data_w: Unknown Register %02x = %02x (ignored)\n", m_i2c_subaddr, data);
+ if (m_i2c_subaddr < REG_COUNT)
+ {
+ m_regs[m_i2c_subaddr] = 0;
+ }
+ break;
+ }
+}
+
diff --git a/src/devices/machine/saa7191.h b/src/devices/machine/saa7191.h
new file mode 100644
index 00000000000..907edfdc3b0
--- /dev/null
+++ b/src/devices/machine/saa7191.h
@@ -0,0 +1,172 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/*********************************************************************
+
+ saa7191.h
+
+ Philips SAA7191B Digital Multistandard Colour Decoder (DMSD)
+
+ TODO:
+ - Actual functionality
+
+*********************************************************************/
+
+#ifndef MAME_MACHINE_SAA7191_H
+#define MAME_MACHINE_SAA7191_H
+
+#pragma once
+
+class saa7191_device : public device_t
+{
+public:
+ saa7191_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U);
+
+ void i2c_data_w(uint8_t data);
+ uint8_t i2c_data_r();
+ DECLARE_WRITE_LINE_MEMBER(i2c_stop_w);
+
+ DECLARE_WRITE_LINE_MEMBER(iicsa_w);
+
+ auto chr_in() { return m_chr_in.bind(); }
+ auto cvbs_in() { return m_cvbs_in.bind(); }
+
+ auto y_out() { return m_y_out.bind(); }
+ auto uv_out() { return m_uv_out.bind(); }
+ auto hs_out() { return m_hs_out.bind(); }
+ auto vs_out() { return m_vs_out.bind(); }
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ void reg_w(uint8_t data);
+
+ enum
+ {
+ REG_IDEL = 0x00,
+ REG_HSYB = 0x01,
+ REG_HSYS = 0x02,
+ REG_HCLB = 0x03,
+ REG_HCLS = 0x04,
+ REG_HPHI = 0x05,
+ REG_LUMC = 0x06,
+ REG_HUEC = 0x07,
+ REG_CKTQ = 0x08,
+ REG_CKTS = 0x09,
+ REG_PLSE = 0x0a,
+ REG_SESE = 0x0b,
+ REG_GAIN = 0x0c,
+ REG_STDC = 0x0d,
+ REG_IOCK = 0x0e,
+ REG_CTL1 = 0x0f,
+ REG_CTL2 = 0x10,
+ REG_CHCV = 0x11,
+ REG_HS6B = 0x14,
+ REG_HS6S = 0x15,
+ REG_HC6B = 0x16,
+ REG_HC6S = 0x17,
+ REG_HP6I = 0x18,
+ REG_COUNT,
+
+ LUMC_APER_SHIFT = 0,
+ LUMC_APER_MASK = (3 << LUMC_APER_SHIFT),
+ LUMC_CORI_SHIFT = 2,
+ LUMC_CORI_MASK = (3 << LUMC_CORI_SHIFT),
+ LUMC_BPSS_SHIFT = 4,
+ LUMC_BPSS_MASK = (3 << LUMC_BPSS_SHIFT),
+ LUMC_PREF_BIT = 6,
+ LUMC_PREF_MASK = (1 << LUMC_PREF_BIT),
+ LUMC_BYPS_BIT = 7,
+ LUMC_BYPS_MASK = (1 << LUMC_BYPS_BIT),
+
+ CKTQ_SHIFT = 3,
+ CKTQ_MASK = (0x1f << CKTQ_SHIFT),
+ CKTS_SHIFT = 3,
+ CKTS_MASK = (0x1f << CKTS_SHIFT),
+
+ GAIN_LFIS_SHIFT = 5,
+ GAIN_LFIS_MASK = (3 << GAIN_LFIS_SHIFT),
+ GAIN_COLO_BIT = 7,
+ GAIN_COLO_MASK = (1 << GAIN_COLO_BIT),
+ GAIN_MASK = GAIN_LFIS_MASK | GAIN_COLO_MASK,
+
+ STDC_SECS_BIT = 0,
+ STDC_SECS_MASK = (1 << STDC_SECS_BIT),
+ STDC_GPSW0_BIT = 1,
+ STDC_GPSW0_MASK = (1 << STDC_GPSW0_BIT),
+ STDC_HRMV_BIT = 2,
+ STDC_HRMV_MASK = (1 << STDC_HRMV_BIT),
+ STDC_NFEN_BIT = 3,
+ STDC_NFEN_MASK = (1 << STDC_NFEN_BIT),
+ STDC_VTRC_BIT = 7,
+ STDC_VTRC_MASK = (1 << STDC_VTRC_BIT),
+ STDC_MASK = STDC_SECS_MASK | STDC_GPSW0_MASK | STDC_HRMV_MASK | STDC_NFEN_MASK | STDC_VTRC_MASK,
+
+ IOCK_GPSW1_BIT = 0,
+ IOCK_GPSW1_MASK = (1 << IOCK_GPSW1_BIT),
+ IOCK_GPSW2_BIT = 1,
+ IOCK_GPSW2_MASK = (1 << IOCK_GPSW2_BIT),
+ IOCK_CHRS_BIT = 2,
+ IOCK_CHRS_MASK = (1 << IOCK_CHRS_BIT),
+ IOCK_OEDY_BIT = 3,
+ IOCK_OEDY_MASK = (1 << IOCK_OEDY_BIT),
+ IOCK_OEVS_BIT = 4,
+ IOCK_OEVS_MASK = (1 << IOCK_OEVS_BIT),
+ IOCK_OEHS_BIT = 5,
+ IOCK_OEHS_MASK = (1 << IOCK_OEHS_BIT),
+ IOCK_OEDC_BIT = 6,
+ IOCK_OEDC_MASK = (1 << IOCK_OEDC_BIT),
+ IOCK_HPLL_BIT = 7,
+ IOCK_HPLL_MASK = (1 << IOCK_HPLL_BIT),
+
+ CTL1_YDEL_SHIFT = 0,
+ CTL1_YDEL_MASK = (7 << CTL1_YDEL_SHIFT),
+ CTL1_OFTS_BIT = 3,
+ CTL1_OFTS_MASK = (1 << CTL1_OFTS_BIT),
+ CTL1_SCEN_BIT = 4,
+ CTL1_SCEN_MASK = (1 << CTL1_SCEN_BIT),
+ CTL1_SXCR_BIT = 5,
+ CTL1_SXCR_MASK = (1 << CTL1_SXCR_BIT),
+ CTL1_FSEL_BIT = 6,
+ CTL1_FSEL_MASK = (1 << CTL1_FSEL_BIT),
+ CTL1_AUFD_BIT = 7,
+ CTL1_AUFD_MASK = (1 << CTL1_AUFD_BIT),
+
+ CTL2_VNOI_SHIFT = 0,
+ CTL2_VNOI_MASK = (3 << CTL2_VNOI_SHIFT),
+ CTL2_HRFS_SHIFT = 2,
+ CTL2_HRFS_MASK = (1 << CTL2_HRFS_SHIFT),
+ CTL2_MASK = CTL2_VNOI_MASK | CTL2_HRFS_MASK
+ };
+
+ enum
+ {
+ I2C_STATE_IDLE,
+ I2C_STATE_SUBADDR_READ,
+ I2C_STATE_SUBADDR_WRITE,
+ I2C_STATE_DATA_READ,
+ I2C_STATE_DATA_WRITE
+ };
+
+ uint8_t m_status;
+ uint8_t m_regs[REG_COUNT];
+
+ uint8_t m_i2c_write_addr;
+ uint8_t m_i2c_read_addr;
+ uint8_t m_i2c_subaddr;
+ int m_i2c_state;
+
+ devcb_read8 m_chr_in;
+ devcb_read8 m_cvbs_in;
+
+ devcb_write8 m_y_out;
+ devcb_write8 m_uv_out;
+ devcb_write_line m_hs_out;
+ devcb_write_line m_vs_out;
+};
+
+DECLARE_DEVICE_TYPE(SAA7191, saa7191_device)
+
+#endif // MAME_MACHINE_SAA7191_H