summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/machine/esqvfd.cpp
blob: b8c2ad44f318d27656b1b6969d8621041fe6fe90 (plain) (tree)
1
2
3
4
5
6
7
8
9

                               
  
                                              


                           
                
                   
 


                      


                                                                                                     

                                                                                   
                             
                                  
































                                                      


























                                         
































                                         

                                         
                                            

  
                                                                                                                                                                
                                                   


                                                   


 
                                  
 
                          

 
                                  
 
                              
                                
                              
                       


                                            

 
                                                                                            


 
                                                                             
                                    
 





                                                      
                                                                                          
 

                                                                           
                                                          
 
                                                                           
 



                                                      



                                                                  

                                                               
                                                   
 
 
                                         
 


                                                                                                                 

                                                












                                                                      









                                                        
                                                      





                                                                              



                                                                     
                                                      


                                                          





                                                                    
 










                                                                      
                                
                                                              



















                                                               

 


































                                                                                   
                                                                                                                 
                                                                                         
 



                                                                 

                                                               
                                                   
 
 
 
                                         
 































                                                                              

 
                                                                                                                 
                                                                                         
 


                                                                             

                                                                   
                                                                                     
 
 
                                             
 
                                           
         
                                                  

         
                          
         

                                            
                                      
         
                               
         
                                      
         






















                                                       
                                     


                              
                                     


            
                                                             
         

 
                                                                                                                         
                                                                                             
 

                              
 
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/*
    Ensoniq Vacuum Fluorescent Displays (VFDs)
    Emulation by R. Belmont
*/

#include "emu.h"
#include "esqvfd.h"

#include "esq1by22.lh"
#include "esq2by40.lh"

DEFINE_DEVICE_TYPE(ESQ1X22,     esq1x22_device,     "esq1x22",     "Ensoniq 1x22 VFD")
DEFINE_DEVICE_TYPE(ESQ2X40,     esq2x40_device,     "esq2x40",     "Ensoniq 2x40 VFD")
DEFINE_DEVICE_TYPE(ESQ2X40_SQ1, esq2x40_sq1_device, "esq2x40_sq1", "Ensoniq 2x40 VFD (SQ-1 variant)")

// adapted from bfm_bd1, rearranged to work with ASCII data used by the Ensoniq h/w
static const uint16_t font[]=
{           // FEDC BA98 7654 3210
	0x0000, // 0000 0000 0000 0000 (space)
	0x0000, // 0000 0000 0000 0000 ! (not defined)
	0x0009, // 0000 0000 0000 1001 ".
	0xC62A, // 1100 0110 0010 1010 #.
	0xC62D, // 1100 0110 0010 1101 $.
	0x0000, // 0000 0000 0000 0000 % (not defined)
	0x0000, // 0000 0000 0000 0000 & (not defined)
	0x0040, // 0000 0000 1000 0000 '.
	0x0880, // 0000 1000 1000 0000 (.
	0x0050, // 0000 0000 0101 0000 ).
	0xCCD8, // 1100 1100 1101 1000 *.
	0xC408, // 1100 0100 0000 1000 +.
	0x0000, // 0000 0000 0000 0000 , (not defined)
	0xC000, // 1100 0000 0000 0000 -.
	0x1000, // 0001 0000 0000 0000 .
	0x0090, // 0000 0000 1001 0000 /
	0x22B7, // 0010 0010 1011 0111 0.
	0x0408, // 0000 0100 0000 1000 1.
	0xE206, // 1110 0010 0000 0110 2.
	0x4226, // 0100 0010 0010 0110 3.
	0xC023, // 1100 0000 0010 0011 4.
	0xC225, // 1100 0010 0010 0101 5.
	0xE225, // 1110 0010 0010 0101 6.
	0x0026, // 0000 0000 0010 0110 7.
	0xE227, // 1110 0010 0010 0111 8.
	0xC227, // 1100 0010 0010 0111 9.
	0x0000, // 0000 0000 0000 0000 : (not defined)
	0x0000, // 0000 0000 0000 0000 ; (not defined)
	0x0290, // 0000 0010 1001 0000 <.
	0xC200, // 1100 0010 0000 0000 =.
	0x0A40, // 0000 1010 0100 0000 >.
	0x0000, // 0000 0000 0000 0000 ? (not defined)
	0xA626, // 1010 0110 0010 0110 @.
	0xE027, // 1110 0000 0010 0111 A.
	0x462E, // 0100 0110 0010 1110 B.
	0x2205, // 0010 0010 0000 0101 C.
	0x062E, // 0000 0110 0010 1110 D.
	0xA205, // 1010 0010 0000 0101 E.
	0xA005, // 1010 0000 0000 0101 F.
	0x6225, // 0110 0010 0010 0101 G.
	0xE023, // 1110 0000 0010 0011 H.
	0x060C, // 0000 0110 0000 1100 I.
	0x2222, // 0010 0010 0010 0010 J.
	0xA881, // 1010 1000 1000 0001 K.
	0x2201, // 0010 0010 0000 0001 L.
	0x20E3, // 0010 0000 1110 0011 M.
	0x2863, // 0010 1000 0110 0011 N.
	0x2227, // 0010 0010 0010 0111 O.
	0xE007, // 1110 0000 0000 0111 P.
	0x2A27, // 0010 1010 0010 0111 Q.
	0xE807, // 1110 1000 0000 0111 R.
	0xC225, // 1100 0010 0010 0101 S.
	0x040C, // 0000 0100 0000 1100 T.
	0x2223, // 0010 0010 0010 0011 U.
	0x2091, // 0010 0000 1001 0001 V.
	0x2833, // 0010 1000 0011 0011 W.
	0x08D0, // 0000 1000 1101 0000 X.
	0x04C0, // 0000 0100 1100 0000 Y.
	0x0294, // 0000 0010 1001 0100 Z.
	0x2205, // 0010 0010 0000 0101 [.
	0x0840, // 0000 1000 0100 0000 \.
	0x0226, // 0000 0010 0010 0110 ].
	0x0810, // 0000 1000 0001 0000 ^.
	0x0200, // 0000 0010 0000 0000 _
	0x0040, // 0000 0000 0100 0000 `
	0xE027, // 1110 0000 0010 0111 A.
	0x462E, // 0100 0110 0010 1110 B.
	0x2205, // 0010 0010 0000 0101 C.
	0x062E, // 0000 0110 0010 1110 D.
	0xA205, // 1010 0010 0000 0101 E.
	0xA005, // 1010 0000 0000 0101 F.
	0x6225, // 0110 0010 0010 0101 G.
	0xE023, // 1110 0000 0010 0011 H.
	0x060C, // 0000 0110 0000 1100 I.
	0x2222, // 0010 0010 0010 0010 J.
	0xA881, // 1010 1000 1000 0001 K.
	0x2201, // 0010 0010 0000 0001 L.
	0x20E3, // 0010 0000 1110 0011 M.
	0x2863, // 0010 1000 0110 0011 N.
	0x2227, // 0010 0010 0010 0111 O.
	0xE007, // 1110 0000 0000 0111 P.
	0x2A27, // 0010 1010 0010 0111 Q.
	0xE807, // 1110 1000 0000 0111 R.
	0xC225, // 1100 0010 0010 0101 S.
	0x040C, // 0000 0100 0000 1100 T.
	0x2223, // 0010 0010 0010 0011 U.
	0x2091, // 0010 0000 1001 0001 V.
	0x2833, // 0010 1000 0011 0011 W.
	0x08D0, // 0000 1000 1101 0000 X.
	0x04C0, // 0000 0100 1100 0000 Y.
	0x0294, // 0000 0010 1001 0100 Z.
	0x2205, // 0010 0010 0000 0101 [.
	0x0408, // 0000 0100 0000 1000 |
	0x0226, // 0000 0010 0010 0110 ].
	0x0810, // 0000 1000 0001 0000 ~.
	0x0000, // 0000 0000 0000 0000 (DEL)
};

esqvfd_device::esqvfd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, dimensions_param &&dimensions) :
	device_t(mconfig, type, tag, owner, clock),
	m_vfds(std::move(std::get<0>(dimensions))),
	m_rows(std::get<1>(dimensions)),
	m_cols(std::get<2>(dimensions))
{
}

void esqvfd_device::device_start()
{
	m_vfds->resolve();
}

void esqvfd_device::device_reset()
{
	m_cursx = m_cursy = 0;
	m_savedx = m_savedy = 0;
	m_curattr = AT_NORMAL;
	m_lastchar = 0;
	memset(m_chars, 0, sizeof(m_chars));
	memset(m_attrs, 0, sizeof(m_attrs));
	memset(m_dirty, 1, sizeof(m_attrs));
}

void esqvfd_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
}

// generic display update; can override from child classes if not good enough
void esqvfd_device::update_display()
{
	for (int row = 0; row < m_rows; row++)
	{
		for (int col = 0; col < m_cols; col++)
		{
			if (m_dirty[row][col])
			{
				uint32_t segdata = conv_segments(font[m_chars[row][col]]);

				// force bottom bar on all underlined chars
				if (m_attrs[row][col] & AT_UNDERLINE)
					segdata |= 0x0008;

				m_vfds->set((row * m_cols) + col, segdata);

				m_dirty[row][col] = 0;
			}
		}
	}
}

/* 2x40 VFD display used in the ESQ-1, VFX-SD, SD-1, and others */

void esq2x40_device::device_add_mconfig(machine_config &config)
{
	config.set_default_layout(layout_esq2by40);
}

void esq2x40_device::write_char(int data)
{
	// ESQ-1 sends (cursor move) 0xfa 0xYY to mark YY characters as underlined at the current cursor location
	if (m_lastchar == 0xfa)
	{
		if ((m_cursx + data) > m_rows)
			data = m_rows - m_cursx;
		for (int i = 0; i < data; i++)
		{
			m_attrs[m_cursy][m_cursx + i] |= AT_UNDERLINE;
			m_dirty[m_cursy][m_cursx + i] = 1;
		}

		m_lastchar = 0;
		update_display();
		return;
	}

	m_lastchar = data;

	if ((data >= 0x80) && (data < 0xd0))
	{
		m_cursy = ((data & 0x7f) >= 40) ? 1 : 0;
		m_cursx = (data & 0x7f) % 40;
	}
	else if (data >= 0xd0)
	{
		switch (data)
		{
			case 0xd0:  // blink start
				m_curattr |= AT_BLINK;
				break;

			case 0xd1:  // blink stop (cancel all attribs on VFX+)
				m_curattr = 0; //&= ~AT_BLINK;
				break;

			case 0xd2:  // blinking underline on VFX
				m_curattr |= AT_BLINK | AT_UNDERLINE;
				break;

			case 0xd3:  // start underline
				m_curattr |= AT_UNDERLINE;
				break;

			case 0xd6:  // clear screen
				m_cursx = m_cursy = 0;
				memset(m_chars, 0, sizeof(m_chars));
				memset(m_attrs, 0, sizeof(m_attrs));
				memset(m_dirty, 1, sizeof(m_dirty));
				break;

			case 0xf5:  // save cursor position
				m_savedx = m_cursx;
				m_savedy = m_cursy;
				break;

			case 0xf6:  // restore cursor position
				m_cursx = m_savedx;
				m_cursy = m_savedy;
				m_curattr = m_attrs[m_cursy][m_cursx];
				break;

			default:
//                printf("Unknown control code %02x\n", data);
				break;
		}
	}
	else
	{
		if ((data >= 0x20) && (data <= 0x5f))
		{
			m_chars[m_cursy][m_cursx] = data - ' ';
			m_attrs[m_cursy][m_cursx] = m_curattr;
			m_dirty[m_cursy][m_cursx] = 1;
			m_cursx++;

			if (m_cursx >= 39)
			{
				m_cursx = 39;
			}
		}
	}

	update_display();
}

bool esq2x40_device::write_contents(std::ostream &o)
{
	o.put((char) 0xd6); // clear screen

	uint8_t attrs = 0;
	for (int row = 0; row < 2; row++)
	{
		o.put((char) (0x80 + (40 * row))); // move to first column this row

		for (int col = 0; col < 40; col++)
		{
			if (m_attrs[row][col] != attrs)
			{
				attrs = m_attrs[row][col];

				o.put((char) 0xd1); // all attributes off

				if (attrs & AT_BLINK)
				{
					o.put((char) 0xd0); // blink on
				}

				if (attrs & AT_UNDERLINE)
				{
					o.put((char) 0xd3); // underline
				}
			}

			o.put((char) (m_chars[row][col] + ' '));
		}
	}
	return true;
}


esq2x40_device::esq2x40_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	esqvfd_device(mconfig, ESQ2X40, tag, owner, clock, make_dimensions<2, 40>(*this))
{
}

/* 1x22 display from the VFX (not right, but it'll do for now) */

void esq1x22_device::device_add_mconfig(machine_config &config)
{
	config.set_default_layout(layout_esq1by22);
}


void esq1x22_device::write_char(int data)
{
	if (data >= 0x60)
	{
		switch (data)
		{
			case 'f':   // clear screen
				m_cursx = m_cursy = 0;
				memset(m_chars, 0, sizeof(m_chars));
				memset(m_attrs, 0, sizeof(m_attrs));
				memset(m_dirty, 1, sizeof(m_dirty));
				break;

			default:
				printf("Unhandled control code %02x\n", data);
				break;
		}
	}
	else
	{
		if ((data >= 0x20) && (data <= 0x5f))
		{
			m_chars[0][m_cursx] = data - ' ';
			m_dirty[0][m_cursx] = 1;
			m_cursx++;

			if (m_cursx >= 23)
			{
				m_cursx = 23;
			}
		}
	}

	update_display();
}

esq1x22_device::esq1x22_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	esqvfd_device(mconfig, ESQ1X22, tag, owner, clock, make_dimensions<1, 22>(*this))
{
}

/* SQ-1 display, I think it's really an LCD but we'll deal with it for now */
void esq2x40_sq1_device::device_add_mconfig(machine_config &config)
{
	config.set_default_layout(layout_esq2by40);  // we use the normal 2x40 layout
}

void esq2x40_sq1_device::write_char(int data)
{
	if (data == 0x09)   // musical note
	{
		data = '^'; // approximate for now
	}

	if (m_wait87shift)
	{
		m_cursy = (data >> 4) & 0xf;
		m_cursx = data & 0xf;
		m_wait87shift = false;
	}
	else if (m_wait88shift)
	{
		m_wait88shift = false;
	}
	else if ((data >= 0x20) && (data <= 0x7f))
	{
		m_chars[m_cursy][m_cursx] = data - ' ';
		m_attrs[m_cursy][m_cursx] = m_curattr;
		m_dirty[m_cursy][m_cursx] = 1;
		m_cursx++;

		if (m_cursx >= 39)
		{
			m_cursx = 39;
		}

		update_display();
	}
	else if (data == 0x83)
	{
		m_cursx = m_cursy = 0;
		memset(m_chars, 0, sizeof(m_chars));
		memset(m_attrs, 0, sizeof(m_attrs));
		memset(m_dirty, 1, sizeof(m_dirty));
	}
	else if (data == 0x87)
	{
		m_wait87shift = true;
	}
	else if (data == 0x88)
	{
		m_wait88shift = true;
	}
	else
	{
//        printf("SQ-1 unhandled display char %02x\n", data);
	}
}

esq2x40_sq1_device::esq2x40_sq1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	esqvfd_device(mconfig, ESQ2X40_SQ1, tag, owner, clock, make_dimensions<2, 40>(*this))
{
	m_wait87shift = false;
	m_wait88shift = false;
}