video/k057714.cpp: Implemented raster timing registers. (#7846)

* Gives precise timings for Firebeat screens.
This commit is contained in:
987123879113 2021-03-13 21:28:40 +09:00 committed by GitHub
parent 61a941762c
commit 721fbb5cfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 148 additions and 60 deletions

View File

@ -259,6 +259,7 @@ const double XTAL::known_xtals[] = {
16'400'000, /* 16.4_MHz_XTAL MS 6102 */
16'572'000, /* 16.572_MHz_XTAL Micro-Term ACT-5A */
16'588'800, /* 16.5888_MHz_XTAL SM 7238 */
16'666'600, /* 16.6666_MHz_XTAL Firebeat GCU */
16'669'800, /* 16.6698_MHz_XTAL Qume QVT-102 */
16'670'000, /* 16.67_MHz_XTAL - */
16'777'216, /* 16.777216_MHz_XTAL Nintendo Game Boy Advance */

View File

@ -10,6 +10,8 @@
GQ972 PWB(A2) 0000070609 Main board
-----------------------------------
25.175 MHz clock (near GCUs and VGA connectors)
16.6666 MHz clock (near GCUs and VGA connectors)
OSC 66.0000MHz
IBM PowerPC 403GCX at 66MHz
(2x) Konami 0000057714 (2D object processor)
@ -396,6 +398,7 @@ public:
m_work_ram(*this, "work_ram"),
m_ata(*this, "ata"),
m_gcu(*this, "gcu"),
m_gcu_sub(*this, "gcu_sub"),
m_duart_com(*this, "duart_com"),
m_status_leds(*this, "status_led_%u", 0U),
m_io_inputs(*this, "IN%u", 0U)
@ -405,6 +408,7 @@ public:
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void device_resolve_objects() override;
uint32_t screen_update_firebeat_0(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
@ -433,6 +437,7 @@ protected:
required_shared_ptr<uint32_t> m_work_ram;
required_device<ata_interface_device> m_ata;
required_device<k057714_device> m_gcu;
optional_device<k057714_device> m_gcu_sub;
private:
uint32_t cabinet_r(offs_t offset, uint32_t mem_mask = ~0);
@ -446,6 +451,8 @@ private:
uint8_t input_r(offs_t offset);
void control_w(offs_t offset, uint8_t data);
uint16_t ata_command_r(offs_t offset, uint16_t mem_mask = ~0);
void ata_command_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
@ -465,6 +472,8 @@ private:
output_finder<8> m_status_leds;
required_ioport_array<4> m_io_inputs;
uint8_t m_control;
};
class firebeat_spu_state : public firebeat_state
@ -574,7 +583,6 @@ public:
firebeat_state(mconfig, type, tag),
m_duart_midi(*this, "duart_midi"),
m_kbd(*this, "kbd%u", 0),
m_gcu_sub(*this, "gcu_sub"),
m_lamps(*this, "lamp_%u", 1U),
m_cab_led_door_lamp(*this, "door_lamp"),
m_cab_led_start1p(*this, "start1p"),
@ -613,7 +621,6 @@ private:
required_device<pc16552_device> m_duart_midi;
required_device_array<midi_keyboard_device, 2> m_kbd;
required_device<k057714_device> m_gcu_sub;
output_finder<3> m_lamps;
output_finder<> m_cab_led_door_lamp;
@ -691,6 +698,13 @@ void firebeat_state::machine_start()
m_maincpu->ppcdrc_add_fastram(0x00000000, 0x01ffffff, false, m_work_ram);
}
void firebeat_state::machine_reset()
{
m_extend_board_irq_enable = 0x3f;
m_extend_board_irq_active = 0x00;
m_control = 0;
}
void firebeat_state::device_resolve_objects()
{
m_status_leds.resolve();
@ -699,12 +713,10 @@ void firebeat_state::device_resolve_objects()
void firebeat_state::init_firebeat()
{
uint8_t *rom = memregion("user2")->base();
set_ibutton(rom);
// pc16552d_init(machine(), 0, 19660800, comm_uart_irq_callback, 0); // Network UART
m_extend_board_irq_enable = 0x3f;
m_extend_board_irq_active = 0x00;
// Set to defaults here, but overridden for most specific games. It represents various bits of
// data, such as the firebeat's ability to play certain games at all, whether the firebeat is
// meant as a rental unit or normal unit, and whether the unit is meant as a JP firebeat or
@ -715,8 +727,6 @@ void firebeat_state::init_firebeat()
m_maincpu->ppc4xx_spu_set_tx_handler(write8smo_delegate(*this, FUNC(firebeat_state::security_w)));
set_ibutton(rom);
init_lights(write32s_delegate(*this), write32s_delegate(*this), write32s_delegate(*this));
}
@ -740,17 +750,14 @@ void firebeat_state::firebeat(machine_config &config)
/* video hardware */
PALETTE(config, "palette", palette_device::RGB_555);
K057714(config, m_gcu, 0);
m_gcu->irq_callback().set(FUNC(firebeat_state::gcu_interrupt));
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
screen.set_size(512, 384);
screen.set_visarea(0, 511, 0, 383);
screen.set_raw(25.175_MHz_XTAL, 800, 0, 640, 525, 0, 480);
screen.set_screen_update(FUNC(firebeat_state::screen_update_firebeat_0));
screen.set_palette("palette");
K057714(config, m_gcu, 0).set_screen("screen");
m_gcu->irq_callback().set(FUNC(firebeat_state::gcu_interrupt));
/* sound hardware */
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
@ -774,6 +781,7 @@ void firebeat_state::firebeat_map(address_map &map)
map(0x74000000, 0x740003ff).noprw(); // SPU shared RAM
map(0x7d000200, 0x7d00021f).r(FUNC(firebeat_state::cabinet_r));
map(0x7d000400, 0x7d000401).rw("ymz", FUNC(ymz280b_device::read), FUNC(ymz280b_device::write));
map(0x7d000500, 0x7d000501).w(FUNC(firebeat_state::control_w));
map(0x7d000800, 0x7d000803).r(FUNC(firebeat_state::input_r));
map(0x7d400000, 0x7d5fffff).rw("flash_main", FUNC(fujitsu_29f016a_device::read), FUNC(fujitsu_29f016a_device::write));
map(0x7d800000, 0x7d9fffff).rw("flash_snd1", FUNC(fujitsu_29f016a_device::read), FUNC(fujitsu_29f016a_device::write));
@ -1018,6 +1026,36 @@ uint8_t firebeat_state::input_r(offs_t offset)
return 0;
}
/*****************************************************************************/
void firebeat_state::control_w(offs_t offset, uint8_t data)
{
// 0x01 - 31kHz (25.175 MHz)/24kHz (16.6666 MHz) clock switch
// 0x02 - Unused?
// 0x04 - Set to 1 by all games except beatmania III, usage unknown. Screen related?
// 0x08 - Toggles screen mirroring when only one GCU is in use? Default 0
// 0x80 - Used by ParaParaParadise and Keyboardmania. Set to 1 when doing YMZ flash initialization?
if (BIT(data, 0) == 0 && BIT(m_control, 0) == 1)
{
// Set screen to 31kHz from 24kHz
m_gcu->set_pixclock(25.175_MHz_XTAL);
if (m_gcu_sub)
m_gcu_sub->set_pixclock(25.175_MHz_XTAL);
}
else if (BIT(data, 0) == 1 && BIT(m_control, 0) == 0)
{
// Set screen to 24kHz from 31kHz
m_gcu->set_pixclock(16.6666_MHz_XTAL);
if (m_gcu_sub)
m_gcu_sub->set_pixclock(16.6666_MHz_XTAL);
}
m_control = data;
}
/*****************************************************************************/
/* ATA Interface */
@ -1176,11 +1214,13 @@ WRITE_LINE_MEMBER(firebeat_state::sound_irq_callback)
void firebeat_spu_state::machine_start()
{
firebeat_state::machine_start();
m_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(firebeat_spu_state::spu_dma_callback), this));
}
void firebeat_spu_state::machine_reset()
{
firebeat_state::machine_reset();
m_spu_ata_dma = 0;
m_spu_ata_dmarq = 0;
m_wave_bank = 0;
@ -1430,11 +1470,6 @@ void firebeat_bm3_state::firebeat_bm3(machine_config &config)
m_maincpu->set_addrmap(AS_PROGRAM, &firebeat_bm3_state::firebeat_bm3_map);
// beatmania III is the only game on the Firebeat platform to use 640x480
screen_device *screen = subdevice<screen_device>("screen");
screen->set_size(640, 480);
screen->set_visarea(0, 639, 0, 479);
ATA_INTERFACE(config, m_spuata).options(firebeat_ata_devices, "hdd", nullptr, true);
m_spuata->irq_handler().set(FUNC(firebeat_bm3_state::spu_ata_interrupt));
m_spuata->dmarq_handler().set(FUNC(firebeat_bm3_state::spu_ata_dmarq));
@ -1803,28 +1838,22 @@ void firebeat_kbm_state::firebeat_kbm(machine_config &config)
/* video hardware */
PALETTE(config, "palette", palette_device::RGB_555);
K057714(config, m_gcu, 0);
m_gcu->irq_callback().set(FUNC(firebeat_kbm_state::gcu_interrupt));
K057714(config, m_gcu_sub, 0);
m_gcu_sub->irq_callback().set(FUNC(firebeat_kbm_state::gcu_interrupt));
screen_device &lscreen(SCREEN(config, "lscreen", SCREEN_TYPE_RASTER));
lscreen.set_refresh_hz(60);
lscreen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
lscreen.set_size(512, 384);
lscreen.set_visarea(0, 511, 0, 383);
lscreen.set_raw(25.175_MHz_XTAL, 800, 0, 640, 525, 0, 480);
lscreen.set_screen_update(FUNC(firebeat_kbm_state::screen_update_firebeat_0));
lscreen.set_palette("palette");
K057714(config, m_gcu, 0).set_screen("lscreen");
m_gcu->irq_callback().set(FUNC(firebeat_kbm_state::gcu_interrupt));
screen_device &rscreen(SCREEN(config, "rscreen", SCREEN_TYPE_RASTER));
rscreen.set_refresh_hz(60);
rscreen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
rscreen.set_size(512, 384);
rscreen.set_visarea(0, 511, 0, 383);
rscreen.set_raw(25.175_MHz_XTAL, 800, 0, 640, 525, 0, 480);
rscreen.set_screen_update(FUNC(firebeat_kbm_state::screen_update_firebeat_1));
rscreen.set_palette("palette");
K057714(config, m_gcu_sub, 0).set_screen("rscreen");
m_gcu_sub->irq_callback().set(FUNC(firebeat_kbm_state::gcu_interrupt));
/* sound hardware */
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();

View File

@ -418,14 +418,11 @@ void konendev_state::konendev(machine_config &config)
PALETTE(config, "palette", palette_device::RGB_555);
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); // Not accurate
screen.set_size(640, 480);
screen.set_visarea(0, 639, 0, 479);
screen.set_raw(25.175_MHz_XTAL, 800, 0, 640, 525, 0, 480); // Based on Firebeat settings
screen.set_screen_update(FUNC(konendev_state::screen_update));
screen.set_palette("palette");
K057714(config, m_gcu, 0);
K057714(config, m_gcu, 0).set_screen("screen");
m_gcu->irq_callback().set(FUNC(konendev_state::gcu_interrupt));
RTC62423(config, m_rtc, XTAL(32'768));

View File

@ -29,6 +29,7 @@ DEFINE_DEVICE_TYPE(K057714, k057714_device, "k057714", "k057714_device GCU")
k057714_device::k057714_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, K057714, tag, owner, clock)
, device_video_interface(mconfig, *this)
, m_irq(*this)
{
}
@ -64,8 +65,15 @@ void k057714_device::device_start()
save_item(NAME(m_fb_origin_y));
save_item(NAME(m_layer_select));
save_item(NAME(m_reg_6c));
save_item(NAME(m_display_width));
save_item(NAME(m_display_height));
save_item(NAME(m_display_h_visarea));
save_item(NAME(m_display_h_frontporch));
save_item(NAME(m_display_h_backporch));
save_item(NAME(m_display_h_syncpulse));
save_item(NAME(m_display_v_visarea));
save_item(NAME(m_display_v_frontporch));
save_item(NAME(m_display_v_backporch));
save_item(NAME(m_display_v_syncpulse));
save_item(NAME(m_pixclock));
}
void k057714_device::device_reset()
@ -75,8 +83,24 @@ void k057714_device::device_reset()
// display width/height through registers.
// The assumption here is that since beatmania III doesn't set the display width/height
// then the game is assuming that it's already at the correct settings upon boot.
m_display_width = 639;
m_display_height = 479;
// Timing information taken from table found in all Firebeat games.
// table idx (h vis area, front porch, sync pulse, back porch, h total) (v vis area, front porch, sync pulse, back porch, v total)
// 0 (640, 16, 96, 48 = 800) (480, 10, 2, 33 = 525)
// 1 (512, 5, 96, 72 = 685) (384, 6, 4, 22 = 416)
// 2 (800, 40, 128, 88 = 1056) (600, 1, 4, 23 = 628)
// 3 (640, 20, 23, 165 = 848) (384, 6, 1, 27 = 418)
// 4 (640, 10, 21, 10 = 681) (480, 10, 2, 33 = 525)
m_display_h_visarea = 640;
m_display_h_frontporch = 16;
m_display_h_backporch = 48;
m_display_h_syncpulse = 96;
m_display_v_visarea = 480;
m_display_v_frontporch = 10;
m_display_v_backporch = 33;
m_display_v_syncpulse = 2;
m_pixclock = 25'175'000; // 25.175_MHz_XTAL, default for Firebeat but maybe not other machiness. The value can be changed externally
crtc_set_screen_params();
m_vram_read_addr = 0;
m_command_fifo0_ptr = 0;
@ -121,6 +145,21 @@ void k057714_device::device_stop()
#endif
}
void k057714_device::set_pixclock(const XTAL &xtal)
{
xtal.validate(std::string("Setting pixel clock for ") + tag());
m_pixclock = xtal.value();
crtc_set_screen_params();
}
inline void k057714_device::crtc_set_screen_params()
{
auto htotal = m_display_h_visarea + m_display_h_frontporch + m_display_h_backporch + m_display_h_syncpulse;
auto vtotal = m_display_v_visarea + m_display_v_frontporch + m_display_v_backporch + m_display_v_syncpulse;
rectangle visarea(0, m_display_h_visarea - 1, 0, m_display_v_visarea - 1);
screen().configure(htotal, vtotal, visarea, HZ_TO_ATTOSECONDS(m_pixclock) * htotal * vtotal);
}
uint32_t k057714_device::read(offs_t offset)
{
@ -149,21 +188,40 @@ void k057714_device::write(offs_t offset, uint32_t data, uint32_t mem_mask)
{
int reg = offset * 4;
switch (reg)
{
case 0x00:
if (ACCESSING_BITS_16_31)
{
// Viewport configurations discovered in game code: 640x480, 512x384, 800x600, 640x384
m_display_width = (data >> 16) & 0xffff;
m_display_h_visarea = ((data >> 16) & 0xffff) + 1;
}
if (ACCESSING_BITS_0_15)
{
m_display_h_frontporch = ((data >> 8) & 0xff) + 1;
m_display_h_backporch = (data & 0xff) + 1;
}
crtc_set_screen_params();
break;
case 0x04:
if (ACCESSING_BITS_16_31)
{
m_display_height = (data >> 16) & 0xffff;
m_display_v_visarea = ((data >> 16) & 0xffff) + 1;
}
if (ACCESSING_BITS_0_15)
{
m_display_v_frontporch = ((data >> 8) & 0xff) + 1;
m_display_v_backporch = (data & 0xff) + 1;
}
crtc_set_screen_params();
break;
case 0x08:
if (ACCESSING_BITS_16_31)
{
m_display_h_syncpulse = ((data >> 24) & 0xff) + 1;
m_display_v_syncpulse = ((data >> 16) & 0xff) + 1;
crtc_set_screen_params();
}
break;
@ -462,17 +520,6 @@ void k057714_device::draw_frame(int frame, bitmap_ind16 &bitmap, const rectangle
int k057714_device::draw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
if (m_display_width != 0 && m_display_height != 0)
{
rectangle visarea = screen.visible_area();
if (visarea.max_x != m_display_width || visarea.max_y != m_display_height)
{
visarea.max_x = m_display_width;
visarea.max_y = m_display_height;
screen.configure(m_display_width, m_display_height, visarea, screen.frame_period().attoseconds());
}
}
bitmap.fill(0, cliprect);
bool inverse_trans = false;

View File

@ -6,12 +6,16 @@
#pragma once
class k057714_device : public device_t
class k057714_device : public device_t, public device_video_interface
{
public:
// construction/destruction
k057714_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto irq_callback() { return m_irq.bind(); }
void set_pixclock(const XTAL &xtal);
int draw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
uint32_t read(offs_t offset);
@ -39,6 +43,8 @@ private:
VRAM_SIZE_HALF = 0x2000000 / 2
};
void crtc_set_screen_params();
void execute_command(uint32_t *cmd);
void execute_display_list(uint32_t addr);
void draw_object(uint32_t *cmd);
@ -70,8 +76,16 @@ private:
uint32_t m_layer_select;
uint32_t m_reg_6c;
uint32_t m_display_width;
uint32_t m_display_height;
uint32_t m_display_h_visarea;
uint32_t m_display_h_frontporch;
uint32_t m_display_h_backporch;
uint32_t m_display_h_syncpulse;
uint32_t m_display_v_visarea;
uint32_t m_display_v_frontporch;
uint32_t m_display_v_backporch;
uint32_t m_display_v_syncpulse;
uint32_t m_pixclock;
devcb_write_line m_irq;
};