summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/sinclair/tsconf_m.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/sinclair/tsconf_m.cpp')
-rw-r--r--src/mame/sinclair/tsconf_m.cpp223
1 files changed, 147 insertions, 76 deletions
diff --git a/src/mame/sinclair/tsconf_m.cpp b/src/mame/sinclair/tsconf_m.cpp
index 896075aee24..3c15f870f27 100644
--- a/src/mame/sinclair/tsconf_m.cpp
+++ b/src/mame/sinclair/tsconf_m.cpp
@@ -12,7 +12,7 @@
#define ROM128 (BIT(m_regs[MEM_CONFIG], 0))
#define OFFS_512(_rl) (((m_regs[_rl + 1] & 1) << 8) | m_regs[_rl])
-#define VM static_cast<v_mode>(BIT(m_regs[V_CONFIG], 0, 2))
+#define VM v_mode(BIT(m_regs[V_CONFIG], 0, 2))
static constexpr rectangle screen_area[4] = {
rectangle(tsconf_state::with_hblank(52), tsconf_state::with_hblank(256 + 51), tsconf_state::with_vblank(48), tsconf_state::with_vblank(192 + 47)), // 52|256|52 x 48-192-48
@@ -107,6 +107,11 @@ u8 tsconf_state::get_border_color(u16 hpos, u16 vpos)
return m_regs[BORDER];
}
+u32 tsconf_state::get_vpage_offset()
+{
+ return PAGE4K(m_regs[V_PAGE] & ((VM == VM_16C) ? 0xf8 : 0xf0));
+}
+
/*
Layered as:
+ Border - already updated with screen_update_spectrum()
@@ -158,7 +163,7 @@ void tsconf_state::tsconf_UpdateZxScreenBitmap(screen_device &screen, bitmap_ind
{
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;
+ u8 *attrs_location = screen_location + 0x1800;
bool invert_attrs = u64(screen.frame_number() / m_frame_invert_count) & 1;
for (u16 vpos = cliprect.top(); vpos <= cliprect.bottom(); vpos++)
{
@@ -213,9 +218,9 @@ void tsconf_state::tsconf_UpdateGfxBitmap(bitmap_ind16 &bitmap, const rectangle
u8 pal_offset = m_regs[PAL_SEL] << 4;
for (u16 vpos = cliprect.top(); vpos <= cliprect.bottom(); vpos++)
{
- u16 y_offset = (0x200 + OFFS_512(G_Y_OFFS_L) + m_gfx_y_frame_offset + vpos) & 0x1ff;
+ u16 y_offset = (OFFS_512(G_Y_OFFS_L) + m_gfx_y_frame_offset + vpos) & 0x1ff;
u16 x_offset = (OFFS_512(G_X_OFFS_L) + (cliprect.left() - get_screen_area().left())) & 0x1ff;
- u8 *video_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + ((y_offset * 512 + x_offset) >> (2 - VM));
+ u8 *video_location = m_ram->pointer() + get_vpage_offset() + ((y_offset * 512 + x_offset) >> (2 - VM));
u16 *bm = &(bitmap.pix(vpos, cliprect.left()));
s16 width = cliprect.width();
if (VM == VM_16C)
@@ -347,20 +352,20 @@ void tsconf_state::ram_page_write(u8 page, offs_t offset, u8 data)
}
else
{
- if (ram_addr >= PAGE4K(m_regs[T0_G_PAGE]) && ram_addr < PAGE4K(m_regs[T0_G_PAGE] + 8))
+ if (ram_addr >= PAGE4K(m_regs[T0_G_PAGE] & 0xf8) && ram_addr < PAGE4K((m_regs[T0_G_PAGE] & 0xf8) + 8))
m_gfxdecode->gfx(TM_TILES0)->mark_all_dirty();
- if (ram_addr >= PAGE4K(m_regs[T1_G_PAGE]) && ram_addr < PAGE4K(m_regs[T1_G_PAGE] + 8))
+ if (ram_addr >= PAGE4K(m_regs[T1_G_PAGE] & 0xf8) && ram_addr < PAGE4K((m_regs[T1_G_PAGE] & 0xf8) + 8))
m_gfxdecode->gfx(TM_TILES1)->mark_all_dirty();
}
- if (ram_addr >= PAGE4K(m_regs[V_PAGE]) && ram_addr < PAGE4K(m_regs[V_PAGE] + 1))
+ if (ram_addr >= get_vpage_offset() && ram_addr < get_vpage_offset() + PAGE4K((VM == VM_16C) ? 8 : 16))
m_ts_tilemap[TM_TS_CHAR]->mark_all_dirty();
if (ram_addr >= PAGE4K(m_regs[m_regs[V_PAGE] ^ 0x01]) && ram_addr < PAGE4K(m_regs[m_regs[V_PAGE] ^ 0x01] + 1))
m_gfxdecode->gfx(TM_TS_CHAR)->mark_all_dirty();
- if (ram_addr >= PAGE4K(m_regs[SG_PAGE]) && ram_addr < PAGE4K(m_regs[SG_PAGE] + 8))
+ if (ram_addr >= PAGE4K(m_regs[SG_PAGE] & 0xf8) && ram_addr < PAGE4K((m_regs[SG_PAGE] & 0xf8) + 8))
m_gfxdecode->gfx(TM_SPRITES)->mark_all_dirty();
m_ram->write(ram_addr, data);
@@ -368,18 +373,19 @@ void tsconf_state::ram_page_write(u8 page, offs_t offset, u8 data)
u16 tsconf_state::ram_read16(offs_t offset)
{
- return ((m_ram->read(offset & 0xfffffffe)) << 8) | m_ram->read(offset | 1);
+ return (m_ram->read(offset & ~offs_t(1)) << 8) | m_ram->read(offset | 1);
}
void tsconf_state::ram_write16(offs_t offset, u16 data)
{
- ram_page_write(0, offset & 0xfffffffe, data >> 8);
+ ram_page_write(0, offset & ~offs_t(1), data >> 8);
ram_page_write(0, offset | 1, data & 0xff);
}
u16 tsconf_state::spi_read16()
{
- return (tsconf_port_57_zctr_r(0) << 8) | tsconf_port_57_zctr_r(0);
+ const u16 data_hi = tsconf_port_57_zctr_r() << 8;
+ return data_hi | tsconf_port_57_zctr_r();
}
void tsconf_state::cram_write(u16 offset, u8 data)
@@ -389,20 +395,26 @@ void tsconf_state::cram_write(u16 offset, u8 data)
u8 pen = dest >> 1;
rgb_t rgb = from_pwm((m_cram->read(dest | 1) << 8 | m_cram->read(dest & 0x1fe)));
m_palette->set_pen_color(pen, rgb);
-};
+}
void tsconf_state::cram_write16(offs_t offset, u16 data)
{
- cram_write(offset & 0xfffe, data >> 8);
+ cram_write(offset & 0x1fe, data >> 8);
cram_write(offset | 1, data & 0xff);
-};
+}
void tsconf_state::sfile_write16(offs_t offset, u16 data)
{
u16 dest = offset & 0x1fe;
m_sfile->write(dest, data >> 8);
m_sfile->write(dest | 1, data & 0xff);
-};
+}
+
+u8 tsconf_state::tsconf_port_xx1f_r(offs_t offset) {
+ return m_beta->started() && m_beta->is_active()
+ ? m_beta->status_r()
+ : 0x00; // TODO kempston read
+}
void tsconf_state::tsconf_port_7ffd_w(u8 data)
{
@@ -469,12 +481,20 @@ void tsconf_state::tsconf_port_xxaf_w(offs_t port, u8 data)
bool delay_update = true;
switch (nreg)
{
- // more registers which marked as *1 in the xls, but rest need to be tested
+ case V_CONFIG:
+ case V_PAGE:
case G_X_OFFS_L:
case G_X_OFFS_H:
case G_Y_OFFS_L:
case G_Y_OFFS_H:
- m_scanline_delayed_regs_update[static_cast<tsconf_regs>(nreg)] = data;
+ case PAL_SEL:
+ case T0_G_PAGE:
+ case T1_G_PAGE:
+ case T0_X_OFFSET_L:
+ case T0_X_OFFSET_H:
+ case T1_X_OFFSET_L:
+ case T1_X_OFFSET_H:
+ m_scanline_delayed_regs_update[tsconf_regs(nreg)] = data;
break;
default:
@@ -569,51 +589,28 @@ void tsconf_state::tsconf_port_xxaf_w(offs_t port, u8 data)
switch (nreg)
{
- case V_CONFIG:
- case V_PAGE:
- tsconf_update_video_mode();
- break;
-
case T_MAP_PAGE:
m_ts_tilemap[TM_TILES0]->mark_all_dirty();
m_ts_tilemap[TM_TILES1]->mark_all_dirty();
break;
- case T0_G_PAGE:
- m_gfxdecode->gfx(TM_TILES0)->set_source(m_ram->pointer() + PAGE4K(data));
- break;
-
- case T0_X_OFFSET_L:
- case T0_X_OFFSET_H:
- m_ts_tilemap[TM_TILES0]->set_scrollx(OFFS_512(T0_X_OFFSET_L));
- break;
-
case T0_Y_OFFSET_L:
case T0_Y_OFFSET_H:
m_ts_tilemap[TM_TILES0]->set_scrolly(OFFS_512(T0_Y_OFFSET_L));
break;
- case T1_G_PAGE:
- m_gfxdecode->gfx(TM_TILES1)->set_source(m_ram->pointer() + PAGE4K(data));
- break;
-
- case T1_X_OFFSET_L:
- case T1_X_OFFSET_H:
- m_ts_tilemap[TM_TILES1]->set_scrollx(OFFS_512(T1_X_OFFSET_L));
- break;
-
case T1_Y_OFFSET_L:
case T1_Y_OFFSET_H:
m_ts_tilemap[TM_TILES1]->set_scrolly(OFFS_512(T1_Y_OFFSET_L));
break;
case SG_PAGE:
- m_gfxdecode->gfx(TM_SPRITES)->set_source(m_ram->pointer() + PAGE4K(data));
+ m_gfxdecode->gfx(TM_SPRITES)->set_source(m_ram->pointer() + PAGE4K(data & 0xf8));
break;
case SYS_CONFIG:
// 0 - 3.5MHz, 1 - 7MHz, 2 - 14MHz, 3 - reserved
- m_maincpu->set_clock(3.5_MHz_XTAL * (1 << (data & 0x03)));
+ m_maincpu->set_clock_scale(1 << (data & 0x03));
m_regs[CACHE_CONFIG] = BIT(data, 2) ? 0x0f : 0x00;
break;
@@ -624,7 +621,6 @@ void tsconf_state::tsconf_port_xxaf_w(offs_t port, u8 data)
break;
case FMAPS:
- case PAL_SEL:
case TS_CONFIG:
case INT_MASK:
// TODO
@@ -669,7 +665,7 @@ void tsconf_state::tsconf_port_f7_w(offs_t offset, u8 data)
if (m_glukrs->address_r() == 0xf0)
{
u8 m_fx[0xf] = {0xff};
- m_port_f7_ext = static_cast<gluk_ext>(data);
+ m_port_f7_ext = gluk_ext(data);
switch (m_port_f7_ext)
{
case CONF_VERSION:
@@ -703,34 +699,40 @@ void tsconf_state::tsconf_port_f7_w(offs_t offset, u8 data)
}
}
-void tsconf_state::tsconf_port_77_zctr_w(offs_t port, u8 data)
+void tsconf_state::tsconf_port_77_zctr_w(u8 data)
{
m_sdcard->spi_ss_w(BIT(data, 0));
m_zctl_cs = BIT(data, 1);
}
-u8 tsconf_state::tsconf_port_77_zctr_r(offs_t port)
+u8 tsconf_state::tsconf_port_77_zctr_r()
{
- return 0x02 | !m_sdcard->get_card_present();
+ return 0x02 | (m_sdcard->get_card_present() ? 0x00 : 0x01);
}
-void tsconf_state::tsconf_port_57_zctr_w(offs_t port, u8 data)
+void tsconf_state::tsconf_port_57_zctr_w(u8 data)
{
if (!m_zctl_cs)
{
for (u8 m = 0x80; m; m >>= 1)
{
- m_sdcard->spi_clock_w(CLEAR_LINE); // 0-S R
m_sdcard->spi_mosi_w(data & m ? 1 : 0);
+ m_sdcard->spi_clock_w(CLEAR_LINE); // 0-S R
m_sdcard->spi_clock_w(ASSERT_LINE); // 1-L W
}
}
}
-u8 tsconf_state::tsconf_port_57_zctr_r(offs_t port)
+u8 tsconf_state::tsconf_port_57_zctr_r()
{
- tsconf_port_57_zctr_w(0, 0xff);
- return m_zctl_cs ? 0xff : m_zctl_di;
+ if (m_zctl_cs)
+ return 0xff;
+
+ u8 data = m_zctl_di;
+ if (!machine().side_effects_disabled())
+ tsconf_port_57_zctr_w(0xff);
+
+ return data;
}
void tsconf_state::tsconf_spi_miso_w(u8 data)
@@ -739,31 +741,74 @@ void tsconf_state::tsconf_spi_miso_w(u8 data)
m_zctl_di |= data;
}
+void tsconf_state::tsconf_ay_address_w(u8 data)
+{
+ if ((m_mod_ay->read() == 1) && ((data & 0xfe) == 0xfe))
+ m_ay_selected = data & 1;
+ else
+ m_ay[m_ay_selected]->address_w(data);
+}
+
+IRQ_CALLBACK_MEMBER(tsconf_state::irq_vector)
+{
+ u8 vector = 0xff;
+ if (m_int_mask & 1)
+ m_int_mask &= ~1;
+ else if (m_int_mask & 2)
+ {
+ m_int_mask &= ~2;
+ vector = 0xfd;
+ }
+ else if (m_int_mask & 4)
+ {
+ m_int_mask &= ~4;
+ vector = 0xfb;
+ }
+
+ if (!m_int_mask)
+ m_maincpu->set_input_line(0, CLEAR_LINE);
+
+ return vector;
+}
+
+TIMER_CALLBACK_MEMBER(tsconf_state::irq_off)
+{
+ m_int_mask &= ~1;
+ if (!m_int_mask)
+ m_maincpu->set_input_line(0, CLEAR_LINE);
+}
+
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));
+ attotime next;
+ if (vpos <= 319 && hpos <= 223)
+ {
+ next = m_screen->time_until_pos(vpos, hpos << 1);
+ if (next >= m_screen->frame_period())
+ next = attotime::zero;
+ }
else
- m_frame_irq_timer->adjust(attotime::never);
+ next = attotime::never;
- m_gfx_y_frame_offset = -get_screen_area().top();
+ m_frame_irq_timer->adjust(next);
}
INTERRUPT_GEN_MEMBER(tsconf_state::tsconf_vblank_interrupt)
{
update_frame_timer();
- m_line_irq_timer->adjust(attotime::zero);
+ m_gfx_y_frame_offset = -get_screen_area().top();
+ m_scanline_irq_timer->adjust(attotime::zero);
}
void tsconf_state::dma_ready(int line)
{
- if (BIT(m_regs[INT_MASK], 4))
+ if (BIT(m_regs[INT_MASK], 2))
{
- 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))));
+ if (!m_int_mask)
+ m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
+ m_int_mask |= 4;
}
}
@@ -771,33 +816,36 @@ TIMER_CALLBACK_MEMBER(tsconf_state::irq_frame)
{
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))));
+ if (!m_int_mask)
+ m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
+ m_irq_off_timer->adjust(attotime::from_ticks(32, m_maincpu->unscaled_clock()));
+ m_int_mask |= 1;
}
}
TIMER_CALLBACK_MEMBER(tsconf_state::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.
- 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))));
+ if (!m_int_mask)
+ m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
+ m_int_mask |= 2;
}
- m_screen->update_now();
+ u16 screen_vpos = m_screen->vpos();
+ m_scanline_irq_timer->adjust(m_screen->time_until_pos(screen_vpos + 1));
+ if (!m_scanline_delayed_regs_update.empty())
+ m_screen->update_now();
for (const auto &[reg, val] : m_scanline_delayed_regs_update)
{
m_regs[reg] = val;
switch (reg)
{
+ case V_CONFIG:
+ case V_PAGE:
+ tsconf_update_video_mode();
+ break;
+
case G_Y_OFFS_L:
case G_Y_OFFS_H:
m_gfx_y_frame_offset = screen_vpos < get_screen_area().top()
@@ -805,6 +853,27 @@ TIMER_CALLBACK_MEMBER(tsconf_state::irq_scanline)
: -screen_vpos;
break;
+ case T0_G_PAGE:
+ m_gfxdecode->gfx(TM_TILES0)->set_source(m_ram->pointer() + PAGE4K(val & 0xf8));
+ break;
+
+ case T1_G_PAGE:
+ m_gfxdecode->gfx(TM_TILES1)->set_source(m_ram->pointer() + PAGE4K(val & 0xf8));
+ break;
+
+ case T0_X_OFFSET_L:
+ case T0_X_OFFSET_H:
+ m_ts_tilemap[TM_TILES0]->set_scrollx(OFFS_512(T0_X_OFFSET_L));
+ break;
+
+ case T1_X_OFFSET_L:
+ case T1_X_OFFSET_H:
+ m_ts_tilemap[TM_TILES1]->set_scrollx(OFFS_512(T1_X_OFFSET_L));
+ break;
+
+ case G_X_OFFS_L:
+ case G_X_OFFS_H:
+ case PAL_SEL:
default:
break;
}
@@ -819,7 +888,8 @@ u8 tsconf_state::beta_neutral_r(offs_t offset)
u8 tsconf_state::beta_enable_r(offs_t offset)
{
- if (!(machine().side_effects_disabled())) {
+ if (!machine().side_effects_disabled())
+ {
if (!W0_RAM && m_bank_rom[0]->entry() == 3)
{
if (m_beta->started() && !m_beta->is_active())
@@ -834,7 +904,8 @@ u8 tsconf_state::beta_enable_r(offs_t offset)
u8 tsconf_state::beta_disable_r(offs_t offset)
{
- if (!(machine().side_effects_disabled())) {
+ if (!machine().side_effects_disabled())
+ {
if (m_beta->started() && m_beta->is_active())
{
m_beta->disable();