summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/pla.cpp
blob: 44db6a4ed100b71a739bd69dfbbb40589aa8153f (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                                    

                                                                       
                                            
 

                                                                       
                
                

                     
 



                             
 
                                                 
                                                                        
                                                                      

                                                   
                            

                                                   

                                                                                                                         







                                          

 
 











                                                                                                             
 








                                                                                                               


                                                   
 

                               
                                    
                                                 

                              

                                                                     
 

                        
 

                           

                                    





                                                                                   
 
                             

 

                                                   
                   

                                                   
                                
 
                     
                                 
 


                         
                                 
                                                                                         
                              
 
                                   
                                                                                      

                              
 
                                  





                                                 
 
                                                                    

                       
 
                   
                             
 


                                         
 
                           
                                   
 
                                                  
                 
                                     
                                                                                              
 
                               
                                                                                       
                 
 
                          
                                  
 

                                                   
                                                                             
                 
 
                                     









                                                                                                              
         
 

                   
 



                                                            
 
                     

                                                                              



                                                   
          

                                                   
                                         
 
                              

                                      
 
                                          
         
                                                    
                 

                                                  

                 
 
                                    

                                                                            
 

                                         
                                        
 
                                                              
                 
                                           



                   
 


                                            
 
                       
 
// license:BSD-3-Clause
// copyright-holders:Curt Coder, hap
/**********************************************************************

    PLA (Programmable Logic Array) emulation

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

#include "emu.h"
#include "pla.h"
#include "jedparse.h"
#include "plaparse.h"

#define LOG_TERMS (1 << 0U)
//#define VERBOSE (LOG_TERMS)
#include "logmacro.h"


DEFINE_DEVICE_TYPE(PLA, pla_device, "pla", "PLA")
DEFINE_DEVICE_TYPE(PLS100, pls100_device, "pls100", "82S100-series PLA")
DEFINE_DEVICE_TYPE(MOS8721, mos8721_device, "mos8721", "MOS 8721 PLA")

//-------------------------------------------------
//  pla_device - constructor
//-------------------------------------------------

pla_device::pla_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, type, tag, owner, clock)
	, m_region(*this, DEVICE_SELF)
	, m_format(FMT::JEDBIN)
	, m_inputs(0)
	, m_outputs(0)
	, m_terms(0)
	, m_input_mask(0)
	, m_xor(0)
	, m_cache_size(0), m_cache2_ptr(0)
{
}

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

pls100_device::pls100_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: pla_device(mconfig, PLS100, tag, owner, clock)
{
	set_num_inputs(16);
	set_num_outputs(8);
	set_num_terms(48);
}

mos8721_device::mos8721_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: pla_device(mconfig, MOS8721, tag, owner, clock)
{
	// TODO: actual number of terms is unknown
	set_num_inputs(27);
	set_num_outputs(18);
	set_num_terms(379);
}

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

void pla_device::device_start()
{
	assert(m_terms < MAX_TERMS);
	assert(m_inputs < 32 && m_outputs <= 32);

	if (m_input_mask == 0)
		m_input_mask = ((uint64_t)1 << m_inputs) - 1;
	m_input_mask = ((uint64_t)m_input_mask << 32) | m_input_mask;

	// parse fusemap
	parse_fusemap();

	// initialize cache
	m_cache2_ptr = 0;
	for (auto & elem : m_cache2)
		elem = 0x80000000;

	m_cache_size = 0;
	int csize = 1 << ((m_inputs > MAX_CACHE_BITS) ? MAX_CACHE_BITS : m_inputs);
	m_cache.resize(csize);
	for (int i = 0; i < csize; i++)
		m_cache[i] = read(i);

	m_cache_size = csize;
}


//-------------------------------------------------
//  parse_fusemap -
//-------------------------------------------------

void pla_device::parse_fusemap()
{
	jed_data jed;
	int result = JEDERR_NONE;

	// read pla file
	switch (m_format)
	{
		case FMT::JEDBIN:
			result = jedbin_parse(m_region->base(), m_region->bytes(), &jed);
			break;

		case FMT::BERKELEY:
			result = pla_parse(m_region->base(), m_region->bytes(), &jed);
			break;
	}

	if (result != JEDERR_NONE)
	{
		for (int p = 0; p < m_terms; p++)
		{
			m_term[p].and_mask = 0;
			m_term[p].or_mask = 0;
		}

		logerror("%s PLA parse error %d!\n", tag(), result);
		return;
	}

	// parse it
	uint32_t fusenum = 0;

	for (int p = 0; p < m_terms; p++)
	{
		term *term = &m_term[p];

		// AND mask
		term->and_mask = 0;

		for (int i = 0; i < m_inputs; i++)
		{
			// complement
			term->and_mask |= (uint64_t)jed_get_fuse(&jed, fusenum++) << (i + 32);

			// true
			term->and_mask |= (uint64_t)jed_get_fuse(&jed, fusenum++) << i;
		}

		// OR mask
		term->or_mask = 0;

		for (int f = 0; f < m_outputs; f++)
		{
			term->or_mask |= !jed_get_fuse(&jed, fusenum++) << f;
		}

		term->or_mask <<= 32;

		LOGMASKED(LOG_TERMS, "F |= %0*X if (I & %0*X) == zeroes and (I & %0*X) == ones [term %d%s]\n",
			(m_outputs + 3) / 4,
			term->or_mask >> 32,
			(m_inputs + 3) / 4,
			(term->and_mask ^ m_input_mask) >> 32,
			(m_inputs + 3) / 4,
			uint32_t(term->and_mask ^ m_input_mask),
			p,
			(~term->and_mask & (~term->and_mask >> 32) & m_input_mask) == 0 ? "" : ", ignored");
	}

	// XOR mask
	m_xor = 0;

	for (int f = 0; f < m_outputs; f++)
	{
		m_xor |= jed_get_fuse(&jed, fusenum++) << f;
	}

	m_xor <<= 32;

	LOGMASKED(LOG_TERMS, "F ^= %0*X\n", (m_outputs + 3) / 4, m_xor >> 32);
}


//-------------------------------------------------
//  read -
//-------------------------------------------------

uint32_t pla_device::read(uint32_t input)
{
	// try the cache first
	if (input < m_cache_size)
		return m_cache[input];

	for (auto cache2_entry : m_cache2)
	{
		if ((uint32_t)cache2_entry == input)
		{
			// cache2 hit
			return cache2_entry >> 32;
		}
	}

	// cache miss, process terms
	uint64_t inputs = ((~(uint64_t)input << 32) | input) & m_input_mask;
	uint64_t s = 0;

	for (int i = 0; i < m_terms; ++i)
	{
		term* term = &m_term[i];

		if ((term->and_mask | inputs) == m_input_mask)
		{
			s |= term->or_mask;
		}
	}

	s ^= m_xor;

	// store output in cache2
	m_cache2[m_cache2_ptr] = s | input;
	++m_cache2_ptr &= (CACHE2_SIZE - 1);

	return s >> 32;
}