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