nintendo/n64_v.cpp: implement interlace mode

This commit is contained in:
angelosa 2023-05-14 19:57:01 +02:00
parent b64982453a
commit aefd1f6843
5 changed files with 61 additions and 37 deletions

View File

@ -360,7 +360,7 @@ void aleck64_state::e90_prot_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
case 0x16:
if(data != 6 && data != 7)
printf("! %04x %04x %08x\n",offset*2,data,mem_mask);
logerror("E90: ! %04x %04x %08x\n",offset*2,data,mem_mask);
if(data & 1) // 0 -> 1 transition
{
@ -370,7 +370,7 @@ void aleck64_state::e90_prot_w(offs_t offset, uint16_t data, uint16_t mem_mask)
break;
//0x1e bit 0 probably enables the chip
default:
printf("%04x %04x %08x\n",offset*2,data,mem_mask);
logerror("E90: unmapped %04x %04x %08x\n",offset*2,data,mem_mask);
break;
}
}
@ -1053,13 +1053,10 @@ void aleck64_state::aleck64(machine_config &config)
m_rsp->set_addrmap(AS_DATA, &aleck64_state::rsp_dmem_map);
m_rsp->set_force_no_drc(false);
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
screen.set_size(640, 525);
screen.set_visarea(0, 639, 0, 239);
screen.set_screen_update(FUNC(aleck64_state::screen_update_n64));
screen.screen_vblank().set(FUNC(aleck64_state::screen_vblank_n64));
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_raw(DACRATE_NTSC*2,3093,0,3093,525,0,480);
m_screen->set_screen_update(FUNC(aleck64_state::screen_update));
m_screen->screen_vblank().set(FUNC(aleck64_state::screen_vblank));
PALETTE(config, "palette").set_entries(0x1000);
@ -1075,7 +1072,7 @@ void aleck64_state::aleck64(machine_config &config)
uint32_t aleck64_state::screen_update_e90(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
bitmap.fill(0, cliprect);
screen_update_n64(screen,bitmap,cliprect);
n64_state::screen_update(screen, bitmap, cliprect);
// TODO: extract from the real tables (maybe RLEd inside paletteram words 0xa - 0xf?)
static constexpr u8 pal_table[8*8] =
{
@ -1089,7 +1086,7 @@ uint32_t aleck64_state::screen_update_e90(screen_device &screen, bitmap_rgb32 &b
8, 9, 9, 9, 9, 9, 9, 8
};
for(int offs=0;offs<0x1000/4;offs+=2)
for(int offs = 0; offs < 0x1000 / 4; offs+=2)
{
// 0x400 is another enable? end code if off?
//uint16_t tile = m_e90_vram[offs] >> 16;

View File

@ -13,7 +13,6 @@
#include "n64.h"
#include "emupal.h"
#include "screen.h"
#include "softlist.h"
#include "speaker.h"
@ -410,11 +409,11 @@ void n64_console_state::n64(machine_config &config)
config.set_maximum_quantum(attotime::from_hz(500000));
/* video hardware */
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
/* Video DACRATE is for quarter pixels, so the horizontal is also given in quarter pixels. However, the horizontal and vertical timing and sizing is adjustable by register and will be reset when the registers are written. */
screen.set_raw(DACRATE_NTSC*2,3093,0,3093,525,0,525);
screen.set_screen_update(FUNC(n64_state::screen_update_n64));
screen.screen_vblank().set(FUNC(n64_state::screen_vblank_n64));
m_screen->set_raw(DACRATE_NTSC*2,3093,0,3093,525,0,480);
m_screen->set_screen_update(FUNC(n64_state::screen_update));
m_screen->screen_vblank().set(FUNC(n64_state::screen_vblank));
PALETTE(config, "palette").set_entries(0x1000);
@ -435,6 +434,8 @@ void n64_console_state::n64(machine_config &config)
SOFTWARE_LIST(config, "cart_list").set_original("n64");
}
// TODO: different xtal for PAL
void n64_console_state::n64dd(machine_config &config)
{
n64(config);

View File

@ -14,6 +14,8 @@
#include "bus/generic/carts.h"
#include "imagedev/harddriv.h"
#include "screen.h"
/*----------- driver state -----------*/
class n64_rdp;
@ -31,6 +33,7 @@ public:
, m_rsp_imem(*this, "rsp_imem")
, m_rsp_dmem(*this, "rsp_dmem")
, m_rcp_periphs(*this, "rcp")
, m_screen(*this, "screen")
{
}
@ -39,8 +42,8 @@ public:
virtual void video_start() override;
void n64_machine_stop();
uint32_t screen_update_n64(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(screen_vblank_n64);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(screen_vblank);
// Getters
n64_rdp* rdp() { return m_rdp.get(); }
@ -58,8 +61,12 @@ protected:
required_device<n64_periphs> m_rcp_periphs;
required_device<screen_device> m_screen;
/* video-related */
std::unique_ptr<n64_rdp> m_rdp;
bitmap_rgb32 m_interlace_bitmap[2];
};
/*----------- devices -----------*/
@ -129,6 +136,9 @@ public:
void si_dma_tick();
void reset_tick();
void video_update(bitmap_rgb32 &bitmap);
void field_update();
u8 get_current_field() { return field; }
bool is_interlace_mode() { return bool(BIT(vi_control, 6)); }
// Video Interface (VI) registers
uint32_t vi_width = 0;

View File

@ -334,12 +334,10 @@ void n64_gateway_state::n64_lodgenet(machine_config &config)
config.set_maximum_quantum(attotime::from_hz(500000));
/* video hardware */
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
/* Video DACRATE is for quarter pixels, so the horizontal is also given in quarter pixels. However, the horizontal and vertical timing and sizing is adjustable by register and will be reset when the registers are written. */
screen.set_raw(DACRATE_NTSC*2,3093,0,3093,525,0,525);
screen.set_screen_update(FUNC(n64_state::screen_update_n64));
screen.screen_vblank().set(FUNC(n64_state::screen_vblank_n64));
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_raw(DACRATE_NTSC*2,3093,0,3093,525,0,480);
m_screen->set_screen_update(FUNC(aleck64_state::screen_update));
m_screen->screen_vblank().set(FUNC(aleck64_state::screen_vblank));
PALETTE(config, "palette").set_entries(0x1000);

View File

@ -118,9 +118,12 @@ void n64_state::video_start()
{
rdp_exec = fopen("rdp_execute.txt", "wt");
}
m_screen->register_screen_bitmap(m_interlace_bitmap[0]);
m_screen->register_screen_bitmap(m_interlace_bitmap[1]);
}
uint32_t n64_state::screen_update_n64(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
uint32_t n64_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
//uint16_t* frame_buffer = (uint16_t*)&rdram[(m_rcp_periphs->vi_origin & 0xffffff) >> 2];
//uint8_t* cvg_buffer = &m_rdp.m_hidden_bits[((m_rcp_periphs->vi_origin & 0xffffff) >> 2) >> 1];
@ -168,27 +171,42 @@ uint32_t n64_state::screen_update_n64(screen_device &screen, bitmap_rgb32 &bitma
return 0;
}
m_rcp_periphs->video_update(bitmap);
if (m_rcp_periphs->is_interlace_mode())
{
m_rcp_periphs->video_update(m_interlace_bitmap[m_rcp_periphs->get_current_field()]);
for (int y=cliprect.min_y; y <= cliprect.max_y; y ++)
{
const u8 line_field = y & 1;
const u16 y_field_line = y >> 1;
for (int x = cliprect.min_x; x<=cliprect.max_x; x++)
{
bitmap.pix(y, x) = m_interlace_bitmap[line_field].pix(y_field_line, x);
}
}
}
else
m_rcp_periphs->video_update(bitmap);
return 0;
}
WRITE_LINE_MEMBER(n64_state::screen_vblank_n64)
WRITE_LINE_MEMBER(n64_state::screen_vblank)
{
if (state)
m_rcp_periphs->field_update();
}
void n64_periphs::field_update()
{
/* Interlace */
if (vi_control & 0x40)
field ^= 1;
else
field = 0;
}
void n64_periphs::video_update(bitmap_rgb32 &bitmap)
{
if (vi_control & 0x40) /* Interlace */
{
field ^= 1;
}
else
{
field = 0;
}
switch (vi_control & 0x3)
{
case PIXEL_SIZE_16BIT: