summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/diablo
diff options
context:
space:
mode:
author joakim <Joakim Larsson Edstrom>2018-02-24 02:32:36 +0100
committer joakim <Joakim Larsson Edstrom>2018-02-24 02:32:36 +0100
commit35a7f3e628a860dd75b2b57a95c3190443fd25a2 (patch)
treefd0d06694d60b7e3ea10e65618dc4f92057fdd95 /src/devices/cpu/diablo
parent534dea91eee1a5b67d8c480d411a10944830f619 (diff)
WIP: Diablo printer CPU
Diffstat (limited to 'src/devices/cpu/diablo')
-rw-r--r--src/devices/cpu/diablo/diablo1300.cpp368
-rw-r--r--src/devices/cpu/diablo/diablo1300.h94
-rw-r--r--src/devices/cpu/diablo/diablo1300dasm.cpp82
-rw-r--r--src/devices/cpu/diablo/diablo1300dasm.h22
4 files changed, 566 insertions, 0 deletions
diff --git a/src/devices/cpu/diablo/diablo1300.cpp b/src/devices/cpu/diablo/diablo1300.cpp
new file mode 100644
index 00000000000..6cfe0778622
--- /dev/null
+++ b/src/devices/cpu/diablo/diablo1300.cpp
@@ -0,0 +1,368 @@
+// license:BSD-3-Clause
+// copyright-holders:Joakim Larsson Edstrom
+// thanks-to: Jeff Laughton
+/*
+ Diablo 1300 series Printer TTL CPU
+ The work is based on the RE done by Jeff Laughton http://laughtonelectronics.com/Arcana/Diablo%20CPU/DiabloCPU.html
+*/
+
+#include "emu.h"
+#include "debugger.h"
+#include "diablo1300.h"
+#include "diablo1300dasm.h"
+
+//**************************************************************************
+// CONFIGURABLE LOGGING
+//**************************************************************************
+#define LOG_OP (1U << 1)
+
+#define VERBOSE (LOG_GENERAL | LOG_OP)
+//#define LOG_OUTPUT_FUNC printf
+
+#include "logmacro.h"
+
+#define LOGOP(...) LOGMASKED(LOG_OP, __VA_ARGS__)
+
+/*****************************************************************************/
+
+inline uint16_t diablo1300_cpu_device::opcode_read(uint16_t address)
+{
+ return m_direct->read_word(address);
+}
+
+inline uint16_t diablo1300_cpu_device::program_read16(uint16_t address)
+{
+ return m_program->read_word(address);
+}
+
+inline void diablo1300_cpu_device::program_write16(uint16_t address, uint16_t data)
+{
+ m_program->write_word(address, data);
+ return;
+}
+
+inline uint8_t diablo1300_cpu_device::data_read8(uint16_t address)
+{
+ return m_data->read_byte(address);
+}
+
+inline void diablo1300_cpu_device::data_write8(uint16_t address, uint8_t data)
+{
+ m_data->write_byte(address, data);
+ return;
+}
+
+inline uint8_t diablo1300_cpu_device::read_reg(uint16_t reg)
+{
+ return data_read8(reg);
+}
+
+inline void diablo1300_cpu_device::write_reg(uint16_t reg, uint8_t data)
+{
+ data_write8(reg, data);
+}
+
+/*****************************************************************************/
+
+DEFINE_DEVICE_TYPE(DIABLO1300, diablo1300_cpu_device, "diablo1300_cpu", "DIABLO 1300 CPU")
+
+//-------------------------------------------------
+// diablo1300_cpu_device - constructor
+//-------------------------------------------------
+
+diablo1300_cpu_device::diablo1300_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : cpu_device(mconfig, DIABLO1300, tag, owner, clock)
+ , m_program_config("program", ENDIANNESS_LITTLE, 16, 9, -1)
+ , m_data_config("data", ENDIANNESS_LITTLE, 8, 5)
+ , m_pc(0)
+ , m_a(0)
+ , m_b(0)
+ , m_carry(0)
+ , m_power_on(ASSERT_LINE)
+ , m_program(nullptr)
+ , m_data(nullptr)
+ , m_direct(nullptr)
+
+{
+ // Allocate & setup
+}
+
+
+void diablo1300_cpu_device::device_start()
+{
+ m_program = &space(AS_PROGRAM);
+ m_data = &space(AS_DATA);
+ m_direct = m_program->direct<-1>();
+
+ // register our state for the debugger
+ state_add(STATE_GENPC, "GENPC", m_pc).noshow();
+ state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow();
+
+ state_add(DIABLO_PC, "PC", m_pc).mask(0x1ff);
+ state_add(DIABLO_A, "A", m_a).mask(0xff);
+ state_add(DIABLO_B, "B", m_b).mask(0xff);
+
+ /* setup regtable */
+ save_item(NAME(m_pc));
+ save_item(NAME(m_a));
+ save_item(NAME(m_b));
+ save_item(NAME(m_power_on));
+
+ // set our instruction counter
+ m_icountptr = &m_icount;
+}
+
+void diablo1300_cpu_device::device_stop()
+{
+}
+
+void diablo1300_cpu_device::device_reset()
+{
+ m_pc = 0;
+ m_a = 0;
+ m_b = 0;
+ m_carry = 0;
+
+ m_power_on = ASSERT_LINE; // should be CLEAR_LINE when card can detect power up
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return the configuration
+// of the specified address space, or nullptr if
+// the space doesn't exist
+//-------------------------------------------------
+
+device_memory_interface::space_config_vector diablo1300_cpu_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_program_config),
+ std::make_pair(AS_DATA, &m_data_config)
+ };
+}
+
+//-------------------------------------------------
+// disaassemble - call the disadiablobly
+// helper function
+//-------------------------------------------------
+
+util::disasm_interface *diablo1300_cpu_device::create_disassembler()
+{
+ return new diablo1300_disassembler;
+}
+
+
+//**************************************************************************
+// CORE EXECUTION LOOP
+//**************************************************************************
+
+//-------------------------------------------------
+// execute_min_cycles - return minimum number of
+// cycles it takes for one instruction to execute
+//-------------------------------------------------
+
+uint32_t diablo1300_cpu_device::execute_min_cycles() const
+{
+ return 1;
+}
+
+
+//-------------------------------------------------
+// execute_max_cycles - return maximum number of
+// cycles it takes for one instruction to execute
+//-------------------------------------------------
+
+uint32_t diablo1300_cpu_device::execute_max_cycles() const
+{
+ return 1;
+}
+
+
+//-------------------------------------------------
+// execute_run - execute a timeslice's worth of
+// opcodes
+//-------------------------------------------------
+void diablo1300_cpu_device::execute_run()
+{
+ uint32_t op;
+
+ m_pc &= 0x1f;
+
+ while (m_icount > 0)
+ {
+ debugger_instruction_hook(this, m_pc);
+
+ if( m_power_on == ASSERT_LINE )
+ {
+ op = opcode_read(m_pc);
+ m_pc++;
+ switch (op & 0x0007)
+ {
+ case 0:
+ /* OUTPUT Dport, Sreg: Output register SSSS via reg A to port DDD, reg B and carry are cleared
+ 111A SSSS 0DDD RIII
+ A = 0: register is ORed into reg A, = 1: register is copied into reg A
+ SSSS = Source register
+ DDD = Destination port address
+ R = RAM bank select
+ III = 000 (opcode)
+ */
+ LOGOP("OUTPUT dv%d, r%02X\n",
+ (op & 0x0070) >> 4,
+ ((op & 0x0f00) >> 8) + ((op & 0x0008) ? 0x10 : 0));
+ m_a = read_reg(((op & 0x0f00) >> 8) + ((op & 0x0008) ? 0x10 : 0));
+ m_b = 0;
+ m_carry = 0;
+ write_port((op & 0x0070) >> 4, m_a);
+ break;
+ case 1:
+ /* JNC Addr: Set PC to address H AAAA AAAA, reg B and carry are cleared
+ AAAA AAAA 0000 HIII
+ AAAA AAAA = 8 low bits in Destination Address
+ H = The 9th hi address bit
+ III = 001 (opcode)
+ */
+ LOGOP("JNC %03X\n", ((op & 0xff00) >> 8) + ((op & 0x0008) ? 0x100 : 0));
+ m_a = (op & 0xff00) >> 8;
+ m_b = 0;
+ m_carry = 0;
+ m_pc = ((op & 0x0008) + m_a);
+ break;
+ case 2:
+ /* RST Dport : Reset Port
+ 1111 0AAA BBBB RIII
+ AAA = Device address
+ BBBB = I8-I5 signals
+ R = RAM bank select
+ III = 010 (opcode)
+ */
+ LOGOP("RST dv%d\n", (op & 0x0700) >> 8);
+ m_b = read_ibus();
+ m_a = read_port((op & 0x0700) >> 8);
+ m_carry = (m_carry + m_a + m_b) > 0xff ? 1 : 0;
+ break;
+ case 3:
+ /* LDBBIT Sreg, #value: Load AAAA AAAA #value into reg A, register BBBB reg B and set carry if #value != 0
+ AAAA AAAA BBBB RIII
+ AAAA AAAA = bits to load immediate into A
+ BBBB = register to load into B
+ R = RAM bank select
+ III = 011 (opcode)
+ */
+ LOGOP("LDBBIT r%02X, %02X\n",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ (op & 0xff00) >> 8);
+ m_a = (op & 0xff00) >> 8;
+ m_b = read_reg(((op & 0x00f0) >> 4));
+ m_carry = (m_a & m_b) != 0 ? 1 : 0;
+ break;
+ case 4:
+ switch(op & 0xc000)
+ {
+ case 0x4000:
+ /* XLAT Dreg: Load table data into A and reg, 0 into B
+ II10 0000 AAAA RIII
+ AAAA = Register
+ R = RAM bank select
+ II III = 01xx xxxx xxxx x100 (opcode)
+ */
+ LOGOP("XLAT r%02X\n",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0));
+ m_a = read_table(m_b + m_carry);
+ m_b = 0;
+ m_carry = 0;
+ write_reg(((op & 0x0008) != 0 ? 0x10 : 0) + ((op & 0x00f0) >> 4), m_a);
+ break;
+
+ case 0xc000:
+ /* MOVCPL Dreg, Sreg: register to register within RAM bank, acc B and carry is cleared
+ II11 SSSS DDDD RIII
+ SSSS = Source Register
+ DDDD = Destination register
+ R = RAM bank select
+ II III = 11xx xxxx xxxx x100 (opcode)
+ */
+ LOGOP("MOVCPL r%02X, r%02X\n",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ ((op & 0x0f00) >> 8) + ((op & 0x0008) ? 0x10 : 0));
+ m_a = read_reg(((op & 0x0008) != 0 ? 0x10 : 0) + ((op & 0x0f00) >> 8));
+ m_b = 0;
+ m_carry = 0;
+ write_reg(((op & 0x0008) != 0 ? 0x10 : 0) + ((op & 0x00f0) >> 4), m_a);
+ break;
+
+ case 0x8000:
+ /* INPUT Dreg, Sport: port to register, acc B and carry is cleared
+ II10 SSSS DDDD RIII
+ SSSS = Source Port
+ DDDD = Destination register
+ R = RAM bank select
+ II III = 01xx xxxx xxxx x100 (opcode)
+ */
+ LOGOP("INPUT r%02X, dv%X\n",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ ((op & 0x0f00) >> 8));
+ m_a = read_port((op & 0x0f00) >> 8);
+ m_b = 0;
+ m_carry = 0;
+ write_reg(((op & 0x0008) != 0 ? 0x10 : 0) + ((op & 0x00f0) >> 4), m_a);
+ break;
+ default:
+ break;
+ }
+ break;
+ case 5:
+ /* LOAD# Dreg,#val: Load value AAAA AAAA into register DDDD, acc B and carry is cleared
+ AAAA AAAA DDDD RIII
+ AAAA AAAA = bits to load into A
+ DDDD = register put A into
+ R = RAM bank select
+ III = 101 (opcode)
+ */
+ LOGOP("LOAD# r%02X, %02X\n",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ (op & 0xff00) >> 8);
+ m_a = (op & 0xff00) >> 8;
+ m_b = 0;
+ m_carry = 0;
+ write_reg(((op & 0x0008) != 0 ? 0x10 : 0) + ((op & 0x00f0) >> 4), m_a);
+ break;
+ case 6:
+ /* ADCCPL S/Dreg, Sreg
+ 1111 AAAA BBBB RIII
+ AAAA = Load register AAAA into reg A
+ BBBB = Load register into reg B
+ R = RAM bank select
+ III = 110 (opcode)
+ */
+ LOGOP("ADCCPL r%02X, r%02X\n",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ ((op & 0x0f00) >> 8) + ((op & 0x0008) ? 0x10 : 0));
+ m_a = read_reg(((op & 0x0008) != 0 ? 0x10 : 0) + ((op & 0x0f00) >> 8));
+ m_b = read_reg(((op & 0x0008) != 0 ? 0x10 : 0) + ((op & 0x00f0) >> 4));
+ m_carry = (m_a + m_b + m_carry) > 255 ? 1 : 0;
+ write_reg(((op & 0x0008) != 0 ? 0x10 : 0) + ((op & 0x00f0) >> 4), m_a);
+ break;
+ case 7:
+ /* ADC# S/Dreg, #val
+ AAAA AAAA BBBB RIII
+ AAAA AAAA = Load bits AAAA AAAA into A
+ BBBB = Load register BBBB into B
+ R = RAM bank select
+ III = 100 (opcode)
+ */
+ LOGOP("ADC# r%02X, %02X\n",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ (op & 0xff00) >> 8);
+ m_a = (op & 0xff00) >> 8;
+ m_b = read_reg(((op & 0x0008) != 0 ? 0x10 : 0) + ((op & 0x00f0) >> 4));
+ m_carry = (m_a + m_b + m_carry) > 255 ? 1 : 0;
+ write_reg(((op & 0x0008) != 0 ? 0x10 : 0) + ((op & 0x00f0) >> 4), m_a);
+ break;
+ default:
+ break;
+ }
+ }
+ --m_icount;
+ }
+}
diff --git a/src/devices/cpu/diablo/diablo1300.h b/src/devices/cpu/diablo/diablo1300.h
new file mode 100644
index 00000000000..fda5b8541c2
--- /dev/null
+++ b/src/devices/cpu/diablo/diablo1300.h
@@ -0,0 +1,94 @@
+// license:BSD-3-Clause copyright-holders:Joakim Larsson Edstrom
+/*
+ Diablo Printer TTL CPU
+*/
+
+#ifndef MAME_CPU_DIABLO_DIABLO1300_H
+#define MAME_CPU_DIABLO_DIABLO1300_H
+
+#pragma once
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> diablo1300_cpu_device
+
+// Used by core CPU interface
+class diablo1300_cpu_device : public cpu_device
+{
+public:
+ // construction/destruction
+ diablo1300_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_stop() override;
+
+ // device_execute_interface overrides
+ virtual uint32_t execute_min_cycles() const override;
+ virtual uint32_t execute_max_cycles() const override;
+ //virtual uint32_t execute_input_lines() const override;
+ virtual void execute_run() override;
+ //virtual void execute_set_input(int inputnum, int state) override;
+
+ // device_memory_interface overrides
+ virtual space_config_vector memory_space_config() const override;
+
+ // device_disasm_interface overrides
+ virtual util::disasm_interface *create_disassembler() override;
+
+ // device_state_interface overrides
+ //virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
+
+ // address spaces
+ const address_space_config m_program_config;
+ const address_space_config m_data_config;
+
+ // memory access
+ inline uint16_t opcode_read(uint16_t addr);
+ inline uint16_t program_read16(uint16_t addr);
+ inline void program_write16(uint16_t addr, uint16_t data);
+ inline uint8_t data_read8(uint16_t addr);
+ inline void data_write8(uint16_t addr, uint8_t data);
+
+ inline uint8_t read_reg(uint16_t reg);
+ inline uint16_t read_port(uint16_t port){ return 0;}
+ inline uint16_t read_table(uint16_t offset){ return 0;}
+ inline void write_reg(uint16_t reg, uint8_t data);
+ inline void write_port(uint16_t port, uint16_t data){}
+ inline uint16_t read_ibus(){ return 0; }
+
+ // CPU registers
+ uint16_t m_pc;
+ uint8_t m_a;
+ uint8_t m_b;
+ uint8_t m_carry;
+ uint8_t m_power_on;
+
+ // other internal states
+ int m_icount;
+
+ // address spaces
+ address_space *m_program;
+ address_space *m_data;
+ direct_read_data<-1> *m_direct;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(DIABLO1300, diablo1300_cpu_device)
+
+/***************************************************************************
+ REGISTER ENUMERATION
+***************************************************************************/
+
+enum
+{
+ DIABLO_PC = 1,
+ DIABLO_A,
+ DIABLO_B
+};
+
+#endif // MAME_CPU_DIABLO_DIABLO1300_H
diff --git a/src/devices/cpu/diablo/diablo1300dasm.cpp b/src/devices/cpu/diablo/diablo1300dasm.cpp
new file mode 100644
index 00000000000..3bc0a921dd2
--- /dev/null
+++ b/src/devices/cpu/diablo/diablo1300dasm.cpp
@@ -0,0 +1,82 @@
+// license:BSD-3-Clause
+// copyright-holders:Joakim Larsson Edstrom
+// thanks-to: Jeff Laughton
+/*
+ Diablo 1300 series Printer TTL CPU disassembler
+ The work is based on the RE done by Jeff Laughton http://laughtonelectronics.com/Arcana/Diablo%20CPU/DiabloCPU.html
+*/
+
+#include "emu.h"
+#include "diablo1300dasm.h"
+
+u32 diablo1300_disassembler::opcode_alignment() const
+{
+ return 1;
+}
+
+offs_t diablo1300_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
+{
+ uint16_t op = opcodes.r16(pc);
+
+ switch (op & 0x0007)
+ {
+ case 0: // OUTPUT Dport, Sreg
+ util::stream_format(stream, "OUTPUT dv%d, r%02X",
+ (op & 0x0070) >> 4,
+ ((op & 0x0f00) >> 8) + ((op & 0x0008) ? 0x10 : 0));
+ break;
+ case 1: // JNC Addr
+ util::stream_format(stream, "JNC %03X", ((op & 0xff00) >> 8) + ((op & 0x0008) ? 0x100 : 0));
+ break;
+ case 2: // RST #Dport
+ util::stream_format(stream, "RST dv%d", (op & 0x0700) >> 8);
+ break;
+ case 3: // LDBBIT Sreg, #val
+ util::stream_format(stream, "LDBBIT r%02X, %02X",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ (op & 0xff00) >> 8);
+ break;
+ case 4: //
+ switch (op & 0xc000)
+ {
+ case 0x4000: // XLAT Dreg
+ util::stream_format(stream, "XLAT r%02X",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0));
+ break;
+ case 0xc000: // MOVCPL Dreg, Sreg
+ util::stream_format(stream, "MOVCPL r%02X, r%02X",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ ((op & 0x0f00) >> 8) + ((op & 0x0008) ? 0x10 : 0));
+ break;
+ case 0x8000: // INPUT Dreg, Sport
+ util::stream_format(stream, "INPUT r%02X, dv%X",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ ((op & 0x0f00) >> 8));
+ break;
+ default:
+ util::stream_format(stream, "???");
+ break;
+ }
+ break;
+ case 5: // LOAD# Dreg,#val
+ util::stream_format(stream, "LOAD# r%02X, %02X",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ (op & 0xff00) >> 8);
+ break;
+ case 6: // ADCCPL S/Dreg, Sreg
+ util::stream_format(stream, "ADCCPL r%02X, r%02X",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ ((op & 0x0f00) >> 8) + ((op & 0x0008) ? 0x10 : 0));
+ break;
+ case 7: // ADC# S/Dreg, val
+ util::stream_format(stream, "ADC# r%02X, %02X",
+ ((op & 0x00f0) >> 4) + ((op & 0x0008) ? 0x10 : 0),
+ (op & 0xff00) >> 8);
+ break;
+ default:
+ util::stream_format(stream, "???");
+ break;
+ }
+
+ return 1 | SUPPORTED;
+}
diff --git a/src/devices/cpu/diablo/diablo1300dasm.h b/src/devices/cpu/diablo/diablo1300dasm.h
new file mode 100644
index 00000000000..496ea9b1775
--- /dev/null
+++ b/src/devices/cpu/diablo/diablo1300dasm.h
@@ -0,0 +1,22 @@
+// license:BSD-3-Clause
+// copyright-holders:Joakim Larsson Edstrom
+/*
+ Diablo Printer TTL CPU disassembler
+*/
+
+#ifndef MAME_CPU_DIABLO_DIABLO1300DASM_H
+#define MAME_CPU_DIABLO_DIABLO1300DASM_H
+
+#pragma once
+
+class diablo1300_disassembler : public util::disasm_interface
+{
+public:
+ diablo1300_disassembler() = default;
+ virtual ~diablo1300_disassembler() = default;
+
+ virtual u32 opcode_alignment() const override;
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
+};
+
+#endif