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.
This commit is contained in:
holub 2022-03-20 23:12:19 -04:00 committed by GitHub
parent c783127ce8
commit 32ef8f7eed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 363 additions and 860 deletions

View File

@ -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

View File

@ -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);

View File

@ -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)
rectangle pentagon_state::get_screen_area()
{
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()
{
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_device>("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, "<unknown>", "Pentagon 128K", 0 )
COMP( 2005, pent1024, spec128, 0, pent1024, spec_plus, pentagon_state, empty_init, "<unknown>", "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 )

View File

@ -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_device>("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" )

View File

@ -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, "<unknown>", "Blic", 0 ) // no keyboard images found
COMP( 1990, byte, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "<unknown>", "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, "<unknown>", "Orizon-Micro", 0 ) // no keyboard images found
COMP( 1993, quorum48, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "<unknown>", "Kvorum 48K", MACHINE_NOT_WORKING )
COMP( 1993, magic6, spectrum, 0, spectrum_clone, spectrum, spectrum_state, init_spectrum, "<unknown>", "Magic 6", MACHINE_NOT_WORKING ) // keyboard should be spectrum, but image was not clear

View File

@ -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_device>("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");

View File

@ -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_device>("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

View File

@ -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

View File

@ -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<uint8_t> 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);

View File

@ -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;

View File

@ -144,17 +144,15 @@ private:
template <u8 Layer>
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<device_palette_interface> m_palette;
required_device<gfxdecode_device> m_gfxdecode;
tilemap_t *m_ts_tilemap[3];
required_device<ram_device> m_cram;
required_device<ram_device> m_sfile;
u16 m_previous_tsu_vpos;
};
/*----------- defined in drivers/tsconf.c -----------*/

View File

@ -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);

View File

@ -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,183 +105,14 @@ 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;
}
void to_display(rectangle area, unsigned int &x, unsigned int &y)
{
if (y < area.top() || y > area.bottom())
{
x = area.left();
y = area.top();
}
else if (x < area.left())
x = area.left();
else if (x > area.right())
{
x = area.left();
to_display(area, x, ++y);
}
}
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 ((m_previous_screen_x == to_x) && (m_previous_screen_y == to_y))
return;
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 (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)));
}
}
void tsconf_state::tsconf_UpdateTxtBitmap(unsigned int from_x, unsigned int from_y)
{
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)))
{
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 *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--)
{
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;
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)
{
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)))
{
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;
if (VM == VM_16C)
{
if (x_offset & 1)
{
*bm++ = (*video_location++ & 0x0f) | pal_offset;
x_offset++;
width--;
}
for (; width > 0; width -= 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;
}
}
}
else // VM_256C
{
for (; width > 0; width--)
{
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);
}
}
return m_regs[BORDER];
}
/*
Layered as:
+ Border
+ Border - already updated with screen_update_spectrum()
+ Graphics
+ Sprites 0
+ Tiles 0
@ -291,70 +120,135 @@ Layered as:
+ Tiles 1
+ Sprites 2
*/
void tsconf_state::spectrum_UpdateScreenBitmap(bool eof)
void tsconf_state::spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
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)
if (!BIT(m_regs[V_CONFIG], 5))
{
to_display(screen, from_x, from_y);
if (VM == VM_TXT)
tsconf_UpdateTxtBitmap(from_x, from_y);
if (VM == VM_ZX)
tsconf_UpdateZxScreenBitmap(screen, bitmap, cliprect);
else if (VM == VM_TXT)
tsconf_UpdateTxtBitmap(bitmap, cliprect);
else
tsconf_UpdateGfxBitmap(from_x, from_y);
tsconf_UpdateGfxBitmap(bitmap, cliprect);
}
else
{
bitmap.fill(get_border_color(), cliprect);
}
if (!BIT(m_regs[V_CONFIG], 4))
{
if (m_screen->vpos() == m_previous_tsu_vpos)
return;
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);
bool draw = false;
s16 y = m_screen->vpos() - screen.top();
if (m_screen->vpos() == screen.bottom())
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);
if (BIT(m_regs[TS_CONFIG], 7))
{
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);
// 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::spectrum_UpdateBorderBitmap()
void tsconf_state::tsconf_UpdateZxScreenBitmap(screen_device &screen_d, bitmap_ind16 &bitmap, const rectangle &screen)
{
spectrum_UpdateScreenBitmap();
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;
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();
u16 y_offset = (OFFS_512(G_Y_OFFS_L) + y) & 0x1ff;
// 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 font_color = *(text_location + 128) & 0x0f;
u8 bg_color = (*(text_location + 128) & 0xf0) >> 4;
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++;
}
}
}
void tsconf_state::tsconf_UpdateGfxBitmap(bitmap_ind16 &bitmap, const rectangle &screen)
{
u8 pal_offset = m_regs[PAL_SEL] << 4;
for (u16 vpos = screen.top(); vpos <= screen.bottom(); vpos++)
{
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++ = pal_offset | (*video_location++ & 0x0f);
x_offset++;
width--;
}
for (; width > 0; width -= 2, x_offset += 2)
{
if (x_offset == 512)
video_location -= 256;
u8 pix = *video_location++;
*bm++ = pal_offset | (pix >> 4);
if (width != 1)
*bm++ = pal_offset | (pix & 0x0f);
}
}
else // VM_256C
{
for (; width > 0; width--, x_offset++)
{
if (x_offset == 512)
video_location -= 512;
*bm++ = *video_location++;
}
}
}
}
/*
@ -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:

View File

@ -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;
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);
do
{
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;
if (m_previous_screen_y >= height)
{
m_previous_screen_y = 0;
}
}
} while (!((m_previous_screen_x == x) && (m_previous_screen_y == y)));
}
// 256x192 screen position without border
return rectangle{48, 48 + 255, 64, 64 + 191};
}
u16 spectrum_state::get_border_color() {
u8 spectrum_state::get_border_color(u16 hpos, u16 vpos)
{
//TODO snow effect
return m_port_fe_data & 0x07;
}
/* The code below is just a per-pixel 'partial update' for the border */
void spectrum_state::spectrum_UpdateBorderBitmap()
u32 spectrum_state::screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
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())
{
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
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++)
{
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;
if (m_previous_border_y >= height)
{
m_previous_border_y = 0;
}
}
rectangle border = bsides[i] & cliprect;
if (!border.empty())
spectrum_update_border(screen, bitmap, border);
}
while (!((m_previous_border_x == x) && (m_previous_border_y == y)));
}
else
{
// no border bitmap allocated? fatalerror?
}
scr &= cliprect;
if (!scr.empty())
spectrum_update_screen(screen, bitmap, scr);
return 0;
}
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);
}
}
void spectrum_state::spectrum_update_screen(screen_device &screen_d, bitmap_ind16 &bitmap, const rectangle &screen)
{
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++)
{
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())
{
u16 ink = ((*attr >> 3) & 0x08) | (*attr & 0x07);
u16 pap = (*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++;
}
}
}

View File

@ -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;
}