summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/es5510/es5510.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/es5510/es5510.c')
-rw-r--r--src/devices/cpu/es5510/es5510.c1226
1 files changed, 1226 insertions, 0 deletions
diff --git a/src/devices/cpu/es5510/es5510.c b/src/devices/cpu/es5510/es5510.c
new file mode 100644
index 00000000000..77b88b5d861
--- /dev/null
+++ b/src/devices/cpu/es5510/es5510.c
@@ -0,0 +1,1226 @@
+// license:BSD-3-Clause
+// copyright-holders:Christian Brunschen
+/***************************************************************************
+ *
+ * es5510.c - Ensoniq ES5510 (ESP) emulation
+ * by Christian Brunschen
+ *
+ ***************************************************************************/
+
+#include <cstdio>
+#include "emu.h"
+#include "debugger.h"
+#include "es5510.h"
+#include "cpu/m68000/m68000.h"
+
+static const INT32 MIN_24 = -(1 << 23);
+static const INT32 MAX_24 = (1 << 23) - 1;
+
+static const INT64 MIN_48 = -(S64(1) << 47);
+static const INT64 MAX_48 = (S64(1) << 47) - 1;
+
+#define SIGN_BIT_24 (0x00800000)
+#define GET_SIGN_BIT_24(x) ((x) & SIGN_BIT_24)
+#define IS_NEGATIVE(x) (((x) & SIGN_BIT_24) != 0)
+
+#define CARRY_OUT_24 (0x01000000)
+
+static inline INT32 SX(INT32 x) { return IS_NEGATIVE(x) ? x | 0xff000000 : x & 0x00ffffff; }
+static inline INT32 SC(INT32 x) { return x & 0x00ffffff; }
+static inline INT64 SX64(INT64 x) { return (x & S64(0x0000800000000000)) ? x | S64(0xffff000000000000) : x & S64(0x0000ffffffffffff); }
+//static inline INT64 SC64(INT64 x) { return x & S64(0x0000ffffffffffff); }
+
+#define VERBOSE 0
+#define VERBOSE_EXEC 0
+
+#if VERBOSE
+INLINE void ATTR_PRINTF(1,2) log_to_stderr(const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+}
+
+#define LOG(x) do { log_to_stderr x; } while(0)
+#else
+#define LOG(x)
+#endif
+
+
+#if VERBOSE_EXEC
+static int exec_cc = 0;
+#define LOG_EXEC(x) do { if (!exec_cc) LOG(x); } while(0)
+#else
+#define LOG_EXEC(x)
+#endif
+
+const device_type ES5510 = &device_creator<es5510_device>;
+
+#define FLAG_N (1 << 7)
+#define FLAG_C (1 << 6)
+#define FLAG_V (1 << 5)
+#define FLAG_LT (1 << 4)
+#define FLAG_Z (1 << 3)
+#define FLAG_NOT (1 << 2)
+
+#define FLAG_MASK (FLAG_N | FLAG_C | FLAG_V | FLAG_LT | FLAG_Z)
+
+char *stpcpy_int (char *dst, const char *src)
+{
+ const size_t len = strlen (src);
+ return (char *) memcpy (dst, src, len + 1) + len;
+}
+
+inline static UINT8 setFlag(UINT8 ccr, UINT8 flag) {
+ return ccr | flag;
+}
+
+inline static UINT8 clearFlag(UINT8 ccr, UINT8 flag) {
+ return ccr & ~flag;
+}
+
+inline static UINT8 setFlagTo(UINT8 ccr, UINT8 flag, bool set) {
+ return set ? setFlag(ccr, flag) : clearFlag(ccr, flag);
+}
+
+inline static bool isFlagSet(UINT8 ccr, UINT8 flag) {
+ return (ccr & flag) != 0;
+}
+
+inline static INT32 add(INT32 a, INT32 b, UINT8 &flags) {
+ INT32 aSign = a & SIGN_BIT_24;
+ INT32 bSign = b & SIGN_BIT_24;
+ INT32 result = a + b;
+ INT32 resultSign = result & SIGN_BIT_24;
+ bool overflow = (aSign == bSign) && (aSign != resultSign);
+ bool carry = result & CARRY_OUT_24;
+ bool negative = resultSign != 0;
+ bool lessThan = (overflow && !negative) || (!overflow && negative);
+ flags = setFlagTo(flags, FLAG_C, carry);
+ flags = setFlagTo(flags, FLAG_N, negative);
+ flags = setFlagTo(flags, FLAG_Z, result == 0);
+ flags = setFlagTo(flags, FLAG_V, overflow);
+ flags = setFlagTo(flags, FLAG_LT, lessThan);
+ return SC(result);
+}
+
+inline static INT32 saturate(INT32 value, UINT8 &flags, bool negative) {
+ if (isFlagSet(flags, FLAG_V)) {
+ setFlagTo(flags, FLAG_N, negative);
+ return negative ? MIN_24 : MAX_24;
+ } else {
+ return value;
+ }
+}
+
+inline static INT32 negate(INT32 value) {
+ return ((value ^ 0x00ffffff) + 1) & 0x00ffffff;
+}
+
+inline static INT32 asl(INT32 value, int shift, UINT8 &flags) {
+ INT32 signBefore = value & SIGN_BIT_24;
+ INT32 result = value << shift;
+ INT32 signAfter = result & SIGN_BIT_24;
+ bool overflow = signBefore != signAfter;
+ flags = setFlagTo(flags, FLAG_V, overflow);
+ return saturate(result, flags, signBefore != 0);
+}
+
+es5510_device::es5510_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+: cpu_device(mconfig, ES5510, "ES5510", tag, owner, clock, "es5510", __FILE__)
+{
+ // Initialize ESP to mostly zeroed, configured for 64k samples of delay line memory, running (not halted)
+ halt_asserted = false;
+ icount = 0;
+ pc = 0;
+ state = STATE_HALTED;
+ memset(gpr, 0, 0xc0 * sizeof(gpr[0]));
+ ser0r = 0;
+ ser0l = 0;
+ ser1r = 0;
+ ser1l = 0;
+ ser2r = 0;
+ ser2l = 0;
+ ser3r = 0;
+ ser3l = 0;
+ machl = 0;
+ dil = 0;
+ memsiz = 0x00ffffff;
+ memmask = 0x00000000;
+ memincrement = 0x01000000;
+ memshift = 24;
+ dlength = 0;
+ abase = 0;
+ bbase = 0;
+ dbase = 0;
+ sigreg = 1;
+ mulshift = 1;
+ ccr = 0;
+ cmr = 0;
+ dol[0] = dol[1] = 0;
+ dol_count = 0;
+
+ memset(instr, 0, 160 * sizeof(instr[0]));
+ memset(dram, 0, (1<<20) * sizeof(dram[0]));
+
+ dol_latch = 0;
+ dil_latch = 0;
+ dadr_latch = 0;
+ gpr_latch = 0;
+ instr_latch = 0;
+ ram_sel = 0;
+ host_control = 0;
+
+ pc = 0;
+ memset(&alu, 0, sizeof(alu));
+ memset(&mulacc, 0, sizeof(mulacc));
+}
+
+typedef es5510_device::alu_op_t alu_op_t;
+typedef es5510_device::op_select_t op_select_t;
+typedef es5510_device::op_src_dst_t op_src_dst_t;
+
+static inline const char * REGNAME(UINT8 r) {
+ static char rn[8];
+ if (r < 234) { sprintf(rn, "GPR_%02x", r); return rn; }
+ switch(r) {
+ case 234: return "SER0R";
+ case 235: return "SER0L";
+ case 236: return "SER1R";
+ case 237: return "SER1L";
+ case 238: return "SER2R";
+ case 239: return "SER2L";
+ case 240: return "SER3R";
+ case 241: return "SER3L";
+ case 242: return "MACL";
+ case 243: return "MACH";
+ case 244: return "DIL/MEMSIZ";
+ case 245: return "DLENGTH";
+ case 246: return "ABASE";
+ case 247: return "BBASE";
+ case 248: return "DBASE";
+ case 249: return "SIGREG";
+ case 250: return "CCR";
+ case 251: return "CMR";
+ case 252: return "MINUS1";
+ case 253: return "MIN";
+ case 254: return "MAX";
+ case 255: return "ZERO";
+ }
+ return NULL;
+}
+
+static inline char * DESCRIBE_REG(char *s, UINT8 r, const char *name) {
+ if (name && *name) {
+ return s + sprintf(s, "%s/%s", REGNAME(r), name);
+ } else {
+ return stpcpy_int(s, REGNAME(r));
+ }
+
+ // never executed
+ //return 0;
+}
+
+const alu_op_t es5510_device::ALU_OPS[16] = {
+ { 2, "ADD" },
+ { 2, "SUB" },
+ { 2, "ADDU" },
+ { 2, "SUBU" },
+ { 2, "CMP" },
+ { 2, "AND" },
+ { 2, "OR" },
+ { 2, "XOR" },
+ { 1, "ABS" },
+ { 1, "MOV" },
+ { 1, "ASL2" },
+ { 1, "ASL8" },
+ { 1, "LS15" },
+ { 1, "DIFF" },
+ { 1, "ASR" },
+ { 0, "END" },
+};
+
+// The CMP operation is not affected by being skippable
+#define OP_CMP (4)
+
+const op_select_t es5510_device::OPERAND_SELECT[16] = {
+ { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG },
+ { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY },
+ { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_BOTH },
+ { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG },
+ { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_BOTH },
+ { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG },
+ { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG },
+ { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_BOTH, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG },
+ { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_BOTH, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG },
+ { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG },
+ { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY },
+ { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_BOTH },
+ { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG },
+ { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_BOTH },
+ { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_BOTH, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG },
+ { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_BOTH, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG },
+};
+
+static inline char * DESCRIBE_SRC_DST(char *s, UINT8 reg, const char *regname, op_src_dst_t src_dst) {
+ switch (src_dst) {
+ case es5510_device::SRC_DST_REG:
+ return DESCRIBE_REG(s, reg, regname);
+ case es5510_device::SRC_DST_DELAY:
+ return stpcpy_int(s, "Delay");
+ case es5510_device::SRC_DST_BOTH:
+ s = DESCRIBE_REG(s, reg, regname);
+ return stpcpy_int(s, ",Delay");
+ }
+ // should never happen!
+ return s;
+}
+
+const es5510_device::ram_control_t es5510_device::RAM_CONTROL[8] = {
+ { es5510_device::RAM_CYCLE_READ, es5510_device::RAM_CONTROL_DELAY, "Read Delay+%06x" },
+ { es5510_device::RAM_CYCLE_WRITE, es5510_device::RAM_CONTROL_DELAY, "Write Delay+%06x" },
+ { es5510_device::RAM_CYCLE_READ, es5510_device::RAM_CONTROL_TABLE_A, "Read Table A+%06x" },
+ { es5510_device::RAM_CYCLE_WRITE, es5510_device::RAM_CONTROL_TABLE_A, "Write Table A+%06x" },
+ { es5510_device::RAM_CYCLE_READ, es5510_device::RAM_CONTROL_TABLE_B, "Read Table B+%06x" },
+ { es5510_device::RAM_CYCLE_DUMP_FIFO, es5510_device::RAM_CONTROL_DELAY, "Read Delay+%06x and Dump FIFO" },
+ { es5510_device::RAM_CYCLE_READ, es5510_device::RAM_CONTROL_IO, "Read from I/O at %06x" },
+ { es5510_device::RAM_CYCLE_WRITE, es5510_device::RAM_CONTROL_IO, "Write to I/O at %06x" },
+};
+
+static inline char * DESCRIBE_RAM(char *s, UINT8 ramControl, UINT32 gprContents) {
+ return s + sprintf(s, es5510_device::RAM_CONTROL[ramControl].description, SC(gprContents));
+}
+
+static inline char * DESCRIBE_ALU(char *s, UINT8 opcode, UINT8 aReg, const char *aName, UINT8 bReg, const char *bName, const op_select_t &opSelect) {
+ const alu_op_t &op = es5510_device::ALU_OPS[opcode];
+
+ switch (op.operands) {
+ case 0:
+ return stpcpy_int(s, op.opcode);
+
+ case 1:
+ s += sprintf(s, "%s ", op.opcode);
+ s = DESCRIBE_SRC_DST(s, bReg, bName, opSelect.alu_src);
+ s += sprintf(s, " >");
+ return DESCRIBE_SRC_DST(s, aReg, aName, opSelect.alu_dst);
+
+ case 2:
+ s += sprintf(s, "%s ", op.opcode);
+ s = DESCRIBE_SRC_DST(s, aReg, aName, opSelect.alu_src);
+ s += sprintf(s, " ");
+ s = DESCRIBE_REG(s, bReg, bName);
+ s += sprintf(s, " >");
+ return DESCRIBE_SRC_DST(s, aReg, aName, opSelect.alu_dst);
+ }
+ return s;
+}
+
+static inline char * DESCRIBE_MAC(char *s, UINT8 mac, UINT8 cReg, const char *cName, UINT8 dReg, const char *dName, const op_select_t &opSelect)
+{
+ if (mac)
+ {
+ s += sprintf(s, "MAC + ");
+ }
+ s = DESCRIBE_SRC_DST(s, cReg, cName, opSelect.mac_src);
+ s += sprintf(s, " * ");
+ s = DESCRIBE_REG(s, dReg, dName);
+ s += sprintf(s, " >");
+ return DESCRIBE_SRC_DST(s, cReg, cName, opSelect.mac_dst);
+}
+
+static inline char * DESCRIBE_INSTR(char *s, UINT64 instr, UINT32 gpr, const char *aName, const char *bName, const char *cName, const char *dName)
+{
+ UINT8 dReg = (UINT8)((instr >> 40) & 0xff);
+ UINT8 cReg = (UINT8)((instr >> 32) & 0xff);
+ UINT8 bReg = (UINT8)((instr >> 24) & 0xff);
+ UINT8 aReg = (UINT8)((instr >> 16) & 0xff);
+ UINT8 aluOpcode = (UINT8)((instr >> 12) & 0x0f);
+ UINT8 operandSelect = (UINT8)((instr >> 8) & 0x0f);
+ UINT8 skip = (UINT8)((instr >> 7) & 0x01);
+ UINT8 mac = (UINT8)((instr >> 6) & 0x01);
+ UINT8 ramControl = (UINT8)((instr >> 3) & 0x07);
+
+ const op_select_t &opSelect = es5510_device::OPERAND_SELECT[operandSelect];
+
+ s = DESCRIBE_ALU(s, aluOpcode, aReg, aName, bReg, bName, opSelect);
+ s += sprintf(s, "; ");
+ s = DESCRIBE_MAC(s, mac, cReg, cName, dReg, dName, opSelect);
+ s += sprintf(s, "; ");
+ s = DESCRIBE_RAM(s, ramControl, gpr);
+ if (skip) {
+ s += sprintf(s, "; skippable");
+ }
+
+ return s;
+}
+
+
+READ8_MEMBER(es5510_device::host_r)
+{
+ // printf("%06x: DSP read offset %04x (data is %04x)\n",space.device().safe_pc(),offset,dsp_ram[offset]);
+
+ // VFX hack
+ if (core_stricmp(space.machine().system().name, "vfx") == 0)
+ {
+ if (space.device().safe_pc() == 0xc091f0)
+ {
+ return space.device().state().state_int(M68K_D2);
+ }
+ }
+
+ switch(offset)
+ {
+ case 0x00: LOG(("ES5510: Host Read GPR latch[2]: %02x\n", (gpr_latch >> 16) & 0xff)); return (gpr_latch >> 16) & 0xff;
+ case 0x01: LOG(("ES5510: Host Read GPR latch[1]: %02x\n", (gpr_latch >> 8) & 0xff)); return (gpr_latch >> 8) & 0xff;
+ case 0x02: LOG(("ES5510: Host Read GPR latch[0]: %02x\n", (gpr_latch >> 0) & 0xff)); return (gpr_latch >> 0) & 0xff;
+
+ case 0x03: LOG(("ES5510: Host Read INSTR latch[5]: %02x\n", (UINT8)((instr_latch >> 40) & 0xff))); return (instr_latch >> 40) & 0xff;
+ case 0x04: LOG(("ES5510: Host Read INSTR latch[4]: %02x\n", (UINT8)((instr_latch >> 32) & 0xff))); return (instr_latch >> 32) & 0xff;
+ case 0x05: LOG(("ES5510: Host Read INSTR latch[3]: %02x\n", (UINT8)((instr_latch >> 24) & 0xff))); return (instr_latch >> 24) & 0xff;
+ case 0x06: LOG(("ES5510: Host Read INSTR latch[2]: %02x\n", (UINT8)((instr_latch >> 16) & 0xff))); return (instr_latch >> 16) & 0xff;
+ case 0x07: LOG(("ES5510: Host Read INSTR latch[1]: %02x\n", (UINT8)((instr_latch >> 8) & 0xff))); return (instr_latch >> 8) & 0xff;
+ case 0x08: LOG(("ES5510: Host Read INSTR latch[0]: %02x\n", (UINT8)((instr_latch >> 0) & 0xff))); return (instr_latch >> 0) & 0xff;
+
+ case 0x09: LOG(("ES5510: Host Read DIL latch[2]: %02x\n", (dil_latch >> 16) & 0xff)); return (dil_latch >> 16) & 0xff;
+ case 0x0a: LOG(("ES5510: Host Read DIL latch[1]: %02x\n", (dil_latch >> 8) & 0xff)); return (dil_latch >> 8) & 0xff;
+ case 0x0b: LOG(("ES5510: Host Read DIL latch[0]: %02x\n", 0)); return 0;
+
+ case 0x0c: LOG(("ES5510: Host Read DOL latch[2]: %02x\n", (dol_latch >> 16) & 0xff)); return (dol_latch >> 16) & 0xff;
+ case 0x0d: LOG(("ES5510: Host Read DOL latch[1]: %02x\n", (dol_latch >> 8) & 0xff)); return (dol_latch >> 8) & 0xff;
+ case 0x0e: LOG(("ES5510: Host Read DOL latch[0]: %02x\n", 0xff)); return 0xff;
+
+ case 0x0f: LOG(("ES5510: Host Read DADR latch[2]: %02x\n", (dadr_latch >> 16) & 0xff)); return (dadr_latch >> 16) & 0xff;
+ case 0x10: LOG(("ES5510: Host Read DADR latch[1]: %02x\n", (dadr_latch >> 8) & 0xff)); return (dadr_latch >> 8) & 0xff;
+ case 0x11: LOG(("ES5510: Host Read DADR latch[0]: %02x\n", (dadr_latch >> 0) & 0xff)); return (dadr_latch >> 0) & 0xff;
+
+ case 0x12: LOG(("ES5510: Host Reading Host Control\n")); return 0; // Host Control
+
+ case 0x16: return 0x27; // Program Counter, for test purposes only
+ }
+
+ // default: 0.
+ return 0x00;
+}
+
+WRITE8_MEMBER(es5510_device::host_w)
+{
+#if VERBOSE
+ static char buf[1024];
+#endif
+ switch (offset) {
+ case 0x00:
+ gpr_latch = (gpr_latch&0x00ffff) | ((data&0xff)<<16);
+ LOG(("ES5510: Host Write GPR latch[2] = %02x -> %06x (%d)\n", data, gpr_latch, SX(gpr_latch)));
+ break;
+ case 0x01:
+ gpr_latch = (gpr_latch&0xff00ff) | ((data&0xff)<< 8);
+ LOG(("ES5510: Host Write GPR latch[1] = %02x -> %06x (%d)\n", data, gpr_latch, SX(gpr_latch)));
+ break;
+ case 0x02:
+ gpr_latch = (gpr_latch&0xffff00) | ((data&0xff)<< 0);
+ LOG(("ES5510: Host Write GPR latch[0] = %02x -> %06x (%d)\n", data, gpr_latch, SX(gpr_latch)));
+ break;
+
+ /* 0x03 to 0x08 INSTR Register */
+ case 0x03: instr_latch = ((instr_latch&U64(0x00ffffffffff)) | ((INT64)data&0xff)<<40); LOG(("ES5510: Host Write INSTR latch[5] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break;
+ case 0x04: instr_latch = ((instr_latch&U64(0xff00ffffffff)) | ((INT64)data&0xff)<<32); LOG(("ES5510: Host Write INSTR latch[4] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break;
+ case 0x05: instr_latch = ((instr_latch&U64(0xffff00ffffff)) | ((INT64)data&0xff)<<24); LOG(("ES5510: Host Write INSTR latch[3] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break;
+ case 0x06: instr_latch = ((instr_latch&U64(0xffffff00ffff)) | ((INT64)data&0xff)<<16); LOG(("ES5510: Host Write INSTR latch[2] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break;
+ case 0x07: instr_latch = ((instr_latch&U64(0xffffffff00ff)) | ((INT64)data&0xff)<< 8); LOG(("ES5510: Host Write INSTR latch[1] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break;
+ case 0x08: instr_latch = ((instr_latch&U64(0xffffffffff00)) | ((INT64)data&0xff)<< 0); LOG(("ES5510: Host Write INSTR latch[0] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break;
+
+ /* 0x09 to 0x0b DIL Register (r/o) */
+
+ case 0x0c: dol_latch = (dol_latch&0x00ffff) | ((data&0xff)<<16); LOG(("ES5510: Host Write DOL latch[2] = %02x -> %06x (%d)\n", data, dol_latch, SX(dol_latch))); break;
+ case 0x0d: dol_latch = (dol_latch&0xff00ff) | ((data&0xff)<< 8); LOG(("ES5510: Host Write DOL latch[1] = %02x -> %06x (%d)\n", data, dol_latch, SX(dol_latch))); break;
+ case 0x0e: dol_latch = (dol_latch&0xffff00) | ((data&0xff)<< 0); LOG(("ES5510: Host Write DOL latch[0] = %02x -> %06x (%d)\n", data, dol_latch, SX(dol_latch))); break; //TODO: docs says that this always returns 0xff
+
+ case 0x0f:
+ dadr_latch = (dadr_latch&0x00ffff) | ((data&0xff)<<16);
+ if (ram_sel)
+ {
+ dil_latch = dram[dadr_latch] << 8;
+ }
+ else
+ {
+ dram[dadr_latch] = dol_latch >> 8;
+ }
+ break;
+
+ case 0x10: dadr_latch = (dadr_latch&0xff00ff) | ((data&0xff)<< 8); break;
+ case 0x11: dadr_latch = (dadr_latch&0xffff00) | ((data&0xff)<< 0); break;
+
+ /* 0x12 Host Control */
+
+ case 0x14: ram_sel = data & 0x80; /* bit 6 is i/o select, everything else is undefined */break;
+
+ /* 0x16 Program Counter (test purpose, r/o?) */
+ /* 0x17 Internal Refresh counter (test purpose) */
+ /* 0x18 Host Serial Control */
+ case 0x18:
+ LOG(("ES5510: Host Write Host Serial control %02x: %s, %s, ser3 %s, ser2 %s, ser1 %s, ser0 %s\n", data,
+ data&0x80 ? "Master" : "Slave",
+ data&0x40 ? "Sony" : "I2S",
+ data & 0x20 ? "Out" : "In",
+ data & 0x10 ? "Out" : "In",
+ data & 0x08 ? "Out" : "In",
+ data & 0x04 ? "Out" : "In"));
+ break;
+
+ /* 0x1f Halt enable (w) / Frame Counter (r) */
+ case 0x1F:
+ LOG(("ES5510: Host Write Halt Enable %02x; HALT line is %d\n", data, halt_asserted));
+ if (halt_asserted) {
+ LOG(("ES5510: Host Write to Halt Enable while HALT line is asserted: Halting!\n"));
+ state = STATE_HALTED;
+ }
+ break;
+
+ case 0x80: /* Read select - GPR + INSTR */
+ LOG(("ES5510: Host Read INSTR+GPR %02x (%s): %012" I64FMT "x %06x (%d)\n", data, REGNAME(data & 0xff), instr[data] & U64(0xffffffffffff), gpr[data] & 0xffffff, gpr[data]));
+
+ /* Check if an INSTR address is selected */
+ if (data < 0xa0) {
+ instr_latch = instr[data];
+ }
+ if (data < 0xc0) {
+ gpr_latch = gpr[data] & 0xffffff;
+ } else if (data >= 0xea) {
+ gpr_latch = read_reg(data);
+ }
+ break;
+
+ case 0xa0: /* Write select - GPR */
+ LOG(("ES5510: Host Write GPR %02x (%s): %06x (%d)\n", data, REGNAME(data&0xff), gpr_latch, SX(gpr_latch)));
+ write_reg(data, gpr_latch);
+ break;
+
+ case 0xc0: /* Write select - INSTR */
+#if VERBOSE
+ DESCRIBE_INSTR(buf, instr_latch, gpr[data], NULL, NULL, NULL, NULL);
+ LOG(("ES5510: Host Write INSTR %02x %012" I64FMT "x: %s\n", data, instr_latch&U64(0xffffffffffff), buf));
+#endif
+ if (data < 0xa0) {
+ instr[data] = instr_latch&U64(0xffffffffffff);
+ }
+ break;
+
+ case 0xe0: /* Write select - GPR + INSTR */
+#if VERBOSE
+ DESCRIBE_INSTR(buf, instr_latch, gpr_latch, NULL, NULL, NULL, NULL);
+ LOG(("ES5510: Host Write INSTR+GPR %02x (%s): %012" I64FMT "x %06x (%d): %s\n", data, REGNAME(data&0xff), instr_latch, gpr_latch, SX(gpr_latch), buf));
+#endif
+ if (data < 0xa0) {
+ instr[data] = instr_latch;
+ }
+ write_reg(data, gpr_latch);
+ break;
+ }
+}
+
+INT16 es5510_device::ser_r(int offset)
+{
+ switch(offset)
+ {
+ case 0: return ser0l;
+ case 1: return ser0r;
+ case 2: return ser1l;
+ case 3: return ser1r;
+ case 4: return ser2l;
+ case 5: return ser2r;
+ case 6: return ser3l;
+ case 7: return ser3r;
+ }
+ return 0;
+}
+
+void es5510_device::ser_w(int offset, INT16 data)
+{
+ switch(offset)
+ {
+ case 0: ser0l = data; break;
+ case 1: ser0r = data; break;
+ case 2: ser1l = data; break;
+ case 3: ser1r = data; break;
+ case 4: ser2l = data; break;
+ case 5: ser2r = data; break;
+ case 6: ser3l = data; break;
+ case 7: ser3r = data; break;
+ }
+}
+
+void es5510_device::device_start() {
+ m_icountptr = &icount;
+ state_add(STATE_GENPC,"GENPC", pc).noshow();
+}
+
+void es5510_device::device_reset() {
+ pc = 0x00;
+ memset(gpr, 0, sizeof(*gpr) * 0xc0);
+ memset(instr, 0, sizeof(*instr) * 0xa0);
+ memset(dram, 0, sizeof(*dram) * (1<<20));
+ state = STATE_RUNNING;
+ dil_latch = dol_latch = dadr_latch = gpr_latch = 0;
+ instr_latch = UINT64(0);
+ ram_sel = 0;
+ host_control = 0;
+ memset(&ram, 0, sizeof(ram_t));
+ memset(&ram_p, 0, sizeof(ram_t));
+ memset(&ram_pp, 0, sizeof(ram_t));
+}
+
+const address_space_config *es5510_device::memory_space_config(address_spacenum spacenum) const {
+ return 0;
+}
+
+UINT64 es5510_device::execute_clocks_to_cycles(UINT64 clocks) const {
+ return clocks / 3;
+}
+
+UINT64 es5510_device::execute_cycles_to_clocks(UINT64 cycles) const {
+ return cycles * 3;
+}
+
+UINT32 es5510_device::execute_min_cycles() const {
+ return 1;
+}
+
+UINT32 es5510_device::execute_max_cycles() const {
+ return 1;
+}
+
+UINT32 es5510_device::execute_input_lines() const {
+ return 1;
+}
+
+void es5510_device::execute_set_input(int linenum, int state) {
+ if (linenum == ES5510_HALT) {
+ halt_asserted = (state == ASSERT_LINE);
+ }
+}
+
+void es5510_device::list_program(void(p)(const char *, ...)) {
+ LOG(("ES5501: Starting!\n"));
+
+ char buf[1024];
+ bool is_written[0x100], is_read[0x100];
+ char name[0x100][16];
+ int addr;
+
+ for (int i = 0; i < 0x100; i++) {
+ is_written[i] = is_read[i] = false;
+ name[i][0] = '\0';
+ }
+
+ for (addr = 0; addr < 0xa0; addr++) {
+ DESCRIBE_INSTR(buf, instr[addr], gpr[addr], NULL, NULL, NULL, NULL);
+ UINT64 inst = instr[addr];
+ UINT8 aReg = (UINT8)((inst >> 16) & 0xff);
+ UINT8 bReg = (UINT8)((inst >> 24) & 0xff);
+ UINT8 cReg = (UINT8)((inst >> 32) & 0xff);
+ UINT8 dReg = (UINT8)((inst >> 40) & 0xff);
+ UINT8 alu_op = (inst >> 12) & 0x0f;
+ if (alu_op == 0x0f) {
+ // END!
+ break;
+ }
+
+ UINT8 operandSelect = (UINT8)((inst >> 8) & 0x0f);
+ const op_select_t &opSelect = OPERAND_SELECT[operandSelect];
+
+ if (opSelect.mac_src == SRC_DST_REG) {
+ is_read[cReg] = true;
+ }
+ is_read[dReg] = true;
+ if (opSelect.mac_dst != SRC_DST_DELAY) { // either REG or BOTH
+ is_written[cReg] = true;
+ }
+
+ alu_op_t aluOp = ALU_OPS[alu_op];
+ if (aluOp.operands == 1) {
+ if (opSelect.alu_src == SRC_DST_REG) {
+ is_read[bReg] = true;
+ }
+ } else if (aluOp.operands == 2) {
+ if (opSelect.alu_src == SRC_DST_REG) {
+ is_read[aReg] = true;
+ }
+ is_read[bReg] = true;
+ }
+ if (opSelect.mac_dst != SRC_DST_DELAY) { // either REG or BOTH
+ is_written[aReg] = true;
+ }
+ }
+
+ int varIndex = 1;
+ int constIndex = 1;
+ for (int i = 0; i < 0xc0; i++) {
+ if (is_written[i]) {
+ // this is a variable
+ sprintf(name[i], "v_%03d", varIndex++);
+ } else if (is_read[i]) {
+ // this is only read, so a constant - or possibly something updated by the CPU
+ sprintf(name[i], "c_%03d", constIndex++);
+ } else {
+ name[i][0] = 0;
+ }
+ }
+ for (int i = 0xc0; i < 0x100; i++) {
+ name[i][0] = 0;
+ }
+
+ for (addr = 0; addr < 0xa0; addr++) {
+ UINT8 aReg = (UINT8)((instr[addr] >> 16) & 0xff);
+ UINT8 bReg = (UINT8)((instr[addr] >> 24) & 0xff);
+ UINT8 cReg = (UINT8)((instr[addr] >> 32) & 0xff);
+ UINT8 dReg = (UINT8)((instr[addr] >> 40) & 0xff);
+ DESCRIBE_INSTR(buf, instr[addr], gpr[addr], name[aReg], name[bReg], name[cReg], name[dReg]);
+ p("%02x: %012" I64FMT "x %06x (%8d) %s\n", addr, instr[addr], gpr[addr]&0xffffff, SX(gpr[addr]&0xffffff), buf);
+ }
+ for (; addr < 0xc0; addr++) {
+ p("%02x: %06x (%d)\n", addr, gpr[addr]&0xffffff, SX(gpr[addr]&0xffffff));
+ }
+}
+
+void es5510_device::execute_run() {
+ while (icount > 0) {
+ if (state == STATE_HALTED) {
+ // Currently halted, sample the HALT line
+ if (halt_asserted) {
+ // remain halted
+ host_control |= 0x04; // Signal Host Access OK
+ } else {
+ // start from the beginning at PC 0
+ state = STATE_RUNNING;
+ host_control &= ~0x04; // Signal Host Access not OK
+ pc = 0;
+ }
+ } else {
+ // currently running, execute one instruction.
+
+#if VERBOSE_EXEC
+ char buf[1024];
+ DESCRIBE_INSTR(buf, instr[pc], gpr[pc], NULL, NULL, NULL, NULL);
+ LOG_EXEC(("EXECUTING %02x: %012" I64FMT "x %06x %s\n", pc, instr[pc], gpr[pc]&0xffffff, buf));
+#endif
+
+ ram_pp = ram_p;
+ ram_p = ram;
+
+ LOG_EXEC(("- T0\n"));
+
+ // *** T0, clock high
+ // --- nothing to do!
+
+ // *** T0, clock low
+ // --- Read instruction N
+ UINT64 instr = this->instr[pc];
+
+ // --- RAM cycle N-2 (if a Read cycle): data read from bus is stored in DIL
+ if (ram_pp.cycle != RAM_CYCLE_WRITE) {
+ if (ram_pp.io) { // read from I/O and store into DIL
+ dil = 0; // read_io(ram_pp.address);;
+ } else { // read from DRAM and store into DIL
+ dil = dram[ram_pp.address] << 8;
+ LOG_EXEC((" . RAM: read %x (%d) from address %x\n", dil, dil, ram_pp.address));
+ }
+ }
+
+ // --- start of RAM cycle N
+ ram_control_t ramControl = RAM_CONTROL[((instr >> 3) & 0x07)];
+ ram.cycle = ramControl.cycle;
+ ram.io = ramControl.access == RAM_CONTROL_IO;
+
+ // --- RAM cycle N: read offset N
+ INT32 offset = gpr[pc];
+ switch(ramControl.access) {
+ case RAM_CONTROL_DELAY:
+ ram.address = (((dbase + offset) % (dlength + memincrement)) & memmask) >> memshift;
+ LOG_EXEC((". Ram Control: Delay, base=%x, offset=%x, length=%x => address=%x\n", dbase >> memshift, offset >> memshift, (dlength + memincrement) >> memshift, ram.address));
+ break;
+ case RAM_CONTROL_TABLE_A:
+ ram.address = ((abase + offset) & memmask) >> memshift;
+ LOG_EXEC((". Ram Control: table A = %x, offset=%x => address=%x\n", abase >> memshift, offset >> memshift, ram.address));
+ break;
+ case RAM_CONTROL_TABLE_B:
+ ram.address = ((bbase + offset) & memmask) >> memshift;
+ LOG_EXEC((". Ram Control: table B = %x, offset=%x => address=%x\n", bbase >> memshift, offset >> memshift, ram.address));
+ break;
+ case RAM_CONTROL_IO:
+ ram.address = offset & 0x00fffff0; // mask off the low 4 bits
+ LOG_EXEC((". Ram Control: I/O at address=%x\n", ram.address));
+ break;
+ }
+
+ // *** T1, clock high
+ // --- Decode instruction N;
+ // we will do this both here and in stages as the different parts of the instruction complete & recommence.
+
+ LOG_EXEC(("- T1.1\n"));
+
+ UINT8 operandSelect = (UINT8)((instr >> 8) & 0x0f);
+ const op_select_t &opSelect = OPERAND_SELECT[operandSelect];
+ bool skip;
+ bool skippable = (instr & (0x01 << 7)) != 0; // aka the 'SKIP' bit in the instruction word
+ if (skippable) {
+ bool skipConditionSatisfied = (ccr & cmr & FLAG_MASK) != 0;
+ if (isFlagSet(cmr, FLAG_NOT)) {
+ skipConditionSatisfied = !skipConditionSatisfied;
+ }
+ skip = skipConditionSatisfied;
+ LOG_EXEC((". skippable: %x vs %x => skippable = %d\n", ccr, cmr, skip));
+ } else {
+ skip = false;
+ }
+
+ // --- Write Multiplier result N-1
+ LOG_EXEC((". write mulacc:\n"));
+ if (mulacc.write_result) {
+ mulacc.product = ((INT64)SX(mulacc.cValue) * (INT64)SX(mulacc.dValue)) << mulshift;
+ if (mulacc.accumulate) {
+ mulacc.result = mulacc.product + machl;
+ } else {
+ mulacc.result = mulacc.product;
+ }
+
+ if (mulacc.result < MIN_48 || mulacc.result > MAX_48) {
+ mac_overflow = true;
+ } else {
+ mac_overflow = false;
+ }
+#if VERBOSE_EXEC
+ if (mulacc.cValue || mulacc.dValue || (mulacc.accumulate && machl)) {
+ LOG_EXEC((". mulacc: %x (%d) * %x (%d) << %d", SX(mulacc.cValue), SX(mulacc.cValue), SX(mulacc.dValue), SX(mulacc.dValue), mulshift));
+ if (mulacc.accumulate) LOG_EXEC((" + %llx (%lld) ", machl, machl));
+ LOG_EXEC((" = %llx (%lld)", mulacc.result, mulacc.result));
+ if (mac_overflow) {
+ LOG_EXEC((" overflow!\n"));
+ } else {
+ LOG_EXEC(("\n"));
+ }
+ }
+#endif
+ machl = mulacc.result;
+ INT32 tmp = mac_overflow ? (machl < 0 ? MIN_24 : MAX_24) : (mulacc.result & U64(0x0000ffffff000000)) >> 24;
+ if (mulacc.dst & SRC_DST_REG) {
+ write_reg(mulacc.cReg, tmp);
+ }
+ if (mulacc.dst & SRC_DST_DELAY) {
+ write_to_dol(tmp);
+ }
+ }
+
+ // *** T1, clock low
+
+ LOG_EXEC(("- T1.0\n"));
+
+ // --- Start of multiplier cycle N
+ LOG_EXEC((". start mulacc:\n"));
+ mulacc.cReg = (UINT8)((instr >> 32) & 0xff);
+ mulacc.dReg = (UINT8)((instr >> 40) & 0xff);
+ mulacc.src = opSelect.mac_src;
+ mulacc.dst = opSelect.mac_dst;
+ mulacc.accumulate = ((instr >> 6) & 0x01) != 0;
+ mulacc.write_result = !skip;
+
+ // --- Read Multiplier Operands N
+ if (mulacc.src == SRC_DST_REG) {
+ mulacc.cValue = read_reg(mulacc.cReg);
+ } else { // must be SRC_DST_DELAY
+ LOG_EXEC((" . reading %x (%d) from dil\n", dil, SX(dil)));
+ mulacc.cValue = dil;
+ }
+ mulacc.dValue = read_reg(mulacc.dReg);
+
+ // *** T2, clock high
+
+ LOG_EXEC(("- T2.1\n"));
+
+ // --- Write ALU Result N-1
+ LOG_EXEC((". write ALU:\n"));
+ if (alu.write_result) {
+ UINT8 flags = ccr;
+ alu.result = alu_operation(alu.op, alu.aValue, alu.bValue, flags);
+ if (alu.dst & SRC_DST_REG) {
+ write_reg(alu.aReg, alu.result);
+ }
+ if (alu.dst & SRC_DST_DELAY) {
+ write_to_dol(alu.result);
+ }
+ if (alu.update_ccr) {
+ ccr = flags;
+ }
+ }
+
+ // *** T2, clock low
+
+ LOG_EXEC(("- T2.0\n"));
+
+ // --- Start of ALU cycle N
+ LOG_EXEC((". start ALU:\n"));
+ alu.aReg = (instr >> 16) & 0xff;
+ alu.bReg = (instr >> 24) & 0xff;
+ alu.op = (instr >> 12) & 0x0f;
+ alu.src = opSelect.alu_src;
+ alu.dst = opSelect.alu_dst;
+ alu.write_result = !skip;
+ alu.update_ccr = !skippable || (alu.op == OP_CMP);
+
+ if (alu.op == 0xF) {
+ alu_operation_end();
+ } else {
+ // --- Read ALU Operands N
+ alu_op_t aluOp = ALU_OPS[alu.op];
+ if (aluOp.operands == 1) {
+ if (alu.src == SRC_DST_REG) {
+ alu.bValue = read_reg(alu.bReg);
+ } else { // must be SRC_DST_DELAY
+ alu.bValue = dil;
+ }
+ } else {
+ if (alu.src == SRC_DST_REG) {
+ alu.aValue = read_reg(alu.aReg);
+ } else { // must be SRC_DST_DELAY
+ alu.aValue = dil;
+ }
+ alu.bValue = read_reg(alu.bReg);
+ }
+ }
+
+ // --- RAM cycle N-1
+ if (ram_p.cycle != RAM_CYCLE_READ) {
+ if (ram_p.cycle == RAM_CYCLE_WRITE) {
+ // If this is a write cycle, write the frontmost DOL value to RAM or I/O
+ if (ram_p.io) {
+ // write_io(ram_p.io, dol[0]);
+ } else {
+ dram[ram_p.address] = dol[0] >> 8;
+ LOG_EXEC((" . RAM: writing %x (%d) [of %x (%d)] to address %x\n", dol[0]&0xffff00, SX(dol[0]&0xffff00), dol[0], SX(dol[0]), ram_p.address));
+ }
+ }
+ // If this is a Write or Dump cycle, eject the frontmost DL value.
+#if VERBOSE_EXEC
+ LOG_EXEC((" . ejecting from DOL: [ "));
+ if (dol_count >= 1) LOG_EXEC(("{ %x (%d) }", dol[0], SX(dol[0])));
+ if (dol_count == 2) LOG_EXEC((", { %x (%d) }", dol[1], SX(dol[1])));
+ LOG_EXEC((" ] -> [ "));
+#endif
+ dol[0] = dol[1];
+ if (dol_count > 0) {
+ --dol_count;
+ }
+#if VERBOSE_EXEC
+ if (dol_count >= 1) LOG_EXEC(("{ %x (%d) }", dol[0], SX(dol[0])));
+ if (dol_count == 2) LOG_EXEC((", { %x (%d) }", dol[1], SX(dol[1])));
+ LOG_EXEC((" ]\n"));
+#endif
+ }
+
+ ++pc;
+ }
+ --icount;
+ }
+}
+
+UINT32 es5510_device::disasm_min_opcode_bytes() const
+{
+ return 6;
+}
+
+UINT32 es5510_device::disasm_max_opcode_bytes() const
+{
+ return 6;
+}
+
+offs_t es5510_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ return pc;
+}
+
+#if VERBOSE_EXEC
+#define RETURN_GPR(r, x) do { INT32 v = (x); LOG_EXEC((" . reading %x (%d) from gpr_%02x\n", v, SX(v), r)); return v; } while(0)
+#define RETURN(r, x) do { INT32 v = (x); LOG_EXEC((" . reading %x (%d) from " #r "\n", v, SX(v))); return v; } while(0)
+#define RETURN16(r, x) do { INT16 vv = (x); INT32 v = vv << 8; LOG_EXEC((" . reading %x (%d) as %x (%d) from " #r "\n", vv, vv, v, SX(v))); return v; } while(0)
+#else
+#define RETURN_GPR(r, x) return x
+#define RETURN(r, x) return x
+#define RETURN16(r, x) return (x) << 8
+#endif
+
+INT32 es5510_device::read_reg(UINT8 reg)
+{
+ if (reg < 0xc0) {
+ RETURN_GPR(reg, gpr[reg]);
+ } else {
+ switch(reg)
+ {
+ case 234: RETURN16(ser0r, ser0r);
+ case 235: RETURN16(ser0l, ser0l);
+ case 236: RETURN16(ser1r, ser1r);
+ case 237: RETURN16(ser1l, ser1l);
+ case 238: RETURN16(ser2r, ser2r);
+ case 239: RETURN16(ser2l, ser2l);
+ case 240: RETURN16(ser3r, ser3r);
+ case 241: RETURN16(ser3l, ser3l);
+ case 242: /* macl */ RETURN(macl, mac_overflow ? (machl < 0 ? 0x00ffffff : 0x00000000) : (machl >> 0) & 0x00ffffff);
+ case 243: /* mach */ RETURN(mach, mac_overflow ? (machl < 0 ? MIN_24 : MAX_24) : (machl >> 24) & 0x00ffffff);
+ case 244: RETURN(dil, dil); // DIL when reading
+ case 245: RETURN(dlength, dlength);
+ case 246: RETURN(abase, abase);
+ case 247: RETURN(bbase, bbase);
+ case 248: RETURN(dbase, dbase);
+ case 249: RETURN(sigreg, sigreg);
+ case 250: RETURN(ccr, ccr);
+ case 251: RETURN(cmr, cmr);
+ case 252: RETURN(minus_one, 0x00ffffff);
+ case 253: RETURN(min, MIN_24);
+ case 254: RETURN(max, MAX_24);
+ case 255: RETURN(zero, 0);
+ default:
+ // unknown SPR
+ RETURN(unknown, 0);
+ }
+ }
+}
+
+void es5510_device::run_once()
+{
+ // turn HALT off
+ set_HALT(false);
+
+ // run for one instruction
+ icount = 1;
+ execute_run();
+
+ // turn HALT on again
+ set_HALT(true);
+
+ // run ESP to the end of its program, a few instructions at a time
+ while (state != STATE_HALTED) {
+ icount = 1;
+ execute_run();
+ }
+}
+
+INT8 countLowOnes(INT32 x) {
+ INT8 n = 0;
+ while ((x & 1) == 1) {
+ ++n;
+ x >>= 1;
+ }
+ return n;
+}
+
+#if VERBOSE_EXEC
+#define WRITE_REG(r, x) do { r = value; LOG_EXEC((" . writing %x (%d) to " #r "\n", r, SX(r))); } while(0)
+#define WRITE_REG16(r, x) do { r = ((value >> 8) & 0xffff); LOG_EXEC((" . writing %x (%d) as %x (%d) to " #r "\n", value, SX(value), r, r)); } while(0)
+#else
+#define WRITE_REG(r, x) do { r = value; } while(0)
+#define WRITE_REG16(r, x) do { r = ((value >> 8) & 0xffff); } while(0)
+#endif
+
+void es5510_device::write_reg(UINT8 reg, INT32 value)
+{
+ #if VERBOSE_EXEC
+ INT64 old;
+ #endif
+ value &= 0x00ffffff;
+ if (reg < 0xc0) {
+ LOG_EXEC((" . writing %x (%d) to gpr_%02x\n", value, SX(value), reg));
+ gpr[reg] = value;
+ } else {
+ switch(reg)
+ {
+ case 234: WRITE_REG16(ser0r, value);
+ break;
+ case 235: WRITE_REG16(ser0l, value);
+ break;
+ case 236: WRITE_REG16(ser1r, value);
+ break;
+ case 237: WRITE_REG16(ser1l, value);
+ break;
+ case 238: WRITE_REG16(ser2r, value);
+ break;
+ case 239: WRITE_REG16(ser2l, value);
+ break;
+ case 240: WRITE_REG16(ser3r, value);
+ break;
+ case 241: WRITE_REG16(ser3l, value);
+ break;
+ case 242: /* macl */ {
+ #if VERBOSE_EXEC
+ old = machl;
+ #endif
+ INT64 masked = machl & (S64(0x00ffffff) << 24);
+ INT64 shifted = (INT64)(value & 0x00ffffff) << 0;
+ machl = SX64(masked | shifted);
+ #if VERBOSE_EXEC
+ LOG_EXEC((" . writing machl: l -> %06x => %llx -> %llx\n", value, old, machl));
+ #endif
+ break;
+ }
+ case 243: /* mach */ {
+ #if VERBOSE_EXEC
+ old = machl;
+ #endif
+ INT64 masked = machl & (S64(0x00ffffff) << 0);
+ INT64 shifted = (INT64)(value & 0x00ffffff) << 24;
+ machl = SX64(masked | shifted);
+ mac_overflow = false;
+ #if VERBOSE_EXEC
+ LOG_EXEC((" . writing machl: h -> %06x => %llx -> %llx\n", value, old, machl));
+ #endif
+ break;
+ }
+ case 244: /* MEMSIZ when writing */
+ memshift = countLowOnes(value);
+ memsiz = 0x00ffffff >> (24 - memshift);
+ memmask = 0x00ffffff & ~memsiz;
+ memincrement = 1 << memshift;
+ LOG_EXEC((" . writing %x (%d) to memsiz => memsiz=%x, shift=%d, mask=%x, increment=%x\n", value, SX(value), memsiz, memshift, memmask, memincrement));
+ break;
+ case 245: WRITE_REG(dlength, value);
+ break;
+ case 246: WRITE_REG(abase, value);
+ break;
+ case 247: WRITE_REG(bbase, value);
+ break;
+ case 248: WRITE_REG(dbase, value);
+ break;
+ case 249: WRITE_REG(sigreg, (value != 0));
+ break;
+ case 250: WRITE_REG(ccr, (value >> 16) & FLAG_MASK);
+ break;
+ case 251: WRITE_REG(cmr, (value >> 16) & (FLAG_MASK | FLAG_NOT));
+ break;
+ case 252: LOG_EXEC((". not writing %x (%d) to minus_one\n", value, SX(value))); // no-op
+ break;
+ case 253: LOG_EXEC((". not writing %x (%d) to min\n", value, SX(value))); // no-op
+ break;
+ case 254: LOG_EXEC((". not writing %x (%d) to max\n", value, SX(value))); // no-op
+ break;
+ case 255: LOG_EXEC((". not writing %x (%d) to zero\n", value, SX(value))); // no-op
+ break;
+ default: // unknown register
+ break;
+ }
+ }
+}
+
+void es5510_device::write_to_dol(INT32 value) {
+#if VERBOSE_EXEC
+ LOG_EXEC((". writing %x (%d) to DOL: [ ", value, value));
+ if (dol_count >= 1) LOG_EXEC(("{ %x (%d) }", dol[0], SX(dol[0])));
+ if (dol_count == 2) LOG_EXEC((", { %x (%d) }", dol[1], SX(dol[1])));
+ LOG_EXEC((" ] -> [ "));
+#endif
+ if (dol_count >= 2) {
+ dol[0] = dol[1];
+ dol[1] = value;
+ } else {
+ dol[dol_count++] = value;
+ }
+#if VERBOSE_EXEC
+ LOG_EXEC(("{%x (%d)}", dol[0], SX(dol[0])));
+ if (dol_count == 2) LOG_EXEC((", {%x (%d)}", dol[1], SX(dol[1])));
+ LOG_EXEC((" ]\n"));
+#endif
+}
+
+void es5510_device::alu_operation_end() {
+ // Handle the END instruction separately
+ LOG_EXEC(("ES5510: END\n"));
+ // sample the HALT line
+ if (halt_asserted) {
+ // halt
+ state = STATE_HALTED;
+ host_control |= 0x04; // Signal Host Access OK
+ }
+ // update the delay line base pointer
+ dbase -= memincrement;
+ if (dbase < 0) {
+ dbase = dlength;
+ }
+ // Possibly reset the PC
+ if (state == STATE_RUNNING) {
+ pc = 0;
+ }
+
+#if VERBOSE_EXEC
+ // update the verbose-execution counter.
+ exec_cc = (exec_cc + 1) % 30000;
+#endif
+}
+
+INT32 es5510_device::alu_operation(UINT8 op, INT32 a, INT32 b, UINT8 &flags) {
+ INT32 tmp;
+ switch(op) {
+ case 0x0: // ADD
+ tmp = add(a, b, flags);
+ return saturate(tmp, flags, (a & 0x00800000) != 0);
+
+ case 0x1: // SUB
+ tmp = add(a, negate(b), flags);
+ return saturate(tmp, flags, (a & 0x00800000) != 0);
+
+ case 0x2: // ADDU
+ return add(a, b, flags);
+
+ case 0x3: // SUBU
+ return add(a, negate(b), flags);
+
+ case 0x4: // CMP
+ // perform the subtraction, only for its effect on the flags
+ add(a, negate(b), flags);
+ return a;
+
+ case 0x5: // AND
+ a &= b;
+ setFlagTo(flags, FLAG_N, (a & 0x0080000000) != 0);
+ setFlagTo(flags, FLAG_Z, a == 0);
+ return a;
+
+ case 0x6: // OR
+ a |= b;
+ setFlagTo(flags, FLAG_N, (a & 0x0080000000) != 0);
+ setFlagTo(flags, FLAG_Z, a == 0);
+ return a;
+
+ case 0x7: // XOR
+ a ^= b;
+ setFlagTo(flags, FLAG_N, (a & 0x0080000000) != 0);
+ setFlagTo(flags, FLAG_Z, a == 0);
+ return a;
+
+ case 0x8: // ABS
+ {
+ clearFlag(flags, FLAG_N);
+ bool isNegative = (a & 0x00800000) != 0;
+ setFlagTo(flags, FLAG_C, isNegative);
+ // Note: the absolute value is calculated by one's complement!
+ return isNegative ? (0x00ffffff ^ a) : a;
+ }
+
+ case 0x9: // MOV
+ return b;
+
+ case 0xA: // ASL2
+ return asl(b, 2, flags);
+
+ case 0xB: // ASL8
+ return asl(b, 8, flags);
+
+ case 0xC: // LS15
+ return (b << 15) & 0x007fffff;
+
+ case 0xD: // DIFF
+ return add(0x007fffff, negate(b), flags);
+
+ case 0xE: // ASR
+ return (b >> 1) | (b & 0x00800000);
+
+ case 0xF: // END - handled separately in alu_operation_end()
+ default:
+ return 0;
+ }
+}