summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author angelosa <lordkale4@gmail.com>2025-02-19 11:10:47 +0100
committer angelosa <lordkale4@gmail.com>2025-02-19 11:10:56 +0100
commitf484388f159761b7873fba9c6205de840a9aff2a (patch)
treec5de723b2de239e5c73f32f8030a54cbaf912814 /src
parentfb7c1fde64ccedc1bf086ab51fef4212073b8306 (diff)
video/saa7110.cpp: type-in OCF1 receiver writes
Diffstat (limited to 'src')
-rw-r--r--src/devices/bus/pci/zr36057.cpp11
-rw-r--r--src/devices/video/saa7110.cpp125
-rw-r--r--src/devices/video/saa7110.h19
3 files changed, 138 insertions, 17 deletions
diff --git a/src/devices/bus/pci/zr36057.cpp b/src/devices/bus/pci/zr36057.cpp
index dff2bf68c96..0d3964e2a0c 100644
--- a/src/devices/bus/pci/zr36057.cpp
+++ b/src/devices/bus/pci/zr36057.cpp
@@ -10,14 +10,17 @@ iterations.
- https://www.kernel.org/doc/html/v6.13/driver-api/media/drivers/zoran.html
- Currently using DC10+ configuration:
ZR36067 + ZR36060 (ZR36050 + ZR36016 glued together)
- SAA7110a (TV decoder, PAL B/G / NTSC M / SECAM) + adv7176 (TV encoder, Linux driver name is adv7175)
+ SAA7110a (TV decoder) + adv7176 (TV encoder, Linux driver name is adv7175)
ZR36057 is known to have two HW quirks that are been fixed with ZR36067.
TODO:
-- Currently at dc10plus HW test "Error at video decoder", requires SAA7110a to continue;
+- Currently at dc10plus HW test "Error at M-JPEG codec", requires ZR36060 to continue;
- Hookup busmaster;
-- Stub, eventually decouple AV PCI controller part from the actual client cards;
+- What are i2c 0x8e >> 1 address device checks for?
+\- Can't be adv7175 (0xd4 >> 1) nor adv7176 (0x54 >> 1)
+...
- Soft Reset & Write lock mechanisms (each register have separate macro-groups);
+- eventually decouple AV PCI controller part from the actual client cards;
Known mix-ins:
- s3virge.cpp uses SAA7110 for Scenic Highway overlay available with its S3 LPB connector;
@@ -167,7 +170,7 @@ void zr36057_device::asr_map(address_map &map)
if (ACCESSING_BITS_24_31)
{
m_softreset = !!BIT(data, 24);
- // TODO: will lock all writes in config_map but this bit
+ // TODO: will lock all writes in asr_map but this bit
// (inclusive of the "all" group?)
if (!m_softreset)
{
diff --git a/src/devices/video/saa7110.cpp b/src/devices/video/saa7110.cpp
index dda0dac2076..e4e0e9425dd 100644
--- a/src/devices/video/saa7110.cpp
+++ b/src/devices/video/saa7110.cpp
@@ -1,10 +1,26 @@
// license: BSD-3-Clause
// copyright-holders: Angelo Salese
+/**************************************************************************************************
+
+SAA7110/SAA7110A One Chip Front-end 1
+
+TV decoder, can decode PAL B/G, NTSC M and SECAM
+
+TODO:
+- Stub, barely enough to make i2c tests happy in ZR36057 core;
+- SA configuration pin;
+- How to read transmitter regs? Should be slave addresses 0x9d (SA=0) or 0x9f (SA=1),
+ ZR36057 doesn't seem to care for now, '60 eventually will?
+- Needs an actual multimedia source to continue;
+
+**************************************************************************************************/
#include "emu.h"
#include "saa7110.h"
-#define VERBOSE (1)
+#define VERBOSE (LOG_GENERAL)
+//#define LOG_OUTPUT_FUNC osd_printf_info
+
#include "logmacro.h"
DEFINE_DEVICE_TYPE(SAA7110A, saa7110a_device, "saa7110a", "SAA7110A OCF1")
@@ -13,26 +29,123 @@ DEFINE_DEVICE_TYPE(SAA7110A, saa7110a_device, "saa7110a", "SAA7110A OCF1")
saa7110a_device::saa7110a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SAA7110A, tag, owner, clock)
, i2c_hle_interface(mconfig, *this, 0x9c >> 1)
- //, device_memory_interface(mconfig, *this)
-{}
+ , device_memory_interface(mconfig, *this)
+{
+ m_space_config = address_space_config("regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(saa7110a_device::regs_map), this));
+}
void saa7110a_device::device_start()
{
+ save_item(NAME(m_secs));
+ save_item(NAME(m_sstb));
+ save_item(NAME(m_hrmv));
+ save_item(NAME(m_rtse));
+ save_item(NAME(m_vtrc));
}
void saa7110a_device::device_reset()
{
+ m_secs = m_sstb = m_hrmv = m_rtse = m_vtrc = false;
+}
+device_memory_interface::space_config_vector saa7110a_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(0, &m_space_config)
+ };
}
u8 saa7110a_device::read_data(u16 offset)
{
- //printf("%02x\n", offset);
- return 0xff;
+ // OCF1 transmitter regs
+ // IC version number, not necessarily device ID?
+ if (m_sstb == false)
+ {
+ LOG("OCF1 transmitter: read IC version number (check me)\n");
+ machine().debug_break();
+ return 0x01;
+ }
+ // TODO: status byte
+ // x--- ---- STTC horizontal time constant (0) TV time constant (1) VCR time constant
+ // -x-- ---- HLCK locked horizontal frequency (1) unlocked
+ // --x- ---- FIDT Identification bit for detected field frequency (0) 50 Hz (1) 60 Hz
+ // ---x ---- GLIM Gain value for active luminance limit
+ // ---- -x-- WIPA White peak loop activation
+ // ---- --x- ALTD line alternating colour burst detection (PAL/SECAM)
+ // ---- ---x CODE color signal has been detected
+ LOG("OCF1 transmitter: read status byte\n");
+ return 0x00;
}
void saa7110a_device::write_data(u16 offset, u8 data)
{
- //printf("%02x %02x\n", offset, data);
+ // OCF1 receiver regs
+ space(0).write_byte(offset, data);
+}
+
+void saa7110a_device::regs_map(address_map &map)
+{
+ // BMSD-SQP + BSC slave receiver
+ map(0x00, 0x00).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU00: Increment delay %02x\n", data); }));
+ map(0x01, 0x01).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU01: HSY begin 50 Hz %02x\n", data); }));
+ map(0x02, 0x02).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU02: HSY stop 50 Hz %02x\n", data); }));
+ map(0x03, 0x03).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU03: HCL begin 50 Hz %02x\n", data); }));
+ map(0x04, 0x04).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU04: HCL stop 50 Hz %02x\n", data); }));
+ map(0x05, 0x05).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU05: HSY after PHI1 50 Hz %02x\n", data); }));
+ map(0x06, 0x06).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU06: Luminance control %02x\n", data); }));
+ map(0x07, 0x07).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU07: Hue control %02x\n", data); }));
+ map(0x08, 0x08).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU08: Colour killer threshold QUAM (PAL/NTSC) %02x\n", data); }));
+ map(0x09, 0x09).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU09: Colour killer threshold SECAM %02x\n", data); }));
+ map(0x0a, 0x0a).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU0A: PAL switch sensitivity %02x\n", data); }));
+ map(0x0b, 0x0b).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU0B: SECAM switch sensitivity %02x\n", data); }));
+ map(0x0c, 0x0c).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU0C: Gain control chrominance %02x\n", data); }));
+ map(0x0d, 0x0d).lw8(NAME([this] (offs_t offset, u8 data) {
+ LOG("SU0D: Standard/mode control %02x\n", data);
+ m_secs = BIT(data, 0);
+ m_sstb = BIT(data, 1);
+ m_hrmv = BIT(data, 2);
+ m_rtse = BIT(data, 3);
+ m_vtrc = BIT(data, 7);
+ LOG("\tSECAM mode bit SECS = %d: %s\n", m_secs, m_secs ? "SECAM mode" : "Other standards");
+ LOG("\tStatus byte select SSTB = %d\n", m_sstb);
+ LOG("\tHREF position select HRMV = %d: %s\n", m_hrmv, m_hrmv ? "HREF position 8 LLC2 later (SAA7191 mode)" : "HREF normal position");
+ LOG("\tReal time outputs mode select RTSE = %d: %s\n", m_rtse, m_rtse ? "HL pin 39, VL pin 40" : "PLIN pin 39, ODD pin 40");
+ LOG("\tTV/VCR mode select VTRC = %d: %s\n", m_vtrc, m_vtrc ? "VTR mode" : "TV mode");
+ }));
+ map(0x0e, 0x0e).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU0E: I/O and clock control %02x\n", data); }));
+ map(0x0f, 0x0f).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU0F: Control #1 %02x\n", data); }));
+ map(0x10, 0x10).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU10: Control #2 %02x\n", data); }));
+ map(0x11, 0x11).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU11: Chrominance gain reference %02x\n", data); }));
+ map(0x12, 0x12).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU12: Chrominance saturation %02x\n", data); }));
+ map(0x13, 0x13).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU13: Luminance contrast %02x\n", data); }));
+ map(0x14, 0x14).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU14: HSY begin 60 Hz %02x\n", data); }));
+ map(0x15, 0x15).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU15: HSY stop 60 Hz %02x\n", data); }));
+ map(0x16, 0x16).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU16: HCL begin 60 Hz %02x\n", data); }));
+ map(0x17, 0x17).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU17: HCL stop 60 Hz %02x\n", data); }));
+ map(0x18, 0x18).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU18: HSY after PHI1 60 Hz %02x\n", data); }));
+ map(0x19, 0x19).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU19: Luminance brightness %02x\n", data); }));
+
+ // DUAD slave receiver
+ map(0x20, 0x20).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU20: Analog control #1 %02x\n", data); }));
+ map(0x21, 0x21).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU21: Analog control #2 %02x\n", data); }));
+ map(0x22, 0x22).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU22: Mixer control #1 %02x\n", data); }));
+ map(0x23, 0x23).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU23: Clamping level control 21 %02x\n", data); }));
+ map(0x24, 0x24).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU24: Clamping level control 22 %02x\n", data); }));
+ map(0x25, 0x25).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU25: Clamping level control 31 %02x\n", data); }));
+ map(0x26, 0x26).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU26: Clamping level control 32 %02x\n", data); }));
+ map(0x27, 0x27).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU27: Gain control analog #1 %02x\n", data); }));
+ map(0x28, 0x28).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU28: White peak control %02x\n", data); }));
+ map(0x29, 0x29).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU29: Sync bottom control %02x\n", data); }));
+ map(0x2a, 0x2a).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU2A: Gain control analog #2 %02x\n", data); }));
+ map(0x2b, 0x2b).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU2B: Gain control analog #3 %02x\n", data); }));
+ map(0x2c, 0x2c).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU2C: Mixer control #2 %02x\n", data); }));
+ map(0x2d, 0x2d).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU2D: Integration value gain %02x\n", data); }));
+ map(0x2e, 0x2e).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU2E: Vertical blanking pulse set %02x\n", data); }));
+ map(0x2f, 0x2f).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU2F: Vertical blanking pulse reset %02x\n", data); }));
+ map(0x30, 0x30).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU30: ADCs gain control %02x\n", data); }));
+ map(0x31, 0x31).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU31: Mixer control #3 %02x\n", data); }));
+ map(0x32, 0x32).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU32: Integration value white peak %02x\n", data); }));
+ map(0x33, 0x33).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU33: Mixer control #4 %02x\n", data); }));
+ map(0x34, 0x34).lw8(NAME([this] (offs_t offset, u8 data) { LOG("SU34: Gain update level %02x\n", data); }));
}
diff --git a/src/devices/video/saa7110.h b/src/devices/video/saa7110.h
index d74976ba4f0..a4c5b741c9b 100644
--- a/src/devices/video/saa7110.h
+++ b/src/devices/video/saa7110.h
@@ -10,21 +10,26 @@
class saa7110a_device :
public device_t,
- public i2c_hle_interface
-// public device_memory_interface
+ public i2c_hle_interface,
+ public device_memory_interface
{
public:
saa7110a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
// saa7110a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- virtual void device_start() override ATTR_COLD;
- virtual void device_reset() override ATTR_COLD;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
-// virtual space_config_vector memory_space_config() const override;
- virtual u8 read_data(u16 offset) override;
- virtual void write_data(u16 offset, u8 data) override;
+ virtual space_config_vector memory_space_config() const override;
+ void regs_map(address_map &map) ATTR_COLD;
+private:
+ virtual u8 read_data(u16 offset) override;
+ virtual void write_data(u16 offset, u8 data) override;
+ address_space_config m_space_config;
+
+ bool m_secs, m_sstb, m_hrmv, m_rtse, m_vtrc;
};
DECLARE_DEVICE_TYPE(SAA7110A, saa7110a_device)