diff options
Diffstat (limited to 'src/mame/video/thomson.cpp')
-rw-r--r-- | src/mame/video/thomson.cpp | 1432 |
1 files changed, 0 insertions, 1432 deletions
diff --git a/src/mame/video/thomson.cpp b/src/mame/video/thomson.cpp deleted file mode 100644 index 120f1cf1167..00000000000 --- a/src/mame/video/thomson.cpp +++ /dev/null @@ -1,1432 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Antoine Mine -/********************************************************************** - - Copyright (C) Antoine Mine' 2006 - - Thomson 8-bit computers - -**********************************************************************/ - -#include "emu.h" -#include "includes/thomson.h" - -#include <algorithm> -#include <cmath> - -//#define VERBOSE 1 -#include "logmacro.h" - - -/* One GPL is what is drawn in 1 us by the video system in the active window. - Most of the time, it corresponds to a 8-pixel wide horizontal span. - For some TO8/9/9+/MO6 modes, it can be 4-pixel or 16-pixel wide. - There are always 40 GPLs in an active row, and it is always defined by - two bytes in video memory (0x2000 bytes appart). -*/ - -#define THOM_GPL_PER_LINE 40 - - -/****************** dynamic screen size *****************/ - - -bool thomson_state::update_screen_size() -{ - const rectangle &visarea = m_screen->visible_area(); - uint8_t p = m_io_vconfig->read(); - bool changed = false; - - switch ( p & 3 ) - { - case 0: m_thom_bwidth = 56; m_thom_bheight = 47; break; /* as in original (?) */ - case 1: m_thom_bwidth = 16; m_thom_bheight = 16; break; /* small */ - default: m_thom_bwidth = 0; m_thom_bheight = 0; break; /* none */ - } - - switch ( p & 0xc ) - { - case 0: m_thom_hires = 0; break; /* low */ - case 4: m_thom_hires = 1; break; /* high */ - default: m_thom_hires = m_thom_hires_better; break; /* auto */ - } - - int new_w = ( 320 + m_thom_bwidth * 2 ) * ( m_thom_hires + 1 ) - 1; - int new_h = ( 200 + m_thom_bheight * 2 ) /** (m_thom_hires + 1 )*/ - 1; - if ( ( visarea.max_x != new_w ) || ( visarea.max_y != new_h ) ) - { - changed = true; - m_screen->set_visible_area(0, new_w, 0, new_h ); - } - - return changed; -} - - - -/*********************** video timing ******************************/ - - -/* elapsed time from beginning of frame, in us */ -unsigned thomson_state::thom_video_elapsed() -{ - unsigned u; - attotime elapsed = m_thom_video_timer->elapsed(); - u = (elapsed * 1000000 ).seconds(); - if ( u >= 19968 ) - u = 19968; - return u; -} - - - -struct thom_vsignal thomson_state::thom_get_vsignal() -{ - struct thom_vsignal v; - int gpl = thom_video_elapsed() - 64 * THOM_BORDER_HEIGHT - 7; - if ( gpl < 0 ) - gpl += 19968; - - v.inil = ( gpl & 63 ) <= 40; - - v.init = gpl < (64 * THOM_ACTIVE_HEIGHT - 24); - - v.lt3 = ( gpl & 8 ) ? 1 : 0; - - v.line = gpl >> 6; - - v.count = v.line * 320 + ( gpl & 63 ) * 8; - - return v; -} - - - -/************************** lightpen *******************************/ - - - -void thomson_state::thom_get_lightpen_pos( int*x, int* y ) -{ - *x = m_io_lightpen_x->read(); - *y = m_io_lightpen_y->read(); - - if ( *x < 0 ) - *x = 0; - - if ( *y < 0 ) - *y = 0; - - if ( *x > 2 * m_thom_bwidth + 319 ) - *x = 2 * m_thom_bwidth + 319; - - if ( *y > 2 * m_thom_bheight + 199 ) - *y = 2 * m_thom_bheight + 199; -} - - - -struct thom_vsignal thomson_state::thom_get_lightpen_vsignal( int xdec, int ydec, int xdec2 ) -{ - struct thom_vsignal v; - int x, y; - int gpl; - - thom_get_lightpen_pos( &x, &y ); - x += xdec - m_thom_bwidth; - y += ydec - m_thom_bheight; - - gpl = (x >> 3) + y * 64; - if ( gpl < 0 ) - gpl += 19968; - - v.inil = (gpl & 63) <= 41; - - v.init = (gpl <= 64 * THOM_ACTIVE_HEIGHT - 24); - - v.lt3 = ( gpl & 8 ) ? 1 : 0; - - v.line = y; - - if ( v.inil && v.init ) - v.count = - ( gpl >> 6 ) * 320 + /* line */ - ( gpl & 63 ) * 8 + /* gpl inside line */ - ( (x + xdec2) & 7 ); /* pixel inside gpl */ - else - v.count = 0; - - return v; -} - - - -void thomson_state::thom_set_lightpen_callback( int nb ) -{ - LOG("%f thom_set_lightpen_callback called\n", machine().time().as_double()); - m_thom_lightpen_nb = nb; -} - -TIMER_CALLBACK_MEMBER( thomson_state::thom_lightpen_step ) -{ - int step = param; - - if ( m_thom_lightpen_cb ) - (this->*m_thom_lightpen_cb)( step ); - - if ( step < m_thom_lightpen_nb ) - m_thom_lightpen_timer->adjust(attotime::from_usec( 64 ), step + 1); -} - - - -/***************** scan-line oriented engine ***********************/ - -/* This code, common for all Thomson machines, emulates the TO8 - video hardware, with its 16-colors chosen among 4096, 9 video modes, - and 4 video pages. Moreover, it emulates changing the palette several times - per frame to simulate more than 16 colors per frame (and the same for mode - and page switchs) and cooper effects (distinguishing the left and right - border color of each row). - - TO7, TO7/70 and MO5 video hardware are much simpler (8 or 16 fixed colors, - one mode and one video page). Although the three are different, they can all - be emulated by the TO8 video hardware. - Thus, we use the same TO8-emulation code to deal with these simpler - hardware (although it is somewhat of an overkill). -*/ - - - -/* ---------------- state & state changes ---------------- */ - - -/* returns 1 if the mode is 640 pixel wide, 0 if it is 160 or 320 */ -int thomson_state::thom_mode_is_hires( int mode ) -{ - return ( mode == THOM_VMODE_80 ) || ( mode == THOM_VMODE_80_TO9 ); -} - - - -/* either the border index or its palette entry has changed */ -void thomson_state::thom_border_changed() -{ - unsigned l = thom_video_elapsed(); - unsigned y = l >> 6; - unsigned x = l & 63; - unsigned color = m_thom_pal[ m_thom_border_index ]; - - if ( y >= THOM_TOTAL_HEIGHT ) - { - /* end of page */ - m_thom_border_r[ THOM_TOTAL_HEIGHT ] = color; - } - else if ( ! x ) - { - /* start of line */ - m_thom_border_l[ y ] = color; - m_thom_border_r[ y ] = color; - } - else if ( x <= 19 ) - { - /* between left and right border */ - /* NOTE: this makes the lower right part of the color picker blink - in the TO8/TO9/TO9+, which actually happens on the real computer! - */ - m_thom_border_r[ y ] = color; - m_thom_border_l[ y + 1 ] = color; - } - else - { - /* end of line */ - m_thom_border_l[ y + 1 ] = color; - m_thom_border_r[ y + 1 ] = color; - } - m_thom_vstate_dirty = true; -} - - - -/* the video mode or page has changed */ -void thomson_state::thom_gplinfo_changed() -{ - unsigned l = thom_video_elapsed() - THOM_BORDER_HEIGHT * 64 - 7; - unsigned y = l >> 6; - unsigned x = l & 63; - int modepage = ((int)m_thom_vmode << 8) | m_thom_vpage; - if ( y >= 200 || x>= 40 ) - m_thom_vmodepage[ 40 ] = modepage; - else - m_thom_vmodepage[ x ] = modepage; - m_thom_vmodepage_changed = 1; -} - - - -void thomson_state::thom_set_border_color( unsigned index ) -{ - assert( index < 16 ); - if ( index != m_thom_border_index ) - { - LOG("thom_set_border_color: %i at line %i col %i\n", index, thom_video_elapsed() / 64, thom_video_elapsed() % 64); - m_thom_border_index = index; - thom_border_changed(); - } -} - - - -void thomson_state::thom_set_palette( unsigned index, uint16_t color ) -{ - assert( index < 16 ); - - if ( color != 0x1000 ) - color &= 0xfff; - - if ( m_thom_pal[ index ] == color ) - return; - - LOG("thom_set_palette: %i to %03x at line %i col %i\n", index, color, thom_video_elapsed() / 64, thom_video_elapsed() % 64); - - m_thom_pal[ index ] = color; - if ( index == m_thom_border_index ) - thom_border_changed(); - m_thom_pal_changed = true; - m_thom_vstate_dirty = true; -} - - - -void thomson_state::thom_set_video_mode( unsigned mode ) -{ - assert( mode < THOM_VMODE_NB ); - - if ( mode != m_thom_vmode ) - { - LOG("thom_set_video_mode: %i at line %i, col %i\n", mode, thom_video_elapsed() / 64, thom_video_elapsed() % 64); - m_thom_vmode = mode; - thom_gplinfo_changed(); - m_thom_vstate_dirty = true; - m_thom_hires_better |= thom_mode_is_hires( mode ); - } -} - - - -void thomson_state::thom_set_video_page( unsigned page ) -{ - assert( page < THOM_NB_PAGES ); - - if ( page != m_thom_vpage ) - { - LOG("thom_set_video_page: %i at line %i col %i\n", page, thom_video_elapsed() / 64, thom_video_elapsed() % 64); - m_thom_vpage = page; - thom_gplinfo_changed(); - m_thom_vstate_dirty = true; - } -} - - - -/* -------------- drawing --------------- */ - - - -typedef void ( thomson_state::*thom_scandraw ) ( uint8_t* vram, uint16_t* dst, uint16_t* pal, int org, int len ); - - - -#define UPDATE( name, res ) \ - void thomson_state::name##_scandraw_##res ( \ - uint8_t* vram, uint16_t* dst, uint16_t* pal, \ - int org, int len ) \ - { \ - unsigned gpl; \ - vram += org; \ - dst += org * res; \ - for ( gpl = 0; gpl < len; gpl++, dst += res, vram++ ) { \ - uint8_t rama = vram[ 0 ]; \ - uint8_t ramb = vram[ 0x2000 ]; - -#define END_UPDATE \ - } \ - } - -#define UPDATE_HI( name ) UPDATE( name, 16 ) -#define UPDATE_LOW( name ) UPDATE( name, 8 ) - - - -/* 320x200, 16-colors, constraints: 2 distinct colors per GPL (8 pixels) */ -/* this also works for TO7, assuming the 2 top bits of each color byte are 1 */ - -UPDATE_HI( to770 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ ((ramb & 7) | ((ramb>>4) & 8)) ^ 8 ]; - c[1] = pal[ ((ramb >> 3) & 15) ^ 8 ]; - for ( i = 0; i < 16; i += 2, rama >>= 1 ) - dst[ 15 - i ] = dst[ 14 - i ] = c[ rama & 1 ]; -} -END_UPDATE - -UPDATE_LOW( to770 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ ((ramb & 7) | ((ramb>>4) & 8)) ^ 8 ]; - c[1] = pal[ ((ramb >> 3) & 15) ^ 8 ]; - for ( i = 0; i < 8; i++, rama >>= 1 ) - dst[ 7 - i ] = c[ rama & 1 ]; -} -END_UPDATE - - - -/* as above, different (more logical but TO7-incompatible) color encoding */ - -UPDATE_HI( mo5 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ ramb & 15 ]; - c[1] = pal[ ramb >> 4 ]; - for ( i = 0; i < 16; i += 2, rama >>= 1 ) - dst[ 15 - i ] = dst[ 14 - i ] = c[ rama & 1 ]; -} -END_UPDATE - -UPDATE_LOW( mo5 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ ramb & 15 ]; - c[1] = pal[ ramb >> 4 ]; - for ( i = 0; i < 8; i++, rama >>= 1 ) - dst[ 7 - i ] = c[ rama & 1 ]; -} -END_UPDATE - - -/* as mo5, but with pastel bit switched */ - -UPDATE_HI( mo5alt ) -{ - int i; - pen_t c[2]; - c[0] = pal[ (ramb & 15) ^ 8 ]; - c[1] = pal[ (ramb >> 4) ^ 8 ]; - for ( i = 0; i < 16; i += 2, rama >>= 1 ) - dst[ 15 - i ] = dst[ 14 - i ] = c[ rama & 1 ]; -} -END_UPDATE - -UPDATE_LOW( mo5alt ) -{ - int i; - pen_t c[2]; - c[0] = pal[ (ramb & 15) ^ 8 ]; - c[1] = pal[ (ramb >> 4) ^ 8 ]; - for ( i = 0; i < 8; i++, rama >>= 1 ) - dst[ 7 - i ] = c[ rama & 1 ]; -} -END_UPDATE - - - -/* as to770, but with pastel color bit unswitched */ - -UPDATE_HI( to9 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ (ramb & 7) | ((ramb>>4) & 8) ]; - c[1] = pal[ (ramb >> 3) & 15 ]; - for ( i = 0; i < 16; i += 2, rama >>= 1 ) - dst[ 15 - i ] = dst[ 14 - i ] = c[ rama & 1 ]; -} -END_UPDATE - -UPDATE_LOW( to9 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ (ramb & 7) | ((ramb>>4) & 8) ]; - c[1] = pal[ (ramb >> 3) & 15 ]; - for ( i = 0; i < 8; i++, rama >>= 1 ) - dst[ 7 - i ] = c[ rama & 1 ]; -} -END_UPDATE - - - -/* 320x200, 4-colors, no constraint */ - -UPDATE_HI( bitmap4 ) -{ - int i; - pen_t c[2][2]; - c[0][0] = pal[ 0 ]; - c[0][1] = pal[ 1 ]; - c[1][0] = pal[ 2 ]; - c[1][1] = pal[ 3 ]; - for ( i = 0; i < 16; i += 2, rama >>= 1, ramb >>= 1 ) - dst[ 15 - i ] = dst[ 14 - i ] = c[ rama & 1 ] [ ramb & 1 ]; -} -END_UPDATE - -UPDATE_LOW( bitmap4 ) -{ - int i; - pen_t c[2][2]; - c[0][0] = pal[ 0 ]; - c[0][1] = pal[ 1 ]; - c[1][0] = pal[ 2 ]; - c[1][1] = pal[ 3 ]; - for ( i = 0; i < 8; i++, rama >>= 1, ramb >>= 1 ) - dst[ 7 - i ] = c[ rama & 1 ] [ ramb & 1 ]; -} -END_UPDATE - - - -/* as above, but using 2-bit pixels instead of 2 planes of 1-bit pixels */ - -UPDATE_HI( bitmap4alt ) -{ - int i; - pen_t c[4]; - c[0] = pal[ 0 ]; - c[1] = pal[ 1 ]; - c[2] = pal[ 2 ]; - c[3] = pal[ 3 ]; - for ( i = 0; i < 8; i += 2, ramb >>= 2 ) - dst[ 15 - i ] = dst[ 14 - i ] = c[ ramb & 3 ]; - for ( i = 0; i < 8; i += 2, rama >>= 2 ) - dst[ 7 - i ] = dst[ 6 - i ] = c[ rama & 3 ]; -} -END_UPDATE - -UPDATE_LOW( bitmap4alt ) -{ - int i; - pen_t c[4]; - c[0] = pal[ 0 ]; - c[1] = pal[ 1 ]; - c[2] = pal[ 2 ]; - c[3] = pal[ 3 ]; - for ( i = 0; i < 4; i++, ramb >>= 2 ) - dst[ 7 - i ] = c[ ramb & 3 ]; - for ( i = 0; i < 4; i++, rama >>= 2 ) - dst[ 3 - i ] = c[ rama & 3 ]; -} -END_UPDATE - - -/* 160x200, 4 colors, no constraint, using only one memory page (undocumented) */ - -UPDATE_HI( bitmap4althalf ) -{ - dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = pal[ rama >> 6 ]; - dst[ 4] = dst[ 5] = dst[ 6] = dst[ 7] = pal[ (rama >> 4) & 3 ]; - dst[ 8] = dst[ 9] = dst[10] = dst[11] = pal[ (rama >> 2) & 3]; - dst[12] = dst[13] = dst[14] = dst[15] = pal[ rama & 3 ]; - (void)ramb; // ramb is not used -} -END_UPDATE - -UPDATE_LOW( bitmap4althalf ) -{ - dst[0] = dst[1] = pal[ rama >> 6 ]; - dst[2] = dst[3] = pal[ (rama >> 4) & 3 ]; - dst[4] = dst[5] = pal[ (rama >> 2) & 3]; - dst[6] = dst[7] = pal[ rama & 3 ]; - (void)ramb; // ramb is not used -} -END_UPDATE - - - -/* 160x200, 16-colors, no constraint */ - -UPDATE_HI( bitmap16 ) -{ - dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = pal[ rama >> 4 ]; - dst[ 4] = dst[ 5] = dst[ 6] = dst[ 7] = pal[ rama & 15 ]; - dst[ 8] = dst[ 9] = dst[10] = dst[11] = pal[ ramb >> 4 ]; - dst[12] = dst[13] = dst[14] = dst[15] = pal[ ramb & 15 ]; -} -END_UPDATE - -UPDATE_LOW( bitmap16 ) -{ - dst[0] = dst[1] = pal[ rama >> 4 ]; - dst[2] = dst[3] = pal[ rama & 15 ]; - dst[4] = dst[5] = pal[ ramb >> 4 ]; - dst[6] = dst[7] = pal[ ramb & 15 ]; -} -END_UPDATE - - -/* 160x200, 16-colors, no constraint, alternate encoding, undocumented, tested */ - -static constexpr unsigned tbl_bit16[4][4] = { - { 0, 2, 8, 10 }, - { 1, 3, 9, 11 }, - { 4, 6, 12, 14 }, - { 5, 7, 13, 15 } }; - -UPDATE_HI( bitmap16alt ) -{ - unsigned p0 = tbl_bit16[ramb >> 6][rama >> 6]; - unsigned p1 = tbl_bit16[(ramb >> 4) & 3][(rama >> 4) & 3]; - unsigned p2 = tbl_bit16[(ramb >> 2) & 3][(rama >> 2) & 3]; - unsigned p3 = tbl_bit16[ramb & 3][rama & 3]; - dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = pal[ p0 ]; - dst[ 4] = dst[ 5] = dst[ 6] = dst[ 7] = pal[ p1 ]; - dst[ 8] = dst[ 9] = dst[10] = dst[11] = pal[ p2 ]; - dst[12] = dst[13] = dst[14] = dst[15] = pal[ p3 ]; -} -END_UPDATE - -UPDATE_LOW( bitmap16alt ) -{ - unsigned p0 = tbl_bit16[ramb >> 6][rama >> 6]; - unsigned p1 = tbl_bit16[(ramb >> 4) & 3][(rama >> 4) & 3]; - unsigned p2 = tbl_bit16[(ramb >> 2) & 3][(rama >> 2) & 3]; - unsigned p3 = tbl_bit16[ramb & 3][rama & 3]; - dst[0] = dst[1] = pal[ p0 ]; - dst[2] = dst[3] = pal[ p1 ]; - dst[4] = dst[5] = pal[ p2 ]; - dst[6] = dst[7] = pal[ p3 ]; -} -END_UPDATE - - - -/* 640x200 (80 text column), 2-colors, no constraint */ - -UPDATE_HI( mode80 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ 0 ]; - c[1] = pal[ 1 ]; - for ( i = 0; i < 8; i++, ramb >>= 1 ) - dst[ 15 - i ] = c[ ramb & 1 ]; - for ( i = 0; i < 8; i++, rama >>= 1 ) - dst[ 7 - i ] = c[ rama & 1 ]; -} -END_UPDATE - -UPDATE_LOW( mode80 ) -{ - /* 640-pixel mode but 320 pixels emulated => we merge pixels */ - int i; - pen_t c[4]; - c[0] = pal[ 0 ]; - c[1] = c[2] = c[3] = pal[ 1 ]; - for ( i = 0; i < 4; i++, ramb >>= 2 ) - dst[ 7 - i ] = c[ ramb & 3 ]; - for ( i = 0; i < 4; i++, rama >>= 2 ) - dst[ 3 - i ] = c[ rama & 3 ]; -} -END_UPDATE - - - -/* as above, but TO9 flavor */ - -UPDATE_HI( mode80_to9 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ 0 ]; - c[1] = pal[ 6 ]; - for ( i = 0; i < 8; i++, ramb >>= 1 ) - dst[ 15 - i ] = c[ ramb & 1 ]; - for ( i = 0; i < 8; i++, rama >>= 1 ) - dst[ 7 - i ] = c[ rama & 1 ]; -} -END_UPDATE - -UPDATE_LOW( mode80_to9 ) -{ - int i; - pen_t c[4]; - c[0] = pal[ 0 ]; - c[1] = c[2] = c[3] = pal[ 6 ]; - for ( i = 0; i < 4; i++, ramb >>= 2 ) - dst[ 7 - i ] = c[ ramb & 3 ]; - for ( i = 0; i < 4; i++, rama >>= 2 ) - dst[ 3 - i ] = c[ rama & 3 ]; -} -END_UPDATE - - - -/* 320x200, 2-colors, two pages (untested) */ - -UPDATE_HI( page1 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ 0 ]; - c[1] = pal[ 1 ]; - for ( i = 0; i < 16; i += 2, rama >>= 1 ) - dst[ 15 - i ] = dst[ 14 - i ] = c[ rama & 1 ]; - (void)ramb; -} -END_UPDATE - -UPDATE_LOW( page1 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ 0 ]; - c[1] = pal[ 1 ]; - for ( i = 0; i < 8; i++, rama >>= 1 ) - dst[ 7 - i ] = c[ rama & 1 ]; - (void)ramb; -} -END_UPDATE - -UPDATE_HI( page2 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ 0 ]; - c[1] = pal[ 2 ]; - for ( i = 0; i < 16; i += 2, ramb >>= 1 ) - dst[ 15 - i ] = dst[ 14 - i ] = c[ ramb & 1 ]; - (void)rama; -} -END_UPDATE - -UPDATE_LOW( page2 ) -{ - int i; - pen_t c[2]; - c[0] = pal[ 0 ]; - c[1] = pal[ 2 ]; - for ( i = 0; i < 8; i++, ramb >>= 1 ) - dst[ 7 - i ] = c[ ramb & 1 ]; - (void)rama; -} -END_UPDATE - - - -/* 320x200, 2-colors, two overlaid pages */ - -UPDATE_HI( overlay ) -{ - int i; - pen_t c[2][2]; - c[0][0] = pal[ 0 ]; - c[0][1] = c[1][1] = pal[ 1 ]; - c[1][0] = pal[ 2 ]; - for ( i = 0; i < 16; i += 2, rama >>= 1, ramb >>= 1 ) - dst[ 15 - i ] = dst[ 14 - i ] = c[ ramb & 1 ] [ rama & 1 ]; -} -END_UPDATE - -UPDATE_LOW( overlay ) -{ - int i; - pen_t c[2][2]; - c[0][0] = pal[ 0 ]; - c[0][1] = c[1][1] = pal[ 1 ]; - c[1][0] = pal[ 2 ]; - for ( i = 0; i < 8; i++, rama >>= 1, ramb >>= 1 ) - dst[ 7 - i ] = c[ ramb & 1 ] [ rama & 1 ]; -} -END_UPDATE - - -/* 160x200 undocumented variant of the above (2-colors, two overlaid pages) */ - -UPDATE_HI( overlayhalf ) -{ - int i; - pen_t c[2][2]; - c[0][0] = pal[ 0 ]; - c[0][1] = c[1][1] = pal[ 1 ]; - c[1][0] = pal[ 2 ]; - rama >>= 4; - ramb >>= 4; - for ( i = 0; i < 16; i += 4, rama >>= 1, ramb >>= 1 ) - dst[ 15 - i ] = dst[ 14 - i ] = dst[ 13 - i ] = dst[ 12 - i ] = - c[ ramb & 1 ] [ rama & 1 ]; -} -END_UPDATE - -UPDATE_LOW( overlayhalf ) -{ - int i; - pen_t c[2][2]; - c[0][0] = pal[ 0 ]; - c[0][1] = c[1][1] = pal[ 1 ]; - c[1][0] = pal[ 2 ]; - rama >>= 4; - ramb >>= 4; - for ( i = 0; i < 8; i += 2, rama >>= 1, ramb >>= 1 ) - dst[ 7 - i ] = dst[ 6 - i ] = c[ ramb & 1 ] [ rama & 1 ]; -} -END_UPDATE - - - -/* 160x200, 4-colors, four overlaid pages */ - -UPDATE_HI( overlay3 ) -{ - /* Note: "Manuel Technique" doc implies that the palette entries are 0,1,2,4,8; - we now use palette entries 0,1,2,3,4 instead, as this is what the TEO emulator uses and it has been confirmed correct - */ - static const int p[2][2][2][2] = { - { { { 0, 1 }, { 2, 1 } }, { { 3, 1 }, { 2, 1 } } }, - { { { 4, 1 }, { 2, 1 } }, { { 3, 1 }, { 2, 1 } } } - }; - int i; - for ( i = 0; i < 16; i += 4, rama >>= 1, ramb >>= 1 ) - dst[ 15 - i ] = dst[ 14 - i ] = dst[ 13 - i ] = dst[ 12 - i ] = - pal[ p[ ramb & 1 ] [ (ramb >> 4) & 1 ] - [ rama & 1 ] [ (rama >> 4) & 1 ] ]; -} -END_UPDATE - -UPDATE_LOW( overlay3 ) -{ - static const int p[2][2][2][2] = { - { { { 0, 1 }, { 2, 1 } }, { { 3, 1 }, { 2, 1 } } }, - { { { 4, 1 }, { 2, 1 } }, { { 3, 1 }, { 2, 1 } } } - }; - int i; - for ( i = 0; i < 8; i += 2, rama >>= 1, ramb >>= 1 ) - dst[ 7 - i ] = dst[ 6 - i ] = - pal[ p[ ramb & 1 ] [ (ramb >> 4) & 1 ] - [ rama & 1 ] [ (rama >> 4) & 1 ] ]; -} -END_UPDATE - - - -#define FUN(x) { &thomson_state::x##_scandraw_8, &thomson_state::x##_scandraw_16 } - - -static const thom_scandraw thom_scandraw_funcs[THOM_VMODE_NB][2] = -{ - FUN(to770), FUN(mo5), FUN(bitmap4), FUN(bitmap4alt), FUN(mode80), - FUN(bitmap16), FUN(page1), FUN(page2), FUN(overlay), FUN(overlay3), - FUN(to9), FUN(mode80_to9), - FUN(bitmap4althalf), FUN(mo5alt), FUN(overlayhalf), - FUN(bitmap16alt) -}; - - - -/* called at the start of each scanline in the active area, just after - left border (-1<=y<199), and also after the last scanline (y=199) -*/ -TIMER_CALLBACK_MEMBER( thomson_state::thom_scanline_start ) -{ - int y = param; - - /* update active-area */ - if ( y >= 0 && (m_thom_vstate_dirty || m_thom_vstate_last_dirty || m_thom_vmem_dirty[y]) ) - { - int x = 0; - while ( x < 40 ) - { - int xx = x; - unsigned mode = m_thom_vmodepage[x] >> 8; - unsigned page = m_thom_vmodepage[x] & 0xff; - assert( mode < THOM_VMODE_NB ); - assert( page < 4 ); - if ( m_thom_vmodepage_changed ) - { - do - { - xx++; - } - while ( xx < 40 && m_thom_vmodepage[xx] == -1 ); - } - else - { - xx = 40; - } - (this->*thom_scandraw_funcs[ mode ][ m_thom_hires ]) - ( m_thom_vram + y * 40 + page * 0x4000, - m_thom_vbody + y * 320 * (m_thom_hires+1), - m_thom_last_pal, x, xx-x ); - x = xx; - } - m_thom_vmem_dirty[y] = false; - } - - /* prepare for next scanline */ - if ( y == 199 ) - m_thom_scanline_timer->adjust(attotime::never); - else - { - if ( m_thom_vmodepage_changed ) - { - int x, m = 0; - for ( x = 0; x <= 40; x++ ) - { - if ( m_thom_vmodepage[x] !=-1 ) - { - m = m_thom_vmodepage[x]; - m_thom_vmodepage[x] = -1; - } - } - m_thom_vmodepage[0] = m; - m_thom_vmodepage_changed = 0; - } - - if ( m_thom_pal_changed ) - { - std::copy_n(&m_thom_pal[0], 16, &m_thom_last_pal[0]); - m_thom_pal_changed = false; - } - - m_thom_scanline_timer->adjust(attotime::from_usec(64), y + 1); - } -} - - - -/* -------------- misc --------------- */ - - -#define FLOP_STATE (m_thom_floppy_wcount ? 2 : m_thom_floppy_rcount ? 1 : 0) - - - -void thomson_state::thom_set_mode_point( int point ) -{ - assert( point >= 0 && point <= 1 ); - m_thom_mode_point = ( ! point ) * 0x2000; - m_vrambank->set_entry( ! point ); -} - - - -void thomson_state::thom_floppy_active( int write ) -{ - int fold = FLOP_STATE, fnew; - - /* stays up for a few frames */ - if ( write ) - m_thom_floppy_wcount = 25; - else - m_thom_floppy_rcount = 25; - - /* update icon */ - fnew = FLOP_STATE; - if ( fold != fnew ) - m_floppy_led = fnew; -} - - - -/* -------------- main update function --------------- */ - - - -uint32_t thomson_state::screen_update_thom(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - int y, ypos; - const int scale = m_thom_hires ? 2 : 1; - const int xbleft = m_thom_bwidth * scale; - const int xbright = ( m_thom_bwidth + THOM_ACTIVE_WIDTH ) * scale; - const int xright = ( m_thom_bwidth * 2 + THOM_ACTIVE_WIDTH ) * scale; - const int xwidth = THOM_ACTIVE_WIDTH * scale; - const int yup = THOM_BORDER_HEIGHT + THOM_ACTIVE_HEIGHT; - const int ybot = THOM_BORDER_HEIGHT + m_thom_bheight + 200; - uint16_t* v = m_thom_vbody; - pen_t border = 0; - rectangle wrect(0, xright - 1, 0, 0); - rectangle lrect(0, xbleft - 1, 0, 0); - rectangle rrect(xbright, xright - 1, 0, 0); - - //LOG("%f thom: video update called\n", machine().time().as_double()); - - /* upper border */ - for ( y = 0; y < THOM_BORDER_HEIGHT - m_thom_bheight; y++ ) - { - if ( m_thom_border_l[ y ] != -1 ) - border = m_thom_border_l[ y ]; - } - ypos = 0; - while ( y < THOM_BORDER_HEIGHT ) - { - if ( m_thom_border_l[ y ] != -1 ) - border = m_thom_border_l[ y ]; - wrect.min_y = ypos; - do - { - y++; - ypos ++ /* += scale */; - } - while ( y < THOM_BORDER_HEIGHT && m_thom_border_l[ y ] == -1 ); - wrect.max_y = ypos - 1; - bitmap.fill(border, wrect ); - } - - /* left border */ - while ( y < yup ) - { - if ( m_thom_border_l[ y ] != -1 ) - border = m_thom_border_l[ y ]; - lrect.min_y = ypos; - do - { - y++; - ypos ++ /* += scale */; - } - while ( y < yup && m_thom_border_l[ y ] == -1 ); - lrect.max_y = ypos - 1; - bitmap.fill(border, lrect ); - } - - /* lower border */ - while (y < ybot ) - { - if ( m_thom_border_l[ y ] != -1 ) - border = m_thom_border_l[ y ]; - wrect.min_y = ypos; - do - { - y++; - ypos ++ /* += scale */; - } while ( y < ybot && m_thom_border_l[ y ] == -1 ); - wrect.max_y = ypos - 1; - bitmap.fill(border, wrect ); - } - - /* right border */ - for ( y = 0; y < THOM_BORDER_HEIGHT; y++ ) { - if ( m_thom_border_r[ y ] != -1 ) - border = m_thom_border_r[ y ]; - } - ypos = m_thom_bheight /* * scale */; - while ( y < yup ) - { - if ( m_thom_border_r[ y ] != -1 ) - border = m_thom_border_r[ y ]; - rrect.min_y = ypos; - do - { - y++; - ypos ++ /* += scale */; - } - while ( y < yup && m_thom_border_r[ y ] == -1 ); - rrect.max_y = ypos - 1; - bitmap.fill(border, rrect ); - } - - /* active area */ - ypos = m_thom_bheight /* * scale */; - for ( y = 0; y < 200; v += xwidth, y++ , ypos ++ /* += scale */ ) - { - draw_scanline16( bitmap, xbleft, ypos, xwidth, v, nullptr ); -#if 0 - if ( thom_hires ) - draw_scanline16( bitmap, xbleft, ypos+1, xwidth, v, nullptr ); -#endif - } - - return 0; -} - - - -/* -------------- frame start ------------------ */ - - -TIMER_CALLBACK_MEMBER( thomson_state::thom_set_init ) -{ - int init = param; - LOG("%f thom_set_init: %i, at line %i col %i\n", machine().time().as_double(), init, thom_video_elapsed() / 64, thom_video_elapsed() % 64); - - if ( m_thom_init_cb ) - (this->*m_thom_init_cb)( init ); - if ( ! init ) - m_thom_init_timer->adjust(attotime::from_usec( 64 * THOM_ACTIVE_HEIGHT - 24 ), 1-init); -} - -/* call this at the very beginning of each new frame */ -WRITE_LINE_MEMBER(thomson_state::thom_vblank) -{ - // rising edge - if (state) - { - int fnew, fold = FLOP_STATE; - int i; - uint16_t b = 0; - struct thom_vsignal l = thom_get_lightpen_vsignal( 0, -1, 0 ); - - LOG("%f thom: video eof called\n", machine().time().as_double()); - - /* floppy indicator count */ - if ( m_thom_floppy_wcount ) - m_thom_floppy_wcount--; - if ( m_thom_floppy_rcount ) - m_thom_floppy_rcount--; - fnew = FLOP_STATE; - if ( fnew != fold ) - m_floppy_led = fnew; - - /* prepare state for next frame */ - for ( i = 0; i <= THOM_TOTAL_HEIGHT; i++ ) - { - if ( m_thom_border_l[ i ] != -1 ) - b = m_thom_border_l[ i ]; - if ( m_thom_border_r[ i ] != -1 ) - b = m_thom_border_r[ i ]; - } - std::fill(std::begin(m_thom_border_l), std::end(m_thom_border_l), -1); - std::fill(std::begin(m_thom_border_r), std::end(m_thom_border_r), -1); - m_thom_border_l[ 0 ] = b; - m_thom_border_r[ 0 ] = b; - m_thom_vstate_last_dirty = m_thom_vstate_dirty; - m_thom_vstate_dirty = false; - - /* schedule first init signal */ - m_thom_init_timer->adjust(attotime::from_usec( 64 * THOM_BORDER_HEIGHT + 7 )); - - /* schedule first lightpen signal */ - l.line &= ~1; /* hack (avoid lock in MO6 palette selection) */ - m_thom_lightpen_timer->adjust( - attotime::from_usec( 64 * ( THOM_BORDER_HEIGHT + l.line - 2 ) + 16 ), 0); - - /* schedule first active-area scanline call-back */ - m_thom_scanline_timer->adjust(attotime::from_usec( 64 * THOM_BORDER_HEIGHT + 7), -1); - - /* reset video frame time */ - m_thom_video_timer->adjust(attotime::zero); - - /* update screen size according to user options */ - if ( update_screen_size() ) - m_thom_vstate_dirty = true; - - /* hi-res automatic */ - m_thom_hires_better = thom_mode_is_hires( m_thom_vmode ); - } -} - - - -/* -------------- initialization --------------- */ - - -/* TO7, TO7/70 palette, hardcoded in ROM - without further information, we assume that the hardcoded values - are the same as those setup by the TO8/TO9+/MO6 when booting up - */ -static const uint16_t thom_pal_init[16] = -{ - 0x1000, /* 0: black */ 0x000f, /* 1: red */ - 0x00f0, /* 2: geen */ 0x00ff, /* 3: yellow */ - 0x0f00, /* 4: blue */ 0x0f0f, /* 5: purple */ - 0x0ff0, /* 6: cyan */ 0x0fff, /* 7: white */ - 0x0777, /* 8: gray */ 0x033a, /* 9: pink */ - 0x03a3, /* a: light green */ 0x03aa, /* b: light yellow */ - 0x0a33, /* c: light blue */ 0x0a3a, /* d: redish pink */ - 0x0ee7, /* e: light cyan */ 0x007b, /* f: orange */ -}; - -/* MO5 palette, hardcoded in a ROM - values are from "Manuel Technique du MO5", p.19 - */ -static const uint16_t mo5_pal_init[16] = -{ - 0x1000, /* 0: black */ 0x055f, /* 1: red */ - 0x00f0, /* 2: geen */ 0x00ff, /* 3: yellow */ - 0x0f55, /* 4: blue */ 0x0f0f, /* 5: purple */ - 0x0ff5, /* 6: cyan */ 0x0fff, /* 7: white */ - 0x0aaa, /* 8: gray */ 0x0aaf, /* 9: pink */ - 0x0afa, /* a: light green */ 0x0aff, /* b: light yellow */ - 0x0fa5, /* c: light blue */ 0x0faf, /* d: parama pink */ - 0x0ffa, /* e: light cyan */ 0x05af, /* f: orange */ -}; - - -void thomson_state::video_start() -{ - LOG("thom: video start called\n"); - - /* scan-line state */ - std::fill(std::begin(m_thom_border_l), std::end(m_thom_border_l), -1); - std::fill(std::begin(m_thom_border_r), std::end(m_thom_border_r), -1); - std::fill(std::begin(m_thom_vbody), std::end(m_thom_vbody), 0); - std::fill(std::begin(m_thom_vmodepage), std::end(m_thom_vmodepage), -1); - std::fill(std::begin(m_thom_vmem_dirty), std::end(m_thom_vmem_dirty), false); - m_thom_border_l[ 0 ] = 0; - m_thom_border_r[ 0 ] = 0; - m_thom_vmodepage[ 0 ] = 0; - m_thom_vmodepage_changed = 0; - m_thom_vmode = 0; - m_thom_vpage = 0; - m_thom_border_index = 0; - m_thom_vstate_dirty = true; - m_thom_vstate_last_dirty = true; - save_pointer(NAME(m_thom_last_pal), sizeof(m_thom_last_pal)); - save_pointer(NAME(m_thom_pal), sizeof(m_thom_pal)); - save_pointer(NAME(m_thom_border_l), sizeof(m_thom_border_l)); - save_pointer(NAME(m_thom_border_r), sizeof(m_thom_border_r)); - save_pointer(NAME(m_thom_vbody), sizeof(m_thom_vbody)); - save_pointer(NAME(m_thom_vmodepage), sizeof(m_thom_vmodepage)); - save_pointer(NAME(m_thom_vmem_dirty), sizeof(m_thom_vmem_dirty)); - save_item(NAME(m_thom_pal_changed)); - save_item(NAME(m_thom_vmodepage_changed)); - save_item(NAME(m_thom_vmode)); - save_item(NAME(m_thom_vpage)); - save_item(NAME(m_thom_border_index)); - save_item(NAME(m_thom_vstate_dirty)); - save_item(NAME(m_thom_vstate_last_dirty)); - - m_thom_mode_point = 0; - save_item(NAME(m_thom_mode_point)); - m_vrambank->set_entry( 0 ); - - m_thom_floppy_rcount = 0; - m_thom_floppy_wcount = 0; - save_item(NAME(m_thom_floppy_wcount)); - save_item(NAME(m_thom_floppy_rcount)); - m_floppy_led.resolve(); - - m_caps_led.resolve(); - - m_thom_video_timer = machine().scheduler().timer_alloc(timer_expired_delegate()); - - m_thom_scanline_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(thomson_state::thom_scanline_start),this)); - - m_thom_lightpen_nb = 0; - m_thom_lightpen_cb = nullptr; - m_thom_lightpen_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(thomson_state::thom_lightpen_step),this)); - save_item(NAME(m_thom_lightpen_nb)); - - m_thom_init_cb = nullptr; - m_thom_init_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(thomson_state::thom_set_init),this)); - - m_thom_bwidth = 0; - m_thom_bheight = 0; - m_thom_hires = 0; - m_thom_hires_better = 0; - save_item(NAME(m_thom_bwidth)); - save_item(NAME(m_thom_bheight)); - save_item(NAME(m_thom_hires)); - save_item(NAME(m_thom_hires_better)); -} - - -/* sets the fixed palette (for MO5,TO7,TO7/70) and gamma correction */ -void thomson_state::thom_configure_palette(double gamma, const uint16_t* pal, palette_device& palette) -{ - std::copy_n(&pal[0], 16, &m_thom_last_pal[0]); - std::copy_n(&pal[0], 16, &m_thom_pal[0]); - - for ( int i = 0; i < 4097; i++ ) - { - uint8_t r = 255. * pow( (i & 15) / 15., gamma ); - uint8_t g = 255. * pow( ((i>> 4) & 15) / 15., gamma ); - uint8_t b = 255. * pow( ((i >> 8) & 15) / 15., gamma ); - /* uint8_t alpha = i & 0x1000 ? 0 : 255; TODO: transparency */ - palette.set_pen_color(i, r, g, b ); - } -} - - -void thomson_state::thom_palette(palette_device &palette) -{ - LOG("thom: palette init called\n"); - - /* TO8 and later use an EF9369 color palette chip - The spec shows a built-in gamma correction for gamma=2.8 - i.e., output is out = in ^ (1/2.8) - - For the TO7, the gamma correction is irrelevant. - - For the TO7/70, we use the same palette and gamma has the TO8, - which gives good results (but is not verified). - */ - thom_configure_palette(1.0 / 2.8, thom_pal_init, palette); -} - -void thomson_state::mo5_palette(palette_device &palette) -{ - LOG("thom: MO5 palette init called\n"); - - /* The MO5 has a different fixed palette than the TO7/70. - We use a smaller gamma correction which gives intutively better - results (but is not verified). - */ - thom_configure_palette(1.0, mo5_pal_init, palette); -} - - - -/***************************** TO7 / T9000 *************************/ - - - -/* write to video memory through addresses 0x4000-0x5fff */ -void thomson_state::to7_vram_w(offs_t offset, uint8_t data) -{ - assert( offset < 0x2000 ); - /* force two topmost color bits to 1 */ - if ( m_thom_mode_point ) - data |= 0xc0; - if ( m_thom_vram[ offset + m_thom_mode_point ] == data ) - return; - m_thom_vram[ offset + m_thom_mode_point ] = data; - /* dirty whole scanline */ - m_thom_vmem_dirty[ offset / 40 ] = true; -} - - - -/* bits 0-13 : latched gpl of lightpen position */ -/* bit 14: latched INIT */ -/* bit 15: latched INIL */ -unsigned thomson_state::to7_lightpen_gpl ( int decx, int decy ) -{ - int x,y; - thom_get_lightpen_pos( &x, &y ); - x -= m_thom_bwidth; - y -= m_thom_bheight; - if ( x < 0 || y < 0 || x >= 320 || y >= 200 ) - return 0; - x += decx; - y += decy; - return y*40 + x/8 + (x < 320 ? 0x4000 : 0) + 0x8000; -} - - - -/************************** TO7/70 / MO5 ****************************/ - - - -/* write to video memory through addresses 0x4000-0x5fff (TO) - or 0x0000-0x1fff (MO) */ -void thomson_state::to770_vram_w(offs_t offset, uint8_t data) -{ - assert( offset < 0x2000 ); - if ( m_thom_vram[ offset + m_thom_mode_point ] == data ) - return; - m_thom_vram[ offset + m_thom_mode_point ] = data; - /* dirty whole scanline */ - m_thom_vmem_dirty[ offset / 40 ] = true; -} - - - - -/***************************** TO8 ******************************/ - - - -/* write to video memory through system space (always page 1) */ - -void thomson_state::to8_sys_lo_w(offs_t offset, uint8_t data) -{ - uint8_t* dst = m_thom_vram + offset + 0x6000; - assert( offset < 0x2000 ); - if ( *dst == data ) - return; - *dst = data; - /* dirty whole scanline */ - m_thom_vmem_dirty[ offset / 40 ] = true; -} - - - -void thomson_state::to8_sys_hi_w(offs_t offset, uint8_t data) -{ - uint8_t* dst = m_thom_vram + offset + 0x4000; - assert( offset < 0x2000 ); - if ( *dst == data ) return; - *dst = data; - /* dirty whole scanline */ - m_thom_vmem_dirty[ offset / 40 ] = true; -} - - - -/* write to video memory through data space */ - -void thomson_state::to8_data_lo_w(offs_t offset, uint8_t data) -{ - uint8_t* dst = m_thom_vram + ( ( offset + 0x4000 * m_to8_data_vpage + 0x2000 ) & m_ram->mask() ); - assert( offset < 0x2000 ); - if ( *dst == data ) - return; - *dst = data; - /* dirty whole scanline */ - if ( m_to8_data_vpage >= 4 ) - return; - m_thom_vmem_dirty[ offset / 40 ] = true; -} - - - -void thomson_state::to8_data_hi_w(offs_t offset, uint8_t data) -{ - uint8_t* dst = m_thom_vram + ( ( offset + 0x4000 * m_to8_data_vpage ) & m_ram->mask() ); - assert( offset < 0x2000 ); - if ( *dst == data ) - return; - *dst = data; - /* dirty whole scanline */ - if ( m_to8_data_vpage >= 4 ) - return; - m_thom_vmem_dirty[ offset / 40 ] = true; -} - - - -/* write to video memory page through cartridge addresses space */ -void thomson_state::to8_vcart_w(offs_t offset, uint8_t data) -{ - uint8_t* dst = m_thom_vram + ( ( offset + 0x4000 * m_to8_cart_vpage ) & m_ram->mask() ); - assert( offset < 0x4000 ); - if ( *dst == data ) - return; - *dst = data; - /* dirty whole scanline */ - if ( m_to8_cart_vpage >= 4 ) - return; - m_thom_vmem_dirty[ (offset & 0x1fff) / 40 ] = true; -} - -void thomson_state::mo6_vcart_lo_w(offs_t offset, uint8_t data) -{ - uint8_t* dst = m_thom_vram + ( ( offset + 0x3000 + 0x4000 * m_to8_cart_vpage ) & m_ram->mask() ); - assert( offset < 0x1000 ); - if ( *dst == data ) - return; - *dst = data; - /* dirty whole scanline */ - if ( m_to8_cart_vpage >= 4 ) - return; - m_thom_vmem_dirty[ (offset & 0x1fff) / 40 ] = true; -} - -void thomson_state::mo6_vcart_hi_w(offs_t offset, uint8_t data) -{ - uint8_t* dst = m_thom_vram + ( ( offset + 0x4000 * m_to8_cart_vpage ) & m_ram->mask() ); - assert( offset < 0x3000 ); - if ( *dst == data ) - return; - *dst = data; - /* dirty whole scanline */ - if ( m_to8_cart_vpage >= 4 ) - return; - m_thom_vmem_dirty[ (offset & 0x1fff) / 40 ] = true; -} |