summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/upd7810/upd7810.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/upd7810/upd7810.c')
-rw-r--r--src/devices/cpu/upd7810/upd7810.c1984
1 files changed, 1984 insertions, 0 deletions
diff --git a/src/devices/cpu/upd7810/upd7810.c b/src/devices/cpu/upd7810/upd7810.c
new file mode 100644
index 00000000000..f22ccb07b4f
--- /dev/null
+++ b/src/devices/cpu/upd7810/upd7810.c
@@ -0,0 +1,1984 @@
+// license:BSD-3-Clause
+// copyright-holders:Juergen Buchmueller
+/*****************************************************************************
+ *
+ * upd7810.c
+ * Portable uPD7810/11, 7810H/11H, 78C10/C11/C14 emulator V0.3
+ *
+ * This work is based on the
+ * "NEC Electronics User's Manual, April 1987"
+ *
+ * NS20030115:
+ * - fixed INRW_wa()
+ * - TODO: add 7807, differences are listed below.
+ * I only added support for these opcodes needed by homedata.c (yes, I am
+ * lazy):
+ * 4C CE (MOV A,PT)
+ * 48 AC (EXA)
+ * 48 AD (EXR)
+ * 48 AE (EXH)
+ * 48 AF (EXX)
+ * 50 xx (SKN bit)
+ * 58 xx (SETB)
+ * 5B xx (CLR)
+ * 5D xx (SK bit)
+ *
+ * 2008-02-24 (Wilbert Pol):
+ * - Added preliminary support for uPD7801
+ * For the uPD7801 only the basic instruction set was added. The current timer
+ * and serial i/o implementations are most likely incorrect.
+ * - Added basic support for uPD78C05 and uPD78C06
+ * Documentation of the actual instruction set layout is missing, so we took
+ * the uPD7801 instruction set and only kept the instructions mentioned in
+ * the little documentation available on the uPD78c05A/06A. The serial i/o
+ * implementation has not been tested and is probably incorrect.
+ *
+ *****************************************************************************/
+/* Hau around 23 May 2004
+ gta, gti, dgt fixed
+ working reg opcodes fixed
+ sio input fixed
+--
+ PeT around 19 February 2002
+ type selection/gamemaster support added
+ gamemaster init hack? added
+ ORAX added
+ jre negativ fixed
+ prefixed opcodes skipping fixed
+ interrupts fixed and improved
+ sub(and related)/add/daa flags fixed
+ mvi ports,... fixed
+ rll, rlr, drll, drlr fixed
+ rets fixed
+ l0, l1 skipping fixed
+ calt fixed
+*/
+
+/*
+
+7807 DESCRIPTION
+
+
+
+ PA0 1 64 Vcc
+ PA1 2 63 Vdd
+ PA2 3 62 PD7/AD7
+ PA3 4 61 PD6/AD6
+ PA4 5 60 PD5/AD5
+ PA5 6 59 PD4/AD4
+ PA6 7 58 PD3/AD3
+ PA7 8 57 PD2/AD2
+ PB0 9 56 PD1/AD1
+ PB1 10 55 PD0/AD0
+ PB2 11 54 PF7/AB15
+ PB3 12 53 PF6/AB14
+ PB4 13 52 PF5/AB13
+ PB5 14 51 PF4/AB12
+ PB6 15 50 PF3/AB11
+ PB7 16 49 PF2/AB10
+ PC0 17 48 PF1/AB9
+ PC1 18 47 PF0/AB8
+ PC2 19 46 ALE
+ PC3 20 45 WR*
+ PC4 21 44 RD*
+ PC5 22 43 HLDA
+ PC6 23 42 HOLD
+ PC7 24 41 PT7
+ NMI* 25 40 PT6
+ INT1 26 39 PT5
+ MODE1 27 38 PT4
+RESET* 28 37 PT3
+ MODE0 29 36 PT2
+ X2 30 35 PT1
+ X1 31 34 PT0
+ Vss 32 33 Vth
+
+PA, PB, PC, PD, and PF is bidirectional I/O port
+and PT is comparator input port in uPD7808.
+uPD7807 uses PD port as data I/O and bottom address output,
+and uses PF port as top address output.
+
+NMI* is non maskable interrupt input signal (negative edge trigger).
+
+INT1 is interrupt input (positive edge trigger). It can be used as
+AC zero-cross input or trigger source of 16bit timer counter.
+
+MODE0 and MODE1 is input terminal which decides total amount of
+external memory of uPD7807 (4KByte, 16KBYte, and 64KByte).
+It also decides number of PF ports used as top address output.
+ 4KByte mode: PF0~PF3=address output, PF4~PF7=data I/O port
+16KByte mode: PF0~PF5=address output, PF6~PF7=data I/O port
+64KByte mode: PF0~PF7=address output
+
+RESET* is system rest terminal.
+
+X1 and X2 does clock signal generation (connect OSC and condenser).
+
+Vth is used to determine threshold voltage for PT port.
+PT0~PT7 is connected to + input of each comparator,
+and Vth deterimnes voltage connected to - input of PT0~PT7.
+But the voltage of Vth is not directly connected to comapators.
+It is connected via 16-level programmable voltage separate circuit.
+
+HOLD and HLDA is terminal for DMA. RD*, WR*, and ALE is bus
+interface signal (they are same type of Intel 8085).
+Unlike 8085, I/O address space is not available, so IO /M* signal
+does not exist. Read/write of external memory can be done
+by RD*, WR*, and ALE only.
+
+Vcc and Vss is main power source. Vdd is backup power source
+for internal RWM (32 Byte).
+
+
+PA and PB is I/O port. They have control register MA and MB.
+If control register is set to 1, the port is input.
+If control register is set to 0, the port is output.
+They are set to 1 by reset.
+
+PT is input-only port. It is consisted of input terminal PT0~PT7
+and Vth (set threshold voltage). Each PT input has analog comparator
+and latch, and + input of analog comparator is connected to
+PT terminal. Every - input of analog comparator is connected
+to devided voltage of Vth. Voltage dividing level can be set by
+bottom 4bits of MT (mode T) register. The range is 1/16~16/16 of Vth.
+
+Other internal I/Os are
+8bit timer (x2): Upcounter. If the counter matches to specified value,
+the timer is reset and counts again from 0.
+You can also set it to generate interrupt, or invert output flip-flop
+when the counter matches to specified value.
+Furthermore, you can output that flip-flop output to PC4/TO output,
+connect it to clock input of timer/event counter or watchdog timer.
+Or you can use it as bitrate clock of serial interface.
+Note: There is only 1 output flip-flop for 2 timers.
+If you use it for timer output of 1 timer, another timer cannot be used
+for other than interrupt generator.
+Clock input for timer can be switched between internal clock (2 type)
+or PC3/TI input. You can set 1 timer's match-output as another timer's
+clock input, so that you can use them as 1 16bit timer.
+
+16bit timer/event counter (x1): It can be used as
+- Interval timer
+- External event counter
+- Frequency measurement
+- Pulse width measurement
+- Programmable rectangle wave output
+- One pulse output
+Related terminals are PC5/CI input, PC6/CO0 output, and PC7/CO1.
+You can measure CI input's H duration, or you can output timing signal
+(with phase difference) to CO0 and CO1.
+
+serial I/F (x1): has 3 modes.
+- Asynchronous mode
+- Synchronous mode
+- I/O interface mode
+In all 3 modes, bitrate can be internal fixed clock, or timer output,
+or external clock.
+In asynchronous mode, you can
+- switch 7bit/8bit data
+- set parity ON/OFF and EVEN/ODD
+- set 1/2 stop bit
+
+
+
+
+DIFFERENCES BETWEEN 7810 and 7807
+
+--------------------------
+8bit transfer instructions
+--------------------------
+
+7810
+inst. 1st byte 2nd byte state action
+EXX 00001001 4 Swap BC DE HL
+EXA 00001000 4 Swap VA EA
+EXH 01010000 4 Swap HL
+BLOCK 00110001 13(C+1) (DE)+ <- (HL)+, C <- C - 1, until CY
+
+7807
+inst. 1st byte 2nd byte state action
+EXR 01001000 10101101 8 Swap VA BC DE HL EA
+EXX 01001000 10101111 8 Swap BC DE HL
+EXA 01001000 10101100 8 Swap VA EA
+EXH 01001000 10101110 8 Swap HL
+BLOCK D+ 00010000 13(C+1) (DE)+ <- (HL)+, C <- C - 1, until CY
+BLOCK D- 00010001 13(C+1) (DE)- <- (HL)-, C <- C - 1, until CY
+
+
+---------------------------
+16bit transfer instructions
+---------------------------
+All instructions are same except operand sr4 of DMOV instruction.
+7810
+V0-sr4 -function
+ 0-ECNT-timer/event counter upcounter
+ 1-ECPT-timer/event counter capture
+
+7807
+V1-V0- sr4 -function
+ 0- 0-ECNT -timer/event counter upcounter
+ 0- 1-ECPT0-timer/event counter capture 0
+ 1- 0-ECPT1-timer/event counter capture 1
+
+
+-----------------------------------------
+8bit operation instructions for registers
+-----------------------------------------
+All instructions are same.
+
+
+--------------------------------------
+8bit operation instructions for memory
+--------------------------------------
+All instructions are same.
+
+
+-----------------------------------------
+Operation instructions for immediate data
+-----------------------------------------
+uPD7807 has read-only PT port and special register group sr5 for it.
+ins. 1st byte 2nd byte 3rd 4th state func
+GTI sr5, byte 01100100 s0101sss dd 14 !CY sr5 - byte - 1
+LTI sr5, byte 01100100 s0111sss dd 14 CY sr5 - byte
+NEI sr5, byte 01100100 s1101sss dd 14 !Z sr5 - byte
+EQI sr5, byte 01100100 s1111sss dd 14 Z sr5 - byte
+ONI sr5, byte 01100100 s1001sss dd 14 !Z sr5 & byte
+OFFI sr5, byte 01100100 s1011sss dd 14 Z sr5 & byte
+
+S5-S4-S3-S2-S1-S0-sr -sr1-sr2-sr5-register function
+ 0 0 1 1 1 0 --- PT --- PT comparator input port T data
+ 1 0 0 1 0 0 WDM WDM --- --- watchdog timer mode register
+ 1 0 0 1 0 1 MT --- --- --- port T mode
+
+7807 doesn't have registers below
+ 0 0 1 0 0 0 ANM ANM ANM A/D channel mode
+ 1 0 0 0 0 0 --- CR0 --- A/D conversion result 0
+ 1 0 0 0 0 1 --- CR1 --- A/D conversion result 1
+ 1 0 0 0 1 0 --- CR2 --- A/D conversion result 2
+ 1 0 0 0 1 1 --- CR3 --- A/D conversion result 3
+ 1 0 1 0 0 0 ZCM --- --- zero cross mode
+
+Special register operand (includes registers for I/O ports) has
+6 groups - sr, sr1, sr2, sr3, sr4, and sr5. Among these groups,
+sr, sr1, sr2, and sr5 includes registers described in the table
+below, and expressed as bit pattern S5-S0.
+
+S5S4S3S2S1S0 sr sr1 sr2 sr5 register function
+0 0 0 0 0 0 PA PA PA PA port A
+0 0 0 0 0 1 PB PB PB PB port B
+0 0 0 0 1 0 PC PC PC PC port C
+0 0 0 0 1 1 PD PD PD PD port D
+0 0 0 1 0 1 PF PF PF PF port F
+0 0 0 1 1 0 MKH MKH MKH MKH mask high
+0 0 0 1 1 1 MKL MKL MKL MKL mask low
+0 0 1 0 0 1 SMH SMH SMH SMH serial mode high
+0 0 1 0 1 0 SML --- --- --- serial mode low
+0 0 1 0 1 1 EOM EOM EOM EOM timer/event counter output mode
+0 0 1 1 0 0 ETMM --- --- --- timer/event counter mode
+0 0 1 1 0 1 TMM TMM TMM TMM timer mode
+0 0 1 1 1 0 --- PT --- PT port T
+0 1 0 0 0 0 MM --- --- --- memory mapping
+0 1 0 0 0 1 MCC --- --- --- mode control C
+0 1 0 0 1 0 MA --- --- --- mode A
+0 1 0 0 1 1 MB --- --- --- mode B
+0 1 0 1 0 0 MC --- --- --- mode C
+0 1 0 1 1 1 MF --- --- --- mode F
+0 1 1 0 0 0 TXB --- --- --- Tx buffer
+0 1 1 0 0 1 --- RXB --- --- Rx buffer
+0 1 1 0 1 0 TM0 --- --- --- timer register 0
+0 1 1 0 1 1 TM1 --- --- --- timer register 1
+1 0 0 1 0 0 WDM WDM --- --- watchdog timer mode
+1 0 0 1 0 1 MT --- --- --- mode T
+
+For sr and sr1, all 6bits (S5, S4, S3, S2, S1, and S0) are used.
+For sr2 and sr5, only 4bits (S3, S2, S1, AND S0) are used.
+They are expressed as 'ssssss' and 's sss' in operation code.
+Note that 's sss' (of sr2 and sr5) is located separately.
+S0 is rightmost bit (LSB).
+
+
+--------------------------------------------
+Operation instructions for working registers
+--------------------------------------------
+All instructions are same.
+
+
+--------------------------------------------------------------------------
+16bit operation instructions and divider/multiplier operation instructions
+--------------------------------------------------------------------------
+All instructions are same.
+
+
+------------------------------------------
+Increment/decrement operation instructions
+------------------------------------------
+All instructions are same.
+
+
+----------------------------
+Other operation instructions
+----------------------------
+7807 has CMC instruction (inverts CY flag).
+ins. 1st byte 2nd byte 3rd 4th state func
+CMC 01001000 10101010 8 CY <- !CY
+
+
+---------------------------
+Rotation/shift instructions
+---------------------------
+All instructions are same.
+
+
+-----------------------------
+Jump/call/return instructions
+-----------------------------
+All instructions are same.
+
+
+-----------------
+Skip instructions
+-----------------
+7807 doesn't have this
+ins. 1st byte 2nd byte 3rd 4th state func
+BIT bit, wa 01011bbb wwwwwwww 10* bit skip if (V.wa).bit = 1
+
+Instead, 7807 has these bit manipulation instructions.
+ins. 1st byte 2nd byte 3rd 4th state func
+MOV CY, bit 01011111 bbbbbbbb 10* CY <- (bit)
+MOV bit, CY 01011010 bbbbbbbb 13* (bit) <- CY
+AND CY, bit 00110001 bbbbbbbb 10* CY <- CY & (bit)
+OR CY, bit 01011100 bbbbbbbb 10* CY <- CY | (bit)
+XOR CY, bit 01011110 bbbbbbbb 10* CY <- CY ^ (bit)
+SETB bit 01011000 bbbbbbbb 13* (bit) <- 1
+CLR bit 01011011 bbbbbbbb 13* (bit) <- 0
+NOT bit 01011001 bbbbbbbb 13* (bit) <- !(bit)
+SK bit 01011101 bbbbbbbb 10* (b) skip if (bit) = 1
+SKN bit 01010000 bbbbbbbb 10* !(b) skip if (bit) = 0
+
+
+------------------------
+CPU control instructions
+------------------------
+ins. 1st byte 2nd byte 3rd 4th state func
+HLT 01001000 00111011 11/12 halt
+11 state in uPD7807 and uPD7810, 12 state in uPD78C10.
+
+STOP 01001000 10111011 12 stop
+7807 doesn't have STOP instruction.
+
+*/
+
+#include "emu.h"
+#include "debugger.h"
+#include "upd7810.h"
+#include "upd7810_macros.h"
+
+
+const device_type UPD7810 = &device_creator<upd7810_device>;
+const device_type UPD7807 = &device_creator<upd7807_device>;
+const device_type UPD7801 = &device_creator<upd7801_device>;
+const device_type UPD78C05 = &device_creator<upd78c05_device>;
+const device_type UPD78C06 = &device_creator<upd78c06_device>;
+
+
+upd7810_device::upd7810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : cpu_device(mconfig, UPD7810, "uPD7810", tag, owner, clock, "upd7810", __FILE__)
+ , m_to_func(*this)
+ , m_co0_func(*this)
+ , m_co1_func(*this)
+ , m_txd_func(*this)
+ , m_rxd_func(*this)
+ , m_an0_func(*this)
+ , m_an1_func(*this)
+ , m_an2_func(*this)
+ , m_an3_func(*this)
+ , m_an4_func(*this)
+ , m_an5_func(*this)
+ , m_an6_func(*this)
+ , m_an7_func(*this)
+ , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0)
+ , m_io_config("io", ENDIANNESS_LITTLE, 8, 8, 0)
+{
+ m_opXX = s_opXX_7810;
+ m_op48 = s_op48;
+ m_op4C = s_op4C;
+ m_op4D = s_op4D;
+ m_op60 = s_op60;
+ m_op64 = s_op64;
+ m_op70 = s_op70;
+ m_op74 = s_op74;
+}
+
+upd7810_device::upd7810_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
+ : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source)
+ , m_to_func(*this)
+ , m_co0_func(*this)
+ , m_co1_func(*this)
+ , m_txd_func(*this)
+ , m_rxd_func(*this)
+ , m_an0_func(*this)
+ , m_an1_func(*this)
+ , m_an2_func(*this)
+ , m_an3_func(*this)
+ , m_an4_func(*this)
+ , m_an5_func(*this)
+ , m_an6_func(*this)
+ , m_an7_func(*this)
+ , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0)
+ , m_io_config("io", ENDIANNESS_LITTLE, 8, 8, 0)
+{
+}
+
+upd7807_device::upd7807_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : upd7810_device(mconfig, UPD7807, "uPD7807", tag, owner, clock, "upd7807", __FILE__)
+{
+ m_opXX = s_opXX_7807;
+ m_op48 = s_op48;
+ m_op4C = s_op4C;
+ m_op4D = s_op4D;
+ m_op60 = s_op60;
+ m_op64 = s_op64;
+ m_op70 = s_op70;
+ m_op74 = s_op74;
+}
+
+upd7801_device::upd7801_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : upd7810_device(mconfig, UPD7801, "uPD7801", tag, owner, clock, "upd7801", __FILE__)
+{
+ m_op48 = s_op48_7801;
+ m_op4C = s_op4C_7801;
+ m_op4D = s_op4D_7801;
+ m_op60 = s_op60_7801;
+ m_op64 = s_op64_7801;
+ m_op70 = s_op70_7801;
+ m_op74 = s_op74_7801;
+ m_opXX = s_opXX_7801;
+}
+
+upd78c05_device::upd78c05_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : upd7810_device(mconfig, UPD78C05, "uPD78C05", tag, owner, clock, "upd78c05", __FILE__)
+{
+ m_op48 = s_op48_78c05;
+ m_op4C = s_op4C_78c05;
+ m_op4D = s_op4D_78c05;
+ m_op60 = s_op60_78c05;
+ m_op64 = s_op64_78c05;
+ m_op70 = s_op70_78c05;
+ m_op74 = s_op74_78c05;
+ m_opXX = s_opXX_78c05;
+}
+
+upd78c05_device::upd78c05_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
+ : upd7810_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+upd78c06_device::upd78c06_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : upd78c05_device(mconfig, UPD78C06, "uPD78C06", tag, owner, clock, "upd78c06", __FILE__)
+{
+ m_op48 = s_op48_78c06;
+ m_op4C = s_op4C_78c06;
+ m_op4D = s_op4D_78c06;
+ m_op60 = s_op60_78c06;
+ m_op64 = s_op64_78c06;
+ m_op70 = s_op70_78c06;
+ m_op74 = s_op74_78c06;
+ m_opXX = s_opXX_78c06;
+}
+
+offs_t upd7810_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ extern CPU_DISASSEMBLE( upd7810 );
+ return CPU_DISASSEMBLE_NAME(upd7810)(this, buffer, pc, oprom, opram, options);
+}
+
+offs_t upd7807_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ extern CPU_DISASSEMBLE( upd7807 );
+ return CPU_DISASSEMBLE_NAME(upd7807)(this, buffer, pc, oprom, opram, options);
+}
+
+offs_t upd7801_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ extern CPU_DISASSEMBLE( upd7801 );
+ return CPU_DISASSEMBLE_NAME(upd7801)(this, buffer, pc, oprom, opram, options);
+}
+
+offs_t upd78c05_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ extern CPU_DISASSEMBLE( upd78c05 );
+ return CPU_DISASSEMBLE_NAME(upd78c05)(this, buffer, pc, oprom, opram, options);
+}
+
+UINT8 upd7810_device::RP(offs_t port)
+{
+ UINT8 data = 0xff;
+ switch (port)
+ {
+ case UPD7810_PORTA:
+ if (m_ma) // NS20031301 no need to read if the port is set as output
+ m_pa_in = m_io->read_byte(port);
+ data = (m_pa_in & m_ma) | (m_pa_out & ~m_ma);
+ break;
+ case UPD7810_PORTB:
+ if (m_mb) // NS20031301 no need to read if the port is set as output
+ m_pb_in = m_io->read_byte(port);
+ data = (m_pb_in & m_mb) | (m_pb_out & ~m_mb);
+ break;
+ case UPD7810_PORTC:
+ if (m_mc) // NS20031301 no need to read if the port is set as output
+ m_pc_in = m_io->read_byte(port);
+ data = (m_pc_in & m_mc) | (m_pc_out & ~m_mc);
+ if (m_mcc & 0x01) /* PC0 = TxD output */
+ data = (data & ~0x01) | (m_txd & 1 ? 0x01 : 0x00);
+ if (m_mcc & 0x02) /* PC1 = RxD input */
+ data = (data & ~0x02) | (m_rxd & 1 ? 0x02 : 0x00);
+ if (m_mcc & 0x04) /* PC2 = SCK input/output */
+ data = (data & ~0x04) | (m_sck & 1 ? 0x04 : 0x00);
+ if (m_mcc & 0x08) /* PC3 = TI/INT2 input */
+ data = (data & ~0x08) | (m_int2 & 1 ? 0x08 : 0x00);
+ if (m_mcc & 0x10) /* PC4 = TO output */
+ data = (data & ~0x10) | (m_to & 1 ? 0x10 : 0x00);
+ if (m_mcc & 0x20) /* PC5 = CI input */
+ data = (data & ~0x20) | (m_ci & 1 ? 0x20 : 0x00);
+ if (m_mcc & 0x40) /* PC6 = CO0 output */
+ data = (data & ~0x40) | (m_co0 & 1 ? 0x40 : 0x00);
+ if (m_mcc & 0x80) /* PC7 = CO1 output */
+ data = (data & ~0x80) | (m_co1 & 1 ? 0x80 : 0x00);
+ break;
+ case UPD7810_PORTD:
+ m_pd_in = m_io->read_byte(port);
+ switch (m_mm & 0x07)
+ {
+ case 0x00: /* PD input mode, PF port mode */
+ data = m_pd_in;
+ break;
+ case 0x01: /* PD output mode, PF port mode */
+ data = m_pd_out;
+ break;
+ default: /* PD extension mode, PF port/extension mode */
+ data = 0xff; /* what do we see on the port here? */
+ break;
+ }
+ break;
+ case UPD7810_PORTF:
+ m_pf_in = m_io->read_byte(port);
+ switch (m_mm & 0x06)
+ {
+ case 0x00: /* PD input/output mode, PF port mode */
+ data = (m_pf_in & m_mf) | (m_pf_out & ~m_mf);
+ break;
+ case 0x02: /* PD extension mode, PF0-3 extension mode, PF4-7 port mode */
+ data = (m_pf_in & m_mf) | (m_pf_out & ~m_mf);
+ data |= 0x0f; /* what would we see on the lower bits here? */
+ break;
+ case 0x04: /* PD extension mode, PF0-5 extension mode, PF6-7 port mode */
+ data = (m_pf_in & m_mf) | (m_pf_out & ~m_mf);
+ data |= 0x3f; /* what would we see on the lower bits here? */
+ break;
+ case 0x06:
+ data = 0xff; /* what would we see on the lower bits here? */
+ break;
+ }
+ break;
+ case UPD7807_PORTT: // NS20031301 partial implementation
+ data = m_io->read_byte(port);
+ break;
+ default:
+ logerror("uPD7810 internal error: RP() called with invalid port number\n");
+ }
+ return data;
+}
+
+void upd7810_device::WP(offs_t port, UINT8 data)
+{
+ switch (port)
+ {
+ case UPD7810_PORTA:
+ m_pa_out = data;
+// data = (data & ~m_ma) | (m_pa_in & m_ma);
+ data = (data & ~m_ma) | (m_ma); // NS20031401
+ m_io->write_byte(port, data);
+ break;
+ case UPD7810_PORTB:
+ m_pb_out = data;
+// data = (data & ~m_mb) | (m_pb_in & m_mb);
+ data = (data & ~m_mb) | (m_mb); // NS20031401
+ m_io->write_byte(port, data);
+ break;
+ case UPD7810_PORTC:
+ m_pc_out = data;
+// data = (data & ~m_mc) | (m_pc_in & m_mc);
+ data = (data & ~m_mc) | (m_mc); // NS20031401
+ if (m_mcc & 0x01) /* PC0 = TxD output */
+ data = (data & ~0x01) | (m_txd & 1 ? 0x01 : 0x00);
+ if (m_mcc & 0x02) /* PC1 = RxD input */
+ data = (data & ~0x02) | (m_rxd & 1 ? 0x02 : 0x00);
+ if (m_mcc & 0x04) /* PC2 = SCK input/output */
+ data = (data & ~0x04) | (m_sck & 1 ? 0x04 : 0x00);
+ if (m_mcc & 0x08) /* PC3 = TI/INT2 input */
+ data = (data & ~0x08) | (m_int2 & 1 ? 0x08 : 0x00);
+ if (m_mcc & 0x10) /* PC4 = TO output */
+ data = (data & ~0x10) | (m_to & 1 ? 0x10 : 0x00);
+ if (m_mcc & 0x20) /* PC5 = CI input */
+ data = (data & ~0x20) | (m_ci & 1 ? 0x20 : 0x00);
+ if (m_mcc & 0x40) /* PC6 = CO0 output */
+ data = (data & ~0x40) | (m_co0 & 1 ? 0x40 : 0x00);
+ if (m_mcc & 0x80) /* PC7 = CO1 output */
+ data = (data & ~0x80) | (m_co1 & 1 ? 0x80 : 0x00);
+ m_io->write_byte(port, data);
+ break;
+ case UPD7810_PORTD:
+ m_pd_out = data;
+ switch (m_mm & 0x07)
+ {
+ case 0x00: /* PD input mode, PF port mode */
+ data = m_pd_in;
+ break;
+ case 0x01: /* PD output mode, PF port mode */
+ data = m_pd_out;
+ break;
+ default: /* PD extension mode, PF port/extension mode */
+ return;
+ }
+ m_io->write_byte(port, data);
+ break;
+ case UPD7810_PORTF:
+ m_pf_out = data;
+ data = (data & ~m_mf) | (m_pf_in & m_mf);
+ switch (m_mm & 0x06)
+ {
+ case 0x00: /* PD input/output mode, PF port mode */
+ break;
+ case 0x02: /* PD extension mode, PF0-3 extension mode, PF4-7 port mode */
+ data |= 0x0f; /* what would come out for the lower bits here? */
+ break;
+ case 0x04: /* PD extension mode, PF0-5 extension mode, PF6-7 port mode */
+ data |= 0x3f; /* what would come out for the lower bits here? */
+ break;
+ case 0x06:
+ data |= 0xff; /* what would come out for the lower bits here? */
+ break;
+ }
+ m_io->write_byte(port, data);
+ break;
+ default:
+ logerror("uPD7810 internal error: RP() called with invalid port number\n");
+ }
+}
+
+void upd7810_device::upd7810_take_irq()
+{
+ UINT16 vector = 0;
+ int irqline = 0;
+
+ /* global interrupt disable? */
+ if (0 == IFF)
+ return;
+
+ /* check the interrupts in priority sequence */
+ if (IRR & INTNMI)
+ {
+ /* Nonmaskable interrupt */
+ irqline = INPUT_LINE_NMI;
+ vector = 0x0004;
+ IRR &= ~INTNMI;
+ }
+ else
+ if ((IRR & INTFT0) && 0 == (MKL & 0x02))
+ {
+ vector = 0x0008;
+ if (!((IRR & INTFT1) && 0 == (MKL & 0x04)))
+ IRR&=~INTFT0;
+ }
+ else
+ if ((IRR & INTFT1) && 0 == (MKL & 0x04))
+ {
+ vector = 0x0008;
+ IRR&=~INTFT1;
+ }
+ else
+ if ((IRR & INTF1) && 0 == (MKL & 0x08))
+ {
+ irqline = UPD7810_INTF1;
+ vector = 0x0010;
+ if (!((IRR & INTF2) && 0 == (MKL & 0x10)))
+ IRR&=~INTF1;
+ }
+ else
+ if ((IRR & INTF2) && 0 == (MKL & 0x10))
+ {
+ irqline = UPD7810_INTF2;
+ vector = 0x0010;
+ IRR&=~INTF2;
+ }
+ else
+ if ((IRR & INTFE0) && 0 == (MKL & 0x20))
+ {
+ vector = 0x0018;
+ if (!((IRR & INTFE1) && 0 == (MKL & 0x40)))
+ IRR&=~INTFE0;
+ }
+ else
+ if ((IRR & INTFE1) && 0 == (MKL & 0x40))
+ {
+ vector = 0x0018;
+ IRR&=~INTFE1;
+ }
+ else
+ if ((IRR & INTFEIN) && 0 == (MKL & 0x80))
+ {
+ vector = 0x0020;
+ }
+ else
+ if ((IRR & INTFAD) && 0 == (MKH & 0x01))
+ {
+ vector = 0x0020;
+ }
+ else
+ if ((IRR & INTFSR) && 0 == (MKH & 0x02))
+ {
+ vector = 0x0028;
+ IRR&=~INTFSR;
+ }
+ else
+ if ((IRR & INTFST) && 0 == (MKH & 0x04))
+ {
+ vector = 0x0028;
+ IRR&=~INTFST;
+ }
+
+ if (vector)
+ {
+ /* acknowledge external IRQ */
+ if (irqline)
+ standard_irq_callback(irqline);
+ SP--;
+ WM( SP, PSW );
+ SP--;
+ WM( SP, PCH );
+ SP--;
+ WM( SP, PCL );
+ IFF = 0;
+ PSW &= ~(SK|L0|L1);
+ PC = vector;
+ }
+}
+
+void upd7801_device::upd7810_take_irq()
+{
+ UINT16 vector = 0;
+ int irqline = 0;
+
+ /* global interrupt disable? */
+ if (0 == IFF)
+ return;
+
+ /* 1 - SOFTI - vector at 0x0060 */
+ /* 2 - INT0 - Masked by MK0 bit */
+ if ( IRR & INTF0 && 0 == (MKL & 0x01 ) )
+ {
+ irqline = UPD7810_INTF0;
+ vector = 0x0004;
+ IRR &= ~INTF0;
+ }
+ /* 3 - INTT - Masked by MKT bit */
+ if ( IRR & INTFT0 && 0 == ( MKL & 0x02 ) )
+ {
+ vector = 0x0008;
+ IRR &= ~INTFT0;
+ }
+ /* 4 - INT1 - Masked by MK1 bit */
+ if ( IRR & INTF1 && 0 == ( MKL & 0x04 ) )
+ {
+ irqline = UPD7810_INTF1;
+ vector = 0x0010;
+ IRR &= ~INTF1;
+ }
+ /* 5 - INT2 - Masked by MK2 bit */
+ if ( IRR & INTF2 && 0 == ( MKL & 0x08 ) )
+ {
+ irqline = UPD7810_INTF2;
+ vector = 0x0020;
+ IRR &= ~INTF2;
+ }
+ /* 6 - INTS - Masked by MKS bit */
+ if ( IRR & INTFST && 0 == ( MKL & 0x10 ) )
+ {
+ vector = 0x0040;
+ IRR &= ~INTFST;
+ }
+
+ if (vector)
+ {
+ /* acknowledge external IRQ */
+ if (irqline)
+ standard_irq_callback(irqline);
+ SP--;
+ WM( SP, PSW );
+ SP--;
+ WM( SP, PCH );
+ SP--;
+ WM( SP, PCL );
+ IFF = 0;
+ PSW &= ~(SK|L0|L1);
+ PC = vector;
+ }
+}
+
+void upd7810_device::upd7810_co0_output_change()
+{
+ /* Output LV0 Content to CO0 */
+ CO0 = LV0;
+
+ /* LV0 Level Inversion */
+ if (EOM & 0x02)
+ LV0 ^= 1;
+
+ m_co0_func(CO0);
+}
+void upd7810_device::upd7810_co1_output_change()
+{
+ /* Output LV1 Content to CO1 */
+ CO1 = LV1;
+
+ /* LV1 Level Inversion */
+ if (EOM & 0x20)
+ LV1 ^= 1;
+
+ m_co1_func(CO1);
+}
+
+void upd7810_device::upd7810_write_EOM()
+{
+ switch (EOM & 0x0c)
+ {
+ case 0x04: /* To Reset LV0 */
+ LV0 = 0;
+ EOM &= 0xfb; /* LRE0 is reset to 0 */
+ break;
+ case 0x08: /* To Set LV0 */
+ LV0 = 1;
+ EOM &= 0xf7; /* LRE1 is reset to 0 */
+ break;
+ }
+ /* Output LV0 Content */
+ if (EOM & 0x01) {
+ upd7810_co0_output_change();
+ EOM &= 0xfe; /* LO0 is reset to 0 */
+ }
+
+ switch (EOM & 0xc0)
+ {
+ case 0x40: /* To Reset LV1 */
+ LV1 = 0;
+ EOM &= 0xbf; /* LRE2 is reset to 0 */
+ break;
+ case 0x80: /* To Set LV1 */
+ LV1 = 1;
+ EOM &= 0x7f; /* LRE3 is reset to 0 */
+ break;
+ }
+ /* Output LV1 Content */
+ if (EOM & 0x10) {
+ upd7810_co1_output_change();
+ EOM &= 0xef; /* LO1 is reset to 0 */
+ }
+}
+
+void upd7810_device::upd7810_write_TXB()
+{
+ m_txbuf = 1;
+}
+
+#define PAR7(n) ((((n)>>6)^((n)>>5)^((n)>>4)^((n)>>3)^((n)>>2)^((n)>>1)^((n)))&1)
+#define PAR8(n) ((((n)>>7)^((n)>>6)^((n)>>5)^((n)>>4)^((n)>>3)^((n)>>2)^((n)>>1)^((n)))&1)
+
+void upd7810_device::upd7810_sio_output()
+{
+ /* shift out more bits? */
+ if (m_txcnt > 0)
+ {
+ TXD = m_txs & 1;
+ m_txd_func(TXD);
+ m_txs >>= 1;
+ m_txcnt--;
+ if (0 == m_txcnt)
+ IRR |= INTFST; /* serial transfer completed */
+ }
+ else
+ if (SMH & 0x04) /* send enable ? */
+ {
+ /* nothing written into the transmitter buffer ? */
+ if (0 == m_txbuf)
+ return;
+ m_txbuf = 0;
+
+ if (SML & 0x03) /* asynchronous mode ? */
+ {
+ switch (SML & 0xfc)
+ {
+ case 0x48: /* 7bits, no parity, 1 stop bit */
+ case 0x68: /* 7bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ /* insert start bit in bit0, stop bit int bit8 */
+ m_txs = (TXB << 1) | (1 << 8);
+ m_txcnt = 9;
+ break;
+ case 0x4c: /* 8bits, no parity, 1 stop bit */
+ case 0x6c: /* 8bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ /* insert start bit in bit0, stop bit int bit9 */
+ m_txs = (TXB << 1) | (1 << 9);
+ m_txcnt = 10;
+ break;
+ case 0x58: /* 7bits, odd parity, 1 stop bit */
+ /* insert start bit in bit0, parity in bit 8, stop bit in bit9 */
+ m_txs = (TXB << 1) | (PAR7(TXB) << 8) | (1 << 9);
+ m_txcnt = 10;
+ break;
+ case 0x5c: /* 8bits, odd parity, 1 stop bit */
+ /* insert start bit in bit0, parity in bit 9, stop bit int bit10 */
+ m_txs = (TXB << 1) | (PAR8(TXB) << 9) | (1 << 10);
+ m_txcnt = 11;
+ break;
+ case 0x78: /* 7bits, even parity, 1 stop bit */
+ /* insert start bit in bit0, parity in bit 8, stop bit in bit9 */
+ m_txs = (TXB << 1) | ((PAR7(TXB) ^ 1) << 8) | (1 << 9);
+ m_txcnt = 10;
+ break;
+ case 0x7c: /* 8bits, even parity, 1 stop bit */
+ /* insert start bit in bit0, parity in bit 9, stop bit int bit10 */
+ m_txs = (TXB << 1) | ((PAR8(TXB) ^ 1) << 9) | (1 << 10);
+ m_txcnt = 11;
+ break;
+ case 0xc8: /* 7bits, no parity, 2 stop bits */
+ case 0xe8: /* 7bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ /* insert start bit in bit0, stop bits int bit8+9 */
+ m_txs = (TXB << 1) | (3 << 8);
+ m_txcnt = 10;
+ break;
+ case 0xcc: /* 8bits, no parity, 2 stop bits */
+ case 0xec: /* 8bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ /* insert start bit in bit0, stop bits in bits9+10 */
+ m_txs = (TXB << 1) | (3 << 9);
+ m_txcnt = 11;
+ break;
+ case 0xd8: /* 7bits, odd parity, 2 stop bits */
+ /* insert start bit in bit0, parity in bit 8, stop bits in bits9+10 */
+ m_txs = (TXB << 1) | (PAR7(TXB) << 8) | (3 << 9);
+ m_txcnt = 11;
+ break;
+ case 0xdc: /* 8bits, odd parity, 2 stop bits */
+ /* insert start bit in bit0, parity in bit 9, stop bits int bit10+11 */
+ m_txs = (TXB << 1) | (PAR8(TXB) << 9) | (3 << 10);
+ m_txcnt = 12;
+ break;
+ case 0xf8: /* 7bits, even parity, 2 stop bits */
+ /* insert start bit in bit0, parity in bit 8, stop bits in bit9+10 */
+ m_txs = (TXB << 1) | ((PAR7(TXB) ^ 1) << 8) | (3 << 9);
+ m_txcnt = 11;
+ break;
+ case 0xfc: /* 8bits, even parity, 2 stop bits */
+ /* insert start bit in bit0, parity in bit 9, stop bits int bits10+10 */
+ m_txs = (TXB << 1) | ((PAR8(TXB) ^ 1) << 9) | (1 << 10);
+ m_txcnt = 12;
+ break;
+ }
+ }
+ else
+ {
+ /* synchronous mode */
+ m_txs = TXB;
+ m_txcnt = 8;
+ }
+ }
+}
+
+void upd7810_device::upd7810_sio_input()
+{
+ /* sample next bit? */
+ if (m_rxcnt > 0)
+ {
+ RXD = m_rxd_func();
+ m_rxs = (m_rxs >> 1) | ((UINT16)RXD << 15);
+ m_rxcnt--;
+ if (0 == m_rxcnt)
+ {
+ /* reset the TSK bit */
+ SMH &= ~0x40;
+ /* serial receive completed interrupt */
+ IRR |= INTFSR;
+ /* now extract the data from the shift register */
+ if (SML & 0x03) /* asynchronous mode ? */
+ {
+ switch (SML & 0xfc)
+ {
+ case 0x48: /* 7bits, no parity, 1 stop bit */
+ case 0x68: /* 7bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ m_rxs >>= 16 - 9;
+ RXB = (m_rxs >> 1) & 0x7f;
+ if ((1 << 8) != (m_rxs & (1 | (1 << 8))))
+ IRR |= INTER; /* framing error */
+ break;
+ case 0x4c: /* 8bits, no parity, 1 stop bit */
+ case 0x6c: /* 8bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ m_rxs >>= 16 - 10;
+ RXB = (m_rxs >> 1) & 0xff;
+ if ((1 << 9) != (m_rxs & (1 | (1 << 9))))
+ IRR |= INTER; /* framing error */
+ break;
+ case 0x58: /* 7bits, odd parity, 1 stop bit */
+ m_rxs >>= 16 - 10;
+ RXB = (m_rxs >> 1) & 0x7f;
+ if ((1 << 9) != (m_rxs & (1 | (1 << 9))))
+ IRR |= INTER; /* framing error */
+ if (PAR7(RXB) != ((m_rxs >> 8) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0x5c: /* 8bits, odd parity, 1 stop bit */
+ m_rxs >>= 16 - 11;
+ RXB = (m_rxs >> 1) & 0xff;
+ if ((1 << 10) != (m_rxs & (1 | (1 << 10))))
+ IRR |= INTER; /* framing error */
+ if (PAR8(RXB) != ((m_rxs >> 9) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0x78: /* 7bits, even parity, 1 stop bit */
+ m_rxs >>= 16 - 10;
+ RXB = (m_rxs >> 1) & 0x7f;
+ if ((1 << 9) != (m_rxs & (1 | (1 << 9))))
+ IRR |= INTER; /* framing error */
+ if (PAR7(RXB) != ((m_rxs >> 8) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0x7c: /* 8bits, even parity, 1 stop bit */
+ m_rxs >>= 16 - 11;
+ RXB = (m_rxs >> 1) & 0xff;
+ if ((1 << 10) != (m_rxs & (1 | (1 << 10))))
+ IRR |= INTER; /* framing error */
+ if (PAR8(RXB) != ((m_rxs >> 9) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xc8: /* 7bits, no parity, 2 stop bits */
+ case 0xe8: /* 7bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ m_rxs >>= 16 - 10;
+ RXB = (m_rxs >> 1) & 0x7f;
+ if ((3 << 9) != (m_rxs & (1 | (3 << 9))))
+ IRR |= INTER; /* framing error */
+ if (PAR7(RXB) != ((m_rxs >> 8) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xcc: /* 8bits, no parity, 2 stop bits */
+ case 0xec: /* 8bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ m_rxs >>= 16 - 11;
+ RXB = (m_rxs >> 1) & 0xff;
+ if ((3 << 10) != (m_rxs & (1 | (3 << 10))))
+ IRR |= INTER; /* framing error */
+ if (PAR8(RXB) != ((m_rxs >> 9) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xd8: /* 7bits, odd parity, 2 stop bits */
+ m_rxs >>= 16 - 11;
+ RXB = (m_rxs >> 1) & 0x7f;
+ if ((3 << 10) != (m_rxs & (1 | (3 << 10))))
+ IRR |= INTER; /* framing error */
+ if (PAR7(RXB) != ((m_rxs >> 8) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xdc: /* 8bits, odd parity, 2 stop bits */
+ m_rxs >>= 16 - 12;
+ RXB = (m_rxs >> 1) & 0xff;
+ if ((3 << 11) != (m_rxs & (1 | (3 << 11))))
+ IRR |= INTER; /* framing error */
+ if (PAR8(RXB) != ((m_rxs >> 9) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xf8: /* 7bits, even parity, 2 stop bits */
+ m_rxs >>= 16 - 11;
+ RXB = (m_rxs >> 1) & 0x7f;
+ if ((3 << 10) != (m_rxs & (1 | (3 << 10))))
+ IRR |= INTER; /* framing error */
+ if (PAR7(RXB) != ((m_rxs >> 8) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ case 0xfc: /* 8bits, even parity, 2 stop bits */
+ m_rxs >>= 16 - 12;
+ RXB = (m_rxs >> 1) & 0xff;
+ if ((3 << 11) != (m_rxs & (1 | (3 << 11))))
+ IRR |= INTER; /* framing error */
+ if (PAR8(RXB) != ((m_rxs >> 9) & 1))
+ IRR |= INTER; /* parity error */
+ break;
+ }
+ }
+ else
+ {
+ m_rxs >>= 16 - 8;
+ RXB = m_rxs;
+// m_rxcnt = 8;
+ }
+ }
+ }
+ else
+ if (SMH & 0x08) /* receive enable ? */
+ {
+ if (SML & 0x03) /* asynchronous mode ? */
+ {
+ switch (SML & 0xfc)
+ {
+ case 0x48: /* 7bits, no parity, 1 stop bit */
+ case 0x68: /* 7bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ m_rxcnt = 9;
+ break;
+ case 0x4c: /* 8bits, no parity, 1 stop bit */
+ case 0x6c: /* 8bits, no parity, 1 stop bit (parity select = 1 but parity is off) */
+ m_rxcnt = 10;
+ break;
+ case 0x58: /* 7bits, odd parity, 1 stop bit */
+ m_rxcnt = 10;
+ break;
+ case 0x5c: /* 8bits, odd parity, 1 stop bit */
+ m_rxcnt = 11;
+ break;
+ case 0x78: /* 7bits, even parity, 1 stop bit */
+ m_rxcnt = 10;
+ break;
+ case 0x7c: /* 8bits, even parity, 1 stop bit */
+ m_rxcnt = 11;
+ break;
+ case 0xc8: /* 7bits, no parity, 2 stop bits */
+ case 0xe8: /* 7bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ m_rxcnt = 10;
+ break;
+ case 0xcc: /* 8bits, no parity, 2 stop bits */
+ case 0xec: /* 8bits, no parity, 2 stop bits (parity select = 1 but parity is off) */
+ m_rxcnt = 11;
+ break;
+ case 0xd8: /* 7bits, odd parity, 2 stop bits */
+ m_rxcnt = 11;
+ break;
+ case 0xdc: /* 8bits, odd parity, 2 stop bits */
+ m_rxcnt = 12;
+ break;
+ case 0xf8: /* 7bits, even parity, 2 stop bits */
+ m_rxcnt = 11;
+ break;
+ case 0xfc: /* 8bits, even parity, 2 stop bits */
+ m_rxcnt = 12;
+ break;
+ }
+ }
+ else
+ /* TSK bit set ? */
+ if (SMH & 0x40)
+ {
+ m_rxcnt = 8;
+ }
+ }
+}
+
+void upd7810_device::upd7810_handle_timer0(int cycles, int clkdiv)
+{
+ OVC0 += cycles;
+ while (OVC0 >= clkdiv)
+ {
+ OVC0 -= clkdiv;
+ CNT0++;
+ if (CNT0 == TM0)
+ {
+ CNT0 = 0;
+ IRR |= INTFT0;
+ /* timer F/F source is timer 0 ? */
+ if (0x00 == (TMM & 0x03))
+ {
+ TO ^= 1;
+ m_to_func(TO);
+ }
+ /* timer 1 chained with timer 0 ? */
+ if ((TMM & 0xe0) == 0x60)
+ {
+ CNT1++;
+ if (CNT1 == TM1)
+ {
+ CNT1 = 0;
+ IRR |= INTFT1;
+ /* timer F/F source is timer 1 ? */
+ if (0x01 == (TMM & 0x03))
+ {
+ TO ^= 1;
+ m_to_func(TO);
+ }
+ }
+ }
+ }
+ }
+}
+
+void upd7810_device::upd7810_handle_timer1(int cycles, int clkdiv)
+{
+ OVC1 += cycles;
+ while (OVC1 >= clkdiv)
+ {
+ OVC1 -= clkdiv;
+ CNT1++;
+ if (CNT1 == TM1)
+ {
+ CNT1 = 0;
+ IRR |= INTFT1;
+ /* timer F/F source is timer 1 ? */
+ if (0x01 == (TMM & 0x03))
+ {
+ TO ^= 1;
+ m_to_func(TO);
+ }
+ }
+ }
+}
+
+void upd7810_device::handle_timers(int cycles)
+{
+ /**** TIMER 0 ****/
+ if (TMM & 0x10) /* timer 0 upcounter reset ? */
+ CNT0 = 0;
+ else
+ {
+ switch (TMM & 0x0c) /* timer 0 clock source */
+ {
+ case 0x00: /* clock divided by 12 */
+ upd7810_handle_timer0(cycles, 12);
+ break;
+ case 0x04: /* clock divided by 384 */
+ upd7810_handle_timer0(cycles, 384);
+ break;
+ case 0x08: /* external signal at TI */
+ break;
+ case 0x0c: /* disabled */
+ break;
+ }
+ }
+
+ /**** TIMER 1 ****/
+ if (TMM & 0x80) /* timer 1 upcounter reset ? */
+ CNT1 = 0;
+ else
+ {
+ switch (TMM & 0x60) /* timer 1 clock source */
+ {
+ case 0x00: /* clock divided by 12 */
+ upd7810_handle_timer1(cycles, 12);
+ break;
+ case 0x20: /* clock divided by 384 */
+ upd7810_handle_timer1(cycles, 384);
+ break;
+ case 0x40: /* external signal at TI */
+ break;
+ case 0x60: /* clocked with timer 0 */
+ break;
+ }
+ }
+
+ /**** TIMER F/F ****/
+ /* timer F/F source is clock divided by 3 ? */
+ if (0x02 == (TMM & 0x03))
+ {
+ OVCF += cycles;
+ while (OVCF >= 3)
+ {
+ TO ^= 1;
+ m_to_func(TO);
+ OVCF -= 3;
+ }
+ }
+
+ /**** ETIMER ****/
+ /* ECNT clear */
+ if (0x00 == (ETMM & 0x0c))
+ ECNT = 0;
+ else
+ if (0x00 == (ETMM & 0x03) || (0x01 == (ETMM & 0x03) && CI))
+ {
+ OVCE += cycles;
+ /* clock divided by 12 */
+ while (OVCE >= 12)
+ {
+ OVCE -= 12;
+ ECNT++;
+ /* Interrupt Control Circuit */
+ if (ETM0 == ECNT)
+ IRR |= INTFE0;
+ if (ETM1 == ECNT)
+ IRR |= INTFE1;
+ /* Conditions When ECNT Causes a CO0 Output Change */
+ if (((0x00 == (ETMM & 0x30)) && (ETM0 == ECNT)) || /* set CO0 if ECNT == ETM0 */
+ /* ((0x10 == (ETMM & 0x30)) prohibited */
+ ((0x20 == (ETMM & 0x30)) && (ETM0 == ECNT)) || /* set CO0 if ECNT == ETM0 or at falling CI input */
+ ((0x30 == (ETMM & 0x30)) && (ETM0 == ECNT || ETM1 == ECNT))) /* latch CO0 if ECNT == ETM0 or ECNT == ETM1 */
+ {
+ upd7810_co0_output_change();
+ }
+ /* Conditions When ECNT Causes a CO1 Output Change */
+ if (((0x00 == (ETMM & 0xc0)) && (ETM1 == ECNT)) || /* set CO1 if ECNT == ETM1 */
+ /* ((0x40 == (ETMM & 0xc0)) prohibited */
+ ((0x80 == (ETMM & 0xc0)) && (ETM1 == ECNT)) || /* set CO1 if ECNT == ETM1 or at falling CI input */
+ ((0xc0 == (ETMM & 0xc0)) && (ETM0 == ECNT || ETM1 == ECNT))) /* latch CO1 if ECNT == ETM0 or ECNT == ETM1 */
+ {
+ upd7810_co1_output_change();
+ }
+ /* How and When ECNT is Cleared */
+ switch (ETMM & 0x0c)
+ {
+ case 0x00: /* clear ECNT */
+ break;
+ case 0x04: /* free running */
+ if (0 == ECNT)
+ ITF |= INTOV; /* set overflow flag if counter wrapped */
+ break;
+ case 0x08: /* reset at falling edge of CI or TO */
+ break;
+ case 0x0c: /* reset if ECNT == ETM1 */
+ if (ETM1 == ECNT)
+ ECNT = 0;
+ break;
+ }
+ }
+ }
+
+ /**** SIO ****/
+ switch (SMH & 0x03)
+ {
+ case 0x00: /* interval timer F/F */
+ break;
+ case 0x01: /* internal clock divided by 384 */
+ OVCS += cycles;
+ while (OVCS >= 384)
+ {
+ OVCS -= 384;
+ if (0 == (EDGES ^= 1))
+ upd7810_sio_input();
+ else
+ upd7810_sio_output();
+ }
+ break;
+ case 0x02: /* internal clock divided by 24 */
+ OVCS += cycles;
+ while (OVCS >= 24)
+ {
+ OVCS -= 24;
+ if (0 == (EDGES ^= 1))
+ upd7810_sio_input();
+ else
+ upd7810_sio_output();
+ }
+ break;
+ }
+
+ /**** ADC ****/
+ m_adcnt += cycles;
+ if (PANM != ANM)
+ {
+ /* reset A/D converter */
+ m_adcnt = 0;
+ if (ANM & 0x10)
+ m_adtot = 144;
+ else
+ m_adtot = 192;
+ m_adout = 0;
+ m_shdone = 0;
+ if (ANM & 0x01)
+ {
+ /* select mode */
+ m_adin = (ANM >> 1) & 0x07;
+ }
+ else
+ {
+ /* scan mode */
+ m_adin = 0;
+ m_adrange = (ANM >> 1) & 0x04;
+ }
+ }
+ PANM = ANM;
+ if (ANM & 0x01)
+ {
+ /* select mode */
+ if (m_shdone == 0)
+ {
+ switch (m_adin)
+ {
+ case 0: m_tmpcr = m_an0_func(); break;
+ case 1: m_tmpcr = m_an1_func(); break;
+ case 2: m_tmpcr = m_an2_func(); break;
+ case 3: m_tmpcr = m_an3_func(); break;
+ case 4: m_tmpcr = m_an4_func(); break;
+ case 5: m_tmpcr = m_an5_func(); break;
+ case 6: m_tmpcr = m_an6_func(); break;
+ case 7: m_tmpcr = m_an7_func(); break;
+ }
+ m_shdone = 1;
+ }
+ if (m_adcnt > m_adtot)
+ {
+ m_adcnt -= m_adtot;
+ switch (m_adout)
+ {
+ case 0: CR0 = m_tmpcr; break;
+ case 1: CR1 = m_tmpcr; break;
+ case 2: CR2 = m_tmpcr; break;
+ case 3: CR3 = m_tmpcr; break;
+ }
+ m_adout = (m_adout + 1) & 0x03;
+ if (m_adout == 0)
+ IRR |= INTFAD;
+ m_shdone = 0;
+ }
+ }
+ else
+ {
+ /* scan mode */
+ if (m_shdone == 0)
+ {
+ switch (m_adin | m_adrange)
+ {
+ case 0: m_tmpcr = m_an0_func(); break;
+ case 1: m_tmpcr = m_an1_func(); break;
+ case 2: m_tmpcr = m_an2_func(); break;
+ case 3: m_tmpcr = m_an3_func(); break;
+ case 4: m_tmpcr = m_an4_func(); break;
+ case 5: m_tmpcr = m_an5_func(); break;
+ case 6: m_tmpcr = m_an6_func(); break;
+ case 7: m_tmpcr = m_an7_func(); break;
+ }
+ m_shdone = 1;
+ }
+ if (m_adcnt > m_adtot)
+ {
+ m_adcnt -= m_adtot;
+ switch (m_adout)
+ {
+ case 0: CR0 = m_tmpcr; break;
+ case 1: CR1 = m_tmpcr; break;
+ case 2: CR2 = m_tmpcr; break;
+ case 3: CR3 = m_tmpcr; break;
+ }
+ m_adin = (m_adin + 1) & 0x07;
+ m_adout = (m_adout + 1) & 0x03;
+ if (m_adout == 0)
+ IRR |= INTFAD;
+ m_shdone = 0;
+ }
+ }
+
+}
+
+void upd7801_device::handle_timers(int cycles)
+{
+ if ( m_ovc0 )
+ {
+ m_ovc0 -= cycles;
+
+ /* Check if timer expired */
+ if ( m_ovc0 <= 0 )
+ {
+ IRR |= INTFT0;
+
+ /* Reset the timer flip/fliop */
+ TO = 0;
+ m_to_func(TO);
+
+ /* Reload the timer */
+ m_ovc0 = 16 * ( TM0 + ( ( TM1 & 0x0f ) << 8 ) );
+ }
+ }
+}
+
+void upd78c05_device::handle_timers(int cycles)
+{
+ if ( m_ovc0 ) {
+ m_ovc0 -= cycles;
+
+ if ( m_ovc0 <= 0 ) {
+ IRR |= INTFT0;
+ if (0x00 == (TMM & 0x03)) {
+ TO ^= 1;
+ m_to_func(TO);
+ }
+
+ while ( m_ovc0 <= 0 ) {
+ m_ovc0 += ( ( TMM & 0x04 ) ? 16 * 8 : 8 ) * TM0;
+ }
+ }
+ }
+}
+
+void upd7810_device::base_device_start()
+{
+ m_program = &space(AS_PROGRAM);
+ m_direct = &m_program->direct();
+ m_io = &space(AS_IO);
+
+ m_to_func.resolve_safe();
+ m_co0_func.resolve_safe();
+ m_co1_func.resolve_safe();
+ m_txd_func.resolve_safe();
+ m_rxd_func.resolve_safe(0);
+ m_an0_func.resolve_safe(0);
+ m_an1_func.resolve_safe(0);
+ m_an2_func.resolve_safe(0);
+ m_an3_func.resolve_safe(0);
+ m_an4_func.resolve_safe(0);
+ m_an5_func.resolve_safe(0);
+ m_an6_func.resolve_safe(0);
+ m_an7_func.resolve_safe(0);
+
+ save_item(NAME(m_ppc.w.l));
+ save_item(NAME(m_pc.w.l));
+ save_item(NAME(m_sp.w.l));
+ save_item(NAME(m_psw));
+ save_item(NAME(m_op));
+ save_item(NAME(m_op2));
+ save_item(NAME(m_iff));
+ save_item(NAME(m_ea.w.l));
+ save_item(NAME(m_va.w.l));
+ save_item(NAME(m_bc.w.l));
+ save_item(NAME(m_de.w.l));
+ save_item(NAME(m_hl.w.l));
+ save_item(NAME(m_ea2.w.l));
+ save_item(NAME(m_va2.w.l));
+ save_item(NAME(m_bc2.w.l));
+ save_item(NAME(m_de2.w.l));
+ save_item(NAME(m_hl2.w.l));
+ save_item(NAME(m_cnt.d));
+ save_item(NAME(m_tm.d));
+ save_item(NAME(m_ecnt.d));
+ save_item(NAME(m_etm.d));
+ save_item(NAME(m_ma));
+ save_item(NAME(m_mb));
+ save_item(NAME(m_mcc));
+ save_item(NAME(m_mc));
+ save_item(NAME(m_mm));
+ save_item(NAME(m_mf));
+ save_item(NAME(m_tmm));
+ save_item(NAME(m_etmm));
+ save_item(NAME(m_eom));
+ save_item(NAME(m_sml));
+ save_item(NAME(m_smh));
+ save_item(NAME(m_anm));
+ save_item(NAME(m_mkl));
+ save_item(NAME(m_mkh));
+ save_item(NAME(m_zcm));
+ save_item(NAME(m_pa_out));
+ save_item(NAME(m_pb_out));
+ save_item(NAME(m_pc_out));
+ save_item(NAME(m_pd_out));
+ save_item(NAME(m_pf_out));
+ save_item(NAME(m_cr0));
+ save_item(NAME(m_cr1));
+ save_item(NAME(m_cr2));
+ save_item(NAME(m_cr3));
+ save_item(NAME(m_txb));
+ save_item(NAME(m_rxb));
+ save_item(NAME(m_txd));
+ save_item(NAME(m_rxd));
+ save_item(NAME(m_sck));
+ save_item(NAME(m_ti));
+ save_item(NAME(m_to));
+ save_item(NAME(m_ci));
+ save_item(NAME(m_lv0));
+ save_item(NAME(m_lv1));
+ save_item(NAME(m_co0));
+ save_item(NAME(m_co1));
+ save_item(NAME(m_irr));
+ save_item(NAME(m_itf));
+ save_item(NAME(m_ovc0));
+ save_item(NAME(m_ovc1));
+ save_item(NAME(m_ovcf));
+ save_item(NAME(m_ovcs));
+ save_item(NAME(m_edges));
+ save_item(NAME(m_nmi));
+ save_item(NAME(m_int1));
+ save_item(NAME(m_int2));
+
+ m_icountptr = &m_icount;
+}
+
+void upd7810_device::device_start()
+{
+ base_device_start();
+
+ state_add( UPD7810_PC, "PC", m_pc.w.l).formatstr("%04X");
+ state_add( UPD7810_SP, "SP", m_sp.w.l).formatstr("%04X");
+ state_add( UPD7810_PSW, "PSW", m_psw).formatstr("%02X");
+ state_add( UPD7810_A, "A", m_va.b.l).formatstr("%02X");
+ state_add( UPD7810_V, "V", m_va.b.h).formatstr("%02X");
+ state_add( UPD7810_EA, "EA", m_ea.w.l).formatstr("%04X");
+ state_add( UPD7810_BC, "BC", m_bc.w.l).formatstr("%04X");
+ state_add( UPD7810_DE, "DE", m_de.w.l).formatstr("%04X");
+ state_add( UPD7810_HL, "HL", m_hl.w.l).formatstr("%04X");
+ state_add( UPD7810_A2, "A'", m_va2.b.l).formatstr("%02X");
+ state_add( UPD7810_V2, "V'", m_va2.b.h).formatstr("%02X");
+ state_add( UPD7810_EA2, "EA'", m_ea2.w.l).formatstr("%04X");
+ state_add( UPD7810_BC2, "BC'", m_bc2.w.l).formatstr("%04X");
+ state_add( UPD7810_DE2, "DE'", m_de2.w.l).formatstr("%04X");
+ state_add( UPD7810_HL2, "HL'", m_hl2.w.l).formatstr("%04X");
+ state_add( UPD7810_CNT0, "CNT0", m_cnt.b.l).formatstr("%02X");
+ state_add( UPD7810_CNT1, "CNT1", m_cnt.b.h).formatstr("%02X");
+ state_add( UPD7810_TM0, "TM0", m_tm.b.l).formatstr("%02X");
+ state_add( UPD7810_TM1, "TM1", m_tm.b.h).formatstr("%02X");
+ state_add( UPD7810_ECNT, "ECNT", m_ecnt.w.l).formatstr("%04X");
+ state_add( UPD7810_ECPT, "ECPT", m_ecnt.w.h).formatstr("%04X");
+ state_add( UPD7810_ETM0, "ETM0", m_etm.w.l).formatstr("%04X");
+ state_add( UPD7810_ETM1, "ETM1", m_etm.w.h).formatstr("%04X");
+ state_add( UPD7810_MA, "MA", m_ma).formatstr("%02X");
+ state_add( UPD7810_MB, "MB", m_mb).formatstr("%02X");
+ state_add( UPD7810_MCC, "MCC", m_mcc).formatstr("%02X");
+ state_add( UPD7810_MC, "MC", m_mc).formatstr("%02X");
+ state_add( UPD7810_MM, "MM", m_mm).formatstr("%02X");
+ state_add( UPD7810_MF, "MF", m_mf).formatstr("%02X");
+ state_add( UPD7810_TMM, "TMM", m_tmm).formatstr("%02X");
+ state_add( UPD7810_ETMM, "ETMM", m_etmm).formatstr("%02X");
+ state_add( UPD7810_EOM, "EOM", m_eom).formatstr("%02X");
+ state_add( UPD7810_SML, "SML", m_sml).formatstr("%02X");
+ state_add( UPD7810_SMH, "SMH", m_smh).formatstr("%02X");
+ state_add( UPD7810_ANM, "ANM", m_anm).formatstr("%02X");
+ state_add( UPD7810_MKL, "MKL", m_mkl).formatstr("%02X");
+ state_add( UPD7810_MKH, "MKH", m_mkh).formatstr("%02X");
+ state_add( UPD7810_ZCM, "ZCM", m_zcm).formatstr("%02X");
+ state_add( UPD7810_CR0, "CR0", m_cr0).formatstr("%02X");
+ state_add( UPD7810_CR1, "CR1", m_cr1).formatstr("%02X");
+ state_add( UPD7810_CR2, "CR2", m_cr2).formatstr("%02X");
+ state_add( UPD7810_CR3, "CR3", m_cr3).formatstr("%02X");
+ state_add( UPD7810_RXB, "RXB", m_rxb).formatstr("%02X");
+ state_add( UPD7810_TXB, "TXB", m_txb).formatstr("%02X");
+ state_add( UPD7810_TXD, "TXD", m_txd).formatstr("%3u");
+ state_add( UPD7810_RXD, "RXD", m_rxd).formatstr("%3u");
+ state_add( UPD7810_SCK, "SCK", m_sck).formatstr("%3u");
+ state_add( UPD7810_TI, "TI", m_ti).formatstr("%3u");
+ state_add( UPD7810_TO, "TO", m_to).formatstr("%3u");
+ state_add( UPD7810_CI, "CI", m_ci).formatstr("%3u");
+ state_add( UPD7810_LV0, "LV0", m_lv0).formatstr("%3u");
+ state_add( UPD7810_LV1, "LV1", m_lv1).formatstr("%3u");
+ state_add( UPD7810_CO0, "CO0", m_co0).formatstr("%3u");
+ state_add( UPD7810_CO1, "CO1", m_co1).formatstr("%3u");
+
+ state_add( STATE_GENPC, "GENPC", m_pc.w.l ).formatstr("%04X").noshow();
+ state_add( STATE_GENPCBASE, "GENPCBASE", m_ppc.w.l ).formatstr("%04X").noshow();
+ state_add( STATE_GENSP, "GENSP", m_sp.w.l ).formatstr("%04X").noshow();
+ state_add( STATE_GENFLAGS, "GENFLAGS", m_psw ).formatstr("%17s").noshow();
+}
+
+void upd78c05_device::device_start()
+{
+ base_device_start();
+
+ state_add( UPD7810_PC, "PC", m_pc.w.l).formatstr("%04X");
+ state_add( UPD7810_SP, "SP", m_sp.w.l).formatstr("%04X");
+ state_add( UPD7810_PSW, "PSW", m_psw).formatstr("%02X");
+ state_add( UPD7810_A, "A", m_va.b.l).formatstr("%02X");
+ state_add( UPD7810_V, "V", m_va.b.h).formatstr("%02X");
+ state_add( UPD7810_EA, "EA", m_ea.w.l).formatstr("%04X");
+ state_add( UPD7810_BC, "BC", m_bc.w.l).formatstr("%04X");
+ state_add( UPD7810_DE, "DE", m_de.w.l).formatstr("%04X");
+ state_add( UPD7810_HL, "HL", m_hl.w.l).formatstr("%04X");
+ state_add( UPD7810_CNT0, "CNT0", m_cnt.b.l).formatstr("%02X");
+ state_add( UPD7810_CNT1, "CNT1", m_cnt.b.h).formatstr("%02X");
+ state_add( UPD7810_TM0, "TM0", m_tm.b.l).formatstr("%02X");
+ state_add( UPD7810_TM1, "TM1", m_tm.b.h).formatstr("%02X");
+ state_add( UPD7810_ECNT, "ECNT", m_ecnt.w.l).formatstr("%04X");
+ state_add( UPD7810_ECPT, "ECPT", m_ecnt.w.h).formatstr("%04X");
+ state_add( UPD7810_ETM0, "ETM0", m_etm.w.l).formatstr("%04X");
+ state_add( UPD7810_ETM1, "ETM1", m_etm.w.h).formatstr("%04X");
+ state_add( UPD7810_MB, "MB", m_mb).formatstr("%02X");
+ state_add( UPD7810_TMM, "TMM", m_tmm).formatstr("%02X");
+ state_add( UPD7810_MKL, "MKL", m_mkl).formatstr("%02X");
+
+ state_add( STATE_GENPC, "GENPC", m_pc.w.l ).formatstr("%04X").noshow();
+ state_add( STATE_GENPCBASE, "GENPCBASE", m_ppc.w.l ).formatstr("%04X").noshow();
+ state_add( STATE_GENSP, "GENSP", m_sp.w.l ).formatstr("%04X").noshow();
+ state_add( STATE_GENFLAGS, "GENFLAGS", m_psw ).formatstr("%17s").noshow();
+
+}
+
+void upd7810_device::state_string_export(const device_state_entry &entry, std::string &str)
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ strprintf(str, "%s:%s:%s:%s:%s:%s",
+ m_psw & 0x40 ? "ZF":"--",
+ m_psw & 0x20 ? "SK":"--",
+ m_psw & 0x10 ? "HC":"--",
+ m_psw & 0x08 ? "L1":"--",
+ m_psw & 0x04 ? "L0":"--",
+ m_psw & 0x01 ? "CY":"--");
+ break;
+ }
+}
+
+void upd7810_device::device_reset()
+{
+ m_ppc.d = 0;
+ m_pc.d = 0;
+ m_sp.d = 0;
+ m_op = 0;
+ m_op2 = 0;
+ m_iff = 0;
+ m_psw = 0;
+ m_ea.d = 0;
+ m_va.d = 0;
+ m_bc.d = 0;
+ m_de.d = 0;
+ m_hl.d = 0;
+ m_ea2.d = 0;
+ m_va2.d = 0;
+ m_bc2.d = 0;
+ m_de2.d = 0;
+ m_hl2.d = 0;
+ m_cnt.d = 0;
+ m_tm.d = 0;
+ m_ecnt.d = 0;
+ m_etm.d = 0;
+ m_ma = 0;
+ m_mb = 0;
+ m_mcc = 0;
+ m_mc = 0;
+ m_mm = 0;
+ m_mf = 0;
+ m_tmm = 0;
+ m_etmm = 0;
+ m_eom = 0;
+ m_sml = 0;
+ m_smh = 0;
+ m_anm = 0;
+ m_mkl = 0;
+ m_mkh = 0;
+ m_zcm = 0;
+ m_pa_in = 0;
+ m_pb_in = 0;
+ m_pc_in = 0;
+ m_pd_in = 0;
+ m_pf_in = 0;
+ m_pa_out = 0;
+ m_pb_out = 0;
+ m_pc_out = 0;
+ m_pd_out = 0;
+ m_pf_out = 0;
+ m_cr0 = 0;
+ m_cr1 = 0;
+ m_cr2 = 0;
+ m_cr3 = 0;
+ m_txb = 0;
+ m_rxb = 0;
+ m_txd = 0;
+ m_rxd = 0;
+ m_sck = 0;
+ m_ti = 0;
+ m_to = 0;
+ m_ci = 0;
+ m_lv0 = 0;
+ m_lv1 = 0;
+ m_co0 = 0;
+ m_co1 = 0;
+ m_irr = 0;
+ m_itf = 0;
+ m_nmi = 0;
+ m_int1 = 0;
+ m_int2 = 1; /* physical (inverted) INT2 line state */
+
+ m_txs = 0;
+ m_rxs = 0;
+ m_txcnt = 0;
+ m_rxcnt = 0;
+ m_txbuf = 0;
+ m_ovc0 = 0;
+ m_ovc1 = 0;
+ m_ovce = 0;
+ m_ovcf = 0;
+ m_ovcs = 0;
+ m_edges = 0;
+ m_adcnt = 0;
+ m_adtot = 0;
+ m_tmpcr = 0;
+ m_shdone = 0;
+ m_adout = 0;
+ m_adin = 0;
+ m_adrange = 0;
+
+ PANM = 0xff;
+ ETMM = 0xff;
+ TMM = 0xff;
+ MA = 0xff;
+ MB = 0xff;
+ MC = 0xff;
+ MF = 0xff;
+ MKL = 0xff;
+ MKH = 0xff; //?
+}
+
+void upd7801_device::device_reset()
+{
+ upd7810_device::device_reset();
+ MA = 0; /* Port A is output port on the uPD7801 */
+ m_ovc0 = 0;
+}
+
+void upd78c05_device::device_reset()
+{
+ upd7810_device::device_reset();
+ MA = 0; /* All outputs */
+ MC = 0xFF; /* All inputs */
+ V = 0xFF; /* The vector register is always pointing to FF00 */
+ TM0 = 0xFF; /* Timer seems to be running from boot */
+ m_ovc0 = ( ( TMM & 0x04 ) ? 16 * 8 : 8 ) * TM0;
+}
+
+void upd7810_device::execute_run()
+{
+ do
+ {
+ int cc = 0;
+
+ debugger_instruction_hook(this, PC);
+
+ PPC = PC;
+ RDOP(OP);
+
+ /*
+ * clear L0 and/or L1 flags for all opcodes except
+ * L0 for "MVI L,xx" or "LXI H,xxxx"
+ * L1 for "MVI A,xx"
+ */
+ PSW &= ~m_opXX[OP].mask_l0_l1;
+
+ /* skip flag set and not SOFTI opcode? */
+ if ((PSW & SK) && (OP != 0x72))
+ {
+ if (m_opXX[OP].cycles)
+ {
+ cc = m_opXX[OP].cycles_skip;
+ PC += m_opXX[OP].oplen - 1;
+ }
+ else
+ {
+ RDOP(OP2);
+ switch (OP)
+ {
+ case 0x48:
+ cc = m_op48[OP2].cycles_skip;
+ PC += m_op48[OP2].oplen - 2;
+ break;
+ case 0x4c:
+ cc = m_op4C[OP2].cycles_skip;
+ PC += m_op4C[OP2].oplen - 2;
+ break;
+ case 0x4d:
+ cc = m_op4D[OP2].cycles_skip;
+ PC += m_op4D[OP2].oplen - 2;
+ break;
+ case 0x60:
+ cc = m_op60[OP2].cycles_skip;
+ PC += m_op60[OP2].oplen - 2;
+ break;
+ case 0x64:
+ cc = m_op64[OP2].cycles_skip;
+ PC += m_op64[OP2].oplen - 2;
+ break;
+ case 0x70:
+ cc = m_op70[OP2].cycles_skip;
+ PC += m_op70[OP2].oplen - 2;
+ break;
+ case 0x74:
+ cc = m_op74[OP2].cycles_skip;
+ PC += m_op74[OP2].oplen - 2;
+ break;
+ default:
+ fatalerror("uPD7810 internal error: check cycle counts for main\n");
+ }
+ }
+ PSW &= ~SK;
+ handle_timers( cc );
+ }
+ else
+ {
+ cc = m_opXX[OP].cycles;
+ handle_timers( cc );
+ (this->*m_opXX[OP].opfunc)();
+ }
+ m_icount -= cc;
+ upd7810_take_irq();
+
+ } while (m_icount > 0);
+}
+
+void upd7801_device::execute_set_input(int irqline, int state)
+{
+ /* The uPD7801 can check for falling and rising edges changes on the INT2 input */
+ switch ( irqline )
+ {
+ case UPD7810_INTF0:
+ /* INT0 is level sensitive */
+ if ( state == ASSERT_LINE )
+ IRR |= INTF0;
+ else
+ IRR &= INTF0;
+ break;
+
+ case UPD7810_INTF1:
+ /* INT1 is rising edge sensitive */
+ if ( m_int1 == CLEAR_LINE && state == ASSERT_LINE )
+ IRR |= INTF1;
+
+ m_int1 = state;
+ break;
+
+ case UPD7810_INTF2:
+ /* INT2 is rising or falling edge sensitive */
+ /* Check if the ES bit is set then check for rising edge, otherwise falling edge */
+ if ( MKL & 0x20 )
+ {
+ if ( m_int2 == CLEAR_LINE && state == ASSERT_LINE )
+ {
+ IRR |= INTF2;
+ }
+ }
+ else
+ {
+ if ( m_int2 == ASSERT_LINE && state == CLEAR_LINE )
+ {
+ IRR |= INTF2;
+ }
+ }
+ m_int2 = state;
+ break;
+ }
+}
+
+void upd7810_device::execute_set_input(int irqline, int state)
+{
+ switch (irqline) {
+ case INPUT_LINE_NMI:
+ /* NMI is falling edge sensitive */
+ if ( m_nmi == CLEAR_LINE && state == ASSERT_LINE )
+ IRR |= INTNMI;
+
+ m_nmi = state;
+ break;
+ case UPD7810_INTF1:
+ /* INT1 is rising edge sensitive */
+ if ( m_int1 == CLEAR_LINE && state == ASSERT_LINE )
+ IRR |= INTF1;
+
+ m_int1 = state;
+ break;
+ case UPD7810_INTF2:
+ /* INT2 is falling edge sensitive */
+ /* we store the physical state (inverse of the logical state) */
+ /* to keep the handling of port C consistent with the upd7801 */
+ if ( (!m_int2) == CLEAR_LINE && state == ASSERT_LINE )
+ IRR |= INTF2;
+
+ m_int2 = !state;
+ break;
+ default:
+ logerror("upd7810_set_irq_line invalid irq line #%d\n", irqline);
+ break;
+ }
+ /* resetting interrupt requests is done with the SKIT/SKNIT opcodes only! */
+}