summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/machine/bert.cpp
blob: 4311a861e656e18fe29197d90e09e680a8746965 (plain) (tree)
1
2
3
4
5
6
7
8






                                                                
                                                                           




                 
                                                                       










                                                                                                    

                                   

                                    





                                                                 

                      

                           




                                                                                      

 




                                          

                                    




                                        


















                                                                                                 

 
                                                              
 






                                                                                           







                                                          
 
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay

/*
 * An emulation of the BERT ASIC found in the NCD 16 X terminal.
 *
 * Sources:
 *   - none known, but there's a full simulation in the firmware to test it
 */

#include "emu.h"
#include "bert.h"

DEFINE_DEVICE_TYPE(BERT, bert_device, "ncd_bert_asic", "NCD BERT ASIC")

bert_device::bert_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
	: device_t(mconfig, BERT, tag, owner, clock)
	, m_memory_space(*this, finder_base::DUMMY_TAG, 24, 16)
	, m_memory(nullptr)
{
}

void bert_device::device_start()
{
	save_item(NAME(m_control));
	save_item(NAME(m_history));
	save_item(NAME(m_step));
	save_item(NAME(m_qlc_mode));
	save_item(NAME(m_qlc_src));
	m_memory = m_memory_space->cache<1, 0, ENDIANNESS_BIG>();
}

void bert_device::device_reset()
{
	m_control = 0;
	m_history = 0;
	m_step = 0;
	m_qlc_mode = false;
	m_qlc_src = 0;
}

void bert_device::map(address_map &map)
{
	map(0x000000, 0x7fffff).rw(FUNC(bert_device::read), FUNC(bert_device::write));
}

void bert_device::set_qlc_mode(bool state)
{
	m_qlc_mode = state;
}

u16 bert_device::read(offs_t offset)
{
	if(m_qlc_mode) {
		m_qlc_src = offset << 1;
		return 0;
	}

	constexpr u16 type = 0x00ca;
	u16 data = m_memory->read_word(offset << 1);
	u16 res;

	if(type & (1 << (((m_control >> 8) & 0xc) | m_step))) {
		// mask
		res = m_control & 0x200 ? ~data : data;
	} else {
		// data
		u32 tmp = m_control & 0x10 ? (data << 16) | m_history : (m_history << 16) | data;
		res = tmp >> (m_control & 15);
		if(m_control & 0x100)
			res = ~res;
		m_history = m_control & 0x1000 ? 0 : data;
	}

	m_step = (m_step + 1) & 3;

	return res;
}

void bert_device::write(offs_t offset, u16 data, u16 mem_mask)
{
	if(m_qlc_mode) {
		u32 dest = offset << 1;
		for(u32 i=0; i<512; i+=2)
			m_memory->write_word(dest + i, m_memory->read_word(m_qlc_src + i));
		return;
	}

	m_step = 0;
	m_memory->write_word(offset << 1, data, mem_mask);
	if(!offset) {
		COMBINE_DATA(&m_control);
		m_step = 0;
		if(m_control & 0x1000)
			m_history = 0;
	}
}