summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/video/ef9340_1.cpp
blob: c218645208c680e7727e0896dfa5d0743e09d159 (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                                     

                                                                            



                                                                                 
                                                 




                                                                          


                                        
                                                                   
               
        
                  


                                                                            
                
                     
 

                   


                               
 
                         
                                                                                  
 
 
                                                                                                            
                                                        
                                                
                                      
                              
                                   
 

                       

 
 
                     
                                          
                                                                                                                                                         








                                                                
                                    
 
                                                                                  
                                                      
 
                                                                               
                                                                                       
 
                                                                               
                                                                                         
 


                        
                              





                        

                                     
                                  
 

                                            
 



                                       
 




                                     

                                                  
                                           
 

                                 

 
 
                                                    
 



                                                                         
 

                                                 
 
 
 
                                                  
 
                               
         
                                                              
         
                     
         
                                                                           
         
                                            

 
 
                                    
 
                     
                                                                                         
         

                                                     


                                       




                               
                                                             
 
                                                                                                    
 
                    
         
                      
                 
                                           
                                             
                                                   
                         










                                                                        
                                                       











                                                                         
                         
                                              


                    
                                           



                 
                      
                 
                                                                                     
 
                                           
                                             
                                                  
                         
                                                   

                                                                    
                                                       

                                              
                                                                     

                                                                    

                                              




                                                                     
 

                                                                                                     
 

                                                                                              
                                              
                                 
 
                                                                   
                                              
                         
                                              


                    
                                           



                 
 
                                                 
 
                
 
                                                                                  
 
                    
         
                      
                 
                                 


                    
                                                          



                 
                      
                 
                                                                                     
 
                                           
                                             
                                                  
                         
                                                  

                                                                    
                                                       

                                              
                                                                    

                                                                    

                                              




                                                                     
 

                                                           
 



                                                                                                                  
 

                                                                                              
                                              
                                 
 
                                                                    


                                              


                    
                                           



                    

 
                                                     
 
                                   



                           




                                          
                                                        
                                                       
 
                                                 
         
                              


                                     

                                       
                                      
 
                              
                 
                                      
                                              
                         
                                                         
                                           


                            
                                                          
                                                                
                                                                                                

                                       


                    
                                                 
                                                                               
                 
 
                                            
                 
                                      
                                                               

                                             


                                                                                                  
                                        
                                         
 
                                     
                         

                                                       
                                 
                                                      
                                                           
 



                                                                                               
                                 



                                                         


                            

                                                       
                                 






















                                                                                       
                                         

                                                                                                                   

                                            



                                                              
                                         

                                                                                             
                                         
                                 

                                              

                                    

                                                           


                                                         


                                 

                                                                                
                                                   

                                   

                                                  





                                                     
                         
                                                                              
                                                                                                  
                                                
                         




                                                                      
                         
                 
         


                                                
                                                                                
         








                                                               
 

 
                                                                                                          



                                                                                               
                                                                      


                 
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol, hap
/***************************************************************************

Thomson EF9340 + EF9341 teletext graphics, this device is a combination of chips.

Minimal components:
- Thomson EF9340 "VIN"
- Thomson EF9341 "GEN" (CPU connects to this one)
- 2*1KB RAM, A for attributes, B for character codes

There's also an optional extended character memory, it can be RAM or ROM.
This is implemented with a callback. The datasheet explains how to hook up
1KB RAM, but it's possible to have more.

TODO:
- busy state (right now it is immediate)
- internal display timing (on g7400, most of it is done externally)
- window boxing
- Y zoom
- RES(restart) pin

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

#include "emu.h"
#include "ef9340_1.h"

#include "screen.h"

//#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"


// device type definition
DEFINE_DEVICE_TYPE(EF9340_1, ef9340_1_device, "ef9340_1", "Thomson EF9340+EF9341")


ef9340_1_device::ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
	: device_t(mconfig, EF9340_1, tag, owner, clock)
	, device_video_interface(mconfig, *this)
	, m_charset(*this, "ef9340_1")
	, m_write_exram(*this)
	, m_read_exram(*this, 0xff)
{
	m_offset_x = 0;
	m_offset_y = 0;
}


ROM_START( ef9340_1 )
	ROM_REGION( 0xa00, "ef9340_1", 0 )
	ROM_LOAD( "charset_ef9340_1.rom", 0x0000, 0x0a00, BAD_DUMP CRC(8de85988) SHA1(f8e3892234da6626eb4302e171179ada5a51fca8) ) // taken from datasheet
ROM_END


const tiny_rom_entry *ef9340_1_device::device_rom_region() const
{
	return ROM_NAME( ef9340_1 );
}


void ef9340_1_device::device_start()
{
	// let the screen create our temporary bitmap with the screen's dimensions
	screen().register_screen_bitmap(m_tmp_bitmap);

	m_line_timer = timer_alloc(FUNC(ef9340_1_device::draw_scanline), this);
	m_line_timer->adjust(screen().time_until_pos(0, 0), 0, screen().scan_period());

	m_blink_timer = timer_alloc(FUNC(ef9340_1_device::blink_update), this);
	m_blink_timer->adjust(screen().time_until_pos(0, 0), 0, screen().frame_period());

	// zerofill
	m_ef9341.TA = 0;
	m_ef9341.TB = 0;
	m_ef9341.busy = false;

	m_ef9340.X = 0;
	m_ef9340.Y = 0;
	m_ef9340.Y0 = 0;
	m_ef9340.R = 0;
	m_ef9340.M = 0;
	m_ef9340.blink = false;
	m_ef9340.blink_prescaler = 0;
	m_ef9340.h_parity = false;

	memset(m_ram_a, 0, sizeof(m_ram_a));
	memset(m_ram_b, 0, sizeof(m_ram_b));

	// register our state
	save_item(NAME(m_ef9341.TA));
	save_item(NAME(m_ef9341.TB));
	save_item(NAME(m_ef9341.busy));

	save_item(NAME(m_ef9340.X));
	save_item(NAME(m_ef9340.Y));
	save_item(NAME(m_ef9340.Y0));
	save_item(NAME(m_ef9340.R));
	save_item(NAME(m_ef9340.M));
	save_item(NAME(m_ef9340.blink));
	save_item(NAME(m_ef9340.blink_prescaler));
	save_item(NAME(m_ef9340.h_parity));

	save_item(NAME(m_ram_a));
	save_item(NAME(m_ram_b));
}


TIMER_CALLBACK_MEMBER(ef9340_1_device::blink_update)
{
	// blink rate is approximately 0.5s
	m_ef9340.blink_prescaler = (m_ef9340.blink_prescaler + 1) & 0x1f;
	if (m_ef9340.R & 0x40 && m_ef9340.blink_prescaler == 24)
		m_ef9340.blink_prescaler = 0;

	if (m_ef9340.blink_prescaler == 0)
		m_ef9340.blink = !m_ef9340.blink;
}


u16 ef9340_1_device::ef9340_get_c_addr(u8 x, u8 y)
{
	if ((y & 0x18) == 0x18)
	{
		return 0x318 | ((x & 0x38) << 2) | (x & 0x07);
	}
	if (x & 0x20)
	{
		return 0x300 | ((y & 0x07) << 5) | (y & 0x18) | (x & 0x07);
	}
	return (y & 0x1f) << 5 | (x & 0x1f);
}


void ef9340_1_device::ef9340_inc_c()
{
	m_ef9340.X++;
	if (m_ef9340.X == 40 || m_ef9340.X == 48 || m_ef9340.X == 56 || m_ef9340.X == 64)
	{
		m_ef9340.Y = (m_ef9340.Y + 1) & 0x1f;
		if (m_ef9340.Y == 24)
		{
			m_ef9340.Y = 0;
		}
		m_ef9340.X = 0;
	}
}


void ef9340_1_device::ef9341_write(u8 command, u8 b, u8 data)
{
	LOG("ef9341 %s write, t%s, data %02X\n", command ? "command" : "data", b ? "B" : "A", data);

	if (command)
	{
		if (b)
		{
			m_ef9341.TB = data;
			m_ef9341.busy = true;
			switch (m_ef9341.TB & 0xe0)
			{
				case 0x00: // begin row
					m_ef9340.X = 0;
					m_ef9340.Y = m_ef9341.TA & 0x1f;
					break;
				case 0x20: // load Y
					m_ef9340.Y = m_ef9341.TA & 0x1f;
					break;
				case 0x40: // load X
					m_ef9340.X = m_ef9341.TA & 0x3f;
					break;
				case 0x60: // increment C
					ef9340_inc_c();
					break;
				case 0x80: // load M
					m_ef9340.M = m_ef9341.TA;
					break;
				case 0xa0: // load R
					m_ef9340.R = m_ef9341.TA;
					break;
				case 0xc0: // load Y0
					m_ef9340.Y0 = m_ef9341.TA & 0x3f;
					break;
				case 0xe0: // not interpreted
					break;
			}
			m_ef9341.busy = false;
		}
		else
		{
			m_ef9341.TA = data;
		}
	}
	else
	{
		if (b)
		{
			u16 addr = ef9340_get_c_addr(m_ef9340.X, m_ef9340.Y) & 0x3ff;

			m_ef9341.TB = data;
			m_ef9341.busy = true;
			switch (m_ef9340.M & 0xe0)
			{
				case 0x00: // write
					m_ram_a[addr] = m_ef9341.TA;
					m_ram_b[addr] = m_ef9341.TB;
					ef9340_inc_c();
					break;

				case 0x40: // write without increment
					m_ram_a[addr] = m_ef9341.TA;
					m_ram_b[addr] = m_ef9341.TB;
					break;

				case 0x80: // write slice
				{
					u8 a = m_ram_a[addr];
					u8 b = m_ram_b[addr];
					u8 slice = m_ef9340.M & 0x0f;

					if (b >= 0xa0)
						m_write_exram(a << 12 | b << 4 | slice, m_ef9341.TA);

					// increment slice number
					m_ef9340.M = (m_ef9340.M & 0xf0) | ((slice + 1) % 10);
					break;
				}

				default: // illegal or read command
					break;
			}
			m_ef9341.busy = false;
		}
		else
		{
			m_ef9341.TA = data;
		}
	}
}


u8 ef9340_1_device::ef9341_read(u8 command, u8 b)
{
	u8 data;

	LOG("ef9341 %s read, t%s\n", command ? "command" : "data", b ? "B" : "A");

	if (command)
	{
		if (b)
		{
			data = 0;
		}
		else
		{
			data = (m_ef9341.busy) ? 0x80 : 0;
		}
	}
	else
	{
		if (b)
		{
			u16 addr = ef9340_get_c_addr(m_ef9340.X, m_ef9340.Y) & 0x3ff;

			data = m_ef9341.TB;
			m_ef9341.busy = true;
			switch (m_ef9340.M & 0xe0)
			{
				case 0x20: // read
					m_ef9341.TA = m_ram_a[addr];
					m_ef9341.TB = m_ram_b[addr];
					ef9340_inc_c();
					break;

				case 0x60: // read without increment
					m_ef9341.TA = m_ram_a[addr];
					m_ef9341.TB = m_ram_b[addr];
					break;

				case 0xa0: // read slice
				{
					u8 a = m_ram_a[addr];
					u8 b = m_ram_b[addr];
					u8 slice = m_ef9340.M & 0x0f;

					m_ef9341.TA = 0xff;
					m_ef9341.TB = 0xff;

					if (b >= 0xa0)
						m_ef9341.TA = m_read_exram(a << 12 | b << 4 | slice);
					else if (b < 0x80 && slice < 10)
						m_ef9341.TA = m_charset[(((a & 0x80) | (b & 0x7f)) * 10) + slice];

					// increment slice number
					m_ef9340.M = (m_ef9340.M & 0xf0) | ((slice + 1) % 10);
					break;
				}

				default: // illegal or write command
					break;
			}
			m_ef9341.busy = false;
		}
		else
		{
			data = m_ef9341.TA;
		}
	}
	return data;
}


TIMER_CALLBACK_MEMBER(ef9340_1_device::draw_scanline)
{
	int vpos = screen().vpos();
	vpos -= m_offset_y;
	if (vpos < 0)
		return;

	int slice = vpos % 10;
	bool dh = false;
	if (vpos == 0)
		m_ef9340.h_parity = false;

	// display automaton active at 40-290, or 32-242
	int max_vpos = (m_ef9340.R & 0x40) ? 250 : 210;

	if (m_ef9340.R & 0x01 && vpos < max_vpos)
	{
		int y_row = 0;
		u16 char_data = 0x00;
		u8 fg = 0;
		u8 bg = 0;
		bool underline = false;
		bool blank = false;
		bool w_parity = false;

		if (vpos < 10)
		{
			// service row
			if (m_ef9340.R & 0x08)
			{
				// service row is enabled
				y_row = 31;
			}
			else
			{
				// service row is disabled
				for (int i = 0; i < 40 * 8; i++)
					m_tmp_bitmap.pix(m_offset_y + vpos, m_offset_x + i) = 8;
				return;
			}
		}
		else
		{
			// displaying regular row
			y_row = ((m_ef9340.Y0 & 0x1f) + (vpos - 10) / 10) % 24;
		}

		for (int x = 0; x < 40; x++)
		{
			int s = slice;
			u16 addr = ef9340_get_c_addr(x, y_row);
			u8 a = m_ram_a[addr];
			u8 b = m_ram_b[addr];
			bool blink = m_ef9340.R & 0x80 && m_ef9340.blink;
			bool cursor = m_ef9340.R & 0x10 && x == m_ef9340.X && y_row == m_ef9340.Y;
			bool invert = cursor && !blink;
			bool dw = false;
			bool del = false;

			if (a & 0x80)
			{
				// graphics
				if ((b & 0xe0) != 0x80)
				{
					fg = a & 0x07;
					bg = a >> 4 & 0x07;

					if (b & 0x80)
						char_data = m_read_exram(a << 12 | b << 4 | s);
					else
						char_data = m_charset[((b | 0x80) * 10) + s];
				}

				// illegal
				else
					char_data = 0xff;
			}
			else
			{
				// alphanumeric
				if ((b & 0xe0) != 0x80)
				{
					// double height
					if (a & 0x10)
					{
						dh = true;
						if (m_ef9340.h_parity)
							s += 10;
						if (s > 0)
							s = (s - 1) / 2;
					}

					fg = a & 0x07;
					u16 c = 0;

					if (b & 0x80)
						c = m_read_exram(a << 12 | b << 4 | s);
					else if (s == 9 && underline)
						c = 0xff;
					else
						c = m_charset[((b & 0x7f) * 10) + s];

					// double width
					dw = bool(a & 0x20);
					if (dw)
					{
						if (!w_parity)
							char_data = bitswap<16>(c,7,7,6,6,5,5,4,4,3,3,2,2,1,1,0,0);
					}
					else
						char_data = c;

					// inverted
					if (a & 0x40)
					{
						invert = !invert;
						blink = m_ef9340.R & 0x80 && !m_ef9340.blink;
					}
				}

				// deliminator
				else
				{
					fg = a & 0x07;
					bg = a >> 4 & 0x07;
					char_data = 0xff;

					del = true;
				}
			}

			// blink character
			if (blink && !cursor && (b & 0xe0) != 0x80 && ~a & 0x08)
				char_data &= ~0xff;

			if (invert)
				char_data ^= 0xff;

			if (dw)
				w_parity = !w_parity;
			else
				w_parity = false;

			for (int i = 0; i < 8; i++)
			{
				u16 d = blank ? 0 : (char_data & 1) ? fg : bg;
				m_tmp_bitmap.pix(m_offset_y + vpos, m_offset_x + x*8 + i) = d | 8;
				char_data >>= 1;
			}

			if (del)
			{
				blank = m_ef9340.R & 0x04 && b & 0x01;
				underline = bool(b & 0x04);
			}
		}
	}
	else
	{
		for (int i = 0; i < 40 * 8; i++)
			m_tmp_bitmap.pix(m_offset_y + vpos, m_offset_x + i) = 0;
	}

	// determine next h parity
	if (vpos >= 10 && slice == 9)
	{
		if (dh)
			m_ef9340.h_parity = !m_ef9340.h_parity;
		else
			m_ef9340.h_parity = false;
	}
}


u32 ef9340_1_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	// note: palette d3 is transparency (datasheet calls it "I"), this handler masks it off
	for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
		for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
			bitmap.pix(y, x) = m_tmp_bitmap.pix(y, x) & 7;

	return 0;
}