summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/mcs51/mcs51.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/mcs51/mcs51.cpp')
-rw-r--r--src/devices/cpu/mcs51/mcs51.cpp473
1 files changed, 339 insertions, 134 deletions
diff --git a/src/devices/cpu/mcs51/mcs51.cpp b/src/devices/cpu/mcs51/mcs51.cpp
index 2e963cec1b7..218e4640aa0 100644
--- a/src/devices/cpu/mcs51/mcs51.cpp
+++ b/src/devices/cpu/mcs51/mcs51.cpp
@@ -131,13 +131,18 @@
*/
#include "emu.h"
-#include "debugger.h"
#include "mcs51.h"
#include "mcs51dasm.h"
-#define VERBOSE 0
+#include <tuple>
+
+#define LOG_RX (1U << 1)
+#define LOG_TX (1U << 2)
+
+#define VERBOSE (0)
+
+#include "logmacro.h"
-#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
/***************************************************************************
CONSTANTS
@@ -224,6 +229,22 @@ enum
V_PFI = 0x02b /* Power Failure Interrupt */
};
+enum serial_state : u8
+{
+ SIO_IDLE,
+ SIO_START_LE,
+ SIO_START,
+ SIO_DATA0,
+ SIO_DATA1,
+ SIO_DATA2,
+ SIO_DATA3,
+ SIO_DATA4,
+ SIO_DATA5,
+ SIO_DATA6,
+ SIO_DATA7,
+ SIO_DATA8,
+ SIO_STOP,
+};
DEFINE_DEVICE_TYPE(I8031, i8031_device, "i8031", "Intel 8031")
DEFINE_DEVICE_TYPE(I8032, i8032_device, "i8032", "Intel 8032")
@@ -247,6 +268,9 @@ DEFINE_DEVICE_TYPE(DS80C320, ds80c320_device, "ds80c320", "Dallas DS80C320 HSM")
DEFINE_DEVICE_TYPE(SAB80C535, sab80c535_device, "sab80c535", "Siemens SAB80C535")
DEFINE_DEVICE_TYPE(I8344, i8344_device, "i8344", "Intel 8344AH RUPI-44")
DEFINE_DEVICE_TYPE(I8744, i8744_device, "i8744", "Intel 8744H RUPI-44")
+DEFINE_DEVICE_TYPE(P80C552, p80c552_device, "p80c552", "Philips P80C552")
+DEFINE_DEVICE_TYPE(P87C552, p87c552_device, "p87c552", "Philips P87C552")
+DEFINE_DEVICE_TYPE(P80C562, p80c562_device, "p80c562", "Philips P80C562")
DEFINE_DEVICE_TYPE(DS5002FP, ds5002fp_device, "ds5002fp", "Dallas DS5002FP")
@@ -268,10 +292,10 @@ void mcs51_cpu_device::data_internal(address_map &map)
-mcs51_cpu_device::mcs51_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int program_width, int data_width, uint8_t features)
+mcs51_cpu_device::mcs51_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor program_map, address_map_constructor data_map, int program_width, int data_width, uint8_t features)
: cpu_device(mconfig, type, tag, owner, clock)
- , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0, address_map_constructor(FUNC(mcs51_cpu_device::program_internal), this))
- , m_data_config("data", ENDIANNESS_LITTLE, 8, 9, 0, address_map_constructor(FUNC(mcs51_cpu_device::data_internal), this))
+ , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0, program_map)
+ , m_data_config("data", ENDIANNESS_LITTLE, 8, 9, 0, data_map)
, m_io_config("io", ENDIANNESS_LITTLE, 8, (features & FEATURE_DS5002FP) ? 17 : 16, 0)
, m_pc(0)
, m_features(features)
@@ -280,10 +304,8 @@ mcs51_cpu_device::mcs51_cpu_device(const machine_config &mconfig, device_type ty
, m_num_interrupts(5)
, m_sfr_ram(*this, "sfr_ram")
, m_scratchpad(*this, "scratchpad")
- , m_port_in_cb(*this)
+ , m_port_in_cb(*this, 0xff)
, m_port_out_cb(*this)
- , m_serial_tx_cb(*this)
- , m_serial_rx_cb(*this)
, m_rtemp(0)
{
m_ds5002fp.mcon = 0;
@@ -296,6 +318,12 @@ mcs51_cpu_device::mcs51_cpu_device(const machine_config &mconfig, device_type ty
}
+mcs51_cpu_device::mcs51_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int program_width, int data_width, uint8_t features)
+ : mcs51_cpu_device(mconfig, type, tag, owner, clock, address_map_constructor(FUNC(mcs51_cpu_device::program_internal), this), address_map_constructor(FUNC(mcs51_cpu_device::data_internal), this), program_width, data_width, features)
+{
+}
+
+
i8031_device::i8031_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mcs51_cpu_device(mconfig, I8031, tag, owner, clock, 0, 7)
{
@@ -429,6 +457,26 @@ i8744_device::i8744_device(const machine_config &mconfig, const char *tag, devic
{
}
+p80c562_device::p80c562_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int program_width, int data_width, uint8_t features)
+ : i80c51_device(mconfig, type, tag, owner, clock, program_width, data_width, features)
+{
+}
+
+p80c562_device::p80c562_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : p80c562_device(mconfig, P80C562, tag, owner, clock, 0, 8)
+{
+}
+
+p80c552_device::p80c552_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : p80c562_device(mconfig, P80C552, tag, owner, clock, 0, 8)
+{
+}
+
+p87c552_device::p87c552_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : p80c562_device(mconfig, P87C552, tag, owner, clock, 12, 8)
+{
+}
+
/* program width field is set to 0 because technically the SRAM isn't internal */
ds5002fp_device::ds5002fp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mcs51_cpu_device(mconfig, DS5002FP, tag, owner, clock, 0, 7, FEATURE_DS5002FP | FEATURE_CMOS)
@@ -792,7 +840,7 @@ void mcs51_cpu_device::clear_current_irq()
m_cur_irq_prio = 0;
else
m_cur_irq_prio = -1;
- LOG(("New: %d %02x\n", m_cur_irq_prio, m_irq_active));
+ LOG("New: %d %02x\n", m_cur_irq_prio, m_irq_active);
}
uint8_t mcs51_cpu_device::r_acc() { return SFR_A(ADDR_ACC); }
@@ -992,19 +1040,65 @@ void mcs51_cpu_device::do_sub_flags(uint8_t a, uint8_t data, uint8_t c)
SET_OV((result1 < -128 || result1 > 127));
}
+void mcs51_cpu_device::transmit(int state)
+{
+ if (BIT(SFR_A(ADDR_P3), 1) != state)
+ {
+ if (state)
+ SFR_A(ADDR_P3) |= 1U << 1;
+ else
+ SFR_A(ADDR_P3) &= ~(1U << 1);
+
+ m_port_out_cb[3](SFR_A(ADDR_P3));
+ }
+}
+
void mcs51_cpu_device::transmit_receive(int source)
{
int mode = (GET_SM0<<1) | GET_SM1;
if (source == 1) /* timer1 */
- m_uart.smod_div = (m_uart.smod_div + 1) & (2-GET_SMOD);
+ m_uart.smod_div = (m_uart.smod_div + 1) & (1-GET_SMOD);
switch(mode) {
- //8 bit shifter ( + start,stop bit ) - baud set by clock freq / 12
+ // 8 bit shifter - rate set by clock freq / 12
case 0:
- m_uart.rx_clk += (source == 0) ? 16 : 0; /* clock / 12 */
- m_uart.tx_clk += (source == 0) ? 16 : 0; /* clock / 12 */
- break;
+ if (source == 0)
+ {
+ // TODO: mode 0 serial input is unemulated
+ // FIXME: output timing is highly simplified and incorrect
+ switch (m_uart.txbit)
+ {
+ case SIO_IDLE:
+ break;
+ case SIO_START:
+ SFR_A(ADDR_P3) |= 0x03;
+ m_port_out_cb[3](SFR_A(ADDR_P3));
+ m_uart.txbit = SIO_DATA0;
+ break;
+ case SIO_DATA0: case SIO_DATA1: case SIO_DATA2: case SIO_DATA3:
+ case SIO_DATA4: case SIO_DATA5: case SIO_DATA6: case SIO_DATA7:
+ SFR_A(ADDR_P3) &= ~0x03;
+ if (BIT(m_uart.data_out, m_uart.txbit - SIO_DATA0))
+ SFR_A(ADDR_P3) |= 1U << 0;
+ m_port_out_cb[3](SFR_A(ADDR_P3));
+
+ if (m_uart.txbit == SIO_DATA7)
+ {
+ SET_TI(1);
+ m_uart.txbit = SIO_STOP;
+ }
+ else
+ m_uart.txbit++;
+ break;
+ case SIO_STOP:
+ SFR_A(ADDR_P3) |= 0x03;
+ m_port_out_cb[3](SFR_A(ADDR_P3));
+ m_uart.txbit = SIO_IDLE;
+ break;
+ }
+ }
+ return;
//8 bit uart ( + start,stop bit ) - baud set by timer1 or timer2
case 1:
case 3:
@@ -1025,39 +1119,139 @@ void mcs51_cpu_device::transmit_receive(int source)
m_uart.tx_clk += (source == 0) ? (GET_SMOD ? 6 : 3) : 0; /* clock / 12 */
break;
}
- /* transmit ? */
+
+ // transmit
if (m_uart.tx_clk >= 16)
{
m_uart.tx_clk &= 0x0f;
- if(m_uart.bits_to_send)
+
+ switch (m_uart.txbit)
{
- m_uart.bits_to_send--;
- if(m_uart.bits_to_send == 0) {
- //Call the callback function
- m_serial_tx_cb(0, m_uart.data_out, 0xff);
- //Set Interrupt Flag
- SET_TI(1);
- }
+ case SIO_IDLE:
+ transmit(1);
+ break;
+ case SIO_START:
+ LOGMASKED(LOG_TX, "tx start bit (%s)\n", machine().time().to_string());
+ transmit(0);
+ m_uart.txbit = SIO_DATA0;
+ break;
+ case SIO_DATA0: case SIO_DATA1: case SIO_DATA2: case SIO_DATA3:
+ case SIO_DATA4: case SIO_DATA5: case SIO_DATA6: case SIO_DATA7:
+ LOGMASKED(LOG_TX, "tx bit %d data %d (%s)\n", m_uart.txbit - SIO_DATA0, BIT(m_uart.data_out, m_uart.txbit - SIO_DATA0), machine().time().to_string());
+ transmit(BIT(m_uart.data_out, m_uart.txbit - SIO_DATA0));
+
+ // mode 1 has no data8/parity bit
+ if (mode == 1 && m_uart.txbit == SIO_DATA7)
+ m_uart.txbit = SIO_STOP;
+ else
+ m_uart.txbit++;
+ break;
+ case SIO_DATA8: // data8/parity bit
+ LOGMASKED(LOG_TX, "tx bit %d data %d (%s)\n", m_uart.txbit - SIO_DATA0, GET_TB8, machine().time().to_string());
+ transmit(GET_TB8);
+ m_uart.txbit = SIO_STOP;
+ break;
+ case SIO_STOP:
+ LOGMASKED(LOG_TX, "tx stop bit (%s)\n", machine().time().to_string());
+ transmit(1);
+ SET_TI(1);
+ m_uart.txbit = SIO_IDLE;
+ break;
}
-
}
- /* receive */
- if (m_uart.rx_clk >= 16)
+
+ // receive
+ if (m_uart.rx_clk >= 16 || m_uart.rxbit < SIO_START)
{
m_uart.rx_clk &= 0x0f;
- if (m_uart.delay_cycles>0)
+
+ if (GET_REN)
{
- m_uart.delay_cycles--;
- if (m_uart.delay_cycles == 0)
+ // directly read RXD input
+ int const data = BIT(m_port_in_cb[3](), 0);
+
+ switch (m_uart.rxbit)
{
- int data = 0;
- //Call our callball function to retrieve the data
- data = m_serial_rx_cb(0, 0xff);
- LOG(("RX Deliver %d\n", data));
- SET_SBUF(data);
- //Flag the IRQ
- SET_RI(1);
- SET_RB8(1); // HACK force 2nd stop bit
+ case SIO_IDLE:
+ if (data)
+ m_uart.rxbit = SIO_START_LE;
+ break;
+ case SIO_START_LE: // start bit leading edge
+ if (!data)
+ {
+ LOGMASKED(LOG_RX, "rx start leading edge (%s)\n", machine().time().to_string());
+ m_uart.rxbit = SIO_START;
+ m_uart.rx_clk = 8;
+ }
+ break;
+ case SIO_START:
+ if (!data)
+ {
+ LOGMASKED(LOG_RX, "rx start bit (%s)\n", machine().time().to_string());
+
+ m_uart.data_in = 0;
+ m_uart.rxbit = SIO_DATA0;
+ }
+ else
+ // false start bit
+ m_uart.rxbit = SIO_START_LE;
+ break;
+ case SIO_DATA0: case SIO_DATA1: case SIO_DATA2: case SIO_DATA3:
+ case SIO_DATA4: case SIO_DATA5: case SIO_DATA6: case SIO_DATA7:
+ LOGMASKED(LOG_RX, "rx bit %d data %d (%s)\n", m_uart.rxbit - SIO_DATA0, data, machine().time().to_string());
+ if (data)
+ m_uart.data_in |= 1U << (m_uart.rxbit - SIO_DATA0);
+
+ // mode 1 has no data8/parity bit
+ if (mode == 1 && m_uart.rxbit == SIO_DATA7)
+ m_uart.rxbit = SIO_STOP;
+ else
+ m_uart.rxbit++;
+ break;
+ case SIO_DATA8: // data8/parity bit
+ LOGMASKED(LOG_RX, "rx bit %d data %d (%s)\n", m_uart.rxbit - SIO_DATA0, data, machine().time().to_string());
+ m_uart.rxb8 = data;
+ m_uart.rxbit = SIO_STOP;
+ break;
+ case SIO_STOP:
+ if (!GET_RI)
+ {
+ switch (mode)
+ {
+ case 1:
+ LOGMASKED(LOG_RX, "rx byte 0x%02x stop %d (%s)\n", m_uart.data_in, data, machine().time().to_string());
+ SET_SBUF(m_uart.data_in);
+ if (!GET_SM2)
+ {
+ // RB8 contains stop bit
+ SET_RB8(data);
+ SET_RI(1);
+ }
+ else if (data)
+ // RI if valid stop bit
+ SET_RI(1);
+ break;
+ case 2:
+ case 3:
+ LOGMASKED(LOG_RX, "rx byte 0x%02x RB8 %d stop %d (%s)\n", m_uart.data_in, m_uart.rxb8, data, machine().time().to_string());
+ SET_SBUF(m_uart.data_in);
+ SET_RB8(m_uart.rxb8);
+
+ // no RI if SM2 && !RB8
+ if (!GET_SM2 || GET_RB8)
+ SET_RI(1);
+ break;
+ }
+ }
+ else
+ LOGMASKED(LOG_RX, "rx overrun discarding data 0x%02x\n", m_uart.data_in);
+
+ // next state depends on stop bit validity
+ if (data)
+ m_uart.rxbit = SIO_START_LE;
+ else
+ m_uart.rxbit = SIO_IDLE;
+ break;
}
}
}
@@ -1320,56 +1514,6 @@ void mcs51_cpu_device::update_timers(int cycles)
}
}
-//Set up to transmit data out of serial port
-//NOTE: Enable Serial Port Interrupt bit is NOT required to send/receive data!
-
-void mcs51_cpu_device::serial_transmit(uint8_t data)
-{
- int mode = (GET_SM0<<1) | GET_SM1;
-
- //Flag that we're sending data
- m_uart.data_out = data;
- LOG(("serial_transmit: %x %x\n", mode, data));
- switch(mode) {
- //8 bit shifter ( + start,stop bit ) - baud set by clock freq / 12
- case 0:
- m_uart.bits_to_send = 8+2;
- break;
- //8 bit uart ( + start,stop bit ) - baud set by timer1 or timer2
- case 1:
- m_uart.bits_to_send = 8+2;
- break;
- //9 bit uart
- case 2:
- case 3:
- m_uart.bits_to_send = 8+3;
- break;
- }
-}
-
-void mcs51_cpu_device::serial_receive()
-{
- int mode = (GET_SM0<<1) | GET_SM1;
-
- if (GET_REN) {
- switch(mode) {
- //8 bit shifter ( + start,stop bit ) - baud set by clock freq / 12
- case 0:
- m_uart.delay_cycles = 8+2;
- break;
- //8 bit uart ( + start,stop bit ) - baud set by timer1 or timer2
- case 1:
- m_uart.delay_cycles = 8+2;
- break;
- //9 bit uart
- case 2:
- case 3:
- m_uart.delay_cycles = 8+3;
- break;
- }
- }
-}
-
/* Check and update status of serial port */
void mcs51_cpu_device::update_serial(int cycles)
{
@@ -1814,16 +1958,28 @@ void mcs51_cpu_device::check_irqs()
/* Skip the interrupt request if currently processing interrupt
* and the new request does not have a higher priority
*/
- LOG(("Request: %d\n", priority_request));
+ LOG("Request: %d\n", priority_request);
if (m_irq_active && (priority_request <= m_cur_irq_prio))
{
- LOG(("higher or equal priority irq (%u) in progress already, skipping ...\n", m_cur_irq_prio));
+ LOG("higher or equal priority irq (%u) in progress already, skipping ...\n", m_cur_irq_prio);
return;
}
- // Hack to work around polling latency issue with JB INT0/INT1
- if (m_last_op == 0x20 && ((int_vec == V_IE0 && m_last_bit == 0xb2) || (int_vec == V_IE1 && m_last_bit == 0xb3)))
- PC = PPC + 3;
+ // indicate we took the external IRQ
+ if (int_vec == V_IE0)
+ {
+ // Hack to work around polling latency issue with JB INT0
+ if (m_last_op == 0x20 && m_last_bit == 0xb2)
+ PC = PPC + 3;
+ standard_irq_callback(0, PC);
+ }
+ else if (int_vec == V_IE1)
+ {
+ // Hack to work around polling latency issue with JB INT1
+ if (m_last_op == 0x20 && m_last_bit == 0xb3)
+ PC = PPC + 3;
+ standard_irq_callback(1, PC);
+ }
//Save current pc to stack, set pc to new interrupt vector
push_pc();
@@ -1836,7 +1992,7 @@ void mcs51_cpu_device::check_irqs()
m_cur_irq_prio = priority_request;
m_irq_active |= (1 << priority_request);
- LOG(("Take: %d %02x\n", m_cur_irq_prio, m_irq_active));
+ LOG("Take: %d %02x\n", m_cur_irq_prio, m_irq_active);
//Clear any interrupt flags that should be cleared since we're servicing the irq!
switch(int_vec) {
@@ -1844,10 +2000,6 @@ void mcs51_cpu_device::check_irqs()
//External Int Flag only cleared when configured as Edge Triggered..
if(GET_IT0) /* for some reason having this, breaks alving dmd games */
SET_IE0(0);
-
- /* indicate we took the external IRQ */
- standard_irq_callback(0);
-
break;
case V_TF0:
//Timer 0 - Always clear Flag
@@ -1857,9 +2009,6 @@ void mcs51_cpu_device::check_irqs()
//External Int Flag only cleared when configured as Edge Triggered..
if(GET_IT1) /* for some reason having this, breaks alving dmd games */
SET_IE1(0);
- /* indicate we took the external IRQ */
- standard_irq_callback(1);
-
break;
case V_TF1:
//Timer 1 - Always clear Flag
@@ -1984,14 +2133,6 @@ void mcs51_cpu_device::execute_set_input(int irqline, int state)
fatalerror("mcs51: Trying to set T2EX_LINE on a non I8052 type cpu.\n");
break;
- case MCS51_RX_LINE: /* Serial Port Receive */
- /* Is the enable flags for this interrupt set? */
- if (state != CLEAR_LINE)
- {
- serial_receive();
- }
- break;
-
/* Power Fail Interrupt */
case DS5002FP_PFI_LINE:
if (m_features & FEATURE_DS5002FP)
@@ -2059,8 +2200,13 @@ void mcs51_cpu_device::execute_run()
/* decrement the timed access window */
if (m_features & FEATURE_DS5002FP)
+ {
m_ds5002fp.ta_window = (m_ds5002fp.ta_window ? (m_ds5002fp.ta_window - 1) : 0x00);
+ if (m_ds5002fp.rnr_delay > 0)
+ m_ds5002fp.rnr_delay-=m_inst_cycles;
+ }
+
/* If the chip entered in idle mode, end the loop */
if ((m_features & FEATURE_CMOS) && GET_IDL)
return;
@@ -2084,12 +2230,14 @@ void mcs51_cpu_device::sfr_write(size_t offset, uint8_t data)
case ADDR_P1: m_port_out_cb[1](data); break;
case ADDR_P2: m_port_out_cb[2](data); break;
case ADDR_P3: m_port_out_cb[3](data); break;
- case ADDR_SBUF: serial_transmit(data); break;
+ case ADDR_SBUF:
+ LOGMASKED(LOG_TX, "tx byte 0x%02x\n", data);
+ m_uart.data_out = data;
+ m_uart.txbit = SIO_START;
+ break;
case ADDR_PSW: SET_PARITY(); break;
case ADDR_ACC: SET_PARITY(); break;
case ADDR_IP: update_irq_prio(data, 0); break;
- /* R_SBUF = data; //This register is used only for "Receiving data coming in!" */
-
case ADDR_B:
case ADDR_SP:
case ADDR_DPL:
@@ -2102,10 +2250,18 @@ void mcs51_cpu_device::sfr_write(size_t offset, uint8_t data)
case ADDR_TL1:
case ADDR_TH0:
case ADDR_TH1:
+ break;
case ADDR_SCON:
+ if (!GET_REN && BIT(data, 4))
+ {
+ LOGMASKED(LOG_RX, "rx enabled SCON 0x%02x\n", data);
+ if (!BIT(data, 6, 2))
+ logerror("mode 0 serial input is not emulated\n");
+ m_uart.rxbit = SIO_IDLE;
+ }
break;
default:
- LOG(("mcs51 '%s': attemping to write to an invalid/non-implemented SFR address: %x at 0x%04x, data=%x\n", tag(), (uint32_t)offset,PC,data));
+ LOG("attemping to write to an invalid/non-implemented SFR address: %x at 0x%04x, data=%x\n", (uint32_t)offset,PC,data);
/* no write in this case according to manual */
return;
}
@@ -2147,7 +2303,7 @@ uint8_t mcs51_cpu_device::sfr_read(size_t offset)
return m_data.read_byte((size_t) offset | 0x100);
/* Illegal or non-implemented sfr */
default:
- LOG(("mcs51 '%s': attemping to read an invalid/non-implemented SFR address: %x at 0x%04x\n", tag(), (uint32_t)offset,PC));
+ LOG("attemping to read an invalid/non-implemented SFR address: %x at 0x%04x\n", (uint32_t)offset,PC);
/* according to the manual, the read may return random bits */
return 0xff;
}
@@ -2160,11 +2316,6 @@ void mcs51_cpu_device::device_start()
space(AS_DATA).specific(m_data);
space(AS_IO).specific(m_io);
- m_port_in_cb.resolve_all_safe(0xff);
- m_port_out_cb.resolve_all_safe();
- m_serial_rx_cb.resolve_safe(0);
- m_serial_tx_cb.resolve_safe();
-
/* Save states */
save_item(NAME(m_ppc));
save_item(NAME(m_pc));
@@ -2182,13 +2333,13 @@ void mcs51_cpu_device::device_start()
save_item(NAME(m_irq_active) );
save_item(NAME(m_ds5002fp.previous_ta) );
save_item(NAME(m_ds5002fp.ta_window) );
+ save_item(NAME(m_ds5002fp.rnr_delay) );
save_item(NAME(m_ds5002fp.range) );
save_item(NAME(m_uart.data_out));
- save_item(NAME(m_uart.bits_to_send));
+ save_item(NAME(m_uart.data_in));
save_item(NAME(m_uart.smod_div));
save_item(NAME(m_uart.rx_clk));
save_item(NAME(m_uart.tx_clk));
- save_item(NAME(m_uart.delay_cycles));
state_add( MCS51_PC, "PC", m_pc).formatstr("%04X");
state_add( MCS51_SP, "SP", SP).formatstr("%02X");
@@ -2326,13 +2477,16 @@ void mcs51_cpu_device::device_reset()
m_ds5002fp.previous_ta = 0;
m_ds5002fp.ta_window = 0;
m_ds5002fp.range = (GET_RG1 << 1) | GET_RG0;
+ m_ds5002fp.rnr_delay = 160;
}
m_uart.data_out = 0;
+ m_uart.data_in = 0;
m_uart.rx_clk = 0;
m_uart.tx_clk = 0;
- m_uart.bits_to_send = 0;
- m_uart.delay_cycles = 0;
+ m_uart.txbit = SIO_IDLE;
+ m_uart.rxbit = SIO_IDLE;
+ m_uart.rxb8 = 0;
m_uart.smod_div = 0;
m_recalc_parity = 0;
@@ -2424,8 +2578,8 @@ uint8_t i80c52_device::sfr_read(size_t offset)
****************************************************************************/
-#define DS5_LOGW(a, d) LOG(("ds5002fp '%s': write to " # a " register at 0x%04x, data=%x\n", tag(), PC, d))
-#define DS5_LOGR(a, d) LOG(("ds5002fp '%s': read from " # a " register at 0x%04x\n", tag(), PC))
+#define DS5_LOGW(a, d) LOG("write to " # a " register at 0x%04x, data=%x\n", PC, d)
+#define DS5_LOGR(a, d) LOG("read from " # a " register at 0x%04x\n", PC)
uint8_t mcs51_cpu_device::ds5002fp_protected(size_t offset, uint8_t data, uint8_t ta_mask, uint8_t mask)
{
@@ -2450,7 +2604,7 @@ void ds5002fp_device::sfr_write(size_t offset, uint8_t data)
if ((data == 0xaa) && (m_ds5002fp.ta_window == 0))
{
m_ds5002fp.ta_window = 6; /* 4*12 + 2*12 */
- LOG(("ds5002fp '%s': TA window initiated at 0x%04x\n", tag(), PC));
+ LOG("TA window initiated at 0x%04x\n", PC);
}
break;
case ADDR_MCON: data = ds5002fp_protected(ADDR_MCON, data, 0x0f, 0xf7); DS5_LOGW(MCON, data); break;
@@ -2469,6 +2623,26 @@ void ds5002fp_device::sfr_write(size_t offset, uint8_t data)
m_data.write_byte((size_t) offset | 0x100, data);
}
+
+uint8_t ds5002fp_device::handle_rnr()
+{
+ if (m_ds5002fp.rnr_delay <= 0)
+ {
+ m_ds5002fp.rnr_delay = 160; // delay before another random number can be read
+ return machine().rand();
+ }
+ else
+ return 0x00;
+}
+
+bool ds5002fp_device::is_rnr_ready()
+{
+ if (m_ds5002fp.rnr_delay <= 0)
+ return true;
+ else
+ return false;
+}
+
uint8_t ds5002fp_device::sfr_read(size_t offset)
{
switch (offset)
@@ -2478,8 +2652,10 @@ uint8_t ds5002fp_device::sfr_read(size_t offset)
case ADDR_CRCH: DS5_LOGR(CRCH, data); break;
case ADDR_MCON: DS5_LOGR(MCON, data); break;
case ADDR_TA: DS5_LOGR(TA, data); break;
- case ADDR_RNR: DS5_LOGR(RNR, data); break;
- case ADDR_RPCTL: DS5_LOGR(RPCTL, data); return 0x80; break; /* touchgo stalls unless bit 7 is set, why? documentation is unclear */
+ case ADDR_RNR: DS5_LOGR(RNR, data);
+ return handle_rnr();
+ case ADDR_RPCTL: DS5_LOGR(RPCTL, data); /* touchgo stalls unless bit 7 is set, RNR status (Random Number status) */
+ return (is_rnr_ready() ? 0x80 : 0x00); /* falling through to sfr_read for the remaining bits stops high score data loading? */
case ADDR_RPS: DS5_LOGR(RPS, data); break;
case ADDR_PCON:
SET_PFW(0); /* reset PFW flag */
@@ -2522,16 +2698,30 @@ void ds5002fp_device::nvram_default()
}
}
-void ds5002fp_device::nvram_read( emu_file &file )
+bool ds5002fp_device::nvram_read(util::read_stream &file)
{
- file.read( m_scratchpad, 0x80 );
- file.read( m_sfr_ram, 0x80 );
+ std::error_condition err;
+ size_t actual;
+ std::tie(err, actual) = read(file, m_scratchpad, 0x80);
+ if (err || (actual != 0x80))
+ return false;
+ std::tie(err, actual) = read(file, m_sfr_ram, 0x80);
+ if (err || (actual != 0x80))
+ return false;
+ return true;
}
-void ds5002fp_device::nvram_write( emu_file &file )
+bool ds5002fp_device::nvram_write(util::write_stream &file)
{
- file.write( m_scratchpad, 0x80 );
- file.write( m_sfr_ram, 0x80 );
+ std::error_condition err;
+ size_t actual;
+ std::tie(err, actual) = write(file, m_scratchpad, 0x80);
+ if (err || (actual != 0x80))
+ return false;
+ std::tie(err, actual) = write(file, m_sfr_ram, 0x80);
+ if (err || (actual != 0x80))
+ return false;
+ return true;
}
std::unique_ptr<util::disasm_interface> mcs51_cpu_device::create_disassembler()
@@ -2593,3 +2783,18 @@ std::unique_ptr<util::disasm_interface> ds5002fp_device::create_disassembler()
{
return std::make_unique<ds5002fp_disassembler>();
}
+
+std::unique_ptr<util::disasm_interface> p80c562_device::create_disassembler()
+{
+ return std::make_unique<p8xc562_disassembler>();
+}
+
+std::unique_ptr<util::disasm_interface> p80c552_device::create_disassembler()
+{
+ return std::make_unique<p8xc552_disassembler>();
+}
+
+std::unique_ptr<util::disasm_interface> p87c552_device::create_disassembler()
+{
+ return std::make_unique<p8xc552_disassembler>();
+}