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









                                                                            
                

                   

                   




                                                                            


                             





                                                                            
                                                                  
 
                                                    























                                                                            
                                                                                                               
                                                     

                                               
                                               
                             












                                                                                                                    





                                                   
                                                  
















                                                                                                                       
                                                                    













                                                                            
                                                



                                             
                                                 
 
                      
 
                                                    











                                                               
                                                            



                                             
                                                             
 
                                                    
















                                                                            
                                                              







                                     

                                                                              





                                               

                                                

                                  
                                     


                                       

                                             










                                              
                                            















                                                                                                             
                                                                            




                                        
                                                        



                                 


                                                                                                                                         
                                                                                                                                          
                                                                                                               
                                                                                                        
                                                                                                 




                                     

                                               
 

                                                                                                                                    













































                                                                              
                                                                                                    



                      
                                                                                                                     









                                                 
                                                                                                                     



                      
                                                                                                                     



                          
                                                                                                                     



                                     
                                                                                                                          
















                                                     
                                                  










                                                                                    
                                                                                                                                         



                                      
                                                                                                                                   




























                                                                                                         
                                



























                                                                                       
                                                            
















                                                                                                                 
                                                                            











                                                                                                                 
                                                                       









                                         
                                                                                  




                                        
                                                                               












                                                                                      
                                                           









                                                                     



                                                                                                                                               

















                                                                                                                                                          
                                                                                 



                          
                                                                                                             



                                                                         
// license:GPL-2.0+
// copyright-holders:Dirk Best
/***************************************************************************

    Intel 82730

    Text Coprocessor

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

#include "emu.h"
#include "i82730.h"

#include "screen.h"


//**************************************************************************
//  CONSTANTS
//**************************************************************************

#define VERBOSE 1
#define VERBOSE_COMMANDS    1
#define VERBOSE_DATASTREAM  0


//**************************************************************************
//  DEVICE DEFINITIONS
//**************************************************************************

DEFINE_DEVICE_TYPE(I82730, i82730_device, "i82730", "Intel 82730")

const char *const i82730_device::s_command_names[] =
{
	/* 00 */ "NOP",
	/* 01 */ "START DISPLAY",
	/* 02 */ "START VIRTUAL DISPLAY",
	/* 03 */ "STOP DISPLAY",
	/* 04 */ "MODE SET",
	/* 05 */ "LOAD CBP",
	/* 06 */ "LOAD INTMASK",
	/* 07 */ "LPEN ENABLE",
	/* 08 */ "READ STATUS",
	/* 09 */ "LD CUR POS",
	/* 0a */ "SELF TEST",
	/* 0b */ "TEST ROW BUFFER"
};


//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  i82730_device - constructor
//-------------------------------------------------

i82730_device::i82730_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, I82730, tag, owner, clock),
	device_video_interface(mconfig, *this),
	m_sint_handler(*this),
	m_cpu_tag(nullptr), m_program(nullptr),
	m_row_timer(nullptr),
	m_initialized(false), m_mode_set(false),
	m_ca(0),
	m_sysbus(0x00), m_ibp(0x0000), m_cbp(0x0000), m_intmask(0xffff), m_status(0x0000),
	m_list_switch(0), m_auto_line_feed(0), m_max_dma_count(0),
	m_lptr(0), m_sptr(0),
	m_dma_burst_space(0), m_dma_burst_length(0),
	m_hfldstrt(0), m_margin(0), m_lpr(0), m_field_attribute_mask(0), m_vsyncstp(0), m_vfldstrt(0), m_vfldstp(0),
	m_frame_int_count(0),
	m_row_index(0)
{
}

//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void i82730_device::device_start()
{
	// register bitmap
	screen().register_screen_bitmap(m_bitmap);

	// resolve callbacks
	m_sint_handler.resolve_safe();

	// bind delegates
	m_update_row_cb.bind_relative_to(*owner());

	// allocate row timer
	m_row_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(i82730_device::row_update), this));
}

//-------------------------------------------------
//  device_reset - device-specific reset
//-------------------------------------------------

void i82730_device::device_reset()
{
	cpu_device *cpu = owner()->subdevice<cpu_device>(m_cpu_tag);
	m_program = &cpu->space(AS_PROGRAM);

	m_initialized = false;
	m_mode_set = false;

	m_ca = 0;
	m_status = 0x0000;
}


//**************************************************************************
//  MEMORY ACCESS
//**************************************************************************

uint8_t i82730_device::read_byte(offs_t address)
{
	return m_program->read_byte(address);
}

uint16_t i82730_device::read_word(offs_t address)
{
	uint16_t data;

	if (sysbus_16bit() && WORD_ALIGNED(address))
	{
		data = m_program->read_word(address);
	}
	else
	{
		data  = m_program->read_byte(address);
		data |= m_program->read_byte(address + 1) << 8;
	}

	return data;
}

void i82730_device::write_byte(offs_t address, uint8_t data)
{
	m_program->write_byte(address, data);
}

void i82730_device::write_word(offs_t address, uint16_t data)
{
	if (sysbus_16bit() && WORD_ALIGNED(address))
	{
		m_program->write_word(address, data);
	}
	else
	{
		m_program->write_byte(address, data & 0xff);
		m_program->write_byte(address + 1, (data >> 8) & 0xff);
	}
}


//**************************************************************************
//  IMPLEMENTATION
//**************************************************************************

void i82730_device::update_interrupts()
{
	uint16_t code = m_status & ~m_intmask & ~(VDIP | DIP);
	write_word(m_cbp + 20, code);

	if (code)
		m_sint_handler(1);
}

void i82730_device::mode_set()
{
	uint32_t mptr = (read_word(m_cbp + 32) << 16) | read_word(m_cbp + 30);
	uint16_t tmp;

	tmp = read_word(mptr);
	m_dma_burst_space = tmp & 0x7f;
	m_dma_burst_length = (tmp >> 8) & 0x7f;

	tmp = read_word(mptr + 2);
	uint8_t hsyncstp = tmp & 0xff;
	uint8_t line_length = (tmp >> 8) & 0xff;

	tmp = read_word(mptr + 4);
	uint8_t hfldstp = tmp & 0xff;
	m_hfldstrt = (tmp >> 8) & 0xff;

	tmp = read_word(mptr + 6);
	uint8_t hbrdstp = tmp & 0xff;
	uint8_t hbrdstrt = (tmp >> 8) & 0xff;

	tmp = read_word(mptr + 8);
	m_margin = tmp & 0x1f;

	tmp = read_word(mptr + 10);
	m_lpr = tmp & 0x1f;

	tmp = read_word(mptr + 24);
	m_field_attribute_mask = tmp & 0x7fff;

	tmp = read_word(mptr + 26);
	uint16_t frame_length = tmp & 0x7ff;

	tmp = read_word(mptr + 28);
	m_vsyncstp = tmp & 0x7ff;

	tmp = read_word(mptr + 30);
	m_vfldstrt = tmp & 0x7ff;

	tmp = read_word(mptr + 32);
	m_vfldstp = tmp & 0x7ff;

	tmp = read_word(mptr + 38);
	m_frame_int_count = tmp & 0x0f;

	// setup screen mode
	rectangle visarea(hbrdstrt * 16, hbrdstp * 16 - 1, m_vsyncstp, m_vfldstp + m_margin + 1 + m_lpr - 1);
	attoseconds_t period = HZ_TO_ATTOSECONDS(clock() * 16) * line_length * 16 * frame_length;
	screen().configure(line_length * 16, frame_length, visarea, period);

	// start display is now valid
	m_mode_set = true;

	// adjust timer for the new mode
	m_row_timer->adjust(screen().time_until_pos(0));

	// output some debug info
	if (VERBOSE)
	{
		logerror("%s('%s'): ---- setting mode ----\n", shortname(), basetag());
		logerror("%s('%s'): dma burst length %02x, space %02x\n", shortname(), basetag(), m_dma_burst_length, m_dma_burst_space);
		logerror("%s('%s'): margin %02x, lpr %02x\n", shortname(), basetag(), m_margin, m_lpr);
		logerror("%s('%s'): hsyncstp: %02x, line_length: %02x, hfldstrt: %02x, hbrdstart: %02x, hfldstop: %02x, hbrdstop: %02x\n",
			shortname(), basetag(), hsyncstp, line_length, m_hfldstrt, hbrdstrt, hfldstp, hbrdstp);
		logerror("%s('%s'): frame_length %04x, vsyncstp: %04x, vfldstrt: %04x, vfldstp: %04x\n",
			shortname(), basetag(), frame_length, m_vsyncstp, m_vfldstrt, m_vfldstp);
	}
}

void i82730_device::execute_command()
{
	uint8_t command = read_byte(m_cbp + 1);
	uint16_t tmp;

	if (VERBOSE_COMMANDS && command < ARRAY_LENGTH(s_command_names))
		logerror("%s('%s'): executing command: %s [cbp = %08x]\n", shortname(), basetag(), s_command_names[command], m_cbp);

	tmp = read_word(m_cbp + 2);
	m_list_switch = BIT(tmp, 6);
	m_auto_line_feed = BIT(tmp, 7);

	tmp = read_word(m_cbp + 4);
	m_max_dma_count = tmp & 0xff;

	switch (command)
	{
	// NOP
	case 0x00:
		break;

	// START DISPLAY
	case 0x01:
		if (m_mode_set)
			m_status = (m_status & ~VDIP) | DIP;
		break;

	// START VIRTUAL DISPLAY
	case 0x02:
		if (m_mode_set)
			m_status = VDIP | (m_status & ~DIP);
		break;

	// STOP DISPLAY
	case 0x03:
		m_status &= ~(VDIP | DIP);
		break;

	// MODE SET
	case 0x04:
		mode_set();
		break;

	// LOAD CBP
	case 0x05:
		m_cbp = (read_word(m_cbp + 16) << 16) | read_word(m_cbp + 14);
		execute_command();
		break;

	// LOAD INTMASK
	case 0x06:
		m_intmask = read_word(m_cbp + 22);
		if (VERBOSE_COMMANDS)
			logerror("%s('%s'): intmask now %04x\n", shortname(), basetag(), m_intmask);
		break;

	// LPEN ENABLE
	case 0x07:
		fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), s_command_names[command]);
		break;

	// READ STATUS
	case 0x08:
		write_word(m_cbp + 18, m_status);
		m_status &= (VDIP | DIP);
		break;

	// LD CUR POS
	case 0x09:
		fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), s_command_names[command]);
		break;

	// SELF TEST
	case 0x0a:
		fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), s_command_names[command]);
		break;

	// TEST ROW BUFFER
	case 0x0b:
		fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), s_command_names[command]);
		break;

	default:
		if (VERBOSE_COMMANDS)
			logerror("%s('%s'): executing command: (reserved) [cbp = %08x]\n", shortname(), basetag(), m_cbp);
		m_status |= RCC;
		update_interrupts();
		break;
	}

	// clear busy
	write_word(m_cbp, read_word(m_cbp) & 0xff00);
}

void i82730_device::load_row()
{
	bool finished = false;

	m_row[m_row_index].count = 0;

	while (!finished)
	{
		uint16_t data = read_word(m_sptr);
		m_sptr += 2;

		if (BIT(data, 15))
		{
			switch (data >> 8)
			{
			case 0x8e:
				m_field_attribute_mask = read_word(m_sptr) & 0x7fff;
				m_sptr += 2;

				if (VERBOSE_DATASTREAM)
					logerror("%s('%s'): SET FIELD ATTRIB to %04x\n", shortname(), basetag(), m_field_attribute_mask);

				break;

			default:
				fatalerror("%s('%s'): Unimplemented datastream command %02x\n", shortname(), basetag(), data >> 8);
			}
		}
		else
		{
			// maximum row size is 200
			if (m_row[m_row_index].count < m_max_dma_count && m_row[m_row_index].count < 200)
			{
				m_row[m_row_index].data[m_row[m_row_index].count++] = data;
			}
			else
			{
#if 0
				// move to next string?
				if (m_auto_line_feed == 0)
				{
					m_sptr = (read_word(m_lptr + 2) << 16) | read_word(m_lptr);
					m_lptr += 4;
				}
#endif
				finished = true;
			}
		}
	}

	m_sptr -= 2;
}

TIMER_CALLBACK_MEMBER( i82730_device::row_update )
{
	int y = screen().vpos();

	if (y == 0)
	{
		// clear interrupt status flags
		m_status &= (VDIP | DIP);

		// clear field attribute mask
		m_field_attribute_mask = 0;

		// get listbase
		if (m_list_switch)
			m_lptr = (read_word(m_cbp + 8) << 16) | read_word(m_cbp + 6);
		else
			m_lptr = (read_word(m_cbp + 12) << 16) | read_word(m_cbp + 10);

		m_sptr = (read_word(m_lptr + 2) << 16) | read_word(m_lptr);
		m_lptr += 4;

		// fetch initial row
		m_row_index = 0;
		load_row();
	}
	else if (y >= m_vsyncstp && y < m_vfldstrt)
	{
		// blank (top border)
	}
	else if (y >= m_vfldstrt && y < m_vfldstp)
	{
		uint8_t lc = (y - m_vfldstrt) % (m_lpr + 1);

		// call driver
		m_update_row_cb(m_bitmap, m_row[m_row_index].data, lc, y - m_vsyncstp, m_row[m_row_index].count);

		// swap buffers at end of row
		if (lc == m_lpr)
		{
			m_row_index ^= 1;
			load_row();
		}
	}
	else if (y >= m_vfldstp && y < m_vfldstp + m_margin + 1)
	{
		// margin
	}
	else if (y >= m_vfldstp + m_margin + 1 && y < m_vfldstp + m_margin + 1 + m_lpr + 1)
	{
		uint8_t lc = (y - (m_vfldstp + m_margin + 1)) % (m_lpr + 1);

		m_sptr = (read_word(m_cbp + 36) << 16) | read_word(m_cbp + 34);
		load_row();

		// call driver
		m_update_row_cb(m_bitmap, m_row[m_row_index].data, lc, y - m_vsyncstp, m_row[m_row_index].count);
	}
	else if (y == m_vfldstp + m_margin + 1 + m_lpr + 1)
	{
		// todo: check ca

		// frame interrupt?
		if ((screen().frame_number() % m_frame_int_count) == 0)
			m_status |= EONF;

		// check interrupts
		update_interrupts();
	}
	else
	{
		// vblank
	}

	m_row_timer->adjust(screen().time_until_pos((y + 1) % screen().height()));
}

WRITE_LINE_MEMBER( i82730_device::ca_w )
{
	if (VERBOSE)
		logerror("%s('%s'): ca_w %d\n", shortname(), basetag(), state);

	// falling edge
	if (m_ca == 1 && state == 0)
	{
		if (!m_initialized)
		{
			// get system bus width
			m_sysbus = m_program->read_byte(0xfffffff6);

			// get intermediate block pointer
			m_ibp = (read_word(0xfffffffe) << 16) | read_word(0xfffffffc);

			// get system configuration byte
			uint8_t scb = read_byte(m_ibp + 6);

			// clear busy
			write_word(m_ibp, read_word(m_ibp) & 0xff00);

			// done
			m_initialized = true;

			// output some debug info
			if (VERBOSE)
			{
				logerror("%s('%s'): ---- initializing ----\n", shortname(), basetag());
				logerror("%s('%s'): %s system bus\n", shortname(), basetag(), sysbus_16bit() ? "16-bit" : "8-bit");
				logerror("%s('%s'): intermediate block pointer: %08x\n", shortname(), basetag(), m_ibp);
				logerror("%s('%s'): addrbus: %s, clno: %d, clpos: %d, mode: %s, dtw16: %s, srdy: %s\n", shortname(), basetag(),
					BIT(scb, 0) ? "32-bit" : "16-bit", (scb >> 1) & 0x03, (scb >> 3) & 0x03,
					BIT(scb, 5) ? "master" : "slave", BIT(scb, 6) ? "16-bit" : "8-bit", BIT(scb, 7) ? "synchronous" : "asynchronous");
			}
		}

		// fetch command block pointer
		m_cbp = (read_word(m_ibp + 4) << 16) | read_word(m_ibp + 2);

		// and execute command
		execute_command();
	}

	m_ca = state;
}

WRITE_LINE_MEMBER( i82730_device::irst_w )
{
	if (VERBOSE)
		logerror("%s('%s'): irst_w %d\n", shortname(), basetag(), state);

	m_sint_handler(0);
}

uint32_t i82730_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
	copybitmap(bitmap, m_bitmap, 0, 0, m_hfldstrt * 16, 0, cliprect);
	return 0;
}