From aefd1f6843ddad3432800ff33910bb5f4017e85e Mon Sep 17 00:00:00 2001 From: angelosa Date: Sun, 14 May 2023 19:57:01 +0200 Subject: [PATCH] nintendo/n64_v.cpp: implement interlace mode --- src/mame/nintendo/aleck64.cpp | 19 ++++++------- src/mame/nintendo/n64.cpp | 11 ++++---- src/mame/nintendo/n64.h | 14 ++++++++-- src/mame/nintendo/n64_gateway.cpp | 10 +++---- src/mame/nintendo/n64_v.cpp | 44 ++++++++++++++++++++++--------- 5 files changed, 61 insertions(+), 37 deletions(-) diff --git a/src/mame/nintendo/aleck64.cpp b/src/mame/nintendo/aleck64.cpp index 53bedc1c5e4..3e747866376 100644 --- a/src/mame/nintendo/aleck64.cpp +++ b/src/mame/nintendo/aleck64.cpp @@ -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; diff --git a/src/mame/nintendo/n64.cpp b/src/mame/nintendo/n64.cpp index 0e52c9c3259..997880b6856 100644 --- a/src/mame/nintendo/n64.cpp +++ b/src/mame/nintendo/n64.cpp @@ -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); diff --git a/src/mame/nintendo/n64.h b/src/mame/nintendo/n64.h index 1b0e0ecf89a..5adafa79999 100644 --- a/src/mame/nintendo/n64.h +++ b/src/mame/nintendo/n64.h @@ -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 m_rcp_periphs; + required_device m_screen; + /* video-related */ std::unique_ptr 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; diff --git a/src/mame/nintendo/n64_gateway.cpp b/src/mame/nintendo/n64_gateway.cpp index e8f5aff2bd0..60dcf3a41cf 100644 --- a/src/mame/nintendo/n64_gateway.cpp +++ b/src/mame/nintendo/n64_gateway.cpp @@ -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); diff --git a/src/mame/nintendo/n64_v.cpp b/src/mame/nintendo/n64_v.cpp index ff7ae8e708c..ecf65dabdfa 100644 --- a/src/mame/nintendo/n64_v.cpp +++ b/src/mame/nintendo/n64_v.cpp @@ -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: