summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/video/fixfreq.cpp
blob: 4957a0343faa5262a18c42e03b1bb801b08b8dda (plain) (tree)
1
2
3
4
5
6
7
                       
                               



                                                                            
                   








                                                                            
                     

                    
                   
                     
 

                    
                                                                            
 
                           
 
                                                                            


 

                                                                                              
 
                                                                                             
 
                                                             
 


                                              
                                                                                                                      

                                                                      
                                                                   


                                       


                                                                                              



                                            

                                                                                                             






                                                                      
                                                                                        



                                                                       
                                           
                 
                                                                                   





                                                                                    

                               
                                

 
                                                              
 
                                                                                                             
                                                                
 
                                                    
 

                                                     
 
                                                                                                                
                                                                                        

                          
 




                                                                                                   
                                                                                    


                           
                                   


                                                                   
 










                                                                                    
 










                                                                                    
 
 
                                                                                   
 








                                                                                    
 

 




                                                                                   
 


                                                                                                                                     


                                               

                                         


 

                                                                                                                   
 
 
 



                                               
 
                                            



                                                                                      
                                          
                                                                                         
 
 

                                     





                                          


                                                       
                                               





                                                   

                                                
 

                                                

                                                          
 


                                                 

 
                                     
 
                        

 
                                         
 
                                 



                                                                                                                

                                                       
         



                                                                                
                                                            
         
                                                                                                                                 
                                                                 

                                                       


                                                   
                                                                                                                                                             


                                                   








                                                                      


                                    
                 

 
                                                          
 

                        
 
                                                                                                  
 

                                                                                                                      
 
 


                                                                            
 


                                                         
 


                                                           
 


                                                 
 






                                                             
 


                                                            
 

                                                 
 
 






                                                            
 
                                                                             
// license:BSD-3-Clause
// copyright-holders:Couriersud
/***************************************************************************

    fixfreq.h

    2013 Couriersud

    Fixed frequency monochrome monitor emulation

    The driver is intended for drivers which provide an analog video signal.
    VSYNC and HSYNC levels are used to create the bitmap.

***************************************************************************/

#include "emu.h"
#include "rendutil.h"
#include "fixfreq.h"

//#define VERBOSE 1
#include "logmacro.h"

#include <algorithm>

/***************************************************************************

    Fixed frequency monitor

***************************************************************************/



// device type definition
DEFINE_DEVICE_TYPE(FIXFREQ, fixedfreq_device, "fixfreq", "Fixed-Frequency Monochrome Monitor")

void fixedfreq_monitor_state::update_sync_channel(const time_type &time, const double newval)
{
	const time_type delta_time = time - m_last_sync_time;

	const int last_vsync = m_sig_vsync;
	const int last_comp = m_sig_composite;

	m_vsync_filter += ((double) last_comp - m_vsync_filter) * (1.0 - exp(-delta_time * m_vsync_filter_timeconst));
	m_sig_composite = (newval < m_desc.m_sync_threshold) ? 1 : 0 ;

	m_sig_vsync = (m_vsync_filter > m_vsync_threshold) ? 1 : 0;

	if (!last_vsync && m_sig_vsync)
	{
		//LOG("VSYNC %d %d\n", m_last_x, m_last_y + m_sig_field);
		m_last_y = m_desc.m_vbackporch - m_desc.m_vsync;
		m_intf.vsync_start_cb(std::max(time - m_last_vsync_time, m_min_frame_period));
		m_last_vsync_time = time;
	}
	else if (last_vsync && !m_sig_vsync)
	{
		m_sig_field = last_comp;   /* force false-progressive */
		m_sig_field = (m_sig_field ^ 1) ^ last_comp;   /* if there is no field switch, auto switch */
		//LOG("Field: %d\n", m_sig_field);
	}

	if (!last_comp && m_sig_composite)
	{
		/* TODO - time since last hsync and field detection */
		//LOG("HSYNC up %d\n", m_last_x);
		// FIXME: pixels > 50 filters some spurious hysnc on line 27 in breakout
		if (!m_sig_vsync && (m_last_x > m_desc.m_hscale * 100))
		{
			m_last_y += m_desc.m_fieldcount;
			m_last_x = 0;
			m_line_time = time;
		}
		//if (m_last_y == 27) printf("HSYNC up %d %d\n", m_last_y, pixels);
	}
	else if (last_comp && !m_sig_composite)
	{
		/* falling composite */
		//LOG("HSYNC down %f %d %f\n", time * 1e6, m_last_x, m_sync_signal);
	}

	m_sync_signal = newval;
	m_last_sync_time = time;
}

void fixedfreq_monitor_state::update_bm(const time_type &time)
{
	const float pixels = (time - m_line_time) * static_cast<time_type>(m_desc.m_hscale) / m_clock_period;
	const int has_fields = (m_desc.m_fieldcount > 1) ? 1: 0;

	uint32_t col(0xffff0000); // Mark sync areas

	if (m_sync_signal >= m_desc.m_sync_threshold)
		col = m_col;

	m_fragments.push_back({static_cast<float>(m_last_y + m_sig_field * has_fields), m_last_x, pixels, col});
	//m_intf.plot_hline(m_last_x, m_last_y + m_sig_field * has_fields, pixels, col);
	m_last_x = pixels;
}

void fixedfreq_monitor_state::update_composite_monochrome(const time_type &time, const double data)
{
	update_bm(time);
	update_sync_channel(time, data);

	int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
	if (colv > 255)
		colv = 255;
	if (colv < 0)
		m_col = 0xffff0000;
	else
		m_col = 0xff000000 | (colv<<16) | (colv<<8) | colv;
}

void fixedfreq_monitor_state::update_red(const time_type &time, const double data)
{
	update_bm(time);

	int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
	if (colv > 255)
		colv = 255;
	if (colv < 0)
		colv = 0;
	m_col = (m_col & 0xff00ffff) | (colv<<16);
}

void fixedfreq_monitor_state::update_green(const time_type &time, const double data)
{
	update_bm(time);
	//update_sync_channel(ctime, data);

	int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
	if (colv > 255)
		colv = 255;
	if (colv < 0)
		colv = 0;
	m_col = (m_col & 0xffff00ff) | (colv<<8);
}

void fixedfreq_monitor_state::update_blue(const time_type &time, const double data)
{
	update_bm(time);
	//update_sync_channel(ctime, data);

	int colv = (int) ((data - m_desc.m_sync_threshold) * m_desc.m_gain * 255.0);
	if (colv > 255)
		colv = 255;
	if (colv < 0)
		colv = 0;
	m_col = (m_col & 0xffffff00) | colv;

}

void fixedfreq_monitor_state::update_sync(const time_type &time, const double data)
{
	update_bm(time);
	update_sync_channel(time, data);
}

fixedfreq_device::fixedfreq_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, type, tag, owner, clock),
		device_video_interface(mconfig, *this, false),
		m_htotal(0),
		m_vtotal(0),
		m_refresh_period(time_type(0)),
		m_monitor(),
		m_state(m_monitor, *this)
{
}

fixedfreq_device::fixedfreq_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: fixedfreq_device(mconfig, FIXFREQ, tag, owner, clock)
{
}

void fixedfreq_device::device_config_complete()
{
	if (!has_screen())
		return;

	if (!screen().refresh_attoseconds())
		screen().set_raw(m_monitor.m_monitor_clock, m_monitor.m_hbackporch, 0,
			m_monitor.m_hbackporch, m_monitor.m_vbackporch, 0,
			m_monitor.m_vbackporch);

	if (!screen().has_screen_update())
		screen().set_screen_update(*this, FUNC(fixedfreq_device::screen_update));
}

void fixedfreq_device::device_start()
{

	m_refresh_period = time_type(0);

	m_htotal = m_monitor.m_hbackporch;
	m_vtotal = m_monitor.m_vbackporch;

	m_state.start();

	// FIXME: will be done by netlist going forward
	save_item(NAME(m_state.m_sync_signal));
	save_item(NAME(m_state.m_last_x));
	save_item(NAME(m_state.m_last_y));
	save_item(NAME(m_state.m_last_sync_time));
	save_item(NAME(m_state.m_line_time));
	save_item(NAME(m_state.m_last_hsync_time));
	save_item(NAME(m_state.m_last_vsync_time));
	save_item(NAME(m_refresh_period));
	save_item(NAME(m_state.m_clock_period));

	/* sync separator */
	save_item(NAME(m_state.m_vsync_filter));
	save_item(NAME(m_state.m_vsync_threshold));
	save_item(NAME(m_state.m_vsync_filter_timeconst));

	save_item(NAME(m_state.m_sig_vsync));
	save_item(NAME(m_state.m_sig_composite));
	save_item(NAME(m_state.m_sig_field));
}

void fixedfreq_device::device_reset()
{
	m_state.reset();
}

void fixedfreq_device::device_post_load()
{
	//recompute_parameters();
}

uint32_t fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{

	if (screen.screen_type() == SCREEN_TYPE_RASTER)
	{
		for (auto &f : m_state.m_fragments)
			if (f.y < bitmap.height())
				bitmap.plot_box(f.x, f.y, f.xr - f.x, 1, f.col);
	}
	else if (screen.screen_type() == SCREEN_TYPE_VECTOR)
	{
		constexpr const uint32_t flags(PRIMFLAG_ANTIALIAS(1) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_VECTOR(1));
		const rectangle &visarea = screen.visible_area();
		float xscale = 1.0f / visarea.width();
		float yscale = 1.0f / visarea.height();
		float xoffs = (float)visarea.min_x;
		float yoffs = (float)visarea.min_y;
		screen.container().empty();
		screen.container().add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff,0x00,0x00,0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_VECTORBUF(1));

		for (auto &f : m_state.m_fragments)
		{
			const float x0((f.x - xoffs) * xscale);
			const float y0((f.y - yoffs) * yscale);
			const float x1((f.xr - xoffs) * xscale);
			const float y1((f.y + 1.0f - yoffs) * yscale);

			screen.container().add_rect(
				x0, y0, x1, y1,
				(0xff << 24) | (f.col & 0xffffff),
				flags);
		}
	}
	m_state.m_fragments.clear();
	return 0;
}

void fixedfreq_device::vsync_start_cb(double refresh_time)
{
	// toggle bitmap
	//m_cur_bm ^= 1;

	rectangle visarea(m_monitor.minh(), m_monitor.maxh(), m_monitor.minv(), m_monitor.maxv());

	m_refresh_period = refresh_time;
	screen().configure(m_htotal * m_monitor.m_hscale, m_vtotal, visarea, DOUBLE_TO_ATTOSECONDS(m_refresh_period));
}

NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_composite_monochrome)
{
	// double is good enough for this exercise;

	const time_type ctime = time.as_double();
	m_state.update_composite_monochrome(ctime, data);
}

NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_red)
{
	// double is good enough for this exercise;

	const time_type ctime = time.as_double();
	m_state.update_red(ctime, data);
}

NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_green)
{
	// double is good enough for this exercise;

	const time_type ctime = time.as_double();
	m_state.update_green(ctime, data);
}

NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_blue)
{
	// double is good enough for this exercise;

	const time_type ctime = time.as_double();
	m_state.update_blue(ctime, data);
}

NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_sync)
{
	// double is good enough for this exercise;

	const time_type ctime = time.as_double();
	m_state.update_sync(ctime, data);
}

/***************************************************************************/