pci/zr36057.cpp: preliminary PostOffice interactions, kick off enough glue logic with a ZR36060 so that DC10+ passes board tests

This commit is contained in:
angelosa 2025-02-22 12:14:44 +01:00
parent 4f8fb4b2af
commit a3bdebb78f
6 changed files with 333 additions and 21 deletions

View File

@ -1697,6 +1697,18 @@ if (VIDEOS["X1_001"]~=null) then
}
end
--------------------------------------------------
--
--@src/devices/video/zr36060.h,VIDEOS["ZR36060"] = true
--------------------------------------------------
if (VIDEOS["ZR36060"]~=null) then
files {
MAME_DIR .. "src/devices/video/zr36060.cpp",
MAME_DIR .. "src/devices/video/zr36060.h",
}
end
--------------------------------------------------
--
--@src/devices/video/zr36110.h,VIDEOS["ZR36110"] = true

View File

@ -14,12 +14,13 @@ iterations.
ZR36057 is known to have two HW quirks that are been fixed with ZR36067.
TODO:
- Currently at dc10plus HW test "Error at M-JPEG codec", requires ZR36060 to continue;
- Enough to pass board functions in dc10plus HW test, requires VSYNC signal from ZR36060 to continue;
- Hookup busmaster;
- 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);
- GuestBus slot mechanism (relevant when multiple devices are hooked);
- eventually decouple AV PCI controller part from the actual client cards;
Known mix-ins:
@ -37,13 +38,14 @@ Known mix-ins:
#include "zr36057.h"
#define LOG_WARN (1U << 1)
#define LOG_PO (1U << 2) // PostOffice interactions
#define VERBOSE (LOG_GENERAL | LOG_WARN)
#define VERBOSE (LOG_GENERAL | LOG_WARN | LOG_PO)
//#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__)
#define LOGPO(...) LOGMASKED(LOG_PO, __VA_ARGS__)
DEFINE_DEVICE_TYPE(ZR36057_PCI, zr36057_device, "zr36057", "Zoran ZR36057-based Enhanced Multimedia Controller")
//DEFINE_DEVICE_TYPE(ZR36067_PCI, zr36067_device, "zr36067", "Zoran ZR36067-based AV Controller")
@ -51,6 +53,7 @@ DEFINE_DEVICE_TYPE(ZR36057_PCI, zr36057_device, "zr36057", "Zoran ZR36057-ba
zr36057_device::zr36057_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: pci_card_device(mconfig, type, tag, owner, clock)
, m_guest(*this, "guest")
, m_decoder(*this, "decoder")
{
// ZR36057PQC Video cutting chipset
@ -73,11 +76,13 @@ zr36057_device::zr36057_device(const machine_config &mconfig, const char *tag, d
void zr36057_device::device_add_mconfig(machine_config &config)
{
// 27'000'000 xtal near ZR36060
ZR36060(config, m_guest, XTAL(27'000'000));
SAA7110A(config, m_decoder, XTAL(26'800'000));
m_decoder->sda_callback().set([this](int state) { m_decoder_sdao_state = state; });
//ADV7176(config, m_encoder, XTAL(27'000'000));
// S-Video input/output
// composite video input/output
@ -116,8 +121,11 @@ void zr36057_device::device_reset()
void zr36057_device::software_reset()
{
LOG("SoftReset\n");
m_video_frontend.horizontal_config = (0 << 30) | (0x001 << 10) | (0x3ff << 0);
m_video_frontend.vertical_config = (0 << 30) | (0x001 << 10) | (0x3ff << 0);
m_vfe.hspol = m_vfe.vspol = 0;
m_vfe.hstart = m_vfe.vstart = 0x001;
m_vfe.hend = m_vfe.vend = 0x3ff;
m_vfe.horizontal_config = (m_vfe.hspol << 30) | (m_vfe.hstart << 10) | (m_vfe.hend << 0);
m_vfe.vertical_config = (m_vfe.vspol << 30) | (m_vfe.vstart << 10) | (m_vfe.vend << 0);
m_pci_waitstate_control = 0;
m_gpio_ddr = 0xff; // all inputs
@ -125,6 +133,15 @@ void zr36057_device::software_reset()
// m_gpio_data = 0xf0;
for (int i = 0; i < 4; i++)
m_guestbus.time[i] = 0;
m_jpeg_guest_id = 4;
m_jpeg_guest_reg = 0;
m_po.pending = false;
m_po.time_out = false;
m_po.dir = true;
m_po.guest_id = 0;
m_po.guest_reg = 0;
}
void zr36057_device::config_map(address_map &map)
@ -134,33 +151,46 @@ void zr36057_device::config_map(address_map &map)
map(0x3f, 0x3f).lr8(NAME([] () { return 0x10; }));
}
// Application Specific Register
// Application Specific Register(s)
void zr36057_device::asr_map(address_map &map)
{
map(0x000, 0x003).lrw32(
NAME([this] (offs_t offset) {
// NOTE: wants to read-back here, throws "Bus Master ASIC error" otherwise (?)
LOG("Video Front End Horizontal Configuration R\n");
return m_video_frontend.horizontal_config;
return m_vfe.horizontal_config;
}),
NAME([this] (offs_t offset, u32 data, u32 mem_mask) {
COMBINE_DATA(&m_video_frontend.horizontal_config);
COMBINE_DATA(&m_vfe.horizontal_config);
LOG("Video Front End Horizontal Configuration W %08x & %08x\n", data, mem_mask);
m_vfe.hspol = BIT(m_vfe.horizontal_config, 30);
m_vfe.hstart = (m_vfe.horizontal_config >> 10) & 0x3ff;
m_vfe.hend = (m_vfe.horizontal_config >> 0) & 0x3ff;
LOG("\tVSPOL %d VSTART %d VEND %d\n", m_vfe.hspol, m_vfe.hstart, m_vfe.hend);
})
);
map(0x004, 0x007).lrw32(
NAME([this] (offs_t offset) {
LOG("Video Front End Vertical Configuration R\n");
return m_video_frontend.vertical_config;
return m_vfe.vertical_config;
}),
NAME([this] (offs_t offset, u32 data, u32 mem_mask) {
COMBINE_DATA(&m_video_frontend.vertical_config);
COMBINE_DATA(&m_vfe.vertical_config);
LOG("Video Front End Vertical Configuration %08x & %08\n", data, mem_mask);
m_vfe.vspol = BIT(m_vfe.vertical_config, 30);
m_vfe.vstart = (m_vfe.vertical_config >> 10) & 0x3ff;
m_vfe.vend = (m_vfe.vertical_config >> 0) & 0x3ff;
LOG("\tVSPOL %d VSTART %d VEND %d\n", m_vfe.vspol, m_vfe.vstart, m_vfe.vend);
})
);
// ...
// map(0x008, 0x00b) VFE Config, Video Scaler and Pixel Format
// map(0x00c, 0x00f) Video Display Top
// map(0x010, 0x013) Video Display Bottom
// map(0x014, 0x017) Video Display Stride, Status and Frame Grab
// map(0x018, 0x01b) Video Display Configuration
// map(0x01c, 0x01f) Masking Map Top
// map(0x020, 0x023) Masking Map Bottom
// map(0x024, 0x027) Overlay Control
map(0x028, 0x02b).lrw32(
NAME([this] (offs_t offset) {
return (m_softreset << 24) | (m_pci_waitstate_control << 16) | m_gpio_ddr;
@ -191,6 +221,7 @@ void zr36057_device::asr_map(address_map &map)
// The doc claims 0xf0 default for GPIO, but win98 driver will throw "subvendor ID failed"
// while testing various ID combinations here
// This should come from GDAT pin at strapping time
return (0x7e << 24) | (m_guestbus.time[3] << 12) | (m_guestbus.time[2] << 8) | (m_guestbus.time[1] << 4) | (m_guestbus.time[0] << 0);
}),
NAME([this] (offs_t offset, u32 data, u32 mem_mask) {
@ -212,7 +243,11 @@ void zr36057_device::asr_map(address_map &map)
}
})
);
// map(0x030, 0x033) MPEG Code Source Address
// map(0x034, 0x037) MPEG Code Transfer Control
// map(0x038, 0x03b) MPEG Code Memory Pointer
// map(0x03c, 0x03f) Interrupt Status
// map(0x040, 0x043) Interrupt Control
map(0x044, 0x047).lrw32(
NAME([this] (offs_t offset) {
LOG("I2C R\n");
@ -229,4 +264,112 @@ void zr36057_device::asr_map(address_map &map)
}
})
);
// map(0x100, 0x103) JPEG Mode and Control
// map(0x104, 0x107) JPEG Process Control
// map(0x108, 0x10b) Vertical Sync Parameters (as sync master)
// map(0x10c, 0x10f) Horizontal Sync Parameters (as sync master)
// map(0x110, 0x113) Field Horizontal Active Portion
// map(0x114, 0x117) Field Vertical Active Portion
// map(0x118, 0x11b) Field Process Parameters
// map(0x11c, 0x11f) JPEG Code Base Address
// map(0x120, 0x123) JPEG Code FIFO Threshold
map(0x124, 0x124).lrw8(
NAME([this] (offs_t offset) {
LOG("JPEG Codec Guest ID R\n");
return (m_jpeg_guest_id << 4) | (m_jpeg_guest_reg << 0);
}),
NAME([this] (offs_t offset, u8 data) {
m_jpeg_guest_id = (data >> 4) & 7;
m_jpeg_guest_reg = (data >> 0) & 7;
LOG("JPEG Codec Guest ID W %02x\n", data);
})
);
map(0x12c, 0x12f).lrw32(
NAME([this] (offs_t offset) {
LOG("GuestBus Control (II) R\n");
return (0 << 16) | (m_guestbus.time[7] << 12) | (m_guestbus.time[6] << 8) | (m_guestbus.time[5] << 4) | (m_guestbus.time[4] << 0);
}),
NAME([this] (offs_t offset, u32 data, u32 mem_mask) {
LOG("GuestBus Control (II) W %08x & %08x\n", data, mem_mask);
if (ACCESSING_BITS_8_15)
{
m_guestbus.time[7] = (data >> 12) & 0xf;
m_guestbus.time[6] = (data >> 8) & 0xf;
}
if (ACCESSING_BITS_0_7)
{
m_guestbus.time[5] = (data >> 4) & 0xf;
m_guestbus.time[4] = (data >> 0) & 0xf;
}
})
);
map(0x200, 0x2ff).rw(FUNC(zr36057_device::postoffice_r), FUNC(zr36057_device::postoffice_w));
// map(0x300, 0x303) Still Transfer
}
// TODO: PostOffice accesses thru GuestBus are dictated with PCI clock cycles, asynchronous
// We pretend they are synchronous as a starting point, and one port only (which may matter later
// with CODE transfers). A time out happens 64 PCI cycles later in ZR36067, '120 halves that threshold.
// This should eventually be expressed in a osd_work_queue, with guestbus address_space roughly as:
// for (int i = 0; i < 8; i++)
// {
// if (<is_device_installed>)
// map(0 | (i << 2), 3 | (i << 2)).flags(<fn>).m(m_guest[i], map);
// else
// map(0 | (i << 2), 3 | (i << 2)).flags(<abort_fn>);
// }
u32 zr36057_device::postoffice_r(offs_t offset)
{
//LOGPO("PO R %d %d\n", m_po.guest_id, m_po.guest_reg);
u8 res = 0;
if (m_po.guest_id == 0)
{
if (m_po.dir == false)
res = m_guest->read(m_po.guest_reg);
}
else if (!machine().side_effects_disabled())
{
m_po.time_out = true;
LOGWARN("Warning: PO access unmapped POGuestID read %d %02x\n", m_po.guest_id, m_po.guest_reg);
}
return (m_po.pending << 25)
| (m_po.time_out << 24)
| (m_po.dir << 23)
| (m_po.guest_id << 20)
| (m_po.guest_reg << 16)
| res;
}
void zr36057_device::postoffice_w(offs_t offset, u32 data, u32 mem_mask)
{
// clear a previously set time out flag
if (BIT(data, 24))
m_po.time_out = false;
m_po.dir = !!(BIT(data, 23));
m_po.guest_id = (data >> 20) & 7;
m_po.guest_reg = (data >> 16) & 7;
LOGPO("PO W [%08x] %08x & %08x PODir %s POGuestID %d POGuestReg %d POData %02x\n"
, offset << 2
, data
, mem_mask
, m_po.dir ? "Write" : "Read"
, m_po.guest_id
, m_po.guest_reg
, data & 0xff
);
if (m_po.guest_id == 0)
{
if (m_po.dir == true)
m_guest->write(m_po.guest_reg, data & 0xff);
}
else
{
m_po.time_out = true;
LOGWARN("Warning: PO access unmapped POGuestID write %d %02x\n", m_po.guest_id, m_po.guest_reg);
}
}

View File

@ -8,6 +8,7 @@
#include "pci_slot.h"
#include "video/saa7110.h"
#include "video/zr36060.h"
class zr36057_device : public pci_card_device
{
@ -25,29 +26,42 @@ protected:
// virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
// virtual void map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space,
// uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) override;
virtual void config_map(address_map &map) override ATTR_COLD;
private:
required_device<zr36060_device> m_guest;
required_device<saa7110a_device> m_decoder;
void asr_map(address_map &map) ATTR_COLD;
void software_reset();
u32 postoffice_r(offs_t offset);
void postoffice_w(offs_t offset, u32 data, u32 mem_mask);
// Video Front End
struct {
u32 horizontal_config;
u32 vertical_config;
} m_video_frontend;
int hspol, vspol;
u16 hstart, hend, vstart, vend;
} m_vfe;
u8 m_jpeg_guest_id, m_jpeg_guest_reg;
bool m_softreset;
u8 m_gpio_ddr, m_pci_waitstate_control;
struct {
u8 time[4];
u8 time[8];
} m_guestbus;
struct {
bool dir; /**< true: Write, false: Read */
bool time_out;
bool pending;
u8 guest_id;
u8 guest_reg;
} m_po; /**< PostOffice */
int m_decoder_sdao_state;
};

View File

@ -0,0 +1,109 @@
// license:BSD-3-Clause
// copyright-holders: Angelo Salese
#include "emu.h"
#include "zr36060.h"
#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(ZR36060, zr36060_device, "zr36060", "Zoran ZR36060 Integrated JPEG codec")
zr36060_device::zr36060_device(const machine_config &mconfig, char const *tag, device_t *owner, u32 clock)
: device_t(mconfig, ZR36060, tag, owner, clock)
, device_memory_interface(mconfig, *this)
{
m_space_config = address_space_config("regs", ENDIANNESS_BIG, 8, 10, 0, address_map_constructor(FUNC(zr36060_device::regs_map), this));
}
device_memory_interface::space_config_vector zr36060_device::memory_space_config() const
{
return space_config_vector {
std::make_pair(0, &m_space_config)
};
}
void zr36060_device::device_start()
{
}
void zr36060_device::device_reset()
{
}
void zr36060_device::regs_map(address_map &map)
{
// map(0x000, 0x000) LOAD Parameters
// map(0x001, 0x001) Code FIFO Status (r/o)
// map(0x002, 0x002) Code Interface
// map(0x003, 0x003) Codec Mode
// map(0x005, 0x005) Maximum Block Code
// map(0x006, 0x006) Markers Enable
// map(0x007, 0x007) Interrupt Mask
// map(0x008, 0x008) Interrupt Status (r/o)
// map(0x009, 0x00c) Target Net Code Volume
// map(0x00d, 0x010) Target Data Code Volume
// map(0x011, 0x012) Scale Factor
// map(0x013, 0x015) Allocation Factor
// map(0x016, 0x019) Accumulated Code Volume
// map(0x01a, 0x01d) Accumulated Total Activity
// map(0x01e, 0x021) Accumulated Truncated Bits
map(0x022, 0x022).lr8(NAME([this] (offs_t offset) { LOG("Read Device ID\n"); return 0x33; }));
map(0x023, 0x023).lr8(NAME([this] (offs_t offset) { LOG("Read Revision ID\n"); return 0x01; }));
// map(0x024, 0x025) Test Control
// map(0x030, 0x030) Video Control
// map(0x031, 0x031) Video Polarity
// map(0x032, 0x032) Scaling
// map(0x033, 0x035) Background Color
// map(0x036, 0x041) Sync Generator
// map(0x042, 0x049) Active Area
// map(0x04a, 0x051) SUBIMG Window
map(0x060, 0x3ff).ram(); // JPEG Markers Array
}
/**************************************
*
* Host I/F
*
*************************************/
u8 zr36060_device::read(offs_t offset)
{
switch(offset & 3)
{
case 0:
LOG("CODE FIFO read\n");
return 0;
case 1:
return (m_address >> 8) & 3;
case 2:
return m_address & 0xff;
case 3:
return space(0).read_byte(m_address);
}
return 0;
}
void zr36060_device::write(offs_t offset, u8 data)
{
switch(offset & 3)
{
case 0:
LOG("CODE FIFO write %02x\n", data);
break;
case 1:
m_address = (data << 8) | (m_address & 0xff);
break;
case 2:
m_address = (data & 0xff) | (m_address & 0x300);
break;
case 3:
space(0).write_byte(m_address, data);
break;
}
}

View File

@ -0,0 +1,31 @@
// license:BSD-3-Clause
// copyright-holders: Angelo Salese
#ifndef MAME_VIDEO_ZR36060_H
#define MAME_VIDEO_ZR36060_H
#pragma once
class zr36060_device : public device_t, public device_memory_interface
{
public:
zr36060_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
u8 read(offs_t offset);
void write(offs_t offset, u8 data);
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual space_config_vector memory_space_config() const override;
private:
void regs_map(address_map &map);
u16 m_address;
address_space_config m_space_config;
};
DECLARE_DEVICE_TYPE(ZR36060, zr36060_device)
#endif // MAME_VIDEO_ZR36060_H

View File

@ -501,7 +501,7 @@ uint32_t magictg_state::zr36120_r(offs_t offset)
}
else
{
/* Post office */
// PostOffice reads
res = 0;//mame_rand(machine);//m_zr36120.as_regs[0x48/4];
}
logerror("PINKEYE_R[%x]\n", offset);
@ -529,6 +529,9 @@ void magictg_state::zr36120_w(offs_t offset, uint32_t data)
}
else
{
// PostOffice writes
// - Takes 32 PCI clocks for time out to happen compared to 64 in ZR36067
// - Has 4 guests instead of 8
uint32_t guest = (data >> 20) & 3;
uint32_t g_data = data & 0xff;
uint32_t g_reg = (data >> 16) & 7;