summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine/upd65031.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/machine/upd65031.c')
-rw-r--r--src/mess/machine/upd65031.c621
1 files changed, 0 insertions, 621 deletions
diff --git a/src/mess/machine/upd65031.c b/src/mess/machine/upd65031.c
deleted file mode 100644
index 86d9ff5e093..00000000000
--- a/src/mess/machine/upd65031.c
+++ /dev/null
@@ -1,621 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Sandro Ronco
-/**********************************************************************
-
- NEC uPD65031 'BLINK' emulation
-
- the uPD65031 manages almost everything in the Z88:
- - memory bankswitch
- - interrupts
- - RTC
- - LCD
- - keyboard
- - serial
- - speaker
-
- TODO:
- - coma and snooze mode
- - speaker controlled by txd
- - EPROM programming
- - UART
-
-*********************************************************************/
-
-
-#include "upd65031.h"
-
-
-// device type definition
-const device_type UPD65031 = &device_creator<upd65031_device>;
-
-
-//**************************************************************************
-// MACROS / CONSTANTS
-//**************************************************************************
-
-#define LOG 0
-
-#define SPEAKER_ALARM_FREQ attotime::from_hz(3200)
-
-// internal registers
-enum
-{
- // write registers
- REG_PB0 = 0x70, // pixel base 0
- REG_PB1 = 0x71, // pixel base 1
- REG_PB2 = 0x72, // pixel base 2
- REG_PB3 = 0x73, // pixel base 3
- REG_SBR = 0x74, // screen base register
-
- REG_COM = 0xb0, // command register
- REG_INT = 0xb1, // interrupt control
- REG_EPR = 0xb3, // EPROM programming
- REG_TACK = 0xb4, // RTC acknowledge
- REG_TMK = 0xb5, // RTC interrupt mask
- REG_ACK = 0xb6, // interrupt acknowledge
-
- REG_SR0 = 0xd0, // segment register 0
- REG_SR1 = 0xd1, // segment register 1
- REG_SR2 = 0xd2, // segment register 2
- REG_SR3 = 0xd3, // segment register 3
-
- REG_RXC = 0xe2, // UART receiver control
- REG_TXD = 0xe3, // UART transmit data
- REG_TXC = 0xe4, // UART transmit control
- REG_UMK = 0xe5, // UART interrupt mask
- REG_UAK = 0xe6, // UART interrupt acknowledge
-
-
- // read registers
- REG_STA = 0xb1, // interrupt status
- REG_KBD = 0xb2, // keyboard read
- REG_TSTA = 0xb5, // RTC interrupt status
-
- REG_TIM0 = 0xd0, // RTC 5ms counter
- REG_TIM1 = 0xd1, // RTC seconds counter (6 bits)
- REG_TIM2 = 0xd2, // RTC minutes counter
- REG_TIM3 = 0xd3, // RTC minutes/256 counter
- REG_TIM4 = 0xd4, // RTC minutes/65536 counter (5 bits)
-
- REG_RXD = 0xe0, // UART receive data register
- REG_RXE = 0xe1, // UART extended receiver data
- REG_UIT = 0xe5 // UART interrupt status
-};
-
-//mode
-enum
-{
- STATE_AWAKE = 0,
- STATE_SNOOZE,
- STATE_COMA
-};
-
-// interrupt status
-#define STA_FLAPOPEN 0x80
-#define STA_A19 0x40
-#define STA_FLAP 0x20
-#define STA_UART 0x10
-#define STA_BTL 0x08
-#define STA_KEY 0x04
-#define STA_TIME 0x01
-
-// interrupt control
-#define INT_KWAIT 0x80
-#define INT_A19 0x40
-#define INT_FLAP 0x20
-#define INT_UART 0x10
-#define INT_BTL 0x08
-#define INT_KEY 0x04
-#define INT_TIME 0x02
-#define INT_GINT 0x01
-
-// command register
-#define COM_SRUN 0x80
-#define COM_SBIT 0x40
-#define COM_OVERP 0x20
-#define COM_RESTIM 0x10
-#define COM_PROGRAM 0x08
-#define COM_RAMS 0x04
-#define COM_VPPON 0x02
-#define COM_LCDON 0x01
-
-// EPROM programming register
-#define EPR_PD1 0x80
-#define EPR_PD0 0x40
-#define EPR_PGMD 0x20
-#define EPR_EOED 0x10
-#define EPR_SE3D 0x08
-#define EPR_PGMP 0x04
-#define EPR_EOEP 0x02
-#define EPR_SE3P 0x01
-
-// RTC interrupt status
-#define TSTA_MIN 0x04
-#define TSTA_SEC 0x02
-#define TSTA_TICK 0x01
-
-//**************************************************************************
-// INLINE HELPERS
-//**************************************************************************
-
-inline void upd65031_device::interrupt_refresh()
-{
- if ((m_int & INT_GINT) && ((m_int & m_sta & 0x7c) || ((m_int & INT_TIME) && (m_sta & STA_TIME))))
- {
- if (LOG) logerror("uPD65031 '%s': set int\n", tag());
-
- m_write_int(ASSERT_LINE);
- }
- else
- {
- if (LOG) logerror("uPD65031 '%s': clear int\n", tag());
-
- m_write_int(CLEAR_LINE);
- }
-}
-
-
-inline void upd65031_device::update_rtc_interrupt()
-{
- // any ints occurred?
- if ((m_int & INT_GINT) && (m_int & INT_TIME) && (m_tsta & (TSTA_MIN | TSTA_SEC | TSTA_TICK)))
- m_sta |= STA_TIME;
- else
- m_sta &= ~STA_TIME;
-}
-
-
-inline void upd65031_device::set_mode(int mode)
-{
- if (m_mode != mode)
- {
- m_mode = mode;
-
- switch(mode)
- {
- case STATE_AWAKE:
- //TODO
- break;
- case STATE_SNOOZE:
- //TODO
- break;
- case STATE_COMA:
- //TODO
- break;
- }
- }
-}
-
-
-//**************************************************************************
-// LIVE DEVICE
-//**************************************************************************
-
-//-------------------------------------------------
-// upd65031_device - constructor
-//-------------------------------------------------
-
-upd65031_device::upd65031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : device_t(mconfig, UPD65031, "NEC uPD65031", tag, owner, clock, "upd65031", __FILE__),
- m_read_kb(*this),
- m_write_int(*this),
- m_write_nmi(*this),
- m_write_spkr(*this)
-{
-}
-
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void upd65031_device::device_start()
-{
- // resolve callbacks
- m_read_kb.resolve_safe(0);
- m_write_int.resolve_safe();
- m_write_nmi.resolve_safe();
- m_write_spkr.resolve_safe();
-
- // bind delegates
- m_screen_update_cb.bind_relative_to(*owner());
- m_out_mem_cb.bind_relative_to(*owner());
-
- // allocate timers
- m_rtc_timer = timer_alloc(TIMER_RTC);
- m_flash_timer = timer_alloc(TIMER_FLASH);
- m_speaker_timer = timer_alloc(TIMER_SPEAKER);
- m_rtc_timer->adjust(attotime::from_msec(5), 0, attotime::from_msec(5));
- m_flash_timer->adjust(attotime::from_hz(2), 0, attotime::from_hz(2));
- m_speaker_timer->reset();
-
- // state saving
- save_item(NAME(m_mode));
- save_item(NAME(m_lcd_regs));
- save_item(NAME(m_tim));
- save_item(NAME(m_sr));
- save_item(NAME(m_sta));
- save_item(NAME(m_int));
- save_item(NAME(m_ack));
- save_item(NAME(m_tsta));
- save_item(NAME(m_tmk));
- save_item(NAME(m_tack));
- save_item(NAME(m_com));
- save_item(NAME(m_flash));
-}
-
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void upd65031_device::device_reset()
-{
- memset(m_lcd_regs, 0, sizeof(m_lcd_regs));
- memset(m_tim, 0, sizeof(m_tim));
- memset(m_sr, 0, sizeof(m_sr));
- m_sta = 0;
- m_int = 0;
- m_ack = 0;
- m_tsta = 0;
- m_tmk = TSTA_TICK | TSTA_SEC | TSTA_MIN;
- m_tack = 0;
- m_com = 0;
- m_flash = 0;
- m_mode = 0;
- set_mode(STATE_AWAKE);
-
- if (!m_out_mem_cb.isnull())
- {
- // reset bankswitch
- m_out_mem_cb(0, 0, 0);
- m_out_mem_cb(1, 0, 0);
- m_out_mem_cb(2, 0, 0);
- m_out_mem_cb(3, 0, 0);
- }
-}
-
-
-//-------------------------------------------------
-// device_timer - handler timer events
-//-------------------------------------------------
-
-void upd65031_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- switch (id)
- {
- case TIMER_RTC:
-
- // if a key is pressed sets the interrupt
- if ((m_int & INT_GINT) && (m_int & INT_KEY) && m_read_kb(0) != 0xff)
- {
- if (LOG) logerror("uPD65031 '%s': Keyboard interrupt!\n", tag());
-
- // awakes CPU from snooze on key down
- if (m_mode == STATE_SNOOZE)
- set_mode(STATE_AWAKE);
-
- m_sta |= STA_KEY;
- }
- else
- {
- m_sta &= ~STA_KEY;
- }
-
- // hold clock at reset? - in this mode it doesn't update
- if (!(m_com & COM_RESTIM))
- {
- bool irq_change = false;
-
- // update 5 millisecond counter
- m_tim[0]++;
-
- // tick
- if (m_tim[0] & 1)
- {
- // set tick int has occurred
- if (m_tmk & TSTA_TICK)
- {
- m_tsta |= TSTA_TICK;
- irq_change = true;
- }
- }
-
- if (m_tim[0] == 200)
- {
- m_tim[0] = 0;
-
- // set seconds int has occurred
- if (m_tmk & TSTA_SEC)
- {
- m_tsta |= TSTA_SEC;
- irq_change = true;
- }
-
- m_tim[1]++;
-
- if (m_tim[1] == 60)
- {
- // set minutes int has occurred
- if (m_tmk & TSTA_MIN)
- {
- m_tsta |= TSTA_MIN;
- irq_change = true;
- }
- m_tim[1] = 0;
- m_tim[2]++;
-
- if (m_tim[2] == 0) // overflowed from 255
- {
- m_tim[3]++;
-
- if (m_tim[3] == 0) // overflowed from 255
- {
- m_tim[4]++;
-
- if (m_tim[4] == 32)
- m_tim[4] = 0;
- }
- }
- }
- }
-
- if ((m_int & INT_GINT) && (m_int & INT_TIME) && irq_change && !(m_sta & STA_FLAPOPEN))
- {
- set_mode(STATE_AWAKE);
-
- update_rtc_interrupt();
- }
-
- // refresh interrupt
- interrupt_refresh();
- }
- break;
- case TIMER_FLASH:
- m_flash = !m_flash;
- break;
- case TIMER_SPEAKER:
- m_speaker_state = !m_speaker_state;
- m_write_spkr(m_speaker_state ? 1 : 0);
- break;
- }
-}
-
-
-//-------------------------------------------------
-// screen_update
-//-------------------------------------------------
-
-UINT32 upd65031_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
-{
- if (!m_screen_update_cb.isnull() && (m_com & COM_LCDON))
- m_screen_update_cb(bitmap, m_lcd_regs[4], m_lcd_regs[2], m_lcd_regs[3], m_lcd_regs[0], m_lcd_regs[1], m_flash);
- else
- bitmap.fill(0, cliprect);
-
- return 0;
-}
-
-//-------------------------------------------------
-// read -
-//-------------------------------------------------
-
-READ8_MEMBER( upd65031_device::read )
-{
- UINT8 port = offset & 0xff;
-
- switch (port)
- {
- case REG_STA: // read interrupt status
- return m_sta;
-
- case REG_KBD:
- {
- // if set, reading the keyboard will put into snooze
- if (m_int & INT_KWAIT)
- {
- set_mode(STATE_SNOOZE);
-
- if (LOG) logerror("uPD65031 '%s': entering snooze!\n", tag());
- }
-
- UINT8 data = m_read_kb(offset>>8);
-
- if (LOG) logerror("uPD65031 '%s': key r %02x: %02x\n", tag(), offset>>8, data);
-
- return data;
- }
-
- // read real time clock status
- case REG_TSTA:
- if (LOG) logerror("uPD65031 '%s': tsta r: %02x\n", tag(), m_tsta);
- return m_tsta & 0x07;
-
- // read real time clock counters
- case REG_TIM0:
- if (LOG) logerror("uPD65031 '%s': TIM0 r: %02x\n", tag(), m_tim[0]);
- return m_tim[0];
- case REG_TIM1:
- if (LOG) logerror("uPD65031 '%s': TIM1 r: %02x\n", tag(), m_tim[1]);
- return m_tim[1];
- case REG_TIM2:
- if (LOG) logerror("uPD65031 '%s': TIM2 r: %02x\n", tag(), m_tim[2]);
- return m_tim[2];
- case REG_TIM3:
- if (LOG) logerror("uPD65031 '%s': TIM3 r: %02x\n", tag(), m_tim[3]);
- return m_tim[3];
- case REG_TIM4:
- if (LOG) logerror("uPD65031 '%s': TIM4 r: %02x\n", tag(), m_tim[4]);
- return m_tim[4];
-
- // UART
- case REG_RXD:
- case REG_RXE:
- case REG_UIT:
- // TODO
- return 0;
-
- default:
- logerror("uPD65031 '%s': blink r: %04x\n", tag(), offset);
- return 0;
- }
-}
-
-
-//-------------------------------------------------
-// write -
-//-------------------------------------------------
-
-WRITE8_MEMBER( upd65031_device::write )
-{
- UINT8 port = offset & 0xff;
-
- switch (port)
- {
- // gfx registers
- case REG_PB0:
- case REG_PB1:
- case REG_PB2:
- case REG_PB3:
- case REG_SBR:
- m_lcd_regs[port - REG_PB0] = ((offset & 0xff00) | data);
- break;
-
- case REG_COM: // command register
- if (LOG) logerror("uPD65031 '%s': com w: %02x\n", tag(), data);
-
- // reset clock?
- if (data & COM_RESTIM)
- m_tim[0] = m_tim[1] = m_tim[2] = m_tim[3] = m_tim[4] = 0;
-
- if ((data & COM_SRUN) && !(data & COM_SBIT))
- {
- // constant tone used for keyclick and alarm
- m_speaker_timer->adjust(SPEAKER_ALARM_FREQ, 0, SPEAKER_ALARM_FREQ);
- }
- else
- {
- if (!(data & COM_SRUN))
- {
- // speaker controlled by SBIT
- m_speaker_state = BIT(data, 6);
- m_write_spkr(m_speaker_state);
- }
- else
- {
- // speaker controlled by txd line
- // TODO
- }
-
- m_speaker_timer->reset();
- }
-
- // bit 2 controls the lower 8kb of memory
- if (BIT(m_com^data, 2) && !m_out_mem_cb.isnull())
- m_out_mem_cb(0, m_sr[0], BIT(data, 2));
-
- m_com = data;
- break;
-
- case REG_INT: // interrupt control
- if (LOG) logerror("uPD65031 '%s': int w: %02x\n", tag(), data);
-
- m_int = data;
-
- // refresh ints
- update_rtc_interrupt();
- interrupt_refresh();
- break;
-
- case REG_EPR: // EPROM programming register
- if (LOG) logerror("uPD65031 '%s': epr w: %02x\n", tag(), data);
- // TODO
- break;
-
- case REG_TACK: // rtc interrupt acknowledge
- if (LOG) logerror("uPD65031 '%s': tack w: %02x\n", tag(), data);
-
- // clear ints that have occurred
- m_tsta &= ~(data & 0x07);
- m_tack = data;
-
- // refresh ints
- update_rtc_interrupt();
- interrupt_refresh();
- break;
-
- case REG_TMK: // write rtc interrupt mask
- if (LOG) logerror("uPD65031 '%s': tmk w: %02x\n", tag(), data);
-
- m_tmk = data & 0x07;
- break;
-
- case REG_ACK: // acknowledge ints
- if (LOG) logerror("uPD65031 '%s': ack w: %02x\n", tag(), data);
-
- m_ack = data;
- m_sta &= ~(data & 0x7f);
-
- // refresh ints
- interrupt_refresh();
- break;
-
- // Segment registers
- case REG_SR0:
- case REG_SR1:
- case REG_SR2:
- case REG_SR3:
- if (!m_out_mem_cb.isnull() && m_sr[port & 3] != data)
- m_out_mem_cb(port & 3, data, BIT(m_com, 2));
-
- m_sr[port & 3] = data;
- break;
-
- // UART
- case REG_RXC:
- case REG_TXD:
- case REG_TXC:
- case REG_UMK:
- case REG_UAK:
- if (LOG) logerror("uPD65031 '%s': UART w: %02x %02x\n", tag(), port & 7 , data);
- // TODO
- break;
-
- default:
- logerror("uPD65031 '%s': blink w: %04x %02x\n", tag(), offset, data);
- break;
- }
-}
-
-
-//-------------------------------------------------
-// flp line
-//-------------------------------------------------
-
-WRITE_LINE_MEMBER( upd65031_device::flp_w )
-{
- if (!(m_sta & STA_FLAPOPEN) && state)
- {
- // set interrupt on rising edge
- m_sta |= STA_FLAP;
-
- interrupt_refresh();
- }
-
- if (state)
- m_sta |= STA_FLAPOPEN;
- else
- m_sta &= ~STA_FLAPOPEN;
-}
-
-//-------------------------------------------------
-// battery low line
-//-------------------------------------------------
-
-WRITE_LINE_MEMBER( upd65031_device::btl_w )
-{
- if (state)
- m_sta |= STA_BTL;
- else
- m_sta &= ~STA_BTL;
-}