// license:BSD-3-Clause
// copyright-holders:F. Ulivi
/*********************************************************************
1mb5.cpp
HP-8x I/O Translator chip (1MB5-0101)
Reference for this chip:
HP, aug 79, 1MB5 Detailed specification - Translator chip
*********************************************************************/
#include "emu.h"
#include "1mb5.h"
// Debugging
#define VERBOSE 0
#include "logmacro.h"
// device type definition
DEFINE_DEVICE_TYPE(HP_1MB5, hp_1mb5_device, "hp_1mb5", "HP 1MB5")
// Bit manipulation
namespace {
template<typename T> constexpr T BIT_MASK(unsigned n)
{
return (T)1U << n;
}
template<typename T> void BIT_CLR(T& w , unsigned n)
{
w &= ~BIT_MASK<T>(n);
}
template<typename T> void BIT_SET(T& w , unsigned n)
{
w |= BIT_MASK<T>(n);
}
template<typename T> void COPY_BIT(bool bit , T& w , unsigned n)
{
if (bit) {
BIT_SET(w , n);
} else {
BIT_CLR(w , n);
}
}
}
hp_1mb5_device::hp_1mb5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig , HP_1MB5 , tag , owner , clock),
m_irl_handler(*this),
m_halt_handler(*this),
m_reset_handler(*this),
m_int_handler(*this)
{
}
uint8_t hp_1mb5_device::cpu_r(offs_t offset)
{
uint8_t res = 0;
switch (offset) {
case 0:
// Read SR
res = m_sr & 0x7e;
if (m_obf) {
BIT_SET(res , 7);
}
if (m_ibf) {
BIT_SET(res , 0);
}
break;
case 1:
// Read IB
res = m_ib;
if (m_ibf) {
m_ibf = false;
update_halt();
}
break;
}
LOG("RD %u=%02x\n" , offset , res);
return res;
}
void hp_1mb5_device::cpu_w(offs_t offset, uint8_t data)
{
LOG("WR %u=%02x\n" , offset , data);
switch (offset) {
case 0:
// Write CR
m_cr = data;
set_reset(BIT(m_cr , 7));
set_int(!BIT(m_cr , 0));
break;
case 1:
// Write OB
m_ob = data;
m_obf = true;
update_halt();
break;
}
}
uint8_t hp_1mb5_device::uc_r(offs_t offset)
{
uint8_t res = 0;
switch (offset) {
case 0:
// Read CR
res = m_cr & 0x7e;
if (m_obf) {
BIT_SET(res , 7);
}
if (m_ibf) {
BIT_SET(res , 0);
}
break;
case 1:
// Read OB
res = m_ob;
m_obf = false;
update_halt();
break;
}
//LOG("RDU %u=%02x\n" , offset , res);
return res;
}
void hp_1mb5_device::uc_w(offs_t offset, uint8_t data)
{
//LOG("WRU %u=%02x SR=%02x\n" , offset , data , m_sr);
switch (offset) {
case 0:
// Write SR
if (!BIT(m_sr , 0) && BIT(data , 0)) {
set_service(true);
}
m_sr = data;
m_hlten = BIT(m_sr , 7);
update_halt();
break;
case 1:
// Write IB
m_ib = data;
m_ibf = true;
update_halt();
break;
}
}
int hp_1mb5_device::irl_r()
{
return m_service;
}
int hp_1mb5_device::halt_r()
{
return m_halt;
}
int hp_1mb5_device::reset_r()
{
return m_reset;
}
int hp_1mb5_device::int_r()
{
return m_cint;
}
void hp_1mb5_device::inten()
{
// Enabling interrupts (i.e. writing to 0xff40) removes uC reset
set_reset(false);
}
void hp_1mb5_device::clear_service()
{
set_service(false);
}
void hp_1mb5_device::device_start()
{
save_item(NAME(m_sr));
save_item(NAME(m_cr));
save_item(NAME(m_ib));
save_item(NAME(m_ob));
save_item(NAME(m_ibf));
save_item(NAME(m_obf));
save_item(NAME(m_hlten));
save_item(NAME(m_service));
save_item(NAME(m_cint));
save_item(NAME(m_reset));
save_item(NAME(m_halt));
}
void hp_1mb5_device::device_reset()
{
m_sr = 0;
m_cr = 0;
m_ib = 0;
m_ob = 0;
m_ibf = false;
m_obf = false;
m_hlten = false;
m_service = false;
m_cint = true;
m_reset = true;
m_halt = false;
m_irl_handler(false);
m_halt_handler(false);
m_reset_handler(true);
m_int_handler(true);
}
void hp_1mb5_device::set_service(bool new_service)
{
if (new_service != m_service) {
m_service = new_service;
LOG("irl=%d\n" , m_service);
m_irl_handler(m_service);
}
}
void hp_1mb5_device::update_halt()
{
bool new_halt = m_hlten && m_obf && !m_ibf;
if (new_halt != m_halt) {
LOG("HALT=%d\n" , new_halt);
m_halt = new_halt;
m_halt_handler(m_halt);
}
}
void hp_1mb5_device::set_reset(bool new_reset)
{
if (new_reset != m_reset) {
m_reset = new_reset;
m_reset_handler(m_reset);
}
}
void hp_1mb5_device::set_int(bool new_int)
{
if (new_int != m_cint) {
m_cint = new_int;
LOG("cint=%d\n" , m_cint);
m_int_handler(m_cint);
}
}