spectrum128/2A/3: Improved contention timing emulation (#9670)

This commit is contained in:
holub 2022-05-05 09:38:58 -04:00 committed by GitHub
parent c253d43f33
commit c1f32bb9cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 150 additions and 182 deletions

View File

@ -186,28 +186,35 @@ uint8_t spectrum_128_state::spectrum_128_pre_opcode_fetch_r(offs_t offset)
return retval;
}
void spectrum_128_state::spectrum_128_bank1_w(offs_t offset, uint8_t data)
void spectrum_128_state::spectrum_128_rom_w(offs_t offset, uint8_t data)
{
m_exp->mreq_w(offset, data);
}
uint8_t spectrum_128_state::spectrum_128_bank1_r(offs_t offset)
u8 spectrum_128_state::spectrum_128_rom_r(offs_t offset)
{
uint8_t data;
return m_exp->romcs()
? m_exp->mreq_r(offset)
: ((u8*)m_bank_rom[0]->base())[offset];
}
if (m_exp->romcs())
{
data = m_exp->mreq_r(offset);
}
else
{
/* ROM switching */
int ROMSelection = BIT(m_port_7ffd_data, 4);
template <u8 Bank>
void spectrum_128_state::spectrum_128_ram_w(offs_t offset, u8 data)
{
u16 addr = 0x4000 * Bank + offset;
if (is_contended(addr)) content_early();
if (is_vram_write(addr)) m_screen->update_now();
/* rom 0 is 128K rom, rom 1 is 48 BASIC */
data = memregion("maincpu")->base()[0x010000 + (ROMSelection << 14) + offset];
}
return data;
((u8*)m_bank_ram[Bank]->base())[offset] = data;
}
template <u8 Bank>
u8 spectrum_128_state::spectrum_128_ram_r(offs_t offset)
{
u16 addr = 0x4000 * Bank + offset;
if (is_contended(addr)) content_early();
return ((u8*)m_bank_ram[Bank]->base())[offset];
}
void spectrum_128_state::spectrum_128_port_7ffd_w(offs_t offset, uint8_t data)
@ -221,11 +228,9 @@ void spectrum_128_state::spectrum_128_port_7ffd_w(offs_t offset, uint8_t data)
/* D5 - Disable paging */
/* disable paging? */
if (m_port_7ffd_data & 0x20)
return;
if (m_port_7ffd_data & 0x20) return;
if ((m_port_7ffd_data ^ data) & 0x08)
m_screen->update_now();
if ((m_port_7ffd_data ^ data) & 0x08) m_screen->update_now();
/* store new state */
m_port_7ffd_data = data;
@ -238,18 +243,15 @@ void spectrum_128_state::spectrum_128_port_7ffd_w(offs_t offset, uint8_t data)
void spectrum_128_state::spectrum_128_update_memory()
{
uint8_t *messram = m_ram->pointer();
m_bank_rom[0]->set_entry(BIT(m_port_7ffd_data, 4));
/* select ram at 0x0c000-0x0ffff */
int ram_page = m_port_7ffd_data & 0x07;
unsigned char *ram_data = messram + (ram_page<<14);
membank("bank4")->set_base(ram_data);
m_bank_ram[3]->set_entry(m_port_7ffd_data & 0x07);
m_screen->update_now();
if (BIT(m_port_7ffd_data, 3))
m_screen_location = messram + (7<<14);
m_screen_location = m_ram->pointer() + (7<<14);
else
m_screen_location = messram + (5<<14);
m_screen_location = m_ram->pointer() + (5<<14);
}
uint8_t spectrum_128_state::spectrum_port_r(offs_t offset)
@ -278,10 +280,10 @@ void spectrum_128_state::spectrum_128_io(address_map &map)
void spectrum_128_state::spectrum_128_mem(address_map &map)
{
map(0x0000, 0x3fff).rw(FUNC(spectrum_128_state::spectrum_128_bank1_r), FUNC(spectrum_128_state::spectrum_128_bank1_w));
map(0x4000, 0x7fff).bankrw("bank2");
map(0x8000, 0xbfff).bankrw("bank3");
map(0xc000, 0xffff).bankrw("bank4");
map(0x0000, 0x3fff).rw(FUNC(spectrum_128_state::spectrum_128_rom_r), FUNC(spectrum_128_state::spectrum_128_rom_w));
map(0x4000, 0x7fff).rw(FUNC(spectrum_128_state::spectrum_128_ram_r<1>), FUNC(spectrum_128_state::spectrum_128_ram_w<1>));
map(0x8000, 0xbfff).rw(FUNC(spectrum_128_state::spectrum_128_ram_r<2>), FUNC(spectrum_128_state::spectrum_128_ram_w<2>));
map(0xc000, 0xffff).rw(FUNC(spectrum_128_state::spectrum_128_ram_r<3>), FUNC(spectrum_128_state::spectrum_128_ram_w<3>));
}
void spectrum_128_state::spectrum_128_fetch(address_map &map)
@ -289,18 +291,23 @@ void spectrum_128_state::spectrum_128_fetch(address_map &map)
map(0x0000, 0xffff).r(FUNC(spectrum_128_state::spectrum_128_pre_opcode_fetch_r));
}
void spectrum_128_state::machine_start()
{
/* rom 0 is 128K rom, rom 1 is 48 BASIC */
memory_region *rom = memregion("maincpu");
m_bank_rom[0]->configure_entries(0, 2, rom->base() + 0x10000, 0x4000);
for (auto i = 1; i < 4; i++)
m_bank_ram[i]->configure_entries(0, m_ram->size() / 0x4000, m_ram->pointer(), 0x4000);
}
void spectrum_128_state::machine_reset()
{
uint8_t *messram = m_ram->pointer();
memset(messram,0,128*1024);
/* 0x0000-0x3fff always holds ROM */
/* Bank 5 is always in 0x4000 - 0x7fff */
membank("bank2")->set_base(messram + (5<<14));
m_bank_ram[1]->set_entry(5);
/* Bank 2 is always in 0x8000 - 0xbfff */
membank("bank3")->set_base(messram + (2<<14));
m_bank_ram[2]->set_entry(2);
spectrum_state::machine_reset();
@ -318,10 +325,10 @@ bool spectrum_128_state::is_vram_write(offs_t offset) {
}
bool spectrum_128_state::is_contended(offs_t offset) {
// Unlike the base 128K machine, RAM banks 4, 5, 6 and 7 are contended.
u8 mapped = m_port_7ffd_data & 0x07;
return spectrum_state::is_contended(offset) || (
(offset >= 0xc000 && offset <= 0xffff) && (mapped >= 4 && mapped <= 7));
// Memory banks 1,3,5 and 7 are contended
u8 bank = m_bank_ram[3]->entry();
return spectrum_state::is_contended(offset)
|| ((offset >= 0xc000 && offset <= 0xffff) && (bank && 1));
}
static const gfx_layout spectrum_charlayout =
@ -353,6 +360,8 @@ void spectrum_128_state::spectrum_128(machine_config &config)
m_maincpu->set_addrmap(AS_IO, &spectrum_128_state::spectrum_128_io);
m_maincpu->set_addrmap(AS_OPCODES, &spectrum_128_state::spectrum_128_fetch);
m_maincpu->set_vblank_int("screen", FUNC(spectrum_128_state::spec_interrupt));
m_maincpu->nomreq_cb().set(FUNC(spectrum_128_state::spectrum_nomreq));
config.set_maximum_quantum(attotime::from_hz(60));
/* video hardware */

View File

@ -175,29 +175,21 @@ static const int spectrum_plus3_memory_selections[]=
void specpls3_state::port_3ffd_w(offs_t offset, uint8_t data)
{
if (m_upd765.found())
m_upd765->fifo_w(data);
if (m_upd765.found()) m_upd765->fifo_w(data);
/* mface3 needs to see this port */
if (m_exp)
m_exp->iorq_w(offset | 0x3000, data);
if (m_exp) m_exp->iorq_w(offset | 0x3000, data);
}
uint8_t specpls3_state::port_3ffd_r()
{
if (m_upd765.found())
return m_upd765->fifo_r();
else
return 0xff;
return m_upd765.found() ? m_upd765->fifo_r() : 0xff;
}
uint8_t specpls3_state::port_2ffd_r()
{
if (m_upd765.found())
return m_upd765->msr_r();
else
return 0xff;
return m_upd765.found() ? m_upd765->msr_r() : 0xff;
}
@ -215,104 +207,66 @@ void specpls3_state::plus3_update_memory()
m_screen_location = m_ram->pointer() + (5 << 14);
}
if ((m_port_1ffd_data & 0x01) == 0)
if (m_port_1ffd_data & 0x01)
{
/* select ram at 0x0c000-0x0ffff */
int ram_page = m_port_7ffd_data & 0x07;
unsigned char *ram_data = m_ram->pointer() + (ram_page<<14);
membank("bank4")->set_base(ram_data);
LOG("RAM at 0xc000: %02x\n", ram_page);
/* Extended memory paging */
int MemorySelection = (m_port_1ffd_data >> 1) & 0x03;
const int *memory_selection = &spectrum_plus3_memory_selections[(MemorySelection << 2)];
m_bank_ram[0]->set_entry(memory_selection[0]);
m_bank_ram[1]->set_entry(memory_selection[1]);
m_bank_ram[2]->set_entry(memory_selection[2]);
m_bank_ram[3]->set_entry(memory_selection[3]);
LOG("extended memory paging: %02x\n", MemorySelection);
}
else
{
m_bank_rom[0]->set_entry(BIT(m_port_7ffd_data, 4) | ((m_port_1ffd_data >> 1) & 0x02));
/* Reset memory between 0x4000 - 0xbfff in case extended paging was being used */
/* Bank 5 in 0x4000 - 0x7fff */
membank("bank2")->set_base(m_ram->pointer() + (5 << 14));
m_bank_ram[1]->set_entry(5);
/* Bank 2 in 0x8000 - 0xbfff */
membank("bank3")->set_base(m_ram->pointer() + (2 << 14));
}
else
{
/* Extended memory paging */
int MemorySelection = (m_port_1ffd_data >> 1) & 0x03;
const int *memory_selection = &spectrum_plus3_memory_selections[(MemorySelection << 2)];
unsigned char *ram_data = m_ram->pointer() + (memory_selection[0] << 14);
ram_data = m_ram->pointer() + (memory_selection[1] << 14);
membank("bank2")->set_base(ram_data);
ram_data = m_ram->pointer() + (memory_selection[2] << 14);
membank("bank3")->set_base(ram_data);
ram_data = m_ram->pointer() + (memory_selection[3] << 14);
membank("bank4")->set_base(ram_data);
LOG("extended memory paging: %02x\n", MemorySelection);
m_bank_ram[2]->set_entry(2);
/* select ram at 0x0c000-0x0ffff */
int ram_page = m_port_7ffd_data & 0x07;
m_bank_ram[3]->set_entry(ram_page);
LOG("RAM at 0xc000: %02x\n", ram_page);
}
}
void specpls3_state::bank1_w(offs_t offset, uint8_t data)
void specpls3_state::rom_w(offs_t offset, uint8_t data)
{
if (m_exp->romcs())
{
m_exp->mreq_w(offset, data);
}
else if ((m_port_1ffd_data & 0x01) != 0)
{
/* Extended memory paging */
int MemorySelection = (m_port_1ffd_data >> 1) & 0x03;
const int *memory_selection = &spectrum_plus3_memory_selections[(MemorySelection << 2)];
m_ram->pointer()[(memory_selection[0] << 14) + offset] = data;
}
else if (m_port_1ffd_data & 0x01)
((u8*)m_bank_ram[0]->base())[offset] = data;
}
uint8_t specpls3_state::bank1_r(offs_t offset)
uint8_t specpls3_state::rom_r(offs_t offset)
{
uint8_t data;
return m_exp->romcs()
? m_exp->mreq_r(offset)
: (m_port_1ffd_data & 0x01)
? ((u8*)m_bank_ram[0]->base())[offset]
: ((u8*)m_bank_rom[0]->base())[offset];
if (m_exp->romcs())
{
data = m_exp->mreq_r(offset);
}
else
{
if ((m_port_1ffd_data & 0x01) == 0)
{
/* ROM switching */
int ROMSelection = BIT(m_port_7ffd_data, 4) | ((m_port_1ffd_data >> 1) & 0x02);
/* rom 0 is editor, rom 1 is syntax, rom 2 is DOS, rom 3 is 48 BASIC */
data = memregion("maincpu")->base()[0x010000 + (ROMSelection << 14) + offset];
}
else
{
/* Extended memory paging */
int MemorySelection = (m_port_1ffd_data >> 1) & 0x03;
const int *memory_selection = &spectrum_plus3_memory_selections[(MemorySelection << 2)];
data = m_ram->pointer()[(memory_selection[0] << 14) + offset];
}
}
return data;
}
void specpls3_state::port_7ffd_w(offs_t offset, uint8_t data)
{
if (is_contended(offset)) content_early();
content_early(1);
/* D0-D2 - RAM page located at 0x0c000-0x0ffff */
/* D3 - Screen select (screen 0 in ram page 5, screen 1 in ram page 7 */
/* D4 - ROM select low bit - which rom paged into 0x0000-0x03fff */
/* D5 - Disable paging (permanent until reset) */
/* mface3 needs to see this port */
if (m_exp)
m_exp->iorq_w(offset | 0x4000, data);
if (m_exp) m_exp->iorq_w(offset | 0x4000, data);
/* paging disabled? */
if (m_port_7ffd_data & 0x20)
return;
if (m_port_7ffd_data & 0x20) return;
if ((m_port_7ffd_data ^ data) & 0x08) m_screen->update_now();
/* store new state */
m_port_7ffd_data = data;
@ -334,13 +288,11 @@ void specpls3_state::port_1ffd_w(offs_t offset, uint8_t data)
if (m_upd765.found())
{
for (auto &flop : m_flop)
if (flop->get_device())
flop->get_device()->mon_w(!BIT(data, 3));
if (flop->get_device()) flop->get_device()->mon_w(!BIT(data, 3));
}
/* mface3 needs to see this port */
if (m_exp)
m_exp->iorq_w(offset | 0x1000, data);
if (m_exp) m_exp->iorq_w(offset | 0x1000, data);
/* paging disabled? */
if ((m_port_7ffd_data & 0x20)==0)
@ -360,9 +312,8 @@ void specpls3_state::port_1ffd_w(offs_t offset, uint8_t data)
void specpls3_state::video_start()
{
spectrum_128_state::video_start();
// This is reported contention pattern for +2A/+3. Keep +2 for now.
//m_contention_pattern = {1, 0, 7, 6, 5, 4, 3, 2};
//m_screen->configure(m_screen->width(), m_screen->height(), m_screen->visible_area(), HZ_TO_ATTOSECONDS(50.01));
m_contention_pattern = {1, 0, 7, 6, 5, 4, 3, 2};
m_contention_offset = 1;
}
/* ports are not decoded full.
@ -381,19 +332,25 @@ void specpls3_state::plus3_io(address_map &map)
void specpls3_state::plus3_mem(address_map &map)
{
map(0x0000, 0x3fff).rw(FUNC(specpls3_state::bank1_r), FUNC(specpls3_state::bank1_w)); //.bankr("bank1");
map(0x4000, 0x7fff).bankrw("bank2");
map(0x8000, 0xbfff).bankrw("bank3");
map(0xc000, 0xffff).bankrw("bank4");
map(0x0000, 0x3fff).rw(FUNC(specpls3_state::rom_r), FUNC(specpls3_state::rom_w));
map(0x4000, 0x7fff).rw(FUNC(specpls3_state::spectrum_128_ram_r<1>), FUNC(specpls3_state::spectrum_128_ram_w<1>));
map(0x8000, 0xbfff).rw(FUNC(specpls3_state::spectrum_128_ram_r<2>), FUNC(specpls3_state::spectrum_128_ram_w<2>));
map(0xc000, 0xffff).rw(FUNC(specpls3_state::spectrum_128_ram_r<3>), FUNC(specpls3_state::spectrum_128_ram_w<3>));
}
void specpls3_state::machine_start()
{
spectrum_128_state::machine_start();
// reconfigure ROMs
memory_region *rom = memregion("maincpu");
m_bank_rom[0]->configure_entries(0, 4, rom->base() + 0x10000, 0x4000);
m_bank_ram[0]->configure_entries(0, m_ram->size() / 0x4000, m_ram->pointer(), 0x4000);
}
void specpls3_state::machine_reset()
{
uint8_t *messram = m_ram->pointer();
memset(messram,0,128*1024);
spectrum_state::machine_reset();
/* Initial configuration */
m_port_7ffd_data = 0;
m_port_1ffd_data = 0;
@ -405,8 +362,7 @@ void specpls3_state::plus3_us_w(uint8_t data)
// US1 is not connected, so US0 alone selects either drive
floppy_image_device *flop = m_flop[data & 1]->get_device();
m_upd765->set_floppy(flop);
if (flop)
flop->ds_w(data & 1);
if (flop) flop->ds_w(data & 1);
}
static void specpls3_floppies(device_slot_interface &device)
@ -417,17 +373,17 @@ static void specpls3_floppies(device_slot_interface &device)
/* 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 */
{ 0, 1, 2, 3, 4, 5, 6, 7 }, /* x offsets */
{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, /* y offsets */
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( specpls3 )
GFXDECODE_ENTRY( "maincpu", 0x1fd00, spectrum_charlayout, 0, 8 )
GFXDECODE_ENTRY( "maincpu", 0x1fd00, spectrum_charlayout, 7, 8 )
GFXDECODE_END
@ -437,6 +393,7 @@ void specpls3_state::spectrum_plus2(machine_config &config)
m_maincpu->set_addrmap(AS_PROGRAM, &specpls3_state::plus3_mem);
m_maincpu->set_addrmap(AS_IO, &specpls3_state::plus3_io);
m_maincpu->nomreq_cb().set_nop();
subdevice<gfxdecode_device>("gfxdecode")->set_info(specpls3);

View File

@ -330,14 +330,9 @@ void spectrum_state::spectrum_rom_w(offs_t offset, uint8_t data)
uint8_t spectrum_state::spectrum_rom_r(offs_t offset)
{
uint8_t data;
if (m_exp->romcs())
data = m_exp->mreq_r(offset);
else
data = memregion("maincpu")->base()[offset];
return data;
return m_exp->romcs()
? m_exp->mreq_r(offset)
: memregion("maincpu")->base()[offset];
}
/*
@ -354,21 +349,17 @@ void spectrum_state::spectrum_ula_w(offs_t offset, uint8_t data)
unsigned char Changed = m_port_fe_data^data;
/* border colour changed? */
if ((Changed & 0x07)!=0)
m_screen->update_now();
if ((Changed & 0x07)!=0) m_screen->update_now();
if ((Changed & (1<<4))!=0)
/* DAC output state */
m_speaker->level_w(BIT(data, 4));
/* DAC output state */
if ((Changed & (1<<4))!=0) 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);
/* write cassette data */
if ((Changed & (1<<3))!=0) 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
if (m_exp)
m_exp->iorq_w(offset, data);
if (m_exp) m_exp->iorq_w(offset, data);
m_port_fe_data = data;
}
@ -392,8 +383,7 @@ uint8_t spectrum_state::spectrum_ula_r(offs_t offset)
int joy2 = m_io_joy2.read_safe(0x1f) & 0x1f;
/* expansion port */
if (m_exp)
data = m_exp->iorq_r(offset);
if (m_exp) data = m_exp->iorq_r(offset);
/* Caps - V */
if ((lines & 1) == 0)
@ -737,7 +727,6 @@ void spectrum_state::init_spectrum()
void spectrum_state::machine_start()
{
save_item(NAME(m_port_fe_data));
//TODO more
}
void spectrum_state::machine_reset()

View File

@ -31,12 +31,13 @@ public:
protected:
virtual void video_start() override;
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void plus3_update_memory() override;
private:
void bank1_w(offs_t offset, uint8_t data);
uint8_t bank1_r(offs_t offset);
void rom_w(offs_t offset, uint8_t data);
uint8_t rom_r(offs_t offset);
void port_3ffd_w(offs_t offset, uint8_t data);
uint8_t port_3ffd_r();
uint8_t port_2ffd_r();

View File

@ -115,6 +115,8 @@ protected:
int m_ROMSelection = 0; // FIXME: this is used for various things in derived classes, but not by this base class, and should be removed
std::vector<u8> m_contention_pattern;
/* Defines offset in CPU cycles from screen left side. Early model (48/128/+2) typically use -1, later (+2A/+3) +1 */
s8 m_contention_offset = -1;
uint8_t m_ram_disabled_by_beta;
uint8_t pre_opcode_fetch_r(offs_t offset);
@ -216,13 +218,19 @@ class spectrum_128_state : public spectrum_state
{
public:
spectrum_128_state(const machine_config &mconfig, device_type type, const char *tag) :
spectrum_state(mconfig, type, tag)
{ }
spectrum_state(mconfig, type, tag),
m_bank_rom(*this, "bank_rom%u", 0U),
m_bank_ram(*this, "bank_ram%u", 0U)
{ }
void spectrum_128(machine_config &config);
protected:
memory_bank_array_creator<1> m_bank_rom;
memory_bank_array_creator<4> m_bank_ram;
virtual void video_start() override;
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void spectrum_128_update_memory() override;
@ -231,11 +239,16 @@ protected:
virtual bool is_contended(offs_t offset) override;
virtual bool is_vram_write(offs_t offset) override;
template <u8 Bank>
void spectrum_128_ram_w(offs_t offset, u8 data);
template <u8 Bank>
u8 spectrum_128_ram_r(offs_t offset);
private:
uint8_t spectrum_128_pre_opcode_fetch_r(offs_t offset);
void spectrum_128_bank1_w(offs_t offset, uint8_t data);
uint8_t spectrum_128_bank1_r(offs_t offset);
void spectrum_128_port_7ffd_w(offs_t offset, uint8_t data);
u8 spectrum_128_pre_opcode_fetch_r(offs_t offset);
void spectrum_128_rom_w(offs_t offset, u8 data);
u8 spectrum_128_rom_r(offs_t offset);
void spectrum_128_port_7ffd_w(offs_t offset, u8 data);
virtual uint8_t spectrum_port_r(offs_t offset) override;
//uint8_t spectrum_128_ula_r();

View File

@ -755,7 +755,7 @@ void tsconf_state::update_frame_timer()
INTERRUPT_GEN_MEMBER(tsconf_state::tsconf_vblank_interrupt)
{
update_frame_timer();
m_line_irq_timer->adjust(attotime::zero);
m_line_irq_timer->adjust(m_screen->time_until_pos(0));
}
void tsconf_state::dma_ready(int line)

View File

@ -85,7 +85,6 @@ rectangle spectrum_state::get_screen_area()
u8 spectrum_state::get_border_color(u16 hpos, u16 vpos)
{
//TODO snow effect
return m_port_fe_data & 0x07;
}
@ -184,7 +183,7 @@ void spectrum_state::content_early(s8 shift)
return;
u64 now = m_maincpu->attotime_to_clocks(m_screen->frame_period() - time_until_int()) + shift;
u64 cf = vpos * m_screen->width() * m_maincpu->clock() / m_screen->clock() - 1;
u64 cf = vpos * m_screen->width() * m_maincpu->clock() / m_screen->clock() + m_contention_offset;
u64 ct = cf + get_screen_area().width() * m_maincpu->clock() / m_screen->clock();
if(cf <= now && now < ct)
@ -202,7 +201,7 @@ void spectrum_state::content_late()
return;
u64 now = m_maincpu->attotime_to_clocks(m_screen->frame_period() - time_until_int()) + 1;
u64 cf = vpos * m_screen->width() * m_maincpu->clock() / m_screen->clock() - 1;
u64 cf = vpos * m_screen->width() * m_maincpu->clock() / m_screen->clock() + m_contention_offset;
u64 ct = cf + get_screen_area().width() * m_maincpu->clock() / m_screen->clock();
for(auto i = 0x04; i; i >>= 1)
{