summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/zr36110.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/video/zr36110.cpp')
-rw-r--r--src/devices/video/zr36110.cpp412
1 files changed, 412 insertions, 0 deletions
diff --git a/src/devices/video/zr36110.cpp b/src/devices/video/zr36110.cpp
new file mode 100644
index 00000000000..6b7ee862af9
--- /dev/null
+++ b/src/devices/video/zr36110.cpp
@@ -0,0 +1,412 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// Zoran ZR36110 mpeg video decoder
+
+#include "emu.h"
+#include "zr36110.h"
+
+#define LOG_MICROCODE (1U << 1)
+#define LOG_SETUP (1U << 2)
+
+#define VERBOSE (LOG_GENERAL|LOG_SETUP)
+#include "logmacro.h"
+
+#define LOGMICROCODE(...) LOGMASKED(LOG_MICROCODE, __VA_ARGS__)
+
+DEFINE_DEVICE_TYPE(ZR36110, zr36110_device, "zr36110", "Zoran ZR36110 mpeg decoder")
+
+zr36110_device::zr36110_device(const machine_config &mconfig, char const *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, ZR36110, tag, owner, clock),
+ m_drq_w(*this),
+ m_sp_frm_w{*this, *this},
+ m_sp_dat_w{*this, *this},
+ m_sp_clk_w{*this, *this}
+{
+}
+
+void zr36110_device::device_start()
+{
+ save_item(NAME(m_mc1_adr));
+ save_item(NAME(m_mc23_adr));
+ save_item(NAME(m_setup_adr));
+ save_item(NAME(m_state));
+ save_item(NAME(m_setup));
+ save_item(NAME(m_cmd_phase));
+ save_item(NAME(m_cmd));
+ save_item(NAME(m_bus_control));
+}
+
+void zr36110_device::device_reset()
+{
+ memset(m_setup, 0, sizeof(m_setup));
+ m_setup[0] = 0x10;
+ m_mc1_adr = 0;
+ m_mc23_adr = 0;
+ m_setup_adr = 0;
+ m_state = S_IDLE;
+ m_cmd_phase = false;
+ m_cmd = 0;
+ m_bus_control = 0x10;
+}
+
+void zr36110_device::mc18_w(u8 data)
+{
+ m_mc23_adr = 0;
+ m_setup_adr = 0;
+ LOGMICROCODE("mc1[%03x] = %02x\n", m_mc1_adr, data);
+ m_mc1_adr = m_mc1_adr + 1;
+}
+
+void zr36110_device::mc1x_w(u16 data)
+{
+ if(!(m_bus_control & 0x80))
+ mc18_w(data >> 8);
+ else if(m_bus_control & 0x40) {
+ mc18_w(data >> 8);
+ mc18_w(data);
+ } else {
+ mc18_w(data);
+ mc18_w(data >> 8);
+ }
+}
+
+void zr36110_device::mc1_w(u16 data)
+{
+ if(!(m_bus_control & 0x80))
+ mc18_w(data);
+ else if(m_bus_control & 0x40) {
+ mc18_w(data);
+ mc18_w(data >> 8);
+ } else {
+ mc18_w(data >> 8);
+ mc18_w(data);
+ }
+}
+
+void zr36110_device::mc238_w(u8 data)
+{
+ m_setup_adr = 0;
+ m_mc1_adr = 0;
+ LOGMICROCODE("mc23[%03x] = %02x\n", m_mc23_adr, data);
+ m_mc23_adr = m_mc23_adr + 1;
+ if(m_mc23_adr >= 0x2000 && m_state == S_INIT)
+ m_state = S_IDLE;
+}
+
+void zr36110_device::mc23_w(u16 data)
+{
+ if(!(m_bus_control & 0x80))
+ mc238_w(data);
+ else if(m_bus_control & 0x40) {
+ mc238_w(data);
+ mc238_w(data >> 8);
+ } else {
+ mc238_w(data >> 8);
+ mc238_w(data);
+ }
+}
+
+void zr36110_device::mc23x_w(u16 data)
+{
+ if(!(m_bus_control & 0x80))
+ mc238_w(data >> 8);
+ else if(m_bus_control & 0x40) {
+ mc238_w(data >> 8);
+ mc238_w(data);
+ } else {
+ mc238_w(data);
+ mc238_w(data >> 8);
+ }
+}
+
+double zr36110_device::u6_10_to_f(u16 val)
+{
+ if(val & 0x8000)
+ return (val - 0x10000) / 1024.0;
+ else
+ return val / 1024.0;
+}
+
+double zr36110_device::u5_19_to_f(u32 val)
+{
+ return val / 524288.0;
+}
+
+void zr36110_device::setup_show() const
+{
+ LOG_OUTPUT_FUNC("Chip setup:\n");
+ LOG_OUTPUT_FUNC(" 00 - buswidth=%d order=%s stream=%s burst_length=%d\n",
+ m_setup[0x00] & 0x80 ? 16 : 8,
+ m_setup[0x00] & 0x40 ? "lsb" : "msb",
+ m_setup[0x00] & 0x20 ? "dma" : "pio",
+ m_setup[0x00] & 0x1f);
+ LOG_OUTPUT_FUNC(" 01 - busoff=%d\n",
+ m_setup[0x01] << 4);
+ LOG_OUTPUT_FUNC(" 02 - type=%s rate=%s interface=%s half=%s dram=%s start=%s last=%s\n",
+ m_setup[0x02] & 0x80 ? m_setup[0x02] & 0x04 ? "serial" : "video" : m_setup[0x02] & 0x04 ? "sectors" : "stream",
+ m_setup[0x02] & 0x40 ? "pal" : "ntsc",
+ m_setup[0x02] & 0x20 ? "enabled" : "normal",
+ m_setup[0x02] & 0x10 ? "as-needed" : "always",
+ m_setup[0x02] & 0x08 ? "8M" : "4M",
+ m_setup[0x02] & 0x02 ? "sequence" : "any",
+ m_setup[0x02] & 0x01 ? "image" : "background");
+ LOG_OUTPUT_FUNC(" 03 - size=%s hinterpolate=%s color=%s bias=%s fi=%s\n",
+ m_setup[0x03] & 0x80 ? "sif-prog" : "ccir-int",
+ m_setup[0x03] & 0x40 ? "off" : "on",
+ m_setup[0x03] & 0x20 ? (m_setup[0x03] & 0x18) == 0x00 ? "rgb888" : (m_setup[0x03] & 0x18) == 0x08 ? "rgb565" : (m_setup[0x03] & 0x18) == 0x10 ? "rgb555" : "rgb?" : m_setup[0x03] & 0x04 ? "yuv411" : "yuv422",
+ m_setup[0x03] & 0x02 ? "on" : "off",
+ m_setup[0x03] & 0x01 ? "blank" : "field");
+ LOG_OUTPUT_FUNC(" 04 - signals=%s hsync=%s,%s vsync=%s,%s field=%s,%s clk=%s\n",
+ m_setup[0x04] & 0x80 ? "output" : "input",
+ m_setup[0x04] & 0x40 ? "high" : "low",
+ m_setup[0x04] & 0x08 ? "blank" : "sync",
+ m_setup[0x04] & 0x20 ? "high" : "low",
+ m_setup[0x04] & 0x04 ? "blank" : "sync",
+ m_setup[0x04] & 0x10 ? "high" : "low",
+ m_setup[0x04] & 0x02 ? "II" : "I",
+ m_setup[0x04] & 0x01 ? "qclk_v" : "vclk");
+ LOG_OUTPUT_FUNC(" 05 - sp2frm=%s sp2clk=%s sp2=%s sp1frm=%s sp1clk=%s sp1=%s\n",
+ m_setup[0x05] & 0x80 ? m_setup[0x05] & 0x20 ? "window" : "transition" : "pulse",
+ m_setup[0x05] & 0x40 ? "output" : "input",
+ m_setup[0x05] & 0x10 ? "on" : "off",
+ m_setup[0x05] & 0x08 ? m_setup[0x05] & 0x02 ? "window" : "transition" : "pulse",
+ m_setup[0x05] & 0x04 ? "output" : "input",
+ m_setup[0x05] & 0x01 ? "on" : "off");
+ LOG_OUTPUT_FUNC(" 06 - serial_audio_mp1=%s fi=%s\n",
+ m_setup[0x06] & 0x02 ? "yes" : "no",
+ m_setup[0x06] & 0x01 ? "normal" : "resolution");
+ LOG_OUTPUT_FUNC(" 08-21 - active=%dx%d offset=%d,%d total=%dx%d blank=%d,%d front_blank=%d,%d delay=%d,%d, sync=%d,%d\n",
+ (m_setup[0x08] << 8) | m_setup[0x09],
+ (m_setup[0x14] << 8) | m_setup[0x15],
+ (m_setup[0x0a] << 8) | m_setup[0x0b],
+ (m_setup[0x16] << 8) | m_setup[0x17],
+ (m_setup[0x0c] << 8) | m_setup[0x0d],
+ (m_setup[0x18] << 8) | m_setup[0x19],
+ (m_setup[0x0e] << 8) | m_setup[0x0f],
+ (m_setup[0x1a] << 8) | m_setup[0x1b],
+ (m_setup[0x10] << 8) | m_setup[0x11],
+ (m_setup[0x1c] << 8) | m_setup[0x1d],
+ (m_setup[0x12] << 8) | m_setup[0x13],
+ (m_setup[0x1e] << 8) | m_setup[0x1f],
+ m_setup[0x20],
+ m_setup[0x21]);
+ LOG_OUTPUT_FUNC(" 22-29 - crv=%f cbu=%f cgv=%f cgu=%f\n",
+ u6_10_to_f((m_setup[0x22] << 8) | m_setup[0x23]),
+ u6_10_to_f((m_setup[0x24] << 8) | m_setup[0x25]),
+ u6_10_to_f((m_setup[0x26] << 8) | m_setup[0x27]),
+ u6_10_to_f((m_setup[0x28] << 8) | m_setup[0x29]));
+ LOG_OUTPUT_FUNC(" 2a-2c - background=%d,%d,%d\n",
+ m_setup[0x2a],
+ m_setup[0x2b],
+ m_setup[0x2c]);
+ LOG_OUTPUT_FUNC(" 2d - high_byte=%02x\n",
+ m_setup[0x2d]);
+ LOG_OUTPUT_FUNC(" 2e-40 - spclk=1/%d,1/%d spbr=%f,%f spdelay=%d,%d vdelay=%d vclk=%d\n",
+ (m_setup[0x34] << 8) | m_setup[0x35],
+ (m_setup[0x36] << 8) | m_setup[0x37],
+ u5_19_to_f((m_setup[0x2e] << 16) | (m_setup[0x2f] << 8) | m_setup[0x30]),
+ u5_19_to_f((m_setup[0x31] << 16) | (m_setup[0x32] << 8) | m_setup[0x33]),
+ (m_setup[0x38] << 8) | m_setup[0x39],
+ (m_setup[0x3a] << 8) | m_setup[0x3b],
+ (m_setup[0x3c] << 8) | m_setup[0x3d],
+ (m_setup[0x3e] << 16) | (m_setup[0x3f] << 8) | m_setup[0x40]);
+ LOG_OUTPUT_FUNC(" 42-44 - sp1id=%02x sp2id=%02x vidid=%02x\n",
+ m_setup[0x42],
+ m_setup[0x43],
+ m_setup[0x44]);
+}
+
+void zr36110_device::setup8_w(u8 data)
+{
+ m_mc1_adr = 0;
+ m_mc23_adr = 0;
+ if(m_setup_adr < 0x80)
+ m_setup[m_setup_adr] = data;
+ if(m_setup_adr == 0x80 && (VERBOSE & LOG_SETUP))
+ setup_show();
+ m_setup_adr = m_setup_adr + 1;
+}
+
+void zr36110_device::setup_w(u16 data)
+{
+ if(!(m_bus_control & 0x80))
+ setup8_w(data);
+ else if(m_bus_control & 0x40) {
+ setup8_w(data);
+ setup8_w(data >> 8);
+ } else {
+ setup8_w(data >> 8);
+ setup8_w(data);
+ }
+}
+
+void zr36110_device::setupx_w(u16 data)
+{
+ if(!(m_bus_control & 0x80))
+ setup8_w(data >> 8);
+ else if(m_bus_control & 0x40) {
+ setup8_w(data >> 8);
+ setup8_w(data);
+ } else {
+ setup8_w(data);
+ setup8_w(data >> 8);
+ }
+}
+
+void zr36110_device::cmd8_w(u8 data)
+{
+ // LOG("cmd_w %02x\n", data);
+
+ if(m_cmd_phase) {
+ m_cmd |= data;
+ switch(m_cmd & 0xff) {
+ case 0x00: go(); break;
+ case 0x81: case 0x82: case 0x83: case 0x84: end_decoding(m_cmd & 3); break;
+ default:
+ logerror("Unknown command %02x.%02x\n", m_cmd >> 8, m_cmd & 0xff);
+ }
+ } else
+ m_cmd = data << 8;
+ m_cmd_phase = !m_cmd_phase;
+}
+
+void zr36110_device::cmd_w(u16 data)
+{
+ if(!(m_bus_control & 0x80))
+ cmd8_w(data);
+ else if(m_bus_control & 0x40) {
+ cmd8_w(data);
+ cmd8_w(data >> 8);
+ } else {
+ cmd8_w(data >> 8);
+ cmd8_w(data);
+ }
+}
+
+void zr36110_device::cmdx_w(u16 data)
+{
+ if(!(m_bus_control & 0x80))
+ cmd8_w(data >> 8);
+ else if(m_bus_control & 0x40) {
+ cmd8_w(data >> 8);
+ cmd8_w(data);
+ } else {
+ cmd8_w(data);
+ cmd8_w(data >> 8);
+ }
+}
+
+void zr36110_device::dma8_w(u8 data)
+{
+ // logerror("dma %02x\n", data);
+}
+
+void zr36110_device::dma_w(u16 data)
+{
+ if(!(m_bus_control & 0x80))
+ dma8_w(data);
+ else if(m_bus_control & 0x40) {
+ dma8_w(data);
+ dma8_w(data >> 8);
+ } else {
+ dma8_w(data >> 8);
+ dma8_w(data);
+ }
+}
+
+void zr36110_device::dmax_w(u16 data)
+{
+ if(!(m_bus_control & 0x80))
+ dma8_w(data >> 8);
+ else if(m_bus_control & 0x40) {
+ dma8_w(data >> 8);
+ dma8_w(data);
+ } else {
+ dma8_w(data);
+ dma8_w(data >> 8);
+ }
+}
+
+u8 zr36110_device::stat08_r()
+{
+ return 0x20 | m_state;
+}
+
+u8 zr36110_device::stat18_r()
+{
+ return 0x0c;
+}
+
+u8 zr36110_device::stat28_r()
+{
+ return 0x01;
+}
+
+u16 zr36110_device::stat0_r()
+{
+ return 0x20 | m_state;
+}
+
+u16 zr36110_device::stat1_r()
+{
+ return 0x0c;
+}
+
+u16 zr36110_device::stat2_r()
+{
+ return 0x01;
+}
+
+u16 zr36110_device::stat0x_r()
+{
+ return (0x20 | m_state) << 8;
+}
+
+u16 zr36110_device::stat1x_r()
+{
+ return 0x0c << 8;
+}
+
+u16 zr36110_device::stat2x_r()
+{
+ return 0x01 << 8;
+}
+
+u8 zr36110_device::user8_r()
+{
+ return 0;
+}
+
+u16 zr36110_device::user_r()
+{
+ return 0;
+}
+
+u16 zr36110_device::userx_r()
+{
+ return 0;
+}
+
+void zr36110_device::go()
+{
+ if(m_state != S_IDLE) {
+ logerror("command GO on wrong state, ignoring\n");
+ return;
+ }
+ logerror("command GO\n");
+ m_bus_control = m_setup[0];
+ m_state = S_NORMAL;
+ m_drq_w(1);
+}
+
+void zr36110_device::end_decoding(u8 mode)
+{
+ if(m_state != S_NORMAL) {
+ logerror("command END DECODING on wrong state, ignoring\n");
+ return;
+ }
+ logerror("command END DECODING %d\n", mode);
+ m_state = S_IDLE;
+ m_drq_w(0);
+}