From 32ef8f7eeda8bb8236eb160ff75830dafc09e3ea Mon Sep 17 00:00:00 2001 From: holub Date: Sun, 20 Mar 2022 23:12:19 -0400 Subject: Spectrum graphics improvements (continuation of #9218). (#9355) * Spectrum graphics improvements (continuation of #9218). Routines have been cleaned and optimized based on the current state of graphics_device. All configurations are done in terms of T-States/pixels which will simplify adjustment to proper timings. --- src/emu/screen.h | 4 + src/mame/drivers/elwro800.cpp | 1 - src/mame/drivers/pentagon.cpp | 171 +++------------------ src/mame/drivers/spec128.cpp | 47 ++---- src/mame/drivers/spectrum.cpp | 72 +++++---- src/mame/drivers/timex.cpp | 27 ++-- src/mame/drivers/tsconf.cpp | 7 +- src/mame/includes/spec128.h | 3 + src/mame/includes/spectrum.h | 59 ++----- src/mame/includes/timex.h | 17 +-- src/mame/includes/tsconf.h | 19 +-- src/mame/machine/spec_snqk.cpp | 2 + src/mame/machine/tsconf.cpp | 340 ++++++++++++++--------------------------- src/mame/video/spectrum.cpp | 272 +++++++-------------------------- src/mame/video/timex.cpp | 120 ++++----------- 15 files changed, 332 insertions(+), 829 deletions(-) diff --git a/src/emu/screen.h b/src/emu/screen.h index d4c8d8a7dfd..d1eed62c20f 100644 --- a/src/emu/screen.h +++ b/src/emu/screen.h @@ -238,6 +238,10 @@ public: xtal.validate(std::string("Configuring screen ") + tag()); return set_raw(xtal.value(), htotal, hbend, hbstart, vtotal, vbend, vbstart); } + screen_device &set_raw(const XTAL &xtal, u16 htotal, u16 vtotal, rectangle visarea) + { + return set_raw(xtal, htotal, visarea.left(), visarea.right() + 1, vtotal, visarea.top(), visarea.bottom() + 1); + } void set_refresh(attoseconds_t rate) { m_refresh = rate; } /// \brief Set refresh rate in Hertz diff --git a/src/mame/drivers/elwro800.cpp b/src/mame/drivers/elwro800.cpp index 6a1476e0333..3f2ff68b0dd 100644 --- a/src/mame/drivers/elwro800.cpp +++ b/src/mame/drivers/elwro800.cpp @@ -578,7 +578,6 @@ void elwro800_state::elwro800(machine_config &config) screen.set_raw(14_MHz_XTAL / 2, 448, 0, SPEC_SCREEN_WIDTH, 312, 0, SPEC_SCREEN_HEIGHT); // Sync and interrupt timings determined by 2716 EPROM screen.set_screen_update(FUNC(elwro800_state::screen_update_spectrum)); - screen.screen_vblank().set(FUNC(elwro800_state::screen_vblank_spectrum)); screen.set_palette("palette"); PALETTE(config, "palette", FUNC(elwro800_state::spectrum_palette), 16); diff --git a/src/mame/drivers/pentagon.cpp b/src/mame/drivers/pentagon.cpp index 9fb8c9b3c65..a98abb8b66b 100644 --- a/src/mame/drivers/pentagon.cpp +++ b/src/mame/drivers/pentagon.cpp @@ -16,8 +16,6 @@ namespace { -#define PENTAGON_SCREEN rectangle{138, 393, 80, 271} - class pentagon_state : public spectrum_128_state { public: @@ -36,15 +34,8 @@ public: protected: virtual void machine_reset() override; virtual void video_start() override; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param) override; private: - enum - { - TIMER_IRQ_ON, - TIMER_IRQ_OFF - }; - void pentagon_port_7ffd_w(uint8_t data); void pentagon_scr_w(offs_t offset, uint8_t data); void pentagon_scr2_w(offs_t offset, uint8_t data); @@ -52,8 +43,6 @@ private: uint8_t beta_enable_r(offs_t offset); uint8_t beta_disable_r(offs_t offset); INTERRUPT_GEN_MEMBER(pentagon_interrupt); - TIMER_CALLBACK_MEMBER(irq_on); - TIMER_CALLBACK_MEMBER(irq_off); void pentagon_io(address_map &map); void pentagon_mem(address_map &map); void pentagon_switch(address_map &map); @@ -67,30 +56,19 @@ private: address_space *m_program; uint8_t *m_p_ram; void pentagon_update_memory(); - - // Redefined here as POC of improved screen porocessing. Intended to update original implementation. - void to_display(unsigned int &x, unsigned int &y); - void spectrum_UpdateScreenBitmap(bool eof = false) override; - // Following 2 are obsolete - u32 screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override; - void spectrum_UpdateBorderBitmap() override; + rectangle get_screen_area() override; }; void pentagon_state::pentagon_update_memory() { uint8_t *messram = m_ram->pointer(); - m_screen_location = messram + ((m_port_7ffd_data & 8) ? (7<<14) : (5<<14)); if (strcmp(machine().system().name, "pent1024") != 0) - { m_bank4->set_base(messram + ((m_port_7ffd_data & 0x07) * 0x4000)); - } else - { // currently 512Kb ram expansion supported m_bank4->set_base(messram + (((m_port_7ffd_data & 0x07) | ((m_port_7ffd_data & 0xc0) >> 3)) * 0x4000)); - } if (m_beta->started() && m_beta->is_active() && !( m_port_7ffd_data & 0x10 ) ) { @@ -115,7 +93,7 @@ void pentagon_state::pentagon_port_7ffd_w(uint8_t data) return; if ((m_port_7ffd_data ^ data) & 0x08) - spectrum_UpdateScreenBitmap(); + m_screen->update_now(); /* store new state */ m_port_7ffd_data = data; @@ -126,121 +104,27 @@ void pentagon_state::pentagon_port_7ffd_w(uint8_t data) void pentagon_state::pentagon_scr_w(offs_t offset, uint8_t data) { - spectrum_UpdateScreenBitmap(); - + m_screen->update_now(); *((uint8_t*)m_bank2->base() + offset) = data; } void pentagon_state::pentagon_scr2_w(offs_t offset, uint8_t data) { if ((m_port_7ffd_data & 0x0f) == 0x0f || (m_port_7ffd_data & 0x0f) == 5) - spectrum_UpdateScreenBitmap(); + m_screen->update_now(); *((uint8_t*)m_bank4->base() + offset) = data; } -// This one not needed as we draw directly at screen's bitmap. -u32 pentagon_state::screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - return 0; -} - -void pentagon_state::to_display(unsigned int &x, unsigned int &y) -{ - rectangle va = m_screen->visible_area(); - if(y < va.top() || y > va.bottom()) { - x = va.left(); - y = va.top(); - } else if(x < va.left()) { - x = va.left(); - } else if(x > va.right()) { - x = va.left(); - y++; - to_display(x, y); - } -} - -void pentagon_state::spectrum_UpdateScreenBitmap(bool eof) -{ - unsigned int to_x = m_screen->hpos(); - unsigned int to_y = m_screen->vpos(); - to_display(to_x, to_y); - - if ((m_previous_screen_x == to_x) && (m_previous_screen_y == to_y) && !eof) - return; - - bitmap_ind16 *bm = &m_screen->curbitmap().as_ind16(); - if (bm->valid()) - { - u16 border_color = get_border_color(); - do - { - u16 x = m_previous_screen_x - PENTAGON_SCREEN.left(); - u16 y = m_previous_screen_y - PENTAGON_SCREEN.top(); - - if(PENTAGON_SCREEN.contains(m_previous_screen_x, m_previous_screen_y)) - { - // this can/must be optimised - if ((x & 7) == 0) - { - u16 *pix = &bm->pix(m_previous_screen_y, m_previous_screen_x); - u8 attr = *(m_screen_location + ((y & 0xF8) << 2) + (x >> 3) + 0x1800); - u8 scr = *(m_screen_location + ((y & 7) << 8) + ((y & 0x38) << 2) + ((y & 0xC0) << 5) + (x >> 3)); - u16 ink = (attr & 0x07) + ((attr >> 3) & 0x08); - u16 pap = (attr >> 3) & 0x0f; - - if (m_flash_invert && (attr & 0x80)) - scr = ~scr; - - for (uint8_t b = 0x80; b != 0; b >>= 1) - *pix++ = (scr & b) ? ink : pap; - } - } - else - { - bm->pix(m_previous_screen_y, m_previous_screen_x) = border_color; - } - - to_display(++m_previous_screen_x, m_previous_screen_y); - } while (!((m_previous_screen_x == to_x) && (m_previous_screen_y == to_y))); - } -} - -// Any calls must be replaced with spectrum_UpdateScreenBitmap() -void pentagon_state::spectrum_UpdateBorderBitmap() +rectangle pentagon_state::get_screen_area() { - spectrum_UpdateScreenBitmap(); -} - -void pentagon_state::device_timer(emu_timer &timer, device_timer_id id, int param) -{ - switch (id) - { - case TIMER_IRQ_ON: - irq_on(param); - break; - case TIMER_IRQ_OFF: - irq_off(param); - break; - default: - throw emu_fatalerror("Unknown id in pentagon_state::device_timer"); - } -} - -TIMER_CALLBACK_MEMBER(pentagon_state::irq_on) -{ - m_maincpu->set_input_line(0, HOLD_LINE); - timer_set(attotime::from_ticks(32, XTAL(14'000'000) / 4), TIMER_IRQ_OFF, 0); -} - -TIMER_CALLBACK_MEMBER(pentagon_state::irq_off) -{ - m_maincpu->set_input_line(0, CLEAR_LINE); + //TODO Possible because of incorrect z80 we have to adjust x+1 to make AccrossTheEdge look nicer + return rectangle{137, 137 + 255, 80, 80 + 191}; } INTERRUPT_GEN_MEMBER(pentagon_state::pentagon_interrupt) { - timer_set(attotime::zero, TIMER_IRQ_ON, 0); + timer_set(m_screen->time_until_pos(0) - m_maincpu->clocks_to_attotime(1), TIMER_IRQ_ON, 0); } uint8_t pentagon_state::beta_neutral_r(offs_t offset) @@ -335,46 +219,35 @@ void pentagon_state::machine_reset() void pentagon_state::video_start() { m_frame_invert_count = 16; - m_frame_number = 0; - m_flash_invert = 0; - - m_previous_border_x = m_previous_border_y = 0; - m_previous_screen_x = m_previous_screen_y = 0; - m_screen_location = m_ram->pointer() + (5 << 14); } -/* F4 Character Displayer */ static const gfx_layout spectrum_charlayout = { - 8, 8, /* 8 x 8 characters */ - 96, /* 96 characters */ - 1, /* 1 bits per pixel */ - { 0 }, /* no bitplanes */ - /* x offsets */ - { 0, 1, 2, 3, 4, 5, 6, 7 }, - /* y offsets */ - { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, - 8*8 /* every char takes 8 bytes */ + 8, 8, /* 8 x 8 characters */ + 96, /* 96 characters */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + {STEP8(0, 1)}, /* x offsets */ + {STEP8(0, 8)}, /* y offsets */ + 8*8 /* every char takes 8 bytes */ }; static GFXDECODE_START( gfx_pentagon ) - GFXDECODE_ENTRY( "maincpu", 0x17d00, spectrum_charlayout, 0, 8 ) + GFXDECODE_ENTRY( "maincpu", 0x17d00, spectrum_charlayout, 7, 8 ) GFXDECODE_END - void pentagon_state::pentagon(machine_config &config) { spectrum_128(config); - m_maincpu->set_clock(XTAL(14'000'000) / 4); + m_maincpu->set_clock(14_MHz_XTAL / 4); m_maincpu->set_addrmap(AS_PROGRAM, &pentagon_state::pentagon_mem); m_maincpu->set_addrmap(AS_IO, &pentagon_state::pentagon_io); m_maincpu->set_addrmap(AS_OPCODES, &pentagon_state::pentagon_switch); m_maincpu->set_vblank_int("screen", FUNC(pentagon_state::pentagon_interrupt)); - //m_screen->set_raw(XTAL(14'000'000) / 2, 448, 0, 352, 320, 0, 304); - m_screen->set_raw(XTAL(14'000'000) / 2, 448, PENTAGON_SCREEN.left() - 48, PENTAGON_SCREEN.right() + 49, 320, PENTAGON_SCREEN.top() - 48, PENTAGON_SCREEN.bottom() + 49); + m_screen->set_raw(14_MHz_XTAL / 2, 448, 320, {get_screen_area().left() - 48, get_screen_area().right() + 48, get_screen_area().top() - 48, get_screen_area().bottom() + 48}); BETA_DISK(config, m_beta, 0); subdevice("gfxdecode")->set_info(gfx_pentagon); @@ -382,7 +255,7 @@ void pentagon_state::pentagon(machine_config &config) SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); - ay8912_device &ay8912(AY8912(config.replace(), "ay8912", XTAL(14'000'000)/8)); + ay8912_device &ay8912(AY8912(config.replace(), "ay8912", 14_MHz_XTAL / 8)); ay8912.add_route(0, "lspeaker", 0.50); ay8912.add_route(1, "lspeaker", 0.25); ay8912.add_route(1, "rspeaker", 0.25); @@ -478,6 +351,6 @@ ROM_END } // Anonymous namespace -// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 1991, pentagon, spec128, 0, pentagon, spec_plus, pentagon_state, empty_init, "", "Pentagon 128K", 0 ) -COMP( 2005, pent1024, spec128, 0, pent1024, spec_plus, pentagon_state, empty_init, "", "Pentagon 1024SL", 0 ) +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 1991, pentagon, spec128, 0, pentagon, spec_plus, pentagon_state, empty_init, "Vladimir Drozdov", "Pentagon 128K", 0 ) +COMP( 2005, pent1024, spec128, 0, pent1024, spec_plus, pentagon_state, empty_init, "Alex Zhabin", "Pentagon 1024SL", 0 ) diff --git a/src/mame/drivers/spec128.cpp b/src/mame/drivers/spec128.cpp index 39a864e76b0..595a3cc0b85 100644 --- a/src/mame/drivers/spec128.cpp +++ b/src/mame/drivers/spec128.cpp @@ -213,7 +213,7 @@ void spectrum_128_state::spectrum_128_port_7ffd_w(offs_t offset, uint8_t data) return; if ((m_port_7ffd_data ^ data) & 0x08) - spectrum_UpdateScreenBitmap(); + m_screen->update_now(); /* store new state */ m_port_7ffd_data = data; @@ -248,19 +248,6 @@ uint8_t spectrum_128_state::spectrum_port_r(offs_t offset) return floating_bus_r(); } -uint8_t spectrum_128_state::floating_bus_r() -{ - // very basic "floating bus" implementation, see notes in spectrum.cpp - uint8_t data = 0xff; - int hpos = m_screen->hpos(); - int vpos = m_screen->vpos(); - - if ((hpos >= 48 && hpos < 304) && (vpos >= 48 && vpos < 240)) - data = m_screen_location[0x1800 + (((vpos-48)/8)*32) + ((hpos-48)/8)]; - - return data; -} - void spectrum_128_state::spectrum_128_io(address_map &map) { map(0x0000, 0x0000).select(0xfffe).rw(FUNC(spectrum_128_state::spectrum_ula_r), FUNC(spectrum_128_state::spectrum_ula_w)); @@ -304,30 +291,31 @@ void spectrum_128_state::machine_reset() spectrum_128_update_memory(); } -/* F4 Character Displayer */ static const gfx_layout spectrum_charlayout = { - 8, 8, /* 8 x 8 characters */ - 96, /* 96 characters */ - 1, /* 1 bits per pixel */ - { 0 }, /* no bitplanes */ - /* x offsets */ - { 0, 1, 2, 3, 4, 5, 6, 7 }, - /* y offsets */ - { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, - 8*8 /* every char takes 8 bytes */ + 8, 8, /* 8 x 8 characters */ + 96, /* 96 characters */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + {STEP8(0, 1)}, /* x offsets */ + {STEP8(0, 8)}, /* y offsets */ + 8*8 /* every char takes 8 bytes */ }; static GFXDECODE_START( spec128 ) - GFXDECODE_ENTRY( "maincpu", 0x17d00, spectrum_charlayout, 0, 8 ) + GFXDECODE_ENTRY( "maincpu", 0x17d00, spectrum_charlayout, 7, 8 ) GFXDECODE_END +rectangle spectrum_128_state::get_screen_area() +{ + return rectangle{48, 48 + 255, 63, 63 + 191}; +} void spectrum_128_state::spectrum_128(machine_config &config) { spectrum(config); - Z80(config.replace(), m_maincpu, X1_128_SINCLAIR / 5); + Z80(config.replace(), m_maincpu, X1_128_SINCLAIR / 10); m_maincpu->set_addrmap(AS_PROGRAM, &spectrum_128_state::spectrum_128_mem); m_maincpu->set_addrmap(AS_IO, &spectrum_128_state::spectrum_128_io); m_maincpu->set_addrmap(AS_OPCODES, &spectrum_128_state::spectrum_128_fetch); @@ -335,12 +323,12 @@ void spectrum_128_state::spectrum_128(machine_config &config) config.set_maximum_quantum(attotime::from_hz(60)); /* video hardware */ - m_screen->set_raw(X1_128_SINCLAIR / 2.5, 456, 0, 352, 311, 0, 296); + m_screen->set_raw(X1_128_SINCLAIR / 5, 456, 311, {get_screen_area().left() - 48, get_screen_area().right() + 48, get_screen_area().top() - 48, get_screen_area().bottom() + 48}); subdevice("gfxdecode")->set_info(spec128); /* sound hardware */ - AY8912(config, "ay8912", X1_128_SINCLAIR / 10).add_route(ALL_OUTPUTS, "mono", 0.25); + AY8912(config, "ay8912", X1_128_SINCLAIR / 20).add_route(ALL_OUTPUTS, "mono", 0.25); /* expansion port */ SPECTRUM_EXPANSION_SLOT(config.replace(), m_exp, spec128_expansion_devices, nullptr); @@ -353,15 +341,12 @@ void spectrum_128_state::spectrum_128(machine_config &config) } - - /*************************************************************************** Game driver(s) ***************************************************************************/ - ROM_START(spec128) ROM_REGION(0x18000,"maincpu",0) ROM_SYSTEM_BIOS( 0, "en", "English" ) diff --git a/src/mame/drivers/spectrum.cpp b/src/mame/drivers/spectrum.cpp index ae9a91a45ba..b9e8a1ccc7b 100644 --- a/src/mame/drivers/spectrum.cpp +++ b/src/mame/drivers/spectrum.cpp @@ -339,30 +339,21 @@ uint8_t spectrum_state::spectrum_rom_r(offs_t offset) bit 3: MIC/Tape Output bit 2-0: border colour */ - void spectrum_state::spectrum_ula_w(offs_t offset, uint8_t data) { - unsigned char Changed; - - Changed = m_port_fe_data^data; + unsigned char Changed = m_port_fe_data^data; /* border colour changed? */ if ((Changed & 0x07)!=0) - { - spectrum_UpdateBorderBitmap(); - } + m_screen->update_now(); if ((Changed & (1<<4))!=0) - { /* DAC output state */ m_speaker->level_w(BIT(data, 4)); - } if ((Changed & (1<<3))!=0) - { /* write cassette data */ m_cassette->output((data & (1<<3)) ? -1.0 : +1.0); - } // Some exp devices use ula port unused bits 5-7: // Beta v2/3/plus use bit 7, Beta clones use bits 6 and 7 @@ -508,8 +499,9 @@ uint8_t spectrum_state::floating_bus_r() // peek into attribute ram when beam is in display area // ula always returns ff when in border area (or h/vblank) - if ((hpos >= 48 && hpos < 304) && (vpos >= 48 && vpos < 240)) - data = m_video_ram[0x1800 + (((vpos-48)/8)*32) + ((hpos-48)/8)]; + rectangle screen = get_screen_area(); + if (screen.contains(hpos, vpos)) + data = m_screen_location[0x1800 + (((vpos - screen.top()) / 8) * 32) + ((hpos - screen.left()) / 8)]; return data; } @@ -713,12 +705,17 @@ INPUT_PORTS_START( spec_plus ) INPUT_PORTS_END /* Machine initialization */ - void spectrum_state::init_spectrum() { m_specmem->space(AS_PROGRAM).install_ram(0x5b00, m_ram->size() + 0x3fff, m_ram->pointer() + 0x1b00); } +void spectrum_state::machine_start() +{ + save_item(NAME(m_port_fe_data)); + //TODO more +} + void spectrum_state::machine_reset() { m_port_7ffd_data = -1; @@ -728,32 +725,39 @@ void spectrum_state::machine_reset() /* F4 Character Displayer */ static const gfx_layout spectrum_charlayout = { - 8, 8, /* 8 x 8 characters */ - 96, /* 96 characters */ - 1, /* 1 bits per pixel */ - { 0 }, /* no bitplanes */ - /* x offsets */ - { 0, 1, 2, 3, 4, 5, 6, 7 }, - /* y offsets */ - { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, - 8*8 /* every char takes 8 bytes */ + 8, 8, /* 8 x 8 characters */ + 96, /* 96 characters */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + {STEP8(0, 1)}, /* x offsets */ + {STEP8(0, 8)}, /* y offsets */ + 8*8 /* every char takes 8 bytes */ }; static GFXDECODE_START( gfx_spectrum ) - GFXDECODE_ENTRY( "maincpu", 0x3d00, spectrum_charlayout, 0, 8 ) + GFXDECODE_ENTRY( "maincpu", 0x3d00, spectrum_charlayout, 7, 8 ) GFXDECODE_END void spectrum_state::device_timer(emu_timer &timer, device_timer_id id, int param) { switch (id) { + case TIMER_IRQ_ON: + m_maincpu->set_input_line(0, HOLD_LINE); + timer_set(m_maincpu->clocks_to_attotime(32), TIMER_IRQ_OFF, 0); + break; case TIMER_IRQ_OFF: m_maincpu->set_input_line(0, CLEAR_LINE); break; case TIMER_SCANLINE: - m_scanline_timer->adjust(m_maincpu->cycles_to_attotime(m_CyclesPerLine)); - spectrum_UpdateScreenBitmap(); + { + auto vpos_next = m_screen->vpos() + 1; + if(vpos_next <= get_screen_area().bottom()) { + m_scanline_timer->adjust(m_screen->time_until_pos(vpos_next), get_screen_area().left()); + m_screen->update_now(); + } break; + } default: throw emu_fatalerror("Unknown id in spectrum_state::device_timer"); } @@ -761,8 +765,14 @@ void spectrum_state::device_timer(emu_timer &timer, device_timer_id id, int para INTERRUPT_GEN_MEMBER(spectrum_state::spec_interrupt) { - m_maincpu->set_input_line(0, ASSERT_LINE); - m_irq_off_timer->adjust(m_maincpu->clocks_to_attotime(32)); + timer_set(m_screen->time_until_pos(0), TIMER_IRQ_ON, 0); + + /* Default implementation performs screen updates per scanline. Some other + clones e.g. pentagon do updates based on video_ram access, border updates, + and full frame refresh (for attributes flashing). Such clones may define own + *_interrupt config. */ + if (m_scanline_timer != nullptr) + m_scanline_timer->adjust(m_screen->time_until_pos(get_screen_area().top() + 1)); } void spectrum_state::spectrum_common(machine_config &config) @@ -784,9 +794,9 @@ void spectrum_state::spectrum_common(machine_config &config) /* video hardware */ SCREEN(config, m_screen, SCREEN_TYPE_RASTER); - m_screen->set_raw(X1 / 2, 448, 0, 352, 312, 0, 296); + + m_screen->set_raw(X1 / 2, 448, 312, {get_screen_area().left() - 48, get_screen_area().right() + 48, get_screen_area().top() - 48, get_screen_area().bottom() + 48}); m_screen->set_screen_update(FUNC(spectrum_state::screen_update_spectrum)); - m_screen->screen_vblank().set(FUNC(spectrum_state::screen_vblank_spectrum)); m_screen->set_palette("palette"); PALETTE(config, "palette", FUNC(spectrum_state::spectrum_palette), 16); @@ -1151,7 +1161,7 @@ COMP( 1993, didakm93, spectrum, 0, spectrum_clone, spec_plus, spectrum_stat COMP( 1988, mistrum, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "Amaterske RADIO", "Mistrum", 0 ) // keyboard could be spectrum in some models (since it was a build-yourself design) COMP( 198?, bk08, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "Orel", "BK-08", 0 ) COMP( 1990, blitzs, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "", "Blic", 0 ) // no keyboard images found -COMP( 1990, byte, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "", "Byte", 0 ) // no keyboard images found +COMP( 1990, byte, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "BEMZ", "PEVM Byte", 0 ) // no keyboard images found COMP( 199?, orizon, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "", "Orizon-Micro", 0 ) // no keyboard images found COMP( 1993, quorum48, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "", "Kvorum 48K", MACHINE_NOT_WORKING ) COMP( 1993, magic6, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "", "Magic 6", MACHINE_NOT_WORKING ) // keyboard should be spectrum, but image was not clear diff --git a/src/mame/drivers/timex.cpp b/src/mame/drivers/timex.cpp index 220963536fd..2a5e5c5b23e 100644 --- a/src/mame/drivers/timex.cpp +++ b/src/mame/drivers/timex.cpp @@ -165,23 +165,23 @@ http://www.z88forever.org.uk/zxplus3e/ /* TS2048 specific functions */ -uint8_t ts2068_state::port_f4_r() +u8 ts2068_state::port_f4_r() { return m_port_f4_data; } -void ts2068_state::port_f4_w(uint8_t data) +void ts2068_state::port_f4_w(u8 data) { m_port_f4_data = data; ts2068_update_memory(); } -uint8_t tc2048_state::port_ff_r() +u8 tc2048_state::port_ff_r() { return m_port_ff_data; } -void ts2068_state::port_ff_w(offs_t offset, uint8_t data) +void ts2068_state::port_ff_w(offs_t offset, u8 data) { /* Bits 0-2 Video Mode Select Bits 3-5 64 column mode ink/paper selection @@ -690,23 +690,21 @@ void ts2068_state::ts2068(machine_config &config) { spectrum_128(config); - Z80(config.replace(), m_maincpu, XTAL(14'112'000)/4); /* From Schematic; 3.528 MHz */ + Z80(config.replace(), m_maincpu, XTAL(14'112'000) / 4); /* From Schematic; 3.528 MHz */ m_maincpu->set_addrmap(AS_PROGRAM, &ts2068_state::ts2068_mem); m_maincpu->set_addrmap(AS_IO, &ts2068_state::ts2068_io); m_maincpu->set_vblank_int("screen", FUNC(ts2068_state::spec_interrupt)); config.set_maximum_quantum(attotime::from_hz(60)); /* video hardware */ + // timings not confirmed! now same as spec128 but doubled for hires + m_screen->set_raw(XTAL(14'112'000) / 2, 456 * 2, 311, {get_screen_area().left() - TS2068_LEFT_BORDER, get_screen_area().right() + TS2068_RIGHT_BORDER, get_screen_area().top() - TS2068_TOP_BORDER, get_screen_area().bottom() + TS2068_BOTTOM_BORDER}); m_screen->set_refresh_hz(60); - m_screen->set_size(TS2068_SCREEN_WIDTH, TS2068_SCREEN_HEIGHT); - m_screen->set_visarea(0, TS2068_SCREEN_WIDTH-1, 0, TS2068_SCREEN_HEIGHT-1); - m_screen->set_screen_update(FUNC(ts2068_state::screen_update)); - m_screen->screen_vblank().set(FUNC(ts2068_state::screen_vblank_timex)); subdevice("gfxdecode")->set_info(gfx_ts2068); /* sound */ - AY8912(config.replace(), "ay8912", XTAL(14'112'000)/8).add_route(ALL_OUTPUTS, "mono", 0.25); /* From Schematic; 1.764 MHz */ + AY8912(config.replace(), "ay8912", XTAL(14'112'000) / 8).add_route(ALL_OUTPUTS, "mono", 0.25); /* From Schematic; 1.764 MHz */ /* cartridge */ GENERIC_CARTSLOT(config, "dockslot", generic_plain_slot, "timex_cart", "dck,bin").set_device_load(FUNC(ts2068_state::cart_load)); @@ -726,6 +724,9 @@ void ts2068_state::uk2086(machine_config &config) m_screen->set_refresh_hz(50); } +rectangle tc2048_state::get_screen_area() { + return {TS2068_LEFT_BORDER, TS2068_LEFT_BORDER + TS2068_DISPLAY_XSIZE - 1, TS2068_TOP_BORDER, TS2068_TOP_BORDER + SPEC_DISPLAY_YSIZE - 1}; +} void tc2048_state::tc2048(machine_config &config) { @@ -734,11 +735,9 @@ void tc2048_state::tc2048(machine_config &config) m_maincpu->set_addrmap(AS_IO, &tc2048_state::tc2048_io); /* video hardware */ + // timings not confirmed! now same as spec48 but doubled for hires + m_screen->set_raw(X1 / 2, 448 * 2, 312, {get_screen_area().left() - TS2068_LEFT_BORDER, get_screen_area().right() + TS2068_RIGHT_BORDER, get_screen_area().top() - TS2068_TOP_BORDER, get_screen_area().bottom() + TS2068_BOTTOM_BORDER}); m_screen->set_refresh_hz(50); - m_screen->set_size(TS2068_SCREEN_WIDTH, SPEC_SCREEN_HEIGHT); - m_screen->set_visarea(0, TS2068_SCREEN_WIDTH-1, 0, SPEC_SCREEN_HEIGHT-1); - m_screen->set_screen_update(FUNC(tc2048_state::screen_update)); - m_screen->screen_vblank().set(FUNC(tc2048_state::screen_vblank_timex)); /* internal ram */ m_ram->set_default_size("48K"); diff --git a/src/mame/drivers/tsconf.cpp b/src/mame/drivers/tsconf.cpp index 101d68769d4..fd1b9115106 100644 --- a/src/mame/drivers/tsconf.cpp +++ b/src/mame/drivers/tsconf.cpp @@ -66,6 +66,7 @@ TODO: #include "emu.h" #include "includes/tsconf.h" +#include "cpu/z80/z80.h" #include "sound/ay8910.h" #include "speaker.h" @@ -256,11 +257,11 @@ void tsconf_state::machine_reset() void tsconf_state::tsconf(machine_config &config) { spectrum_128(config); - m_maincpu->set_clock(3.5_MHz_XTAL); config.device_remove("exp"); config.device_remove("palette"); + Z80(config.replace(), m_maincpu, 14_MHz_XTAL / 4); m_maincpu->set_addrmap(AS_PROGRAM, &tsconf_state::tsconf_mem); m_maincpu->set_addrmap(AS_IO, &tsconf_state::tsconf_io); m_maincpu->set_addrmap(AS_OPCODES, &tsconf_state::tsconf_switch); @@ -271,7 +272,7 @@ void tsconf_state::tsconf(machine_config &config) GLUKRS(config, m_glukrs); - TSCONF_DMA(config, m_dma, 7_MHz_XTAL); + TSCONF_DMA(config, m_dma, 14_MHz_XTAL / 2); m_dma->in_mreq_callback().set(FUNC(tsconf_state::ram_read16)); m_dma->out_mreq_callback().set(FUNC(tsconf_state::ram_write16)); m_dma->in_spireq_callback().set(FUNC(tsconf_state::spi_read16)); @@ -293,7 +294,7 @@ void tsconf_state::tsconf(machine_config &config) .add_route(2, "rspeaker", 0.50); PALETTE(config, "palette", FUNC(tsconf_state::tsconf_palette), 256); - m_screen->set_raw(7_MHz_XTAL, 448, with_hblank(), 448, 320, with_vblank(), 320); + m_screen->set_raw(14_MHz_XTAL / 2, 448, with_hblank(), 448, 320, with_vblank(), 320); subdevice("gfxdecode")->set_info(gfx_tsconf); RAM(config, m_cram).set_default_size("512").set_default_value(0); RAM(config, m_sfile).set_default_size("512").set_default_value(0); // 85*6 diff --git a/src/mame/includes/spec128.h b/src/mame/includes/spec128.h index 1184713a564..46b6ff3e2b0 100644 --- a/src/mame/includes/spec128.h +++ b/src/mame/includes/spec128.h @@ -9,6 +9,9 @@ #ifndef MAME_INCLUDES_SPEC128_H #define MAME_INCLUDES_SPEC128_H +#define X1_128_AMSTRAD 35'469'000 // Main clock (Amstrad 128K model, +2A?) +#define X1_128_SINCLAIR 35.469_MHz_XTAL // Main clock (Sinclair 128K model) + /* 128K machines take an extra 4 cycles per scan line - add this to retrace */ #define SPEC128_UNSEEN_LINES 15 #define SPEC128_RETRACE_CYCLES 52 diff --git a/src/mame/includes/spectrum.h b/src/mame/includes/spectrum.h index 202013642c3..5a52ae6e713 100644 --- a/src/mame/includes/spectrum.h +++ b/src/mame/includes/spectrum.h @@ -23,11 +23,8 @@ /* Spectrum crystals */ -#define X1 XTAL(14'000'000) // Main clock (48k Spectrum) -#define X1_128_AMSTRAD 35469000 // Main clock (Amstrad 128K model, +2A?) -#define X1_128_SINCLAIR 17734475 // Main clock (Sinclair 128K model) - -#define X2 XTAL(4'433'619) // PAL color subcarrier +#define X1 14_MHz_XTAL // Main clock (48k Spectrum) +#define X2 XTAL(4'433'619) // PAL color subcarrier /* Spectrum screen size in pixels */ #define SPEC_UNSEEN_LINES 16 /* Non-visible scanlines before first border @@ -48,18 +45,6 @@ #define SPEC_RETRACE_CYCLES 48 /* Cycles taken for horizontal retrace */ #define SPEC_CYCLES_PER_LINE 224 /* Number of cycles to display a single line */ -struct EVENT_LIST_ITEM -{ - /* driver defined ID for this write */ - int Event_ID; - /* driver defined data for this write */ - int Event_Data; - /* time at which this write occurred */ - int Event_Time; -}; - - - class spectrum_state : public driver_device { @@ -100,6 +85,7 @@ public: void init_spectrum(); protected: + virtual void machine_start() override; virtual void machine_reset() override; virtual void video_start() override; virtual void device_timer(emu_timer &timer, device_timer_id id, int param) override; @@ -113,7 +99,7 @@ protected: { TIMER_IRQ_ON, TIMER_IRQ_OFF, - TIMER_SCANLINE + TIMER_SCANLINE // tsconf assumes it last know. if need more add above or fix references in clones }; int m_port_fe_data; @@ -123,28 +109,17 @@ protected: int m_port_f4_data; /* Horizontal Select Register */ /* video support */ - int m_frame_invert_count; - int m_frame_number; /* Used for handling FLASH 1 */ - int m_flash_invert; + int m_frame_invert_count; /* Used for handling FLASH 1 */ optional_shared_ptr m_video_ram; uint8_t *m_screen_location; int m_ROMSelection; - emu_timer *m_irq_off_timer; - // Build up the screen bitmap line-by-line as the z80 uses CPU cycles. - // Elimiates sprite flicker on various games (E.g. Marauder and + // Eliminates sprite flicker on various games (E.g. Marauder and // Stormlord) and makes Firefly playable. emu_timer *m_scanline_timer; - EVENT_LIST_ITEM *m_pCurrentItem; - int m_NumEvents; - int m_TotalEvents; - char *m_pEventListBuffer; - int m_LastFrameStartTime; - int m_CyclesPerLine; - uint8_t m_ram_disabled_by_beta; uint8_t pre_opcode_fetch_r(offs_t offset); void spectrum_rom_w(offs_t offset, uint8_t data); @@ -156,19 +131,13 @@ protected: uint8_t spectrum_ula_r(offs_t offset); void spectrum_port_w(offs_t offset, uint8_t data); virtual uint8_t spectrum_port_r(offs_t offset); - virtual uint8_t floating_bus_r(); + uint8_t floating_bus_r(); uint8_t spectrum_clone_port_r(offs_t offset); void spectrum_palette(palette_device &palette) const; - virtual uint32_t screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - DECLARE_WRITE_LINE_MEMBER(screen_vblank_spectrum); + virtual u32 screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); INTERRUPT_GEN_MEMBER(spec_interrupt); - unsigned int m_previous_border_x, m_previous_border_y; - bitmap_ind16 m_border_bitmap; - unsigned int m_previous_screen_x, m_previous_screen_y; - bitmap_ind16 m_screen_bitmap; - DECLARE_SNAPSHOT_LOAD_MEMBER(snapshot_cb); DECLARE_QUICKLOAD_LOAD_MEMBER(quickload_cb); @@ -210,11 +179,11 @@ protected: optional_ioport m_io_joy1; optional_ioport m_io_joy2; - virtual void spectrum_UpdateBorderBitmap(); - virtual u16 get_border_color(); - virtual void spectrum_UpdateScreenBitmap(bool eof = false); - inline unsigned char get_display_color(unsigned char color, int invert); - inline void spectrum_plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color); + virtual u8 get_border_color(u16 hpos = ~0, u16 vpos = ~0); + // Defines position of main screen excluding border + virtual rectangle get_screen_area(); + virtual void spectrum_update_border(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + virtual void spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); // snapshot helpers void update_paging(); @@ -255,6 +224,7 @@ protected: virtual void machine_reset() override; virtual void spectrum_128_update_memory() override; + virtual rectangle get_screen_area() override; private: uint8_t spectrum_128_pre_opcode_fetch_r(offs_t offset); @@ -262,7 +232,6 @@ private: uint8_t spectrum_128_bank1_r(offs_t offset); void spectrum_128_port_7ffd_w(offs_t offset, uint8_t data); virtual uint8_t spectrum_port_r(offs_t offset) override; - virtual uint8_t floating_bus_r() override; //uint8_t spectrum_128_ula_r(); void spectrum_128_io(address_map &map); diff --git a/src/mame/includes/timex.h b/src/mame/includes/timex.h index 80fb2cfe07b..dc8d25d7a4e 100644 --- a/src/mame/includes/timex.h +++ b/src/mame/includes/timex.h @@ -39,17 +39,16 @@ public: protected: virtual void machine_reset() override; - uint8_t port_ff_r(); - DECLARE_WRITE_LINE_MEMBER(screen_vblank_timex); + u8 port_ff_r(); + void spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override; + rectangle get_screen_area() override; void hires_scanline(bitmap_ind16 &bitmap, int y, int borderlines); void _64col_scanline(bitmap_ind16 &bitmap, int y, int borderlines, unsigned short inkcolor); void lores_scanline(bitmap_ind16 &bitmap, int y, int borderlines, int screen); private: - void port_ff_w(offs_t offset, uint8_t data); - - uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + void port_ff_w(offs_t offset, u8 data); void tc2048_io(address_map &map); void tc2048_mem(address_map &map); @@ -84,11 +83,9 @@ private: TIMEX_CART_HOME }; - uint8_t port_f4_r(); - void port_f4_w(uint8_t data); - void port_ff_w(offs_t offset, uint8_t data); - - uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + u8 port_f4_r(); + void port_f4_w(u8 data); + void port_ff_w(offs_t offset, u8 data); DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart_load); int m_dock_cart_type, m_ram_chunks; diff --git a/src/mame/includes/tsconf.h b/src/mame/includes/tsconf.h index 5dcee961dd4..99a19675a1d 100644 --- a/src/mame/includes/tsconf.h +++ b/src/mame/includes/tsconf.h @@ -144,17 +144,15 @@ private: template TILE_GET_INFO_MEMBER(get_tile_info_16c); - // Changing this consider to revert 'virtual' in spectrum.h - u32 screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override; - void spectrum_UpdateScreenBitmap(bool eof = false) override; - void spectrum_UpdateBorderBitmap() override; - void spectrum_UpdateZxScreenBitmap(); - void tsconf_UpdateTxtBitmap(unsigned int from_x, unsigned int from_y); - void tsconf_UpdateGfxBitmap(unsigned int from_x, unsigned int from_y); + u8 get_border_color(u16 hpos = ~0, u16 vpos = ~0) override; + rectangle get_screen_area() override; + void spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override; + void tsconf_UpdateZxScreenBitmap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + void tsconf_UpdateTxtBitmap(bitmap_ind16 &bitmap, const rectangle &cliprect); + void tsconf_UpdateGfxBitmap(bitmap_ind16 &bitmap, const rectangle &cliprect); + void draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); void tsconf_palette(palette_device &palette) const; - void draw_sprites(const rectangle &cliprect); void tsconf_update_video_mode(); - rectangle get_screen_area(); void tsconf_port_7ffd_w(u8 data); void tsconf_ula_w(offs_t offset, u8 data); @@ -209,13 +207,12 @@ private: gluk_ext m_port_f7_ext; u8 m_port_f7_gluk_reg; - u16 m_rendering_gfx_y_offset; + s16 m_gfx_y_frame_offset; required_device m_palette; required_device m_gfxdecode; tilemap_t *m_ts_tilemap[3]; required_device m_cram; required_device m_sfile; - u16 m_previous_tsu_vpos; }; /*----------- defined in drivers/tsconf.c -----------*/ diff --git a/src/mame/machine/spec_snqk.cpp b/src/mame/machine/spec_snqk.cpp index e714fc0be5d..a854fd5409b 100644 --- a/src/mame/machine/spec_snqk.cpp +++ b/src/mame/machine/spec_snqk.cpp @@ -400,9 +400,11 @@ void spectrum_state::setup_sp(uint8_t *snapdata, uint32_t snapsize) m_maincpu->set_input_line(INPUT_LINE_IRQ0, intr); m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + /* Not supported as it's wrong anyway: even if we define current invert it can change to opposite either on next frame or N frames later depending on current state. data = BIT(status, 5); m_flash_invert = data; logerror("FLASH state: %s\n", data ? "PAPER on INK" : "INK on PAPER"); + */ // Memory dump logerror("Loading %04X bytes of RAM at %04X\n", size, start); diff --git a/src/mame/machine/tsconf.cpp b/src/mame/machine/tsconf.cpp index 73074967e99..6c8f8413685 100644 --- a/src/mame/machine/tsconf.cpp +++ b/src/mame/machine/tsconf.cpp @@ -50,9 +50,7 @@ rectangle tsconf_state::get_screen_area() { rectangle info = screen_area[BIT(m_regs[V_CONFIG], 6, 2)]; if (VM == VM_TXT) - { info.set_width(info.width() << 1); - } return info; } @@ -107,256 +105,152 @@ void tsconf_state::tsconf_update_video_mode() m_screen->configure(visarea.max_x + 1, visarea.max_y + 1, visarea, m_screen->frame_period().as_attoseconds()); } -uint32_t tsconf_state::screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +u8 tsconf_state::get_border_color(u16 hpos, u16 vpos) { - return 0; + return m_regs[BORDER]; } -void to_display(rectangle area, unsigned int &x, unsigned int &y) +/* +Layered as: + + Border - already updated with screen_update_spectrum() + + Graphics + + Sprites 0 + + Tiles 0 + + Sprites 1 + + Tiles 1 + + Sprites 2 +*/ +void tsconf_state::spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { - if (y < area.top() || y > area.bottom()) + if (!BIT(m_regs[V_CONFIG], 5)) { - x = area.left(); - y = area.top(); + if (VM == VM_ZX) + tsconf_UpdateZxScreenBitmap(screen, bitmap, cliprect); + else if (VM == VM_TXT) + tsconf_UpdateTxtBitmap(bitmap, cliprect); + else + tsconf_UpdateGfxBitmap(bitmap, cliprect); } - else if (x < area.left()) - x = area.left(); - else if (x > area.right()) + else { - x = area.left(); - to_display(area, x, ++y); + bitmap.fill(get_border_color(), cliprect); } -} -void tsconf_state::spectrum_UpdateZxScreenBitmap() -{ - unsigned int to_x = m_screen->hpos(); - unsigned int to_y = m_screen->vpos(); - to_display(m_screen->visible_area(), to_x, to_y); + if (!BIT(m_regs[V_CONFIG], 4)) + { + screen.priority().fill(0, cliprect); + if (BIT(m_regs[TS_CONFIG], 5)) + m_ts_tilemap[TM_TILES0]->draw(screen, bitmap, cliprect, + BIT(m_regs[TS_CONFIG], 2) ? TILEMAP_DRAW_ALL_CATEGORIES : TILEMAP_DRAW_CATEGORY(1), 1); - if ((m_previous_screen_x == to_x) && (m_previous_screen_y == to_y)) - return; + if (BIT(m_regs[TS_CONFIG], 6)) + m_ts_tilemap[TM_TILES1]->draw(screen, bitmap, cliprect, + BIT(m_regs[TS_CONFIG], 3) ? TILEMAP_DRAW_ALL_CATEGORIES : TILEMAP_DRAW_CATEGORY(1), 2); - bitmap_ind16 *bm = &m_screen->curbitmap().as_ind16(); - if (bm->valid()) - { - u8 pal_offset = m_regs[PAL_SEL] << 4; - u16 border_color = m_regs[BORDER]; - bool border_only = VM != VM_ZX || BIT(m_regs[V_CONFIG], 5); - rectangle screen = screen_area[0]; - do + if (BIT(m_regs[TS_CONFIG], 7)) { - if (border_only || !screen.contains(m_previous_screen_x, m_previous_screen_y)) - bm->pix(m_previous_screen_y, m_previous_screen_x) = border_color; - else - { - u16 x = m_previous_screen_x - screen.left(); - if ((x & 7) == 0) - { - u16 y = m_previous_screen_y - screen.top(); - u16 *pix = &bm->pix(m_previous_screen_y, m_previous_screen_x); - u8 attr = *(m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + ((y & 0xF8) << 2) + (x >> 3) + 0x1800); - u8 scr = *(m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + ((y & 7) << 8) + ((y & 0x38) << 2) + ((y & 0xC0) << 5) + (x >> 3)); - u16 ink = ((attr & 0x07) + ((attr >> 3) & 0x08)) | pal_offset; - u16 pap = ((attr >> 3) & 0x0f) | pal_offset; - - if (m_flash_invert && (attr & 0x80)) - scr = ~scr; - - for (uint8_t b = 0x80; b != 0; b >>= 1) - *pix++ = (scr & b) ? ink : pap; - } - } - - to_display(m_screen->visible_area(), ++m_previous_screen_x, m_previous_screen_y); - } while (!((m_previous_screen_x == to_x) && (m_previous_screen_y == to_y))); + // draw_sprites(screen, bitmap, cliprect); + // Avoid frequent expensive updates for now. Currently once per frame + if (cliprect.bottom() == get_screen_area().bottom() && cliprect.right() == get_screen_area().right()) + draw_sprites(screen, bitmap, get_screen_area()); + } } } -void tsconf_state::tsconf_UpdateTxtBitmap(unsigned int from_x, unsigned int from_y) +void tsconf_state::tsconf_UpdateZxScreenBitmap(screen_device &screen_d, bitmap_ind16 &bitmap, const rectangle &screen) { - unsigned int to_x = m_screen->hpos(); - unsigned int to_y = m_screen->vpos(); - rectangle screen = get_screen_area(); - to_display(screen, to_x, to_y); + u8 pal_offset = m_regs[PAL_SEL] << 4; + u8 *screen_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]); + u8 *attrs_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + 0x1800; + bool invert_attrs = u64(screen_d.frame_number() / m_frame_invert_count) & 1; + for (u16 vpos = screen.top(); vpos <= screen.bottom(); vpos++) + { + u16 hpos = screen.left(); + u16 x = hpos - get_screen_area().left(); + u16 y = vpos - get_screen_area().top(); + u8 *scr = &screen_location[((y & 7) << 8) | ((y & 0x38) << 2) | ((y & 0xc0) << 5) | (x >> 3)]; + u8 *attr = &attrs_location[((y & 0xf8) << 2) | (x >> 3)]; + u16 *pix = &(bitmap.pix(vpos, hpos)); + while (hpos <= screen.right()) + { + u16 ink = pal_offset | ((*attr >> 3) & 0x08) | (*attr & 0x07); + u16 pap = pal_offset | ((*attr >> 3) & 0x0f); + u8 pix8 = (invert_attrs && (*attr & 0x80)) ? ~*scr : *scr; + + for (u8 b = 0x80 >> (x & 0x07); b != 0 && hpos <= screen.right(); b >>= 1, x++, hpos++) + *pix++ = (pix8 & b) ? ink : pap; + scr++; + attr++; + } + } +} +void tsconf_state::tsconf_UpdateTxtBitmap(bitmap_ind16 &bitmap, const rectangle &screen) +{ + u8 *font_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE] ^ 0x01); u8 pal_offset = m_regs[PAL_SEL] << 4; - while (!((from_x == to_x) && (from_y == to_y))) + for (u16 vpos = screen.top(); vpos <= screen.bottom(); vpos++) { - if (from_x == screen.left() && (from_y == screen.top())) - m_rendering_gfx_y_offset = OFFS_512(G_Y_OFFS_L); + u16 hpos = screen.left(); + u16 x = hpos - get_screen_area().left(); + u16 y = vpos - get_screen_area().top(); + u16 y_offset = (OFFS_512(G_Y_OFFS_L) + y) & 0x1ff; - u16 x = from_x - screen.left(); - u16 *bm = &m_screen->curbitmap().as_ind16().pix(from_y, from_x); - s16 width = (screen.width() - x) / 8; - - // TODO u16 x_offset = OFFS_512(G_X_OFFS_L); - u8 *font_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE] ^ 0x01); - u8 *text_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + (m_rendering_gfx_y_offset / 8 * 256 + x / 8); - for (; width > 0; width--) + // TODO? u16 x_offset = OFFS_512(G_X_OFFS_L); + u8 *text_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + (y_offset / 8 * 256 + x / 8); + u16 *pix = &(bitmap.pix(vpos, hpos)); + while (hpos <= screen.right()) { - u8 char_x = *(font_location + (*text_location * 8) + (m_rendering_gfx_y_offset % 8)); u8 font_color = *(text_location + 128) & 0x0f; u8 bg_color = (*(text_location + 128) & 0xf0) >> 4; - for (auto i = 7; i >= 0; i--) - *bm++ = (BIT(char_x, i) ? font_color : bg_color) | pal_offset; + u8 char_x = *(font_location + (*text_location * 8) + (y_offset % 8)); + for (u8 b = 0x80 >> (x & 0x07); b != 0 && hpos <= screen.right(); b >>= 1, x++, hpos++) + *pix++ = pal_offset | ((char_x & b) ? font_color : bg_color); text_location++; } - - if (from_y == to_y) - // done - scanline updated partially - from_x = to_x; - else - { - from_y += 1; - m_rendering_gfx_y_offset = (m_rendering_gfx_y_offset + 1) & 0x1ff; - from_x = screen.left(); - to_display(screen, from_x, from_y); - } } } -void tsconf_state::tsconf_UpdateGfxBitmap(unsigned int from_x, unsigned int from_y) +void tsconf_state::tsconf_UpdateGfxBitmap(bitmap_ind16 &bitmap, const rectangle &screen) { - unsigned int to_x = m_screen->hpos(); - unsigned int to_y = m_screen->vpos(); - rectangle screen = get_screen_area(); - to_display(screen, to_x, to_y); - u8 pal_offset = m_regs[PAL_SEL] << 4; - while (!((from_x == to_x) && (from_y == to_y))) + for (u16 vpos = screen.top(); vpos <= screen.bottom(); vpos++) { - if (from_x == screen.left() && (from_y == screen.top())) - m_rendering_gfx_y_offset = OFFS_512(G_Y_OFFS_L); - - u16 x = from_x - screen.left(); - u16 x_offset = (OFFS_512(G_X_OFFS_L) + x) & 0x1ff; - u16 *bm = &m_screen->curbitmap().as_ind16().pix(from_y, from_x); - u8 *video_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + ((m_rendering_gfx_y_offset * 512 + x_offset) >> (2 - VM)); - s16 width = screen.width() - x; + u16 y_offset = (0x200 + OFFS_512(G_Y_OFFS_L) + m_gfx_y_frame_offset + (vpos - get_screen_area().top())) & 0x1ff; + u16 x_offset = (OFFS_512(G_X_OFFS_L) + (screen.left() - get_screen_area().left())) & 0x1ff; + u8 *video_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + ((y_offset * 512 + x_offset) >> (2 - VM)); + u16 *bm = &(bitmap.pix(vpos, screen.left())); + s16 width = screen.width(); if (VM == VM_16C) { if (x_offset & 1) { - *bm++ = (*video_location++ & 0x0f) | pal_offset; + *bm++ = pal_offset | (*video_location++ & 0x0f); x_offset++; width--; } - for (; width > 0; width -= 2) + for (; width > 0; width -= 2, x_offset += 2) { if (x_offset == 512) video_location -= 256; u8 pix = *video_location++; - *bm++ = (pix >> 4) | pal_offset; - if (width == 1) - x_offset++; - else - { - *bm++ = (pix & 0x0f) | pal_offset; - x_offset += 2; - } + *bm++ = pal_offset | (pix >> 4); + if (width != 1) + *bm++ = pal_offset | (pix & 0x0f); } } else // VM_256C { - for (; width > 0; width--) + for (; width > 0; width--, x_offset++) { if (x_offset == 512) video_location -= 512; *bm++ = *video_location++; - x_offset++; - } - } - - if (from_y == to_y) - // done - scanline updated partially - from_x = to_x; - else - { - from_y += 1; - m_rendering_gfx_y_offset = (m_rendering_gfx_y_offset + 1) & 0x1ff; - from_x = screen.left(); - to_display(screen, from_x, from_y); - } - } -} - -/* -Layered as: - + Border - + Graphics - + Sprites 0 - + Tiles 0 - + Sprites 1 - + Tiles 1 - + Sprites 2 -*/ -void tsconf_state::spectrum_UpdateScreenBitmap(bool eof) -{ - rectangle screen = get_screen_area(); - unsigned int from_x = m_previous_screen_x; - unsigned int from_y = m_previous_screen_y; - - spectrum_UpdateZxScreenBitmap(); - if (!BIT(m_regs[V_CONFIG], 5) && VM != VM_ZX) - { - to_display(screen, from_x, from_y); - if (VM == VM_TXT) - tsconf_UpdateTxtBitmap(from_x, from_y); - else - tsconf_UpdateGfxBitmap(from_x, from_y); - } - - if (!BIT(m_regs[V_CONFIG], 4)) - { - if (m_screen->vpos() == m_previous_tsu_vpos) - return; - - bool draw = false; - s16 y = m_screen->vpos() - screen.top(); - if (m_screen->vpos() == screen.bottom()) - { - m_previous_tsu_vpos = screen.top(); - screen.min_y = m_previous_tsu_vpos; - draw = true; - } - else if (y >= 0 && y < screen.height()) - { - // Update unrendered above excluding current line. - screen.sety(m_previous_tsu_vpos, m_screen->vpos() - 1); - // Too expencive to draw every line. Batch 8+ for now. - draw = screen.height() > 7; - if (!draw && (screen.bottom() + 1) == get_screen_area().bottom()) - { - screen.max_y++; - draw = true; } - if (draw) - m_previous_tsu_vpos = m_screen->vpos(); - } - - if (draw) - { - m_screen->priority().fill(0, screen); - if (BIT(m_regs[TS_CONFIG], 5)) - m_ts_tilemap[TM_TILES0]->draw(*m_screen, m_screen->curbitmap().as_ind16(), screen, - BIT(m_regs[TS_CONFIG], 2) ? TILEMAP_DRAW_ALL_CATEGORIES : TILEMAP_DRAW_CATEGORY(1), 1); - - if (BIT(m_regs[TS_CONFIG], 6)) - m_ts_tilemap[TM_TILES1]->draw(*m_screen, m_screen->curbitmap().as_ind16(), screen, - BIT(m_regs[TS_CONFIG], 3) ? TILEMAP_DRAW_ALL_CATEGORIES : TILEMAP_DRAW_CATEGORY(1), 2); - - if (BIT(m_regs[TS_CONFIG], 7)) - draw_sprites(screen); } } } -void tsconf_state::spectrum_UpdateBorderBitmap() -{ - spectrum_UpdateScreenBitmap(); -} - /* SFILE Reg.16 7 6 5 4 3 2 1 0 0 R0L Y[7:0] @@ -366,7 +260,7 @@ SFILE Reg.16 7 6 5 4 3 2 1 0 4 R2L TNUM[7:0] 5 R2H SPAL[7:4] TNUM[11:8] */ -void tsconf_state::draw_sprites(const rectangle &cliprect) +void tsconf_state::draw_sprites(screen_device &screen_d, bitmap_ind16 &bitmap, const rectangle &cliprect) { rectangle screen = get_screen_area(); @@ -415,7 +309,7 @@ void tsconf_state::draw_sprites(const rectangle &cliprect) u8 tile_col = (code % 64) + flipx * width8; for (auto ix = x; ix <= x + width8 * 8; ix = ix + 8) { - m_gfxdecode->gfx(TM_SPRITES)->prio_transpen(m_screen->curbitmap().as_ind16(), cliprect, tmp_tile_oversized_to_code((tile_row % 64) * 64 + (tile_col % 64)), pal, flipx, flipy, ix, iy, m_screen->priority(), pmask, 0); + m_gfxdecode->gfx(TM_SPRITES)->prio_transpen(bitmap, cliprect, tmp_tile_oversized_to_code((tile_row % 64) * 64 + (tile_col % 64)), pal, flipx, flipy, ix, iy, screen_d.priority(), pmask, 0); tile_col += flipx ? -1 : 1; } tile_row += flipy ? -1 : 1; @@ -600,7 +494,7 @@ void tsconf_state::tsconf_port_xxaf_w(offs_t port, u8 data) { case BORDER: if (val_changed) - spectrum_UpdateScreenBitmap(); + m_screen->update_now(); break; default: @@ -751,13 +645,9 @@ u8 tsconf_state::tsconf_port_f7_r(offs_t offset) // BFF7 u8 data = 0xff; if (m_port_f7_ext == PS2KEYBOARDS_LOG && m_port_f7_gluk_reg == 0xf0) - { data = m_keyboard->read(); - } else if (m_port_f7_ext != DISABLED) - { data = m_glukrs->read(m_port_f7_gluk_reg); - } return data; } @@ -854,14 +744,12 @@ void tsconf_state::update_frame_timer() u16 vpos = OFFS_512(VS_INT_L); u16 hpos = m_regs[HS_INT]; if (hpos > 0 && vpos <= 319 && hpos <= 223) - { // Only if not overlapping with scanline. Otherwise we need to prioritize. m_frame_irq_timer->adjust(m_screen->time_until_pos(vpos, hpos << 1)); - } else - { m_frame_irq_timer->adjust(attotime::never); - } + + m_gfx_y_frame_offset = 0; } INTERRUPT_GEN_MEMBER(tsconf_state::tsconf_vblank_interrupt) @@ -875,7 +763,7 @@ void tsconf_state::dma_ready(int line) if (BIT(m_regs[INT_MASK], 4)) { m_maincpu->set_input_line_and_vector(line, ASSERT_LINE, 0xfb); - m_irq_off_timer->adjust(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03)))); + timer_set(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03))), TIMER_IRQ_OFF, 0); } } @@ -888,12 +776,27 @@ void tsconf_state::device_timer(emu_timer &timer, device_timer_id id, int param) if (BIT(m_regs[INT_MASK], 0)) { m_maincpu->set_input_line_and_vector(0, ASSERT_LINE, 0xff); - m_irq_off_timer->adjust(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03)))); + timer_set(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03))), TIMER_IRQ_OFF, 0); } break; } case TIMER_IRQ_SCANLINE: { + u16 screen_vpos = m_screen->vpos(); + m_line_irq_timer->adjust(m_screen->time_until_pos(screen_vpos + 1)); + if (BIT(m_regs[INT_MASK], 1)) + { + m_maincpu->set_input_line_and_vector(0, ASSERT_LINE, 0xfd); + // Not quite precise. Scanline can't be skipped. + timer_set(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03))), TIMER_IRQ_OFF, 0); + } + if (BIT(m_regs[INT_MASK], 0) && OFFS_512(VS_INT_L) == screen_vpos && m_regs[HS_INT] == 0) + { + m_maincpu->set_input_line_and_vector(0, ASSERT_LINE, 0xff); + timer_set(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03))), TIMER_IRQ_OFF, 0); + } + + m_screen->update_now(); for (const auto &[reg, val] : m_scanline_delayed_regs_update) { m_regs[reg] = val; @@ -901,7 +804,7 @@ void tsconf_state::device_timer(emu_timer &timer, device_timer_id id, int param) { case G_Y_OFFS_L: case G_Y_OFFS_H: - m_rendering_gfx_y_offset = OFFS_512(G_Y_OFFS_L); + m_gfx_y_frame_offset = get_screen_area().top() - m_screen->vpos(); break; default: @@ -909,21 +812,6 @@ void tsconf_state::device_timer(emu_timer &timer, device_timer_id id, int param) } } m_scanline_delayed_regs_update.clear(); - - u16 screen_vpos = m_screen->vpos(); - m_line_irq_timer->adjust(m_screen->time_until_pos(screen_vpos + 1)); - if (BIT(m_regs[INT_MASK], 1)) - { - m_maincpu->set_input_line_and_vector(0, ASSERT_LINE, 0xfd); - // Not quite precise. Scanline can't be skipped. - m_irq_off_timer->adjust(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03)))); - } - if (BIT(m_regs[INT_MASK], 0) && OFFS_512(VS_INT_L) == screen_vpos && m_regs[HS_INT] == 0) - { - m_maincpu->set_input_line_and_vector(0, ASSERT_LINE, 0xff); - m_irq_off_timer->adjust(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03)))); - } - spectrum_UpdateScreenBitmap(); break; } default: diff --git a/src/mame/video/spectrum.cpp b/src/mame/video/spectrum.cpp index c465921b587..57204c3a26b 100644 --- a/src/mame/video/spectrum.cpp +++ b/src/mame/video/spectrum.cpp @@ -25,85 +25,23 @@ void spectrum_state::video_start() { m_frame_invert_count = 16; - m_frame_number = 0; - m_flash_invert = 0; - - m_previous_border_x = 0; - m_previous_border_y = 0; - m_screen->register_screen_bitmap(m_border_bitmap); - m_previous_screen_x = 0; - m_previous_screen_y = 0; - m_screen->register_screen_bitmap(m_screen_bitmap); - m_screen_location = m_video_ram; - - m_irq_off_timer = timer_alloc(TIMER_IRQ_OFF); - - m_CyclesPerLine = SPEC_CYCLES_PER_LINE; m_scanline_timer = timer_alloc(TIMER_SCANLINE); - m_scanline_timer->adjust(m_maincpu->cycles_to_attotime(m_CyclesPerLine)); } void spectrum_128_state::video_start() { m_frame_invert_count = 16; - m_frame_number = 0; - m_flash_invert = 0; - - m_previous_border_x = 0; - m_previous_border_y = 0; - m_screen->register_screen_bitmap(m_border_bitmap); - m_previous_screen_x = 0; - m_previous_screen_y = 0; - m_screen->register_screen_bitmap(m_screen_bitmap); - m_screen_location = m_ram->pointer() + (5 << 14); - - m_irq_off_timer = timer_alloc(TIMER_IRQ_OFF); - - m_CyclesPerLine = SPEC128_CYCLES_PER_LINE; m_scanline_timer = timer_alloc(TIMER_SCANLINE); - m_scanline_timer->adjust(m_maincpu->cycles_to_attotime(m_CyclesPerLine)); -} - - -/* return the color to be used inverting FLASHing colors if necessary */ -inline unsigned char spectrum_state::get_display_color (unsigned char color, int invert) -{ - if (invert && (color & 0x80)) - return (color & 0xc0) + ((color & 0x38) >> 3) + ((color & 0x07) << 3); - else - return color; -} - -/* Code to change the FLASH status every 25 frames. Note this must be - independent of frame skip etc. */ -WRITE_LINE_MEMBER(spectrum_state::screen_vblank_spectrum) -{ - // rising edge - if (state) - { - spectrum_UpdateBorderBitmap(); - spectrum_UpdateScreenBitmap(true); - - m_frame_number++; - - if (m_frame_number >= m_frame_invert_count) - { - m_frame_number = 0; - m_flash_invert = !m_flash_invert; - } - } } - - /*************************************************************************** Update the spectrum screen display. The screen consists of 312 scanlines as follows: 64 border lines (the last 48 are actual border lines; the others may be - border lines or vertical retrace) + border lines or vertical retrace) 192 screen lines 56 border lines @@ -121,72 +59,6 @@ WRITE_LINE_MEMBER(spectrum_state::screen_vblank_spectrum) ***************************************************************************/ -inline void spectrum_state::spectrum_plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color) -{ - bitmap.pix(y, x) = (uint16_t)color; -} - -uint32_t spectrum_state::screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - static const rectangle rect(SPEC_LEFT_BORDER, SPEC_LEFT_BORDER + SPEC_DISPLAY_XSIZE - 1, SPEC_TOP_BORDER, SPEC_TOP_BORDER + SPEC_DISPLAY_YSIZE - 1); - - if (m_border_bitmap.valid()) - copyscrollbitmap(bitmap, m_border_bitmap, 0, nullptr, 0, nullptr, cliprect); - - spectrum_UpdateScreenBitmap(); - if (m_screen_bitmap.valid()) - copyscrollbitmap(bitmap, m_screen_bitmap, 0, nullptr, 0, nullptr, rect); - -#if 0 - // note, don't update borders in here, this can time travel w/regards to other timers and may end up giving you - // screen positions earlier than the last write handler gave you - - /* for now do a full-refresh */ - int x, y, b, scrx, scry; - unsigned short ink, pap; - unsigned char *attr, *scr; - // int full_refresh = 1; - - scr=m_screen_location; - - for (y=0; y<192; y++) - { - scrx=SPEC_LEFT_BORDER; - scry=((y&7) * 8) + ((y&0x38)>>3) + (y&0xC0); - attr=m_screen_location + ((scry>>3)*32) + 0x1800; - - for (x=0;x<32;x++) - { - /* Get ink and paper colour with bright */ - if (m_flash_invert && (*attr & 0x80)) - { - ink=((*attr)>>3) & 0x0f; - pap=((*attr) & 0x07) + (((*attr)>>3) & 0x08); - } - else - { - ink=((*attr) & 0x07) + (((*attr)>>3) & 0x08); - pap=((*attr)>>3) & 0x0f; - } - - for (b=0x80;b!=0;b>>=1) - { - if (*scr&b) - spectrum_plot_pixel(bitmap,scrx++,SPEC_TOP_BORDER+scry,ink); - else - spectrum_plot_pixel(bitmap,scrx++,SPEC_TOP_BORDER+scry,pap); - } - - scr++; - attr++; - } - } -#endif - - return 0; -} - - static constexpr rgb_t spectrum_pens[16] = { { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0xbf }, @@ -205,111 +77,83 @@ static constexpr rgb_t spectrum_pens[16] = { { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0xff } }; + // Initialise the palette void spectrum_state::spectrum_palette(palette_device &palette) const { palette.set_pen_colors(0, spectrum_pens); } -void spectrum_state::spectrum_UpdateScreenBitmap(bool eof) +rectangle spectrum_state::get_screen_area() { - unsigned int x = m_screen->hpos(); - unsigned int y = m_screen->vpos(); - int width = m_screen_bitmap.width(); - int height = m_screen_bitmap.height(); - - - if ((m_previous_screen_x == x) && (m_previous_screen_y == y) && !eof) - return; + // 256x192 screen position without border + return rectangle{48, 48 + 255, 64, 64 + 191}; +} - if (m_screen_bitmap.valid()) - { - //printf("update screen from %d,%d to %d,%d\n", m_previous_screen_x, m_previous_screen_y, x, y); +u8 spectrum_state::get_border_color(u16 hpos, u16 vpos) +{ + //TODO snow effect + return m_port_fe_data & 0x07; +} - do +u32 spectrum_state::screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + rectangle scr = get_screen_area(); + rectangle vis = screen.visible_area(); + if (vis != scr) { + rectangle bsides[4] = { + rectangle(vis.left(), vis.right(), vis.top(), scr.top() - 1), + rectangle(vis.left(), scr.left() - 1, scr.top(), scr.bottom()), + rectangle(scr.right() + 1, vis.right(), scr.top(), scr.bottom()), + rectangle(vis.left(), vis.right(), scr.bottom() + 1, vis.bottom()) + }; + for (auto i = 0; i < 4; i++) { - uint16_t scrx = m_previous_screen_x - SPEC_LEFT_BORDER; - uint16_t scry = m_previous_screen_y - SPEC_TOP_BORDER; - - if (scrx < SPEC_DISPLAY_XSIZE && scry < SPEC_DISPLAY_YSIZE) - { - // this can/must be optimised - if ((scrx & 7) == 0) { - uint16_t *bm = &m_screen_bitmap.pix(m_previous_screen_y, m_previous_screen_x); - uint8_t attr = *(m_screen_location + ((scry & 0xF8) << 2) + (scrx >> 3) + 0x1800); - uint8_t scr = *(m_screen_location + ((scry & 7) << 8) + ((scry & 0x38) << 2) + ((scry & 0xC0) << 5) + (scrx >> 3)); - uint16_t ink = (attr & 0x07) + ((attr >> 3) & 0x08); - uint16_t pap = (attr >> 3) & 0x0f; - - if (m_flash_invert && (attr & 0x80)) - scr = ~scr; - - for (uint8_t b = 0x80; b != 0; b >>= 1) - *bm++ = (scr & b) ? ink : pap; - } - } - - m_previous_screen_x += 1; - - if (m_previous_screen_x >= width) - { - m_previous_screen_x = 0; - m_previous_screen_y += 1; + rectangle border = bsides[i] & cliprect; + if (!border.empty()) + spectrum_update_border(screen, bitmap, border); + } + } - if (m_previous_screen_y >= height) - { - m_previous_screen_y = 0; - } - } - } while (!((m_previous_screen_x == x) && (m_previous_screen_y == y))); + scr &= cliprect; + if (!scr.empty()) + spectrum_update_screen(screen, bitmap, scr); - } + return 0; } -u16 spectrum_state::get_border_color() { - return m_port_fe_data & 0x07; +void spectrum_state::spectrum_update_border(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &border) +{ + for (auto y = border.top(); y <= border.bottom(); y++) + { + u16 *pix = &(bitmap.pix(y, border.left())); + for (auto x = border.left(); x <= border.right(); x++) + *pix++ = get_border_color(y, x); + } } -/* The code below is just a per-pixel 'partial update' for the border */ - -void spectrum_state::spectrum_UpdateBorderBitmap() +void spectrum_state::spectrum_update_screen(screen_device &screen_d, bitmap_ind16 &bitmap, const rectangle &screen) { - unsigned int x = m_screen->hpos(); - unsigned int y = m_screen->vpos(); - int width = m_border_bitmap.width(); - int height = m_border_bitmap.height(); - - - if (m_border_bitmap.valid()) + u8 *attrs_location = m_screen_location + 0x1800; + bool invert_attrs = u64(screen_d.frame_number() / m_frame_invert_count) & 1; + for (u16 vpos = screen.top(); vpos <= screen.bottom(); vpos++) { - uint16_t border = get_border_color(); - - //printf("update border from %d,%d to %d,%d\n", m_previous_border_x, m_previous_border_y, x, y); - - do + u16 hpos = screen.left(); + u16 x = hpos - get_screen_area().left(); + u16 y = vpos - get_screen_area().top(); + u8 *scr = &m_screen_location[((y & 7) << 8) | ((y & 0x38) << 2) | ((y & 0xc0) << 5) | (x >> 3)]; + u8 *attr = &attrs_location[((y & 0xf8) << 2) | (x >> 3)]; + u16 *pix = &(bitmap.pix(vpos, hpos)); + while (hpos <= screen.right()) { - m_border_bitmap.pix(m_previous_border_y, m_previous_border_x) = border; - - m_previous_border_x += 1; - - if (m_previous_border_x >= width) - { - m_previous_border_x = 0; - m_previous_border_y += 1; + u16 ink = ((*attr >> 3) & 0x08) | (*attr & 0x07); + u16 pap = (*attr >> 3) & 0x0f; + u8 pix8 = (invert_attrs && (*attr & 0x80)) ? ~*scr : *scr; - if (m_previous_border_y >= height) - { - m_previous_border_y = 0; - } - } + for (u8 b = 0x80 >> (x & 0x07); b != 0 && hpos <= screen.right(); b >>= 1, x++, hpos++) + *pix++ = (pix8 & b) ? ink : pap; + scr++; + attr++; } - while (!((m_previous_border_x == x) && (m_previous_border_y == y))); - - } - else - { - // no border bitmap allocated? fatalerror? } - - } diff --git a/src/mame/video/timex.cpp b/src/mame/video/timex.cpp index 2e0638728eb..acc4c62b9ab 100644 --- a/src/mame/video/timex.cpp +++ b/src/mame/video/timex.cpp @@ -22,44 +22,15 @@ inline void tc2048_state::spectrum_plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color) { - bitmap.pix(y, x) = (uint16_t)color; + rectangle screen = m_screen->visible_area(); + bitmap.pix(screen.top() + y, screen.left() + x) = (uint16_t)color; } /* Update FLASH status for ts2068. Assumes flash update every 1/2s. */ void ts2068_state::video_start() { m_frame_invert_count = 30; - - m_frame_number = 0; - m_flash_invert = 0; - - m_previous_border_x = 0; - m_previous_border_y = 0; - m_screen->register_screen_bitmap(m_border_bitmap); - m_previous_screen_x = 0; - m_previous_screen_y = 0; - m_screen->register_screen_bitmap(m_screen_bitmap); - m_screen_location = m_video_ram; - - m_irq_off_timer = timer_alloc(TIMER_IRQ_OFF); -} - -WRITE_LINE_MEMBER(tc2048_state::screen_vblank_timex) -{ - // rising edge - if (state) - { - spectrum_UpdateBorderBitmap(); - - m_frame_number++; - - if (m_frame_number >= m_frame_invert_count) - { - m_frame_number = 0; - m_flash_invert = !m_flash_invert; - } - } } @@ -91,6 +62,7 @@ void tc2048_state::hires_scanline(bitmap_ind16 &bitmap, int y, int borderlines) int x,b,scrx,scry; unsigned short ink,pap; unsigned char *attr, *scr; + bool invert_attrs = u64(m_screen->frame_number() / m_frame_invert_count) & 1; scrx=TS2068_LEFT_BORDER; scry=((y&7) * 8) + ((y&0x38)>>3) + (y&0xC0); @@ -101,7 +73,7 @@ void tc2048_state::hires_scanline(bitmap_ind16 &bitmap, int y, int borderlines) for (x=0;x<32;x++) { /* Get ink and paper colour with bright */ - if (m_flash_invert && (*attr & 0x80)) + if (invert_attrs && (*attr & 0x80)) { ink=((*attr)>>3) & 0x0f; pap=((*attr) & 0x07) + (((*attr)>>3) & 0x08); @@ -116,13 +88,13 @@ void tc2048_state::hires_scanline(bitmap_ind16 &bitmap, int y, int borderlines) { if (*scr&b) { - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,ink); - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,ink); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,ink); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,ink); } else { - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,pap); - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,pap); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,pap); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,pap); } } scr++; @@ -147,18 +119,18 @@ void tc2048_state::_64col_scanline(bitmap_ind16 &bitmap, int y, int borderlines, for (b=0x80;b!=0;b>>=1) { if (*scr1&b) - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,inkcolor); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,inkcolor); else - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,7-inkcolor); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,7-inkcolor); } scr1++; for (b=0x80;b!=0;b>>=1) { if (*scr2&b) - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,inkcolor); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,inkcolor); else - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,7-inkcolor); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,7-inkcolor); } scr2++; } @@ -170,6 +142,7 @@ void tc2048_state::lores_scanline(bitmap_ind16 &bitmap, int y, int borderlines, int x,b,scrx,scry; unsigned short ink,pap; unsigned char *attr, *scr; + bool invert_attrs = u64(m_screen->frame_number() / m_frame_invert_count) & 1; scrx=TS2068_LEFT_BORDER; scry=((y&7) * 8) + ((y&0x38)>>3) + (y&0xC0); @@ -180,7 +153,7 @@ void tc2048_state::lores_scanline(bitmap_ind16 &bitmap, int y, int borderlines, for (x=0;x<32;x++) { /* Get ink and paper colour with bright */ - if (m_flash_invert && (*attr & 0x80)) + if (invert_attrs && (*attr & 0x80)) { ink=((*attr)>>3) & 0x0f; pap=((*attr) & 0x07) + (((*attr)>>3) & 0x08); @@ -195,13 +168,13 @@ void tc2048_state::lores_scanline(bitmap_ind16 &bitmap, int y, int borderlines, { if (*scr&b) { - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,ink); - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,ink); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,ink); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,ink); } else { - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,pap); - spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,pap); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,pap); + spectrum_plot_pixel(bitmap, scrx++,scry+borderlines,pap); } } scr++; @@ -209,76 +182,35 @@ void tc2048_state::lores_scanline(bitmap_ind16 &bitmap, int y, int borderlines, } } -uint32_t ts2068_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +void tc2048_state::spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { - /* for now TS2068 will do a full-refresh */ - int count; - - if (m_border_bitmap.valid()) - copyscrollbitmap(bitmap, m_border_bitmap, 0, nullptr, 0, nullptr, cliprect); + /* for now TC2048/TS2068 will do a full-refresh */ + if (cliprect.bottom() != get_screen_area().bottom() || cliprect.right() != get_screen_area().right()) + return; if ((m_port_ff_data & 7) == 6) { /* 64 Column mode */ unsigned short inkcolor = (m_port_ff_data & 0x38) >> 3; - for (count = 0; count < 192; count++) + for (auto count = 0; count < 192; count++) _64col_scanline(bitmap, count, TS2068_TOP_BORDER, inkcolor); } else if ((m_port_ff_data & 7) == 2) { /* Extended Color mode */ - for (count = 0; count < 192; count++) + for (auto count = 0; count < 192; count++) hires_scanline(bitmap, count, TS2068_TOP_BORDER); } else if ((m_port_ff_data & 7) == 1) { /* Screen 6000-7aff */ - for (count = 0; count < 192; count++) + for (auto count = 0; count < 192; count++) lores_scanline(bitmap, count, TS2068_TOP_BORDER, 1); } else { /* Screen 4000-5aff */ - for (count = 0; count < 192; count++) + for (auto count = 0; count < 192; count++) lores_scanline(bitmap, count, TS2068_TOP_BORDER, 0); } - - return 0; -} - -uint32_t tc2048_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - /* for now TC2048 will do a full-refresh */ - int count; - - if (m_border_bitmap.valid()) - copyscrollbitmap(bitmap, m_border_bitmap, 0, nullptr, 0, nullptr, cliprect); - - if ((m_port_ff_data & 7) == 6) - { - /* 64 Column mode */ - unsigned short inkcolor = (m_port_ff_data & 0x38) >> 3; - for (count = 0; count < 192; count++) - _64col_scanline(bitmap, count, SPEC_TOP_BORDER, inkcolor); - } - else if ((m_port_ff_data & 7) == 2) - { - /* Extended Color mode */ - for (count = 0; count < 192; count++) - hires_scanline(bitmap, count, SPEC_TOP_BORDER); - } - else if ((m_port_ff_data & 7) == 1) - { - /* Screen 6000-7aff */ - for (count = 0; count < 192; count++) - lores_scanline(bitmap, count, SPEC_TOP_BORDER, 1); - } - else - { - /* Screen 4000-5aff */ - for (count = 0; count < 192; count++) - lores_scanline(bitmap, count, SPEC_TOP_BORDER, 0); - } - - return 0; } -- cgit v1.2.3