mirror of
https://github.com/holub/mame
synced 2025-04-24 09:20:02 +03:00
jaleco/jaleco_vj_qtaro.cpp: Added preliminary King Qtaro PCI video decoder card device.
Video decoding is not implemented yet.
This commit is contained in:
parent
78b9d5d98b
commit
1b9cdb3f59
@ -48,6 +48,7 @@ jaleco_vj_pc_device::jaleco_vj_pc_device(const machine_config &mconfig, const ch
|
||||
device_t(mconfig, JALECO_VJ_PC, tag, owner, clock),
|
||||
device_mixer_interface(mconfig, *this, 2),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_king_qtaro(*this, "pci:08.0"),
|
||||
m_sound(*this, "isa1:vj_sound"),
|
||||
m_is_steppingstage(false)
|
||||
{
|
||||
@ -125,6 +126,9 @@ void jaleco_vj_pc_device::device_add_mconfig(machine_config &config)
|
||||
|
||||
// TODO: pci:07.3 0x30401106 VIA VT83C572, VT86C586/A/B Power Management Controller
|
||||
|
||||
JALECO_VJ_KING_QTARO(config, m_king_qtaro, 0);
|
||||
m_king_qtaro->set_bus_master_space(m_maincpu, AS_PROGRAM); // FIXME: remove this workaround when PCI framework grows bus mastering support
|
||||
|
||||
// TODO: Should actually be pci:0a.0 but it only shows a black screen
|
||||
PCI_SLOT(config, "pci:2", pci_cards, 16, 1, 2, 3, 0, "virgedx").set_fixed(true);
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jaleco_vj_qtaro.h"
|
||||
#include "jaleco_vj_sound.h"
|
||||
|
||||
#include "cpu/i386/i386.h"
|
||||
@ -23,6 +24,9 @@ public:
|
||||
void comm_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { m_sound->comm_w(offset, data, mem_mask); }
|
||||
void ymz_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { m_sound->ymz_w(offset, data, mem_mask); }
|
||||
|
||||
template <int DeviceId> void video_mix_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { m_king_qtaro->video_mix_w<DeviceId>(offset, data); }
|
||||
void video_control_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { m_king_qtaro->video_control_w(offset, data); }
|
||||
|
||||
protected:
|
||||
virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
@ -35,6 +39,7 @@ private:
|
||||
void boot_state_w(uint8_t data);
|
||||
|
||||
required_device<pentium_device> m_maincpu;
|
||||
required_device<jaleco_vj_king_qtaro_device> m_king_qtaro;
|
||||
required_device<jaleco_vj_isa16_sound_device> m_sound;
|
||||
bool m_is_steppingstage;
|
||||
};
|
||||
|
527
src/mame/jaleco/jaleco_vj_qtaro.cpp
Normal file
527
src/mame/jaleco/jaleco_vj_qtaro.cpp
Normal file
@ -0,0 +1,527 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
|
||||
/*
|
||||
King Qtaro PCI card and Qtaro subboards for VJ
|
||||
|
||||
Main board ("King Qtaro"):
|
||||
No markings
|
||||
----------------------------------------------
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| FLEX |
|
||||
| CN3 CN2 |
|
||||
| |
|
||||
| |
|
||||
| LS6201 |
|
||||
| |
|
||||
| |-------| |-| |------------|
|
||||
------ ------------- ------
|
||||
|
||||
LS6201 - LSI LS6201 027 9850KX001 PCI Local Bus Interface
|
||||
FLEX - Altera Flex EPF10K10QC208-4 DAB239813
|
||||
CN2, CN3 - 68-pin connectors
|
||||
|
||||
Information about the LS6201:
|
||||
https://web.archive.org/web/20070912033617/http://www.lsisys.co.jp/prod/ls6201/ls6201.htm
|
||||
https://web.archive.org/web/20001015203836/http://www.lsisys.co.jp:80/prod/LS6201.pdf
|
||||
|
||||
The King Qtaro board appears to be a custom spec ordered from LSI Systems and shares some
|
||||
layout similarities to the LS6201 evaluation card offered by LSI Systems.
|
||||
|
||||
|
||||
|
||||
|
||||
JALECO VJ-98347
|
||||
MADE IN JAPAN
|
||||
EB-00-20125-0
|
||||
(Front)
|
||||
-----------------------------------
|
||||
| CN2 CN4 CN6 |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| CN1 CN3 CN5 |
|
||||
-----------------------------------
|
||||
|
||||
CN1/2/3/4/5/6 - 80-pin connectors
|
||||
|
||||
(Back)
|
||||
-----------------------------------
|
||||
| CN9 |
|
||||
| |
|
||||
| U4 |
|
||||
| CN7 U1 CN8 |
|
||||
| U2 |
|
||||
| U3 |
|
||||
| |
|
||||
-----------------------------------
|
||||
|
||||
U1 - ?
|
||||
U2, U3 - (Unpopulated)
|
||||
U4 - HM87AV LM3940IS
|
||||
CN7, CN8 - 68-pin connectors. Connects to CN3, CN2 on main board
|
||||
|
||||
|
||||
|
||||
|
||||
JALECO VJ-98341 ("Qtaro")
|
||||
MADE IN JAPAN
|
||||
EB-00-20124-0
|
||||
----------------------------------------
|
||||
| |
|
||||
| |----------| |
|
||||
| | | D4516161 |
|
||||
| | FLEX | U2 CN3 |
|
||||
| | | CN4 |
|
||||
| |----------| U1 |
|
||||
| |
|
||||
| |
|
||||
----------------------------------------
|
||||
FLEX - Altera FLEX EPF10K30AQC240-3 DBA439849
|
||||
D4516161 - NEC uPD4516161AG5-A80 512K x 16-bit x 2-banks (16MBit) SDRAM (SSOP50)
|
||||
U1, U2 - LVX244
|
||||
|
||||
CN3 - 40 pin connector (connects to VJ-98342)
|
||||
CN4 - 40 pin connector (connects to VJ-98342)
|
||||
|
||||
|
||||
Hardware testing confirms that the Qtaro board is responsible for mixing the sprites from the subboard
|
||||
with the movies from the PC side.
|
||||
On real hardware, when the CN3 ribbon cables for two monitors going into the subboard are swapped
|
||||
but CN4 is left in its proper ordering, the sprites will appear based on the placement of the ribbon
|
||||
cable on the subboard. The movies are still in the correct ordering.
|
||||
|
||||
|
||||
TODO: Timing of when the videos start and stop is not accurate
|
||||
VJ needs all of the videos to start and end at the same time, and if one video finishes before the others then
|
||||
it will try to stop *all* of the video data streams at the same time on the PC side.
|
||||
Setting the buffer size <= 0x8000 fixes it to some degree because the DMAs can't run ahead of each other too far,
|
||||
but there's an issue with Stepping Stage where it'll just not send data for a small period causing videos to pause
|
||||
and then go out of sync (???).
|
||||
|
||||
The MPEG decoder is on the FPGA on each of the Qtaro boards. The implementation here doesn't try to handle
|
||||
any potential quirks with the decoding. I think a more accurate to the FPGA version implementation would
|
||||
be required to make things work exactly like the real hardware, because the FPGA version seems to be able
|
||||
to start the video stream sooner, and it does not seem to reset any kind of state between videos.
|
||||
To the last point, I have multiple video recordings of Stepping Stage showing garbage from the previous
|
||||
video at the very start of a new video for a few frames. DMA timings are almost surely incorrect.
|
||||
|
||||
TODO: The last decoded video frame can show up at inappropriate times
|
||||
Color bar check background in VJ for example enables the video stream so will show the last decoded frame sometimes.
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "jaleco_vj_qtaro.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define LOG_VIDEO (1U << 1)
|
||||
#define LOG_DMA (1U << 2)
|
||||
#define LOG_VERBOSE_VIDEO (1U << 3)
|
||||
#define LOG_VERBOSE_DMA (1U << 4)
|
||||
#define LOG_VERBOSE_VIDEO_DATA (1U << 5)
|
||||
|
||||
// #define VERBOSE (LOG_VIDEO | LOG_DMA | LOG_VERBOSE_VIDEO | LOG_VERBOSE_DMA)
|
||||
// #define LOG_OUTPUT_STREAM std::cout
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(JALECO_VJ_QTARO, jaleco_vj_qtaro_device, "jaleco_vj_qtaro", "Jaleco VJ Qtaro Subboard")
|
||||
DEFINE_DEVICE_TYPE(JALECO_VJ_KING_QTARO, jaleco_vj_king_qtaro_device, "jaleco_vj_king_qtaro", "Jaleco VJ King Qtaro PCI Device")
|
||||
|
||||
|
||||
static constexpr unsigned DMA_BURST_SIZE = 128U;
|
||||
#define DMA_TIMER_PERIOD attotime::from_hz(33'000'000 / 64)
|
||||
|
||||
|
||||
jaleco_vj_qtaro_device::jaleco_vj_qtaro_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
device_t(mconfig, JALECO_VJ_QTARO, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
void jaleco_vj_qtaro_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_int));
|
||||
save_item(NAME(m_mix_level));
|
||||
}
|
||||
|
||||
void jaleco_vj_qtaro_device::device_reset()
|
||||
{
|
||||
m_int = 0;
|
||||
m_mix_level = 0;
|
||||
}
|
||||
|
||||
void jaleco_vj_qtaro_device::video_mix_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
if (data != m_mix_level) {
|
||||
LOGMASKED(LOG_VIDEO, "[%s] video_mix_w %04x\n", tag(), data);
|
||||
}
|
||||
|
||||
m_mix_level = data;
|
||||
}
|
||||
|
||||
uint8_t jaleco_vj_qtaro_device::reg_r(offs_t offset)
|
||||
{
|
||||
return m_int;
|
||||
}
|
||||
|
||||
void jaleco_vj_qtaro_device::reg_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
// Bit 7 is set when starting DMA for an entirely new video, then unset when video is ended
|
||||
if (BIT(data, 7) && !BIT(m_int, 7)) {
|
||||
LOGMASKED(LOG_VIDEO, "[%s] DMA transfer thread started %02x\n", tag(), data);
|
||||
} else if (!BIT(data, 7) && BIT(m_int, 7)) {
|
||||
LOGMASKED(LOG_VIDEO, "[%s] DMA transfer thread ended %02x\n", tag(), data);
|
||||
}
|
||||
|
||||
m_int = data;
|
||||
}
|
||||
|
||||
uint8_t jaleco_vj_qtaro_device::reg2_r(offs_t offset)
|
||||
{
|
||||
// WriteStream cleanup function will loop until this returns 0.
|
||||
// Probably relates to DMA or video playback state.
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t jaleco_vj_qtaro_device::reg3_r(offs_t offset)
|
||||
{
|
||||
// 0x20 is some kind of default state. Relates to DMA or video playback.
|
||||
// If this value is 0x40 then the code sets it back to 0x20 during the WriteStream cleanup function.
|
||||
return 0x20;
|
||||
}
|
||||
|
||||
void jaleco_vj_qtaro_device::reg3_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
}
|
||||
|
||||
void jaleco_vj_qtaro_device::write(uint8_t *data, uint32_t len)
|
||||
{
|
||||
LOGMASKED(LOG_VERBOSE_VIDEO_DATA, "[%s] video data write %02x\n", tag(), data);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
|
||||
void jaleco_vj_king_qtaro_device::video_control_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
// Speed controlled by IRQ 4 on subboard CPU
|
||||
LOGMASKED(LOG_VIDEO, "video_control_w %04x\n", data);
|
||||
|
||||
// Bits 0, 2, 4 change when a video frame should or shouldn't be decoded
|
||||
// Bits 1, 3, 5 are always set?
|
||||
}
|
||||
|
||||
uint32_t jaleco_vj_king_qtaro_device::qtaro_fpga_firmware_status_r(offs_t offset)
|
||||
{
|
||||
// Tested when uploading Qtaro firmware
|
||||
// 0x100 is set when busy and will keep looping until it's not 0x100
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::qtaro_fpga_firmware_status_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
// Set to 0x80000020 when uploading Qtaro firmware
|
||||
}
|
||||
|
||||
uint32_t jaleco_vj_king_qtaro_device::qtaro_fpga_firmware_r(offs_t offset)
|
||||
{
|
||||
// Should only return 1 when the Qtaro subboard firmware is finished writing.
|
||||
// Returning 1 on the first byte will cause it to stop uploading the firmware,
|
||||
// then it'll write 3 0xffs and on the last 0xff if it sees 1 then it thinks it finished
|
||||
// uploading the firmware successfully.
|
||||
return 1;
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::qtaro_fpga_firmware_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t jaleco_vj_king_qtaro_device::fpga_firmware_status_r(offs_t offset)
|
||||
{
|
||||
// Tested when uploading King Qtaro firmware
|
||||
// 0x100 is set when busy and will keep looping until it's not 0x100
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::fpga_firmware_status_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
// Set to 0x80000020 when uploading King Qtaro firmware
|
||||
}
|
||||
|
||||
uint32_t jaleco_vj_king_qtaro_device::fpga_firmware_r(offs_t offset)
|
||||
{
|
||||
// Should only return 1 when the King Qtaro firmware is finished writing.
|
||||
// Returning 1 on the first byte will cause it to stop uploading the firmware,
|
||||
// then it'll write 3 0xffs and on the last 0xff if it sees 1 then it thinks it finished
|
||||
// uploading the firmware successfully.
|
||||
return 1;
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::fpga_firmware_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t jaleco_vj_king_qtaro_device::event_io_mask_r(offs_t offset)
|
||||
{
|
||||
return m_event_io_mask[offset];
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::event_io_mask_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
m_event_io_mask[offset] = data;
|
||||
}
|
||||
|
||||
uint8_t jaleco_vj_king_qtaro_device::event_unk_r(offs_t offset)
|
||||
{
|
||||
return m_event_unk[offset];
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::event_unk_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
m_event_unk[offset] = data;
|
||||
}
|
||||
|
||||
uint8_t jaleco_vj_king_qtaro_device::event_io_r(offs_t offset)
|
||||
{
|
||||
uint8_t r = m_event_io[offset];
|
||||
if (offset == 0)
|
||||
r |= 0b111; // Some kind of status flag for each Qtaro board? Must be 1 after writing FPGA firmware
|
||||
return r;
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::event_io_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
m_event_io[offset] = data;
|
||||
}
|
||||
|
||||
uint32_t jaleco_vj_king_qtaro_device::event_r(offs_t offset)
|
||||
{
|
||||
// 0x200 = Read event, based on debug strings (What was read? DMA data?)
|
||||
return m_event;
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::event_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
m_event &= ~data;
|
||||
}
|
||||
|
||||
uint32_t jaleco_vj_king_qtaro_device::event_mask_r(offs_t offset)
|
||||
{
|
||||
return m_event_mask;
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::event_mask_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
m_event_mask = data;
|
||||
}
|
||||
|
||||
uint32_t jaleco_vj_king_qtaro_device::int_r(offs_t offset)
|
||||
{
|
||||
auto r = m_int & ~0x10;
|
||||
|
||||
if (m_dma_running[0] || m_dma_running[1] || m_dma_running[2]) {
|
||||
// The only time 0x10 is referenced is when ending WriteStream for the individual Qtaro devices.
|
||||
// All 3 of the WriteStream cleanup functions start by writing 0 to dma_requested_w and dma_running_w
|
||||
// then loop until 0x10 is not set here.
|
||||
r |= 0x10;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::int_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
// 0x1000000 is used to trigger an event interrupt in the Qtaro driver.
|
||||
// The interrupt will only be accepted and cleared when event_r, event2_r, event_io_r are non-zero.
|
||||
// It's set, read, and cleared all in the device driver on the PC so no need to handle it here.
|
||||
m_int = data;
|
||||
}
|
||||
|
||||
uint32_t jaleco_vj_king_qtaro_device::int_fpga_r(offs_t offset)
|
||||
{
|
||||
return m_int_fpga;
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::int_fpga_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
m_int_fpga = data;
|
||||
}
|
||||
|
||||
template <int DeviceId>
|
||||
void jaleco_vj_king_qtaro_device::dma_requested_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
m_dma_running[DeviceId] = data == 1;
|
||||
|
||||
if (data == 1 && m_dma_descriptor_requested_addr[DeviceId] != 0) {
|
||||
m_dma_descriptor_addr[DeviceId] = m_dma_descriptor_requested_addr[DeviceId];
|
||||
m_dma_descriptor_length[DeviceId] = 0;
|
||||
m_dma_descriptor_requested_addr[DeviceId] = 0;
|
||||
}
|
||||
|
||||
LOGMASKED(LOG_DMA, "%lf %s dma_requested_w<%d>: %08x\n", machine().time().as_double(), machine().describe_context().c_str(), DeviceId, data);
|
||||
}
|
||||
|
||||
template <int DeviceId>
|
||||
void jaleco_vj_king_qtaro_device::dma_descriptor_phys_addr_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
LOGMASKED(LOG_DMA, "dma_descriptor_phys_addr_w<%d>: %08x %d\n", DeviceId, data, m_dma_running[DeviceId]);
|
||||
m_dma_descriptor_requested_addr[DeviceId] = data;
|
||||
}
|
||||
|
||||
template <int DeviceId>
|
||||
uint32_t jaleco_vj_king_qtaro_device::dma_running_r(offs_t offset)
|
||||
{
|
||||
return m_dma_running[DeviceId];
|
||||
}
|
||||
|
||||
template <int DeviceId>
|
||||
void jaleco_vj_king_qtaro_device::dma_running_w(offs_t offset, uint32_t data)
|
||||
{
|
||||
LOGMASKED(LOG_DMA, "dma_running_w<%d>: %08x\n", DeviceId, data);
|
||||
|
||||
if (data == 0)
|
||||
m_dma_running[DeviceId] = false;
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(jaleco_vj_king_qtaro_device::video_dma_callback)
|
||||
{
|
||||
for (int device_id = 0; device_id < 3; device_id++) {
|
||||
if (!m_dma_running[device_id] || BIT(m_dma_descriptor_addr[device_id], 0)) {
|
||||
m_dma_running[device_id] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t dmaLength = m_dma_space->read_dword(m_dma_descriptor_addr[device_id] + 4);
|
||||
const uint32_t bufferPhysAddr = m_dma_space->read_dword(m_dma_descriptor_addr[device_id] + 8);
|
||||
const uint32_t burstLength = std::min(dmaLength - m_dma_descriptor_length[device_id], DMA_BURST_SIZE);
|
||||
|
||||
if (burstLength == 0)
|
||||
continue;
|
||||
|
||||
LOGMASKED(LOG_VERBOSE_DMA, "DMA %d copy %08x + %04x = %08x: %08x bytes\n", device_id, bufferPhysAddr, m_dma_descriptor_length[device_id], bufferPhysAddr + m_dma_descriptor_length[device_id], burstLength);
|
||||
|
||||
uint8_t buf[DMA_BURST_SIZE];
|
||||
for (int i = 0; i < burstLength; i++) {
|
||||
buf[i] = m_dma_space->read_byte(bufferPhysAddr + m_dma_descriptor_length[device_id]);
|
||||
m_dma_descriptor_length[device_id]++;
|
||||
}
|
||||
|
||||
m_qtaro[device_id]->write(buf, burstLength);
|
||||
|
||||
if (m_dma_running[device_id] && m_dma_descriptor_length[device_id] >= dmaLength) {
|
||||
const uint32_t nextDescriptorPhysAddr = m_dma_space->read_dword(m_dma_descriptor_addr[device_id]);
|
||||
const uint32_t flags = m_dma_space->read_dword(m_dma_descriptor_addr[device_id] + 12); // Bit 24 is set to denote the last entry at the same time as bit 0 of the next descriptor addr is set
|
||||
|
||||
LOGMASKED(LOG_DMA, "DMA %d: %08x -> %08x %08x (%d %d)\n", device_id, m_dma_descriptor_addr[device_id], nextDescriptorPhysAddr, m_dma_descriptor_length[device_id], BIT(nextDescriptorPhysAddr, 0), BIT(flags, 24));
|
||||
|
||||
m_dma_descriptor_addr[device_id] = nextDescriptorPhysAddr;
|
||||
m_dma_descriptor_length[device_id] = 0;
|
||||
m_dma_running[device_id] = BIT(m_dma_descriptor_addr[device_id], 0) == 0 && BIT(flags, 24) == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::map(address_map &map)
|
||||
{
|
||||
map(0x10, 0x10).r(m_qtaro[0], FUNC(jaleco_vj_qtaro_device::reg2_r));
|
||||
map(0x18, 0x1b).rw(m_qtaro[0], FUNC(jaleco_vj_qtaro_device::reg3_r), FUNC(jaleco_vj_qtaro_device::reg3_w));
|
||||
map(0x20, 0x20).r(m_qtaro[1], FUNC(jaleco_vj_qtaro_device::reg2_r));
|
||||
map(0x28, 0x2b).rw(m_qtaro[1], FUNC(jaleco_vj_qtaro_device::reg3_r), FUNC(jaleco_vj_qtaro_device::reg3_w));
|
||||
map(0x30, 0x30).r(m_qtaro[2], FUNC(jaleco_vj_qtaro_device::reg2_r));
|
||||
map(0x38, 0x3b).rw(m_qtaro[2], FUNC(jaleco_vj_qtaro_device::reg3_r), FUNC(jaleco_vj_qtaro_device::reg3_w));
|
||||
|
||||
map(0x50, 0x53).w(FUNC(jaleco_vj_king_qtaro_device::dma_requested_w<0>));
|
||||
map(0x54, 0x57).w(FUNC(jaleco_vj_king_qtaro_device::dma_descriptor_phys_addr_w<0>));
|
||||
map(0x58, 0x5b).rw(FUNC(jaleco_vj_king_qtaro_device::dma_running_r<0>), FUNC(jaleco_vj_king_qtaro_device::dma_running_w<0>));
|
||||
map(0x60, 0x63).w(FUNC(jaleco_vj_king_qtaro_device::dma_requested_w<1>));
|
||||
map(0x64, 0x67).w(FUNC(jaleco_vj_king_qtaro_device::dma_descriptor_phys_addr_w<1>));
|
||||
map(0x68, 0x6b).rw(FUNC(jaleco_vj_king_qtaro_device::dma_running_r<1>), FUNC(jaleco_vj_king_qtaro_device::dma_running_w<1>));
|
||||
map(0x70, 0x73).w(FUNC(jaleco_vj_king_qtaro_device::dma_requested_w<2>));
|
||||
map(0x74, 0x77).w(FUNC(jaleco_vj_king_qtaro_device::dma_descriptor_phys_addr_w<2>));
|
||||
map(0x78, 0x7b).rw(FUNC(jaleco_vj_king_qtaro_device::dma_running_r<2>), FUNC(jaleco_vj_king_qtaro_device::dma_running_w<2>));
|
||||
|
||||
map(0x80, 0x83).rw(FUNC(jaleco_vj_king_qtaro_device::qtaro_fpga_firmware_status_r), FUNC(jaleco_vj_king_qtaro_device::qtaro_fpga_firmware_status_w));
|
||||
map(0x84, 0x87).rw(FUNC(jaleco_vj_king_qtaro_device::qtaro_fpga_firmware_r), FUNC(jaleco_vj_king_qtaro_device::qtaro_fpga_firmware_w));
|
||||
map(0x88, 0x8b).rw(FUNC(jaleco_vj_king_qtaro_device::fpga_firmware_status_r), FUNC(jaleco_vj_king_qtaro_device::fpga_firmware_status_w));
|
||||
map(0x8c, 0x8f).rw(FUNC(jaleco_vj_king_qtaro_device::fpga_firmware_r), FUNC(jaleco_vj_king_qtaro_device::fpga_firmware_w));
|
||||
|
||||
map(0x90, 0x94).rw(FUNC(jaleco_vj_king_qtaro_device::event_io_r), FUNC(jaleco_vj_king_qtaro_device::event_io_w));
|
||||
map(0x98, 0x9c).rw(FUNC(jaleco_vj_king_qtaro_device::event_unk_r), FUNC(jaleco_vj_king_qtaro_device::event_unk_w));
|
||||
map(0xa0, 0xa4).rw(FUNC(jaleco_vj_king_qtaro_device::event_io_mask_r), FUNC(jaleco_vj_king_qtaro_device::event_io_mask_w));
|
||||
map(0xa8, 0xab).rw(FUNC(jaleco_vj_king_qtaro_device::event_mask_r), FUNC(jaleco_vj_king_qtaro_device::event_mask_w));
|
||||
map(0xac, 0xaf).rw(FUNC(jaleco_vj_king_qtaro_device::event_r), FUNC(jaleco_vj_king_qtaro_device::event_w));
|
||||
|
||||
map(0xb1, 0xb1).rw(m_qtaro[0], FUNC(jaleco_vj_qtaro_device::reg_r), FUNC(jaleco_vj_qtaro_device::reg_w));
|
||||
map(0xb2, 0xb2).rw(m_qtaro[1], FUNC(jaleco_vj_qtaro_device::reg_r), FUNC(jaleco_vj_qtaro_device::reg_w));
|
||||
map(0xb3, 0xb3).rw(m_qtaro[2], FUNC(jaleco_vj_qtaro_device::reg_r), FUNC(jaleco_vj_qtaro_device::reg_w));
|
||||
map(0xb4, 0xb7).rw(FUNC(jaleco_vj_king_qtaro_device::int_r), FUNC(jaleco_vj_king_qtaro_device::int_w));
|
||||
map(0xb8, 0xbb).rw(FUNC(jaleco_vj_king_qtaro_device::int_fpga_r), FUNC(jaleco_vj_king_qtaro_device::int_fpga_w));
|
||||
}
|
||||
|
||||
jaleco_vj_king_qtaro_device::jaleco_vj_king_qtaro_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
jaleco_vj_king_qtaro_device(mconfig, JALECO_VJ_KING_QTARO, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
jaleco_vj_king_qtaro_device::jaleco_vj_king_qtaro_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
|
||||
pci_device(mconfig, type, tag, owner, clock),
|
||||
m_dma_space(*this, finder_base::DUMMY_TAG, -1, 32),
|
||||
m_qtaro(*this, "qtaro%u", 1)
|
||||
{
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::device_start()
|
||||
{
|
||||
pci_device::device_start();
|
||||
set_ids(0x11ca0007, 0x01, 0x068000, 0x00000000);
|
||||
|
||||
intr_pin = 1; // TODO: Verify with real hardware
|
||||
intr_line = 10; // TODO: No idea what this should be on real hardware, but a valid IRQ is required to work
|
||||
|
||||
add_map(256, M_MEM, FUNC(jaleco_vj_king_qtaro_device::map));
|
||||
|
||||
m_dma_timer = timer_alloc(FUNC(jaleco_vj_king_qtaro_device::video_dma_callback), this);
|
||||
m_dma_timer->adjust(DMA_TIMER_PERIOD, 0, DMA_TIMER_PERIOD);
|
||||
|
||||
save_item(NAME(m_int));
|
||||
save_item(NAME(m_int_fpga));
|
||||
save_item(NAME(m_event));
|
||||
save_item(NAME(m_event_mask));
|
||||
save_item(NAME(m_event_io));
|
||||
save_item(NAME(m_event_io_mask));
|
||||
save_item(NAME(m_event_unk));
|
||||
save_item(NAME(m_event_unk_mask));
|
||||
save_item(NAME(m_dma_running));
|
||||
save_item(NAME(m_dma_descriptor_requested_addr));
|
||||
save_item(NAME(m_dma_descriptor_addr));
|
||||
save_item(NAME(m_dma_descriptor_length));
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::device_reset()
|
||||
{
|
||||
m_int = 0;
|
||||
m_int_fpga = 0;
|
||||
|
||||
m_event = m_event_mask = 0;
|
||||
std::fill(std::begin(m_event_io), std::end(m_event_io), 0);
|
||||
std::fill(std::begin(m_event_io_mask), std::end(m_event_io_mask), 0);
|
||||
std::fill(std::begin(m_event_unk), std::end(m_event_unk), 0);
|
||||
std::fill(std::begin(m_event_unk_mask), std::end(m_event_unk_mask), 0);
|
||||
|
||||
std::fill(std::begin(m_dma_running), std::end(m_dma_running), false);
|
||||
std::fill(std::begin(m_dma_descriptor_requested_addr), std::end(m_dma_descriptor_requested_addr), 0);
|
||||
std::fill(std::begin(m_dma_descriptor_addr), std::end(m_dma_descriptor_addr), 0);
|
||||
std::fill(std::begin(m_dma_descriptor_length), std::end(m_dma_descriptor_length), 0);
|
||||
}
|
||||
|
||||
void jaleco_vj_king_qtaro_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
JALECO_VJ_QTARO(config, m_qtaro[0], 0);
|
||||
JALECO_VJ_QTARO(config, m_qtaro[1], 0);
|
||||
JALECO_VJ_QTARO(config, m_qtaro[2], 0);
|
||||
}
|
133
src/mame/jaleco/jaleco_vj_qtaro.h
Normal file
133
src/mame/jaleco/jaleco_vj_qtaro.h
Normal file
@ -0,0 +1,133 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
|
||||
#ifndef MAME_JALECO_JALECO_VJ_QTARO_H
|
||||
#define MAME_JALECO_JALECO_VJ_QTARO_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "machine/pci.h"
|
||||
|
||||
|
||||
class jaleco_vj_qtaro_device : public device_t
|
||||
{
|
||||
public:
|
||||
jaleco_vj_qtaro_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
static constexpr feature_type imperfect_features() {
|
||||
return feature::TIMING; // DMA timings aren't perfectly synced between all displays so one video stream may end up out of sync
|
||||
}
|
||||
|
||||
void video_mix_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
uint8_t reg_r(offs_t offset);
|
||||
void reg_w(offs_t offset, uint8_t data);
|
||||
|
||||
uint8_t reg2_r(offs_t offset);
|
||||
|
||||
uint32_t reg3_r(offs_t offset);
|
||||
void reg3_w(offs_t offset, uint32_t data);
|
||||
|
||||
void write(uint8_t *data, uint32_t len);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
private:
|
||||
uint8_t m_int;
|
||||
uint32_t m_mix_level;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
|
||||
class jaleco_vj_king_qtaro_device : public pci_device
|
||||
{
|
||||
public:
|
||||
jaleco_vj_king_qtaro_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// FIXME: this is a workaround for the PCI framework’s lack of bus mastering DMA support
|
||||
template <typename... T> void set_bus_master_space(T &&... args) { m_dma_space.set_tag(std::forward<T>(args)...); }
|
||||
|
||||
template <int DeviceId> void video_mix_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) { m_qtaro[DeviceId]->video_mix_w(offset, data, mem_mask); }
|
||||
|
||||
void video_control_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
|
||||
|
||||
protected:
|
||||
jaleco_vj_king_qtaro_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
private:
|
||||
void map(address_map &map);
|
||||
|
||||
uint32_t qtaro_fpga_firmware_status_r(offs_t offset);
|
||||
void qtaro_fpga_firmware_status_w(offs_t offset, uint32_t data);
|
||||
|
||||
uint32_t qtaro_fpga_firmware_r(offs_t offset);
|
||||
void qtaro_fpga_firmware_w(offs_t offset, uint32_t data);
|
||||
|
||||
uint32_t fpga_firmware_status_r(offs_t offset);
|
||||
void fpga_firmware_status_w(offs_t offset, uint32_t data);
|
||||
|
||||
uint32_t fpga_firmware_r(offs_t offset);
|
||||
void fpga_firmware_w(offs_t offset, uint32_t data);
|
||||
|
||||
uint8_t event_io_mask_r(offs_t offset);
|
||||
void event_io_mask_w(offs_t offset, uint8_t data);
|
||||
|
||||
uint8_t event_unk_r(offs_t offset);
|
||||
void event_unk_w(offs_t offset, uint8_t data);
|
||||
|
||||
uint8_t event_io_r(offs_t offset);
|
||||
void event_io_w(offs_t offset, uint8_t data);
|
||||
|
||||
uint32_t event_r(offs_t offset);
|
||||
void event_w(offs_t offset, uint32_t data);
|
||||
|
||||
uint32_t event_mask_r(offs_t offset);
|
||||
void event_mask_w(offs_t offset, uint32_t data);
|
||||
|
||||
uint32_t int_r(offs_t offset);
|
||||
void int_w(offs_t offset, uint32_t data);
|
||||
|
||||
uint32_t int_fpga_r(offs_t offset);
|
||||
void int_fpga_w(offs_t offset, uint32_t data);
|
||||
|
||||
template <int DeviceId> void dma_requested_w(offs_t offset, uint32_t data);
|
||||
|
||||
template <int DeviceId> void dma_descriptor_phys_addr_w(offs_t offset, uint32_t data);
|
||||
|
||||
template <int DeviceId> uint32_t dma_running_r(offs_t offset);
|
||||
template <int DeviceId> void dma_running_w(offs_t offset, uint32_t data);
|
||||
|
||||
TIMER_CALLBACK_MEMBER(video_dma_callback);
|
||||
|
||||
required_address_space m_dma_space;
|
||||
required_device_array<jaleco_vj_qtaro_device, 3> m_qtaro;
|
||||
|
||||
emu_timer* m_dma_timer;
|
||||
|
||||
uint32_t m_int;
|
||||
uint32_t m_int_fpga;
|
||||
|
||||
uint32_t m_event, m_event_mask;
|
||||
uint8_t m_event_io[5], m_event_io_mask[5];
|
||||
uint8_t m_event_unk[5], m_event_unk_mask[5];
|
||||
|
||||
bool m_dma_running[3];
|
||||
uint32_t m_dma_descriptor_requested_addr[3];
|
||||
uint32_t m_dma_descriptor_addr[3];
|
||||
uint32_t m_dma_descriptor_length[3];
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
|
||||
DECLARE_DEVICE_TYPE(JALECO_VJ_QTARO, jaleco_vj_qtaro_device)
|
||||
DECLARE_DEVICE_TYPE(JALECO_VJ_KING_QTARO, jaleco_vj_king_qtaro_device)
|
||||
|
||||
#endif // MAME_JALECO_JALECO_VJ_QTARO_H
|
@ -939,11 +939,10 @@ void stepstag_state::stepstag_sub_map(address_map &map)
|
||||
map(0x400000, 0x43ffff).ram().w(FUNC(stepstag_state::stepstag_palette_mid_w)).share("paletteram2");
|
||||
map(0x500000, 0x53ffff).ram().w(FUNC(stepstag_state::stepstag_palette_right_w)).share("paletteram3");
|
||||
|
||||
// rgb brightness?
|
||||
map(0x700000, 0x700001).nopw(); // 0-f
|
||||
map(0x700002, 0x700003).nopw(); // 0-f
|
||||
map(0x700004, 0x700005).nopw(); // 0-f
|
||||
map(0x700006, 0x700007).nopw(); // 0-3f (high bits?)
|
||||
map(0x700000, 0x700001).w(m_jaleco_vj_pc, FUNC(jaleco_vj_pc_device::video_mix_w<0>));
|
||||
map(0x700002, 0x700003).w(m_jaleco_vj_pc, FUNC(jaleco_vj_pc_device::video_mix_w<1>));
|
||||
map(0x700004, 0x700005).w(m_jaleco_vj_pc, FUNC(jaleco_vj_pc_device::video_mix_w<2>));
|
||||
map(0x700006, 0x700007).w(m_jaleco_vj_pc, FUNC(jaleco_vj_pc_device::video_control_w));
|
||||
|
||||
// left screen sprites
|
||||
map(0x800000, 0x8007ff).ram().share("spriteram1"); // Object RAM
|
||||
|
Loading…
Reference in New Issue
Block a user