diff options
author | 2018-02-24 02:32:36 +0100 | |
---|---|---|
committer | 2018-02-24 02:32:36 +0100 | |
commit | 35a7f3e628a860dd75b2b57a95c3190443fd25a2 (patch) | |
tree | fd0d06694d60b7e3ea10e65618dc4f92057fdd95 /src/devices/cpu/diablo | |
parent | 534dea91eee1a5b67d8c480d411a10944830f619 (diff) |
WIP: Diablo printer CPU
Diffstat (limited to 'src/devices/cpu/diablo')
-rw-r--r-- | src/devices/cpu/diablo/diablo1300.cpp | 368 | ||||
-rw-r--r-- | src/devices/cpu/diablo/diablo1300.h | 94 | ||||
-rw-r--r-- | src/devices/cpu/diablo/diablo1300dasm.cpp | 82 | ||||
-rw-r--r-- | src/devices/cpu/diablo/diablo1300dasm.h | 22 |
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 ¶ms) +{ + 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 ¶ms) override; +}; + +#endif |