// license:GPL-2.0+
// copyright-holders:Kevin Thacker
/***************************************************************************
timex.cpp
Functions to emulate the video hardware of the Timex ZX Spectrum clones.
Changes:
DJR 08/02/00 - Added support for FLASH 1.
DJR 16/05/00 - Support for TS2068/TC2048 hires and 64 column modes.
DJR 19/05/00 - Speeded up Spectrum 128 screen refresh.
DJR 23/05/00 - Preliminary support for border colour emulation.
***************************************************************************/
#include "emu.h"
#include "includes/spectrum.h"
#include "includes/timex.h"
#include "machine/ram.h"
inline void spectrum_state::spectrum_plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color)
{
bitmap.pix16(y, x) = (uint16_t)color;
}
/* Update FLASH status for ts2068. Assumes flash update every 1/2s. */
VIDEO_START_MEMBER(spectrum_state,ts2068)
{
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(spectrum_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;
}
}
}
/*******************************************************************
*
* Update the TS2068 display.
*
* Port ff is used to set the display mode.
*
* bits 2..0 Video Mode Select
* 000 = Primary DFILE active (at 0x4000-0x5aff)
* 001 = Secondary DFILE active (at 0x6000-0x7aff)
* 010 = Extended Colour Mode (chars at 0x4000-0x57ff, colors 0x6000-0x7aff)
* 110 = 64 column mode (columns 0,2,4,...62 from DFILE 1
* columns 1,3,5,...63 from DFILE 2)
* other = unpredictable results
*
* bits 5..3 64 column mode ink/paper selection (attribute value in brackets)
* 000 = Black/White (56) 100 = Green/Magenta (28)
* 001 = Blue/Yellow (49) 101 = Cyan/Red (21)
* 010 = Red/Cyan (42) 110 = Yellow/Blue (14)
* 011 = Magenta/Green (35) 111 = White/Black (7)
*
*******************************************************************/
/* Draw a scanline in TS2068/TC2048 hires mode (code modified from COUPE.C) */
void spectrum_state::ts2068_hires_scanline(bitmap_ind16 &bitmap, int y, int borderlines)
{
int x,b,scrx,scry;
unsigned short ink,pap;
unsigned char *attr, *scr;
scrx=TS2068_LEFT_BORDER;
scry=((y&7) * 8) + ((y&0x38)>>3) + (y&0xC0);
scr=m_ram->pointer() + y*32;
attr=scr + 0x2000;
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++,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);
}
}
scr++;
attr++;
}
}
/* Draw a scanline in TS2068/TC2048 64-column mode */
void spectrum_state::ts2068_64col_scanline(bitmap_ind16 &bitmap, int y, int borderlines, unsigned short inkcolor)
{
int x,b,scrx,scry;
unsigned char *scr1, *scr2;
scrx=TS2068_LEFT_BORDER;
scry=((y&7) * 8) + ((y&0x38)>>3) + (y&0xC0);
scr1=m_ram->pointer() + y*32;
scr2=scr1 + 0x2000;
for (x=0;x<32;x++)
{
for (b=0x80;b!=0;b>>=1)
{
if (*scr1&b)
spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,inkcolor);
else
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);
else
spectrum_plot_pixel(bitmap,scrx++,scry+borderlines,7-inkcolor);
}
scr2++;
}
}
/* Draw a scanline in TS2068/TC2048 lores (normal Spectrum) mode */
void spectrum_state::ts2068_lores_scanline(bitmap_ind16 &bitmap, int y, int borderlines, int screen)
{
int x,b,scrx,scry;
unsigned short ink,pap;
unsigned char *attr, *scr;
scrx=TS2068_LEFT_BORDER;
scry=((y&7) * 8) + ((y&0x38)>>3) + (y&0xC0);
scr = m_ram->pointer() + y*32 + screen*0x2000;
attr = m_ram->pointer() + ((scry>>3)*32) + screen*0x2000 + 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++,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);
}
}
scr++;
attr++;
}
}
uint32_t spectrum_state::screen_update_ts2068(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);
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++)
ts2068_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++)
ts2068_hires_scanline(bitmap, count, TS2068_TOP_BORDER);
}
else if ((m_port_ff_data & 7) == 1)
{
/* Screen 6000-7aff */
for (count = 0; count < 192; count++)
ts2068_lores_scanline(bitmap, count, TS2068_TOP_BORDER, 1);
}
else
{
/* Screen 4000-5aff */
for (count = 0; count < 192; count++)
ts2068_lores_scanline(bitmap, count, TS2068_TOP_BORDER, 0);
}
return 0;
}
uint32_t spectrum_state::screen_update_tc2048(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);
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++)
ts2068_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++)
ts2068_hires_scanline(bitmap, count, SPEC_TOP_BORDER);
}
else if ((m_port_ff_data & 7) == 1)
{
/* Screen 6000-7aff */
for (count = 0; count < 192; count++)
ts2068_lores_scanline(bitmap, count, SPEC_TOP_BORDER, 1);
}
else
{
/* Screen 4000-5aff */
for (count = 0; count < 192; count++)
ts2068_lores_scanline(bitmap, count, SPEC_TOP_BORDER, 0);
}
return 0;
}