From 0b345e7bb62f90651c38f51157325886f29ece8d Mon Sep 17 00:00:00 2001 From: AJR Date: Fri, 29 May 2020 16:32:11 -0400 Subject: [PATCH] New machines marked as NOT_WORKING ---------------------------------- JoMoX XBase 09 Midi Controlled Analogue Drum Module [DBWBP] Add disassembler for PIC17 family and preliminary PIC17C4X emulation [AJR] --- scripts/src/cpu.lua | 19 + scripts/target/mame/mess.lua | 4 + src/devices/cpu/pic17/pic17.cpp | 1096 ++++++++++++++++++++++++++++ src/devices/cpu/pic17/pic17.h | 180 +++++ src/devices/cpu/pic17/pic17c4x.cpp | 537 ++++++++++++++ src/devices/cpu/pic17/pic17c4x.h | 181 +++++ src/devices/cpu/pic17/pic17d.cpp | 239 ++++++ src/devices/cpu/pic17/pic17d.h | 36 + src/mame/drivers/teamjocs.cpp | 4 +- src/mame/drivers/xbase09.cpp | 197 +++++ src/mame/mame.lst | 3 + src/mame/mess.flt | 1 + src/tools/unidasm.cpp | 2 + 13 files changed, 2497 insertions(+), 2 deletions(-) create mode 100644 src/devices/cpu/pic17/pic17.cpp create mode 100644 src/devices/cpu/pic17/pic17.h create mode 100644 src/devices/cpu/pic17/pic17c4x.cpp create mode 100644 src/devices/cpu/pic17/pic17c4x.h create mode 100644 src/devices/cpu/pic17/pic17d.cpp create mode 100644 src/devices/cpu/pic17/pic17d.h create mode 100644 src/mame/drivers/xbase09.cpp diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index ac904576e65..2f6ed7aabff 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -1308,6 +1308,25 @@ if (CPUS["PIC16"]~=null or _OPTIONS["with-tools"]) then table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/pic16/pic16d.h") end +-------------------------------------------------- +-- Microchip PIC17 +--@src/devices/cpu/pic17/pic17.h,CPUS["PIC17"] = true +-------------------------------------------------- + +if (CPUS["PIC17"]~=null) then + files { + MAME_DIR .. "src/devices/cpu/pic17/pic17.cpp", + MAME_DIR .. "src/devices/cpu/pic17/pic17.h", + MAME_DIR .. "src/devices/cpu/pic17/pic17c4x.cpp", + MAME_DIR .. "src/devices/cpu/pic17/pic17c4x.h", + } +end + +if (CPUS["PIC17"]~=null or _OPTIONS["with-tools"]) then + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/pic17/pic17d.cpp") + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/pic17/pic17d.h") +end + -------------------------------------------------- -- MIPS R3000 (MIPS I/II) series --@src/devices/cpu/mips/mips1.h,CPUS["MIPS1"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 529f96c5354..27c76e7629a 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -65,6 +65,7 @@ CPUS["DSP16"] = true CPUS["DSP32C"] = true CPUS["PIC16C5X"] = true CPUS["PIC16C62X"] = true +CPUS["PIC17"] = true CPUS["G65816"] = true CPUS["SPC700"] = true CPUS["E1"] = true @@ -2819,6 +2820,8 @@ files { MAME_DIR .. "src/mame/drivers/ergo201.cpp", MAME_DIR .. "src/mame/drivers/microterm.cpp", MAME_DIR .. "src/mame/drivers/microterm_f8.cpp", + MAME_DIR .. "src/mame/machine/ergo201_kbd.cpp", + MAME_DIR .. "src/mame/machine/ergo201_kbd.h", } createMESSProjects(_target, _subtarget, "mips") @@ -4466,6 +4469,7 @@ files { MAME_DIR .. "src/mame/drivers/vp415.cpp", MAME_DIR .. "src/mame/drivers/vsmilepro.cpp", MAME_DIR .. "src/mame/drivers/wicat.cpp", + MAME_DIR .. "src/mame/drivers/xbase09.cpp", MAME_DIR .. "src/mame/drivers/xor100.cpp", MAME_DIR .. "src/mame/includes/xor100.h", MAME_DIR .. "src/mame/drivers/zms8085.cpp", diff --git a/src/devices/cpu/pic17/pic17.cpp b/src/devices/cpu/pic17/pic17.cpp new file mode 100644 index 00000000000..47aa63553f3 --- /dev/null +++ b/src/devices/cpu/pic17/pic17.cpp @@ -0,0 +1,1096 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/********************************************************************** + + Microchip PIC17CXXX High-Performance 8-bit MCU family + + Common features of this family include: + — Four oscillator options (maximum rate of 33 MHz except on + PIC17C42) + — 2048 to 16,384 16-bit words of internal EPROM program memory + in microcontroller modes (may be protected; certain models use + mask ROM instead); special “long” table writes are used to + program EPROM when Vpp is applied + — 64K 16-bit words of external address space in microprocessor + mode, readable and writable through TABPTR and TABLAT + — 232 or more bytes of internal data RAM + — Two registers for indirect access to entire register file, with + optional post-increment or post-decrement for each + — Independent bank selection for peripheral SFRs and general- + purpose RAM (up to 16 banks are selectable for each, though no + more than 8 of the former and 4 of the latter were implemented) + — All instructions execute in a single cycle except for program + transfers and table reads/writes + – Signed overflow flag and decimal adjustment for addition + - 8 x 8 unsigned multiplication in hardware (except PIC17C42) + — Single-bit instructions can manipulate any addressable register + — MOVFP and MOVPF can transfer data between registers without + touching the working register + — CALL and GOTO allow efficient program transfers within 8K page + — 16-level on-chip program stack (non-addressable) + — Multiple 8-bit and 16-bit on-chip timer/counters, with 16-bit + input capture and 10-bit PWM output + — USART serial I/O with dedicated 8-bit baud rate generator + — Watchdog timer with internal RC oscillator + — SLEEP mode with wake-up upon interrupt + + Notable architectural quirks: + — PCH is copied to PCLATH whenever PCL is read unless the + operation on that register is of the read-modify-write type. + — MOVWF, CLRF, SETF, NEGW and DAW read the previous value of + the destination register before discarding and replacing it. + — A quirk of instruction decoding causes RETURN, SLEEP, CLRWDT + and RETFIE to perform dummy reads from PCL, PCLATH, ALUSTA + and T0STA respectively. This means that RETURN also copies PCH + to PCLATH before it pops the stack. + — The internal workings of the stack are fully specified, even + though no instruction can push or pop values from the stack, + adjust the stack pointer or even sense its current level + (aside from the crude heuristic of the STKAV flag). + — TABLWT and TABLRD access different implementations of TABLAT. + Neither half of a data word latched from external memory by + TABLRD will be written back by a following TABLWT. To ensure + correct data is present on both halves of the bus, TLWT must + precede TABLWT to refresh the alternate half of TABLAT. + — “Long” writes to internal EPROM (not emulated) can be aborted + by the setting of any interrupt flag, whether enabled or not. + +**********************************************************************/ + +#include "emu.h" +#include "pic17.h" +#include "pic17d.h" + +ALLOW_SAVE_TYPE(pic17_cpu_device::exec_phase); + +pic17_cpu_device::pic17_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 rom_size, address_map_constructor data_map) + : cpu_device(mconfig, type, tag, owner, clock) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 16, -1, address_map_constructor(FUNC(pic17_cpu_device::program_map), this)) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 12, 0, data_map) + , m_rom_size(rom_size) + , m_mode(mode::EXTENDED_MICROCONTROLLER) + , m_pc(0) + , m_ppc(0) + , m_paddr(0) + , m_raddr(0) + , m_ir(0) + , m_tmp(0) + , m_execphase(exec_phase::Q1) + , m_execflags(0) + , m_icount(0) + , m_pclath(0) + , m_wreg(0) + , m_alusta(0) + , m_cpusta(0x3c) + , m_intsta(0) + , m_tblptr(0) + , m_tablat(0) + , m_tlwt(0) + , m_prod(0) + , m_fsr{0, 0} + , m_bsr(0) + , m_stkptr(0) + , m_t0sta(0) + , m_tmr0(0) + , m_ps(0) +{ + std::fill_n(&m_stack[0], 16, 0); +} + +void pic17_cpu_device::program_map(address_map &map) +{ + if (m_mode != mode::MICROPROCESSOR) + { + map(0x0000, m_rom_size - 1).rom().region(DEVICE_SELF, 0); + //map(0xfe00, 0xffff).rom().region("config", 0); + } +} + +void pic17_cpu_device::core_data_map(address_map &map) +{ + // Unbanked registers (INDF0 and INDF1 are not physical registers) + map(0x000, 0x000).lr8([]() { return 0; }, "0").nopw(); + map(0x001, 0x001).rw(FUNC(pic17_cpu_device::fsr0_r), FUNC(pic17_cpu_device::fsr0_w)); + map(0x002, 0x002).rw(FUNC(pic17_cpu_device::pcl_r), FUNC(pic17_cpu_device::pcl_w)); + map(0x003, 0x003).rw(FUNC(pic17_cpu_device::pclath_r), FUNC(pic17_cpu_device::pclath_w)); + map(0x004, 0x004).rw(FUNC(pic17_cpu_device::alusta_r), FUNC(pic17_cpu_device::alusta_w)); + map(0x005, 0x005).rw(FUNC(pic17_cpu_device::t0sta_r), FUNC(pic17_cpu_device::t0sta_w)); + map(0x006, 0x006).rw(FUNC(pic17_cpu_device::cpusta_r), FUNC(pic17_cpu_device::cpusta_w)); + map(0x007, 0x007).rw(FUNC(pic17_cpu_device::intsta_r), FUNC(pic17_cpu_device::intsta_w)); + map(0x008, 0x008).lr8([]() { return 0; }, "0").nopw(); + map(0x009, 0x009).rw(FUNC(pic17_cpu_device::fsr1_r), FUNC(pic17_cpu_device::fsr1_w)); + map(0x00a, 0x00a).rw(FUNC(pic17_cpu_device::wreg_r), FUNC(pic17_cpu_device::wreg_w)); + map(0x00b, 0x00b).rw(FUNC(pic17_cpu_device::tmr0l_r), FUNC(pic17_cpu_device::tmr0l_w)); + map(0x00c, 0x00c).rw(FUNC(pic17_cpu_device::tmr0h_r), FUNC(pic17_cpu_device::tmr0h_w)); + map(0x00d, 0x00d).rw(FUNC(pic17_cpu_device::tblptrl_r), FUNC(pic17_cpu_device::tblptrl_w)); + map(0x00e, 0x00e).rw(FUNC(pic17_cpu_device::tblptrh_r), FUNC(pic17_cpu_device::tblptrh_w)); + map(0x00f, 0x00f).rw(FUNC(pic17_cpu_device::bsr_r), FUNC(pic17_cpu_device::bsr_w)); + map(0x018, 0x018).rw(FUNC(pic17_cpu_device::prodl_r), FUNC(pic17_cpu_device::prodl_w)); // not on PIC17C42 + map(0x019, 0x019).rw(FUNC(pic17_cpu_device::prodh_r), FUNC(pic17_cpu_device::prodh_w)); // not on PIC17C42 +} + +std::unique_ptr pic17_cpu_device::create_disassembler() +{ + return std::make_unique(); +} + +device_memory_interface::space_config_vector pic17_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) + }; +} + +u8 pic17_cpu_device::pcl_r() +{ + // Note that this side effect is implicitly performed by the RETURN instruction + if (!machine().side_effects_disabled() && (m_execflags & REGWT) == 0) + m_pclath = m_pc >> 8; + return m_pc & 0x00ff; +} + +void pic17_cpu_device::pcl_w(u8 data) +{ + m_pc = u8(m_pclath) << 8 | data; + m_execflags |= FORCENOP; +} + +void pic17_cpu_device::debug_set_pc(u16 data) +{ + m_pc = m_ppc = data; + m_ir = m_cache.read_word(m_pc); +} + +u8 pic17_cpu_device::pclath_r() +{ + return m_pclath; +} + +void pic17_cpu_device::pclath_w(u8 data) +{ + m_pclath = data; +} + +u8 pic17_cpu_device::wreg_r() +{ + return m_wreg; +} + +void pic17_cpu_device::wreg_w(u8 data) +{ + m_wreg = data; +} + +u8 pic17_cpu_device::alusta_r() +{ + return m_alusta; +} + +void pic17_cpu_device::alusta_w(u8 data) +{ + m_alusta = data; +} + +u8 pic17_cpu_device::cpusta_r() +{ + // STKAV is read as 0 when stack is full + if (m_stkptr == 0xf) + return m_cpusta & 0xdf; + else + return m_cpusta; +} + +void pic17_cpu_device::cpusta_w(u8 data) +{ + // Only GLINTD is writable + if (BIT(data, 4)) + { + m_cpusta |= 0x10; + + // PIC17C42 lacks this failsafe, allowing an interrupt to be taken right after an instruction that sets GLINTD + m_execflags &= ~INTRPT; + } + else + m_cpusta &= 0xef; +} + +u8 pic17_cpu_device::intsta_r() +{ + return m_intsta; +} + +void pic17_cpu_device::intsta_w(u8 data) +{ + // PEIF is read-only + m_intsta = (m_intsta & 0x80) | (data & 0x7f); +} + +void pic17_cpu_device::int_edge(bool rising) +{ + if (BIT(m_t0sta, 7) == rising) + m_intsta |= 0x10; +} + +void pic17_cpu_device::t0cki_edge(bool rising) +{ + if (BIT(m_t0sta, 6) == rising) + { + m_intsta |= 0x40; + if (!BIT(m_t0sta, 5)) + increment_tmr0(); + } +} + +void pic17_cpu_device::set_peif(bool state) +{ + if (state) + m_intsta |= 0x80; + else + { + m_intsta &= 0x7f; + if (((m_intsta >> 4) & m_intsta) == 0) + m_execflags &= ~INTRPT; + } +} + +u8 pic17_cpu_device::t0sta_r() +{ + return m_t0sta; +} + +void pic17_cpu_device::t0sta_w(u8 data) +{ + m_t0sta = data & 0xfe; +} + +u8 pic17_cpu_device::tmr0l_r() +{ + return m_tmr0 & 0x00ff; +} + +void pic17_cpu_device::tmr0l_w(u8 data) +{ + m_tmr0 = u8(data) | (m_tmr0 & 0xff00); + m_ps = 0; +} + +u8 pic17_cpu_device::tmr0h_r() +{ + return m_tmr0 >> 8; +} + +void pic17_cpu_device::tmr0h_w(u8 data) +{ + m_tmr0 = u8(data) << 8 | (m_tmr0 & 0x00ff); + m_ps = 0; +} + +void pic17_cpu_device::increment_tmr0() +{ + // Prescaler is an 8-bit ripple counter + ++m_ps; + + // Tap the prescaler output (PSOUT) + if ((m_ps & make_bitmask((m_t0sta & 0x1e) >> 1)) == 0) + { + // Set T0IF on overflow + if (m_tmr0 == 0xffff) + m_intsta |= 0x20; + ++m_tmr0; + } +} + +u8 pic17_cpu_device::fsr0_r() +{ + return m_fsr[0]; +} + +void pic17_cpu_device::fsr0_w(u8 data) +{ + m_fsr[0] = data; +} + +u8 pic17_cpu_device::fsr1_r() +{ + return m_fsr[1]; +} + +void pic17_cpu_device::fsr1_w(u8 data) +{ + m_fsr[1] = data; +} + +u8 pic17_cpu_device::bsr_r() +{ + return m_bsr; +} + +void pic17_cpu_device::bsr_w(u8 data) +{ + m_bsr = data; +} + +u8 pic17_cpu_device::tblptrl_r() +{ + return m_tblptr & 0x00ff; +} + +void pic17_cpu_device::tblptrl_w(u8 data) +{ + m_tblptr = (m_tblptr & 0xff00) | data; +} + +u8 pic17_cpu_device::tblptrh_r() +{ + return m_tblptr >> 8; +} + +void pic17_cpu_device::tblptrh_w(u8 data) +{ + m_tblptr = (m_tblptr & 0x00ff) | u16(data) << 8; +} + +u8 pic17_cpu_device::prodl_r() +{ + return m_prod & 0x00ff; +} + +void pic17_cpu_device::prodl_w(u8 data) +{ + m_prod = (m_prod & 0xff00) | data; +} + +u8 pic17_cpu_device::prodh_r() +{ + return m_prod >> 8; +} + +void pic17_cpu_device::prodh_w(u8 data) +{ + m_prod = (m_prod & 0x00ff) | u16(data) << 8; +} + +void pic17_cpu_device::set_skip() +{ + m_execflags |= SKIP; +} + +void pic17_cpu_device::clear_watchdog_timer() +{ + //logerror("%04X: Watchdog timer cleared\n", m_ppc); +} + +u16 pic17_cpu_device::banked_register(u8 r) +{ + // INDF0 and INDF1 substitute contents of FSR0/FSR1 + if ((r & 0xf7) == 0) + { + // Post auto-decrement, post auto-increment or no change + u8 fsmode = m_alusta >> (BIT(r, 3) ? 6 : 4); + if (BIT(fsmode, 1)) + r = m_fsr[BIT(r, 3)]; + else if (BIT(fsmode, 0)) + r = m_fsr[BIT(r, 3)]++; + else + r = m_fsr[BIT(r, 3)]--; + } + + if (r >= 0x20) + { + // Addresses from 20h to FFh use GPR banks + return u16(m_bsr & 0xf0) << 4 | r; + } + else if ((r & 0x18) == 0x10) + { + // Addresses from 10h to 17h use SFR banks + return u16(m_bsr & 0x0f) << 8 | r; + } + else + { + // Other addresses are unbanked + return r; + } +} + +void pic17_cpu_device::stack_push(u16 addr) +{ + m_stack[m_stkptr] = addr; + + // Check for stack overflow + if (m_stkptr == 0xf) + { + logerror("%04X: Stack overflow\n", m_pc); + + // STKAV remains cleared until reset + m_cpusta &= 0xdf; + } + + m_stkptr = (m_stkptr + 1) & 0xf; +} + +u16 pic17_cpu_device::stack_pop() +{ + m_stkptr = (m_stkptr - 1) & 0xf; + return m_stack[m_stkptr]; +} + +u16 pic17_cpu_device::interrupt_vector() +{ + u8 active_ints = (m_intsta >> 4) & m_intsta; + if (BIT(active_ints, 0)) + { + // Interrupt on RA0/INT pin edge + standard_irq_callback(0); + m_intsta &= 0xef; // INTF is cleared + return 0x0008; + } + else if (BIT(active_ints, 1)) + { + // Interrupt on TMR0 overflow + standard_irq_callback(1); + m_intsta &= 0xdf; // T0IF is cleared + return 0x0010; + } + else if (BIT(active_ints, 2)) + { + // Interrupt on RA1/T0CKI pin edge + standard_irq_callback(2); + m_intsta &= 0xbf; // T0CKIF is cleared + return 0x0018; + } + else if (BIT(active_ints, 3)) + { + // Peripheral interrupts (not further distinguished here, and PEIF is *not* cleared) + standard_irq_callback(3); + return 0x0020; + } + else + { + // This may happen when interrupt enable flags are cleared at the wrong moment + logerror("%04X: Spurious interrupt taken\n"); + return 0x0000; + } +} + +void pic17_cpu_device::set_zero(bool z) +{ + if (z) + m_alusta |= 0x04; + else + m_alusta &= 0xfb; +} + +void pic17_cpu_device::set_carry(bool c) +{ + if (c) + m_alusta |= 0x01; + else + m_alusta &= 0xfe; +} + +void pic17_cpu_device::add_with_carry(u8 augend, bool cin) +{ + // Carry out is inverted borrow for subtraction + bool cout = m_tmp + augend + cin >= 0x100; + bool dc = (m_tmp & 0x0f) + (augend & 0x0f) + cin >= 0x10; + s16 sum = s8(m_tmp) + s8(augend) + cin; + m_tmp = sum & 0x00ff; + + // Set OV, Z, DC and C flags + m_alusta &= 0xf0; + if (sum < -128 || sum >= 128) + m_alusta |= 0x08; + if (m_tmp == 0) + m_alusta |= 0x04; + if (dc) + m_alusta |= 0x02; + if (cout) + m_alusta |= 0x01; +} + +void pic17_cpu_device::decimal_adjust() +{ + u16 result = m_wreg; + + if (BIT(m_alusta, 1) || (result & 0x0f) > 0x09) + { + result += 0x06; + if (result >= 0x100) + m_alusta |= 0x01; + } + if (BIT(m_alusta, 0) || (result & 0xf0) > 0x90) + { + result += 0x60; + if (result >= 0x100) + m_alusta |= 0x01; + } +} + +void pic17_cpu_device::q1_decode() +{ + m_raddr = 0x000; + if (m_ir >= 0xc000) + { + // GOTO and CALL write to PCL (after setting PCLATH) + m_raddr = 0x002; + m_execflags |= REGWT; + } + else if (m_ir >= 0xb000) + { + if ((m_ir & 0x0f00) == 0x700) + { + // LCALL is a literal write to PCL + m_raddr = 0x002; + m_execflags |= REGWT; + } + else if ((m_ir & 0x0f00) == 0x800 || (m_ir & 0x0e00) == 0xa00) + { + // MOVLB and MOVLR operate on BSR + m_raddr = 0x00f; + m_execflags |= REGWT; + } + } + else if ((m_ir & 0xe000) == 0x4000) + { + // MOVPF reads register in 'p' field first + m_raddr = banked_register((m_ir & 0x1f00) >> 8); + } + else + { + if (m_ir != 0x0000) + m_raddr = banked_register(m_ir & 0x00ff); + if (m_ir < 0x3000) + { + // Byte-oriented register operations with d = 1 + // CLRF, SETF, NEGW, DAW always copy their result to the register, even when s = 0 + if (m_ir >= 0x2800 || BIT(m_ir, 8)) + m_execflags |= REGWT; + } + else if ((m_ir & 0xf800) == 0x3800 || (m_ir & 0xf000) == 0x8000) + { + // Bitwise read-modify-write instructions + m_execflags |= REGWT; + } + else if ((m_ir & 0xf400) == 0xa000) + { + // TABLRD/TBRD + m_execflags |= REGWT; + } + } +} + +void pic17_cpu_device::q2_read() +{ + if (m_ir >= 0xb000) + { + // Read literal data only + m_tmp = m_ir & 0x00ff; + + // Set PCLATH for GOTO/CALL + if (m_ir >= 0xc000) + m_pclath = (m_pc & 0xe000) >> 8 | (m_ir & 0x1f00) >> 8; + } + else if ((m_ir & 0xa400) == 0xa000) + { + // Read TABLATH or TABLATL + if (BIT(m_ir, 9)) + m_tmp = m_tablat >> 8; + else + m_tmp = m_tablat & 0x00ff; + } + else if (m_ir != 0x0000) + { + // Read register (dummy read for some instructions) + m_tmp = m_data.read_byte(m_raddr); + + if ((m_ir & 0xc000) == 0x4000) + { + // Swap out address for MOVFP/MOVPF + u8 f = m_ir & 0x00ff; + u8 p = (m_ir & 0x1f00) >> 8; + if (p != f) + m_raddr = banked_register(BIT(m_ir, 13) ? p : f); + + // Change from read to write mode + m_execflags |= REGWT; + } + } +} + +void pic17_cpu_device::q3_execute() +{ + if (m_ir >= 0xe000) + stack_push(m_pc); + else switch (m_ir & 0xff00) + { + case 0x0000: + switch (m_ir & 0x00ff) + { + case 0x00: // NOP + break; + + case 0x02: // RETURN + m_pc = stack_pop(); + m_execflags |= FORCENOP; + break; + + case 0x03: // SLEEP + clear_watchdog_timer(); + m_cpusta |= 0x08; // set TO + m_cpusta &= 0xfb; // clear PD + m_execflags |= SLEEP; + break; + + case 0x04: // CLRWDT + clear_watchdog_timer(); + break; + + case 0x05: // RETFIE + m_pc = stack_pop(); + m_execflags |= FORCENOP; + + // Clear global interrupt disable bit + m_cpusta &= 0xef; + break; + } + break; + + case 0x0100: // MOVWF + m_tmp = m_wreg; + break; + + case 0x0200: case 0x0300: // SUBWFB + add_with_carry(~m_wreg, BIT(m_alusta, 0)); + break; + + case 0x0400: case 0x0500: // SUBWF + case 0xb200: // SUBLW + add_with_carry(~m_wreg, true); + break; + + case 0x0600: case 0x0700: // DECF + add_with_carry(0xff, false); + break; + + case 0x0800: case 0x0900: // IORWF + case 0xb300: // IORLW + m_tmp |= m_wreg; + set_zero(m_tmp); + break; + + case 0x0a00: case 0x0b00: // ANDWF + case 0xb500: // ANDLW + m_tmp &= m_wreg; + set_zero(m_tmp); + break; + + case 0x0c00: case 0x0d00: // XORWF + case 0xb400: // XORLW + m_tmp ^= m_wreg; + set_zero(m_tmp); + break; + + case 0x0e00: case 0x0f00: // ADDWF + case 0xb100: // ADDLW + add_with_carry(m_wreg, false); + break; + + case 0x1000: case 0x1100: // ADDWFC + add_with_carry(m_wreg, BIT(m_alusta, 0)); + break; + + case 0x1200: case 0x1300: // COMF + m_tmp ^= 0xff; + set_zero(m_tmp); + break; + + case 0x1400: case 0x1500: // INCF + add_with_carry(1, false); + break; + + case 0x1600: case 0x1700: // DECFSZ + --m_tmp; + if (m_tmp == 0) + set_skip(); + break; + + case 0x1800: case 0x1900: // RRCF + set_carry(BIT(std::exchange(m_tmp, (m_tmp >> 1) | (m_alusta << 7)), 0)); + break; + + case 0x1a00: case 0x1b00: // RLCF + set_carry(BIT(std::exchange(m_tmp, (m_tmp << 1) | (m_alusta & 0x01)), 7)); + break; + + case 0x1c00: case 0x1d00: // SWAPF + m_tmp = (m_tmp << 4) | (m_tmp >> 4); + break; + + case 0x1e00: case 0x1f00: // INCFSZ + ++m_tmp; + if (m_tmp == 0) + set_skip(); + break; + + case 0x2000: case 0x2100: // RRNCF + m_tmp = (m_tmp >> 1) | (m_tmp << 7); + break; + + case 0x2200: case 0x2300: // RLNCF + m_tmp = (m_tmp << 1) | (m_tmp >> 7); + break; + + case 0x2400: case 0x2500: // INFSNZ + ++m_tmp; + if (m_tmp != 0) + set_skip(); + break; + + case 0x2600: case 0x2700: // DCFSNZ + --m_tmp; + if (m_tmp != 0) + set_skip(); + break; + + case 0x2800: case 0x2900: // CLRF + m_tmp = 0; + break; + + case 0x2a00: case 0x2b00: // SETF + m_tmp = 0xff; + break; + + case 0x2c00: case 0x2d00: // NEGW + m_tmp = 0; + add_with_carry(~m_wreg, true); + break; + + case 0x2e00: case 0x2f00: // DAW + decimal_adjust(); + break; + + case 0x3000: // CPFSLT (unsigned comparison) + if (m_tmp < m_wreg) + set_skip(); + break; + + case 0x3100: // CPFSEQ + if (m_tmp == m_wreg) + set_skip(); + break; + + case 0x3200: // CPFSGT (unsigned comparison) + if (m_tmp > m_wreg) + set_skip(); + break; + + case 0x3300: // TSTFSZ + if (m_tmp == 0) + set_skip(); + break; + + case 0x3400: // MULWF + case 0xbc00: // MULLW + m_prod = u16(m_wreg) * u16(m_tmp); + break; + + case 0x3800: case 0x3900: case 0x3a00: case 0x3b00: case 0x3c00: case 0x3d00: case 0x3e00: case 0x3f00: // BTG + m_tmp ^= 1 << ((m_ir & 0x0700) >> 8); + break; + + case 0x8000: case 0x8100: case 0x8200: case 0x8300: case 0x8400: case 0x8500: case 0x8600: case 0x8700: // BSF + m_tmp |= 1 << ((m_ir & 0x0700) >> 8); + break; + + case 0x8800: case 0x8900: case 0x8a00: case 0x8b00: case 0x8c00: case 0x8d00: case 0x8e00: case 0x8f00: // BCF + m_tmp &= ~(1 << ((m_ir & 0x0700) >> 8)); + break; + + case 0x9000: case 0x9100: case 0x9200: case 0x9300: case 0x9400: case 0x9500: case 0x9600: case 0x9700: // BTFSS + if ((m_tmp & (1 << ((m_ir & 0x0700) >> 8))) != 0) + set_skip(); + break; + + case 0x9800: case 0x9900: case 0x9a00: case 0x9b00: case 0x9c00: case 0x9d00: case 0x9e00: case 0x9f00: // BTFSC + if ((m_tmp & (1 << ((m_ir & 0x0700) >> 8))) == 0) + set_skip(); + break; + + case 0xb600: // RETLW + m_pc = stack_pop(); + m_execflags |= FORCENOP; + break; + + case 0xb700: // LCALL + stack_push(m_pc); + break; + + case 0xb800: // MOVLB + m_tmp = (m_bsr & 0xf0) | (m_tmp & 0x0f); + break; + + case 0xba00: case 0xbb00: // MOVLR + m_tmp = (m_tmp & 0xf0) | (m_bsr & 0x0f); + break; + } +} + +void pic17_cpu_device::q4_write() +{ + if ((m_execflags & REGWT) != 0) + { + m_data.write_byte(m_raddr, m_tmp); + m_execflags &= ~REGWT; + if ((m_ir & 0xfc00) == 0xa800) + { + m_execflags |= TABLRD; + if (BIT(m_ir, 8)) + m_execflags |= TBLPTRI; + } + } + else if ((m_ir & 0xf400) == 0xa400) + { + // Set TABLATH or TABLATL for TABLWT/TLWT + if (BIT(m_ir, 9)) + { + m_tablat = (m_tablat & 0x00ff) | u16(m_tmp) << 8; + m_tlwt = (m_tlwt & 0x00ff) | u16(m_tmp) << 8; + } + else + { + m_tablat = (m_tablat & 0xff00) | m_tmp; + m_tlwt = (m_tlwt & 0xff00) | m_tmp; + } + if (BIT(m_ir, 11)) + { + m_execflags |= TABLWT; + if (BIT(m_ir, 8)) + m_execflags |= TBLPTRI; + } + } + + // MOVLW, ADDLW, SUBLW, IORLW, XORLW, ANDLW, RETLW always store result in W; other ALU instructions do so when d = 0 + if ((m_ir >= 0x0200 && m_ir < 0x3000 && !BIT(m_ir, 8)) || (m_ir >= 0xb000 && m_ir < 0xb700)) + m_wreg = m_tmp; +} + +void pic17_cpu_device::increment_timers() +{ + // TMR0 increment is inhibited by count writes to TMR0L + if (BIT(m_t0sta, 5) && ((m_execflags & REGWT) == 0 || m_raddr != 0x00b)) + increment_tmr0(); +} + +void pic17_cpu_device::execute_run() +{ + switch (m_execphase) + { + while (true) + { + case exec_phase::Q1: + if ((m_execflags & SLEEP) != 0) + { + if (((m_intsta >> 4) & m_intsta) != 0) + m_execflags &= ~SLEEP; + else + { + // Do nothing until time to wake up + m_icount = 0; + m_execphase = exec_phase::Q1; + return; + } + } + if (m_execflags == 0) + { + m_ppc = m_pc; + debugger_instruction_hook(m_pc); + ++m_pc; + q1_decode(); + } + else if ((m_execflags & (TABLRD | TABLWT)) == 0) + { + if ((m_execflags & SKIP) != 0) + ++m_pc; + m_ir = 0; + m_execflags &= ~(SKIP | FORCENOP); + } + if (--m_icount <= 0) + { + m_execphase = exec_phase::Q2; + return; + } + + case exec_phase::Q2: + if ((m_execflags & (TABLRD | TABLWT)) != 0) + { + m_paddr = m_tblptr; + if ((m_execflags & TBLPTRI) != 0) + ++m_tblptr; + } + else + { + m_paddr = m_pc; + q2_read(); + } + if (--m_icount <= 0) + { + m_execphase = exec_phase::Q3; + return; + } + + case exec_phase::Q3: + if ((m_execflags & (TABLRD | TABLWT)) == 0) + { + if ((m_execflags & INTRPT) != 0) + { + m_execflags &= ~INTRPT; + + // Set global interrupt disable flag + m_cpusta |= 0x10; + + // Call to interrupt vector + stack_push(m_pc); + m_pc = interrupt_vector(); + m_execflags |= FORCENOP; + } + else + q3_execute(); + } + if (--m_icount <= 0) + { + m_execphase = exec_phase::Q4; + return; + } + + case exec_phase::Q4: + if (!BIT(m_cpusta, 4) && ((m_intsta >> 4) & m_intsta) != 0) + m_execflags = (m_execflags | INTRPT) & ~SLEEP; + increment_timers(); + if ((m_execflags & TABLWT) != 0) + { + // TABLAT value used here may not be from TABLRD, but must be written with TABLAT/TLWT. + // See PIC17C44 Rev. A Silicon Errata Sheet, DS30412C/44/E1A2. + m_program.write_word(m_paddr, m_tlwt); + m_execflags &= ~(TABLWT | TBLPTRI); + } + else if ((m_execflags & TABLRD) != 0) + { + m_tablat = m_program.read_word(m_paddr); + m_execflags &= ~(TABLRD | TBLPTRI); + } + else + { + u16 inst = m_cache.read_word(m_paddr); + q4_write(); + m_ir = inst; + } + if (--m_icount <= 0) + { + m_execphase = exec_phase::Q1; + return; + } + } + } +} + +void pic17_cpu_device::device_start() +{ + // Hook address spaces + space(AS_PROGRAM).cache(m_cache); + space(AS_PROGRAM).specific(m_program); + space(AS_DATA).specific(m_data); + set_icountptr(m_icount); + + // Register debug state + state_add(PIC17_PC, "PC", + [this]() { return m_pc; }, + [this](u16 data) { debug_set_pc(data); } + ); + state_add(STATE_GENPC, "GENPC", + [this]() { return m_pc; }, + [this](u16 data) { debug_set_pc(data); } + ).noshow(); + state_add(STATE_GENPCBASE, "CURPC", + [this]() { return m_ppc; }, + [this](u16 data) { debug_set_pc(data); } + ).noshow(); + state_add(PIC17_PCLATH, "PCLATH", m_pclath); + state_add(PIC17_STKPTR, "STKPTR", m_stkptr).mask(0xf); + state_add(PIC17_TOS, "TOS", + [this]() { return m_stack[(m_stkptr - 1) & 0xf]; }, + [this](u16 data) { m_stack[(m_stkptr - 1) & 0xf] = data; } + ); + state_add(PIC17_WREG, "W", m_wreg); + state_add(PIC17_PROD, "PROD", m_prod); // not in PIC17C42 + state_add(PIC17_ALUSTA, "ALUSTA", m_alusta); + state_add(STATE_GENFLAGS, "FLAGS", m_alusta).formatstr("%10s").noshow(); + state_add(PIC17_CPUSTA, "CPUSTA", m_cpusta).mask(0x3c); // PIC17C75X also implements bits 1 and 0 + state_add(PIC17_INTSTA, "INTSTA", m_intsta); + state_add(PIC17_FSR0, "FSR0", m_fsr[0]); + state_add(PIC17_FSR1, "FSR1", m_fsr[1]); + state_add(PIC17_BSR, "BSR", m_bsr); + state_add(PIC17_TBLPTR, "TBLPTR", m_tblptr); + state_add(PIC17_TABLAT, "TABLAT", m_tablat); + state_add(PIC17_TLWT, "TLWT", m_tlwt); + state_add(PIC17_T0STA, "T0STA", m_t0sta).mask(0xfe); + state_add(PIC17_TMR0, "TMR0", m_tmr0); + state_add(PIC17_PS, "PS", m_ps); + + // Save state + save_item(NAME(m_pc)); + save_item(NAME(m_ppc)); + save_item(NAME(m_paddr)); + save_item(NAME(m_raddr)); + save_item(NAME(m_ir)); + save_item(NAME(m_tmp)); + save_item(NAME(m_execphase)); + save_item(NAME(m_execflags)); + save_item(NAME(m_pclath)); + save_item(NAME(m_wreg)); + save_item(NAME(m_alusta)); + save_item(NAME(m_cpusta)); + save_item(NAME(m_intsta)); + save_item(NAME(m_tblptr)); + save_item(NAME(m_tablat)); + save_item(NAME(m_tlwt)); + save_item(NAME(m_prod)); + save_item(NAME(m_fsr)); + save_item(NAME(m_bsr)); + save_item(NAME(m_stkptr)); + save_item(NAME(m_stack)); + save_item(NAME(m_t0sta)); + save_item(NAME(m_tmr0)); + save_item(NAME(m_ps)); +} + +void pic17_cpu_device::device_reset() +{ + // Reset CPU + m_pc = 0; + m_execphase = exec_phase::Q1; + m_execflags = FORCENOP; + m_alusta |= 0xf0; + m_t0sta = 0; + m_cpusta |= 0x3c; + m_intsta = 0; + m_tblptr = 0; // not cleared on PIC17C42 + m_bsr = 0; + m_stkptr = 0; +} + +void pic17_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + str = string_format("1%c 0%c %c%c%c%c", + BIT(m_alusta, 7) ? '=' : BIT(m_alusta, 6) ? '+' : '-', + BIT(m_alusta, 5) ? '=' : BIT(m_alusta, 4) ? '+' : '-', + BIT(m_alusta, 3) ? 'V' : '.', // OV + BIT(m_alusta, 2) ? 'Z' : '.', + BIT(m_alusta, 1) ? 'D' : '.', // DC + BIT(m_alusta, 0) ? 'C' : '.'); + break; + } +} diff --git a/src/devices/cpu/pic17/pic17.h b/src/devices/cpu/pic17/pic17.h new file mode 100644 index 00000000000..d29a25fc958 --- /dev/null +++ b/src/devices/cpu/pic17/pic17.h @@ -0,0 +1,180 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_PIC17_PIC17_H +#define MAME_CPU_PIC17_PIC17_H + +#pragma once + +class pic17_cpu_device : public cpu_device +{ +public: + enum { + PIC17_PC, + PIC17_PCLATH, + PIC17_STKPTR, + PIC17_TOS, + PIC17_WREG, + PIC17_PROD, + PIC17_ALUSTA, + PIC17_CPUSTA, + PIC17_INTSTA, + PIC17_FSR0, + PIC17_FSR1, + PIC17_BSR, + PIC17_TBLPTR, + PIC17_TABLAT, + PIC17_TLWT, + PIC17_T0STA, + PIC17_TMR0, + PIC17_PS + }; + + enum class mode { + MICROPROCESSOR, + MICROCONTROLLER, + EXTENDED_MICROCONTROLLER + }; + + // misc. configuration + void set_mode(mode m) { m_mode = m; } + +protected: + pic17_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 rom_size, address_map_constructor data_map); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_execute_interface overrides + virtual void execute_run() override; + + // device_disasm_interface overrides + virtual std::unique_ptr create_disassembler() override; + + // device_memory_interface overrides + virtual space_config_vector memory_space_config() const override; + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + + // internal data map + void core_data_map(address_map &map); + + // helpers for derived classes + void int_edge(bool rising); + void t0cki_edge(bool rising); + void set_peif(bool state); + virtual void increment_timers(); + +private: + enum class exec_phase : u8 { Q1, Q2, Q3, Q4 }; + + enum exec_flags : u8 { + REGWT = 1 << 0U, + FORCENOP = 1 << 1U, + SKIP = 1 << 2U, + INTRPT = 1 << 3U, + TBLPTRI = 1 << 4U, + TABLRD = 1 << 5U, + TABLWT = 1 << 6U, + SLEEP = 1 << 7U + }; + + // internal register accessors + u8 pcl_r(); + void pcl_w(u8 data); + void debug_set_pc(u16 data); + u8 pclath_r(); + void pclath_w(u8 data); + u8 wreg_r(); + void wreg_w(u8 data); + u8 alusta_r(); + void alusta_w(u8 data); + u8 cpusta_r(); + void cpusta_w(u8 data); + u8 intsta_r(); + void intsta_w(u8 data); + u8 t0sta_r(); + void t0sta_w(u8 data); + u8 tmr0l_r(); + void tmr0l_w(u8 data); + u8 tmr0h_r(); + void tmr0h_w(u8 data); + void increment_tmr0(); + u8 fsr0_r(); + void fsr0_w(u8 data); + u8 fsr1_r(); + void fsr1_w(u8 data); + u8 bsr_r(); + void bsr_w(u8 data); + u8 tblptrl_r(); + void tblptrl_w(u8 data); + u8 tblptrh_r(); + void tblptrh_w(u8 data); + u8 prodl_r(); + void prodl_w(u8 data); + u8 prodh_r(); + void prodh_w(u8 data); + + // execution helpers + void set_skip(); + void clear_watchdog_timer(); + u16 banked_register(u8 r); + void stack_push(u16 addr); + u16 stack_pop(); + u16 interrupt_vector(); + void set_zero(bool z); + void set_carry(bool c); + void add_with_carry(u8 augend, bool cin); + void decimal_adjust(); + void q1_decode(); + void q2_read(); + void q3_execute(); + void q4_write(); + + // address map constructor + void program_map(address_map &map); + + // address spaces + const address_space_config m_program_config; + const address_space_config m_data_config; + const u16 m_rom_size; + memory_access<16, 1, -1, ENDIANNESS_LITTLE>::cache m_cache; + memory_access<16, 1, -1, ENDIANNESS_LITTLE>::specific m_program; + memory_access<12, 0, 0, ENDIANNESS_LITTLE>::specific m_data; + + // mode configuration + mode m_mode; + + // execution state + u16 m_pc; + u16 m_ppc; + u16 m_paddr; + u16 m_raddr; + u16 m_ir; + u8 m_tmp; + exec_phase m_execphase; + u8 m_execflags; + s32 m_icount; + + // internal status and control registers + u8 m_pclath; + u8 m_wreg; + u8 m_alusta; + u8 m_cpusta; + u8 m_intsta; + u16 m_tblptr; + u16 m_tablat; + u16 m_tlwt; + u16 m_prod; + u8 m_fsr[2]; + u8 m_bsr; + u8 m_stkptr; + u16 m_stack[16]; + u8 m_t0sta; + u16 m_tmr0; + u8 m_ps; +}; + +#endif // MAME_CPU_PIC17_PIC17_H diff --git a/src/devices/cpu/pic17/pic17c4x.cpp b/src/devices/cpu/pic17/pic17c4x.cpp new file mode 100644 index 00000000000..07976c32b79 --- /dev/null +++ b/src/devices/cpu/pic17/pic17c4x.cpp @@ -0,0 +1,537 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/********************************************************************** + + Microchip PIC17C4X microcontrollers + + Comparative list of features: + + Clock frequency 33 MHz maximum (PIC17C42: 25 MHz maximum) + EPROM (PIC17C42(A)) 2K (mask ROM on PIC17CR42) + EPROM (PIC17C43) 4K (mask ROM on PIC17CR43) + EPROM (PIC17C44) 8K + RAM (PIC17C42(A)) 232 bytes + RAM (PIC17C43/44) 454 bytes + Pin count 40 (PDIP, CERDIP) or 44 (PLCC, MQFP, TQFP) + Port pins 33 (19 shared with external bus) + Interrupt sources 11 + 8-bit timers 2 (cascadable) + 16-bit timers 16 (including TMR0) + Capture inputs 2 + PWM outputs 2 + USART 1 + + The original PIC17C42 lacks a hardware multiplier and has a few + CPU core bugs that were corrected in PIC17C42A and the rest of + the family. + +**********************************************************************/ + +#include "emu.h" +#include "pic17c4x.h" + +// device type definitions +DEFINE_DEVICE_TYPE(PIC17C43, pic17c43_device, "pic17c43", "Microchip PIC17C43") +DEFINE_DEVICE_TYPE(PIC17C44, pic17c44_device, "pic17c44", "Microchip PIC17C44") + +pic17c4x_device::pic17c4x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 rom_size, address_map_constructor data_map) + : pic17_cpu_device(mconfig, type, tag, owner, clock, rom_size, data_map) + , m_port_out_cb(*this) + , m_rain(0x3f) + , m_lata(0) + , m_rbpu(false) + , m_ddrb(0) + , m_latb(0) + , m_tmr8bit{0, 0} + , m_pr8bit{0, 0} + , m_tmr3(0) + , m_ca16bit{0, 0} + , m_tcon1(0) + , m_tcon2(0) + , m_rcsta(0) + , m_txsta(0) + , m_spbrg(0) + , m_pir(0) + , m_pie(0) +{ +} + +pic17c43_device::pic17c43_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 rom_size) + : pic17c4x_device(mconfig, type, tag, owner, clock, rom_size, address_map_constructor(FUNC(pic17c43_device::data_map), this)) +{ +} + +pic17c43_device::pic17c43_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : pic17c43_device(mconfig, PIC17C43, tag, owner, clock, 0x1000) +{ +} + +pic17c44_device::pic17c44_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : pic17c43_device(mconfig, PIC17C44, tag, owner, clock, 0x2000) +{ +} + +void pic17c4x_device::data_map(address_map &map) +{ + core_data_map(map); + + // TODO: add handlers for more of these SFRs + map(0x010, 0x010).rw(FUNC(pic17c4x_device::porta_r), FUNC(pic17c4x_device::porta_w)); + map(0x011, 0x011).rw(FUNC(pic17c4x_device::ddrb_r), FUNC(pic17c4x_device::ddrb_w)); + map(0x012, 0x012).rw(FUNC(pic17c4x_device::portb_r), FUNC(pic17c4x_device::portb_w)); + map(0x013, 0x013).rw(FUNC(pic17c4x_device::rcsta_r), FUNC(pic17c4x_device::rcsta_w)); + //map(0x014, 0x014).r(FUNC(pic17c4x_device::rcreg_r)); + map(0x015, 0x015).rw(FUNC(pic17c4x_device::txsta_r), FUNC(pic17c4x_device::txsta_w)); + map(0x016, 0x016).w(FUNC(pic17c4x_device::txreg_w)); + map(0x017, 0x017).rw(FUNC(pic17c4x_device::spbrg_r), FUNC(pic17c4x_device::spbrg_w)); + //map(0x110, 0x110).rw(FUNC(pic17c4x_device::ddrc_r), FUNC(pic17c4x_device::ddrc_w)); + //map(0x111, 0x111).rw(FUNC(pic17c4x_device::portc_r), FUNC(pic17c4x_device::portc_w)); + //map(0x112, 0x112).rw(FUNC(pic17c4x_device::ddrd_r), FUNC(pic17c4x_device::ddrd_w)); + //map(0x113, 0x113).rw(FUNC(pic17c4x_device::portd_r), FUNC(pic17c4x_device::portd_w)); + //map(0x114, 0x114).rw(FUNC(pic17c4x_device::ddre_r), FUNC(pic17c4x_device::ddre_w)); + //map(0x115, 0x115).rw(FUNC(pic17c4x_device::porte_r), FUNC(pic17c4x_device::porte_w)); + map(0x116, 0x116).rw(FUNC(pic17c4x_device::pir_r), FUNC(pic17c4x_device::pir_w)); + map(0x117, 0x117).rw(FUNC(pic17c4x_device::pie_r), FUNC(pic17c4x_device::pie_w)); + map(0x210, 0x210).rw(FUNC(pic17c4x_device::tmr1_r), FUNC(pic17c4x_device::tmr1_w)); + map(0x211, 0x211).rw(FUNC(pic17c4x_device::tmr2_r), FUNC(pic17c4x_device::tmr2_w)); + map(0x212, 0x212).rw(FUNC(pic17c4x_device::tmr3l_r), FUNC(pic17c4x_device::tmr3l_w)); + map(0x213, 0x213).rw(FUNC(pic17c4x_device::tmr3h_r), FUNC(pic17c4x_device::tmr3h_w)); + map(0x214, 0x214).rw(FUNC(pic17c4x_device::pr1_r), FUNC(pic17c4x_device::pr1_w)); + map(0x215, 0x215).rw(FUNC(pic17c4x_device::pr2_r), FUNC(pic17c4x_device::pr2_w)); + map(0x216, 0x216).rw(FUNC(pic17c4x_device::pr3l_ca1l_r), FUNC(pic17c4x_device::pr3l_ca1l_w)); + map(0x217, 0x217).rw(FUNC(pic17c4x_device::pr3h_ca1h_r), FUNC(pic17c4x_device::pr3h_ca1h_w)); + //map(0x310, 0x310).rw(FUNC(pic17c4x_device::pw1dcl_r), FUNC(pic17c4x_device::pw1dcl_w)); + //map(0x311, 0x311).rw(FUNC(pic17c4x_device::pw2dcl_r), FUNC(pic17c4x_device::pw2dcl_w)); + //map(0x312, 0x312).rw(FUNC(pic17c4x_device::pw1dch_r), FUNC(pic17c4x_device::pw1dch_w)); + //map(0x313, 0x313).rw(FUNC(pic17c4x_device::pw2dch_r), FUNC(pic17c4x_device::pw2dch_w)); + map(0x314, 0x314).r(FUNC(pic17c4x_device::ca2l_r)); + map(0x315, 0x315).r(FUNC(pic17c4x_device::ca2h_r)); + map(0x316, 0x316).rw(FUNC(pic17c4x_device::tcon1_r), FUNC(pic17c4x_device::tcon1_w)); + map(0x317, 0x317).rw(FUNC(pic17c4x_device::tcon2_r), FUNC(pic17c4x_device::tcon2_w)); +} + +void pic17c43_device::data_map(address_map &map) +{ + pic17c4x_device::data_map(map); + + // RAM: 454 bytes + map(0x01a, 0x0ff).ram(); + map(0x120, 0x1ff).ram(); +} + +u8 pic17c4x_device::porta_r() +{ + // RA2 and RA3 are open-drain I/O + // TODO: RA4 and RA5 carry USART signals + u8 porta = (m_rain & 0x33) | (m_rain & m_lata & 0x0c); + if (m_rbpu) + porta |= 0x80; + return porta; +} + +void pic17c4x_device::porta_w(u8 data) +{ + // RA0 and RA1 have no output drivers + // RA4 and RA5 can only be output from USART + m_lata = (m_lata & 0x30) | (data & 0x0c); + m_port_out_cb[0](m_lata); + + if (m_rbpu != BIT(data, 7)) + { + m_rbpu = BIT(data, 7); + if (m_ddrb != 0) + m_port_out_cb[1](m_rbpu ? (m_latb | m_ddrb) : (m_latb & m_ddrb)); + } +} + +u8 pic17c4x_device::ddrb_r() +{ + return m_ddrb; +} + +void pic17c4x_device::ddrb_w(u8 data) +{ + if (m_ddrb != data) + { + m_ddrb = data; + m_port_out_cb[1](m_rbpu ? (m_latb | m_ddrb) : (m_latb & m_ddrb)); + } +} + +u8 pic17c4x_device::portb_r() +{ + return m_latb | (m_rbpu ? m_ddrb : 0); +} + +void pic17c4x_device::portb_w(u8 data) +{ + m_latb = data; + m_port_out_cb[1](m_rbpu ? (m_latb | m_ddrb) : (m_latb & m_ddrb)); +} + +u8 pic17c4x_device::rcsta_r() +{ + return m_rcsta; +} + +void pic17c4x_device::rcsta_w(u8 data) +{ + // FERR, OERR and RX9D are read-only; bit 3 is unimplemented + m_rcsta = (data & 0xf0) | (m_rcsta & 0x07); +} + +u8 pic17c4x_device::txsta_r() +{ + return m_txsta; +} + +void pic17c4x_device::txsta_w(u8 data) +{ + // TRMT is read-only; bits 2 & 3 are unimplemented + m_txsta = (data & 0xf1) | (m_txsta & 0x02); +} + +void pic17c4x_device::txreg_w(u8 data) +{ + logerror("%s: Writing %02X to TXREG\n", machine().describe_context(), data); + + // Clear TXIF + m_pir &= 0xfd; + if ((m_pir & m_pie) == 0) + set_peif(false); +} + +u8 pic17c4x_device::spbrg_r() +{ + return m_spbrg; +} + +void pic17c4x_device::spbrg_w(u8 data) +{ + m_spbrg = data; +} + +u8 pic17c4x_device::tmr1_r() +{ + return m_tmr8bit[0]; +} + +void pic17c4x_device::tmr1_w(u8 data) +{ + m_tmr8bit[0] = data; +} + +u8 pic17c4x_device::tmr2_r() +{ + return m_tmr8bit[1]; +} + +void pic17c4x_device::tmr2_w(u8 data) +{ + m_tmr8bit[1] = data; +} + +u8 pic17c4x_device::tmr3l_r() +{ + return m_tmr3 & 0x00ff; +} + +void pic17c4x_device::tmr3l_w(u8 data) +{ + m_tmr3 = (m_tmr3 & 0xff00) | data; +} + +u8 pic17c4x_device::tmr3h_r() +{ + return m_tmr3 >> 8; +} + +void pic17c4x_device::tmr3h_w(u8 data) +{ + m_tmr3 = u16(data) << 8 | (m_tmr3 & 0x00ff); +} + +u8 pic17c4x_device::pr1_r() +{ + return m_pr8bit[0]; +} + +void pic17c4x_device::pr1_w(u8 data) +{ + m_pr8bit[0] = data; +} + +u8 pic17c4x_device::pr2_r() +{ + return m_pr8bit[1]; +} + +void pic17c4x_device::pr2_w(u8 data) +{ + m_pr8bit[1] = data; +} + +u8 pic17c4x_device::pr3l_ca1l_r() +{ + return m_ca16bit[0] & 0x00ff; +} + +void pic17c4x_device::pr3l_ca1l_w(u8 data) +{ + m_ca16bit[0] = (m_ca16bit[0] & 0xff00) | data; +} + +u8 pic17c4x_device::pr3h_ca1h_r() +{ + return m_ca16bit[0] >> 8; +} + +void pic17c4x_device::pr3h_ca1h_w(u8 data) +{ + m_ca16bit[0] = u16(data) << 8 | (m_ca16bit[0] & 0x00ff); +} + +u8 pic17c4x_device::ca2l_r() +{ + return m_ca16bit[1] & 0x00ff; +} + +u8 pic17c4x_device::ca2h_r() +{ + return m_ca16bit[1] >> 8; +} + +u8 pic17c4x_device::tcon1_r() +{ + return m_tcon1; +} + +void pic17c4x_device::tcon1_w(u8 data) +{ + m_tcon1 = data; +} + +u8 pic17c4x_device::tcon2_r() +{ + return m_tcon2; +} + +void pic17c4x_device::tcon2_w(u8 data) +{ + // CA1OVF and CA2OVF are read-only + m_tcon2 = (m_tcon2 & 0xc0) | (data & 0x3f); +} + +u8 pic17c4x_device::pir_r() +{ + return m_pir; +} + +void pic17c4x_device::pir_w(u8 data) +{ + // TXIF and RCIF are read-only + m_pir = (data & 0xfc) | (m_pir & 0x03); + set_peif((m_pie & m_pir) != 0); +} + +u8 pic17c4x_device::pie_r() +{ + return m_pie; +} + +void pic17c4x_device::pie_w(u8 data) +{ + m_pie = data; + set_peif((m_pie & m_pir) != 0); +} + +void pic17c4x_device::increment_timers() +{ + pic17_cpu_device::increment_timers(); + + // Advance TMR1 + if (BIT(m_tcon2, 0) && !BIT(m_tcon1, 0)) + { + if (BIT(m_tcon1, 3)) + { + // T16 mode: TMR1 and TMR2 cascaded + if (m_tmr8bit[0] == m_pr8bit[0] && m_tmr8bit[1] == m_pr8bit[1]) + { + // Roll over and set TMR1IF + m_tmr8bit[0] = 0; + m_tmr8bit[1] = 0; + m_pir |= 0x10; + if (BIT(m_pie, 4)) + set_peif(true); + } + else + { + ++m_tmr8bit[0]; + if (m_tmr8bit[0] == 0 && BIT(m_tcon2, 1)) + ++m_tmr8bit[1]; + } + } + else + { + if (m_tmr8bit[0] == m_pr8bit[0]) + { + // Roll over and set TMR1IF + m_tmr8bit[0] = 0; + m_pir |= 0x10; + if (BIT(m_pie, 4)) + set_peif(true); + } + else + ++m_tmr8bit[0]; + } + } + + // Advance TMR2 (as 8-bit counter only) + if (BIT(m_tcon2, 1) && (m_tcon1 & 0x0a) == 0) + { + if (m_tmr8bit[1] == m_pr8bit[1]) + { + // Roll over and set TMR2IF + m_tmr8bit[1] = 0; + m_pir |= 0x20; + if (BIT(m_pie, 5)) + set_peif(true); + } + else + ++m_tmr8bit[1]; + } + + // Advance TMR3 + if (BIT(m_tcon2, 2) && !BIT(m_tcon1, 2)) + { + // Period register is not used to determine overflow when CA1 mode is selected + if (m_tmr3 == (BIT(m_tcon2, 3) ? 0xffff : m_ca16bit[0])) + { + // Roll over and set TMR3IF + m_tmr3 = 0; + m_pir |= 0x40; + if (BIT(m_pie, 6)) + set_peif(true); + } + else + ++m_tmr3; + } +} + +void pic17c4x_device::device_resolve_objects() +{ + // Resolve callback objects + m_port_out_cb.resolve_all_safe(); +} + +void pic17c4x_device::device_start() +{ + pic17_cpu_device::device_start(); + + // Register debug state + state_add(PIC17_LATA, "LATA", m_lata).mask(0x3c); + state_add(PIC17_DDRB, "DDRB", m_ddrb); + state_add(PIC17_LATB, "LATB", m_latb); + state_add(PIC17_TMR1, "TMR1", m_tmr8bit[0]); + state_add(PIC17_TMR2, "TMR2", m_tmr8bit[1]); + state_add(PIC17_TMR3, "TMR3", m_tmr3); + state_add(PIC17_PR1, "PR1", m_pr8bit[0]); + state_add(PIC17_PR2, "PR2", m_pr8bit[1]); + state_add(PIC17_CA1, "CA1", m_ca16bit[0]); + state_add(PIC17_CA2, "CA2", m_ca16bit[1]); + state_add(PIC17_TCON1, "TCON1", m_tcon1); + state_add(PIC17_TCON2, "TCON2", m_tcon2); + state_add(PIC17_RCSTA, "RCSTA", m_rcsta).mask(0xf7); + state_add(PIC17_TXSTA, "TXSTA", m_txsta).mask(0xf3); + state_add(PIC17_SPBRG, "SPBRG", m_spbrg); + state_add(PIC17_PIE, "PIE", m_pie); + state_add(PIC17_PIR, "PIR", m_pir); + + // Save state + save_item(NAME(m_lata)); + save_item(NAME(m_rbpu)); + save_item(NAME(m_ddrb)); + save_item(NAME(m_latb)); + save_item(NAME(m_tmr8bit)); + save_item(NAME(m_pr8bit)); + save_item(NAME(m_tmr3)); + save_item(NAME(m_ca16bit)); + save_item(NAME(m_tcon1)); + save_item(NAME(m_tcon2)); + save_item(NAME(m_rcsta)); + save_item(NAME(m_txsta)); + save_item(NAME(m_spbrg)); + save_item(NAME(m_pie)); + save_item(NAME(m_pir)); +} + +void pic17c4x_device::device_reset() +{ + pic17_cpu_device::device_reset(); + + // Reset ports + m_lata = 0x3c; + m_rbpu = false; + m_ddrb = 0xff; + m_port_out_cb[0](0x3c); + m_port_out_cb[1](0xff); + + // Reset timers + //m_pw2dcl &= 0xc0; + m_tcon1 = 0; + m_tcon2 = 0; + + // Reset USART + m_rcsta &= 0x01; + m_txsta = (m_txsta & 0x01) | 0x02; + + // Reset peripheral interrupts + m_pir = 0x02; + m_pie = 0; +} + +void pic17c4x_device::execute_set_input(int linenum, int state) +{ + switch (linenum) + { + case RA0_LINE: + if (state != CLEAR_LINE && BIT(m_rain, 0)) + { + // Falling edge + m_rain &= 0x3e; + int_edge(false); + } + else if (state == CLEAR_LINE && !BIT(m_rain, 0)) + { + // Rising edge + m_rain |= 0x01; + int_edge(true); + } + break; + + case RA1_LINE: + if (state != CLEAR_LINE && BIT(m_rain, 1)) + { + // Falling edge + m_rain &= 0x3d; + t0cki_edge(false); + } + else if (state == CLEAR_LINE && !BIT(m_rain, 1)) + { + // Rising edge + m_rain |= 0x02; + t0cki_edge(true); + } + break; + + case RA2_LINE: + case RA3_LINE: + case RA4_LINE: + case RA5_LINE: + if (state == ASSERT_LINE) + m_rain &= ~(1 << (linenum - RA0_LINE)); + else + m_rain |= 1 << (linenum - RA0_LINE); + break; + } +} diff --git a/src/devices/cpu/pic17/pic17c4x.h b/src/devices/cpu/pic17/pic17c4x.h new file mode 100644 index 00000000000..e1ae9290230 --- /dev/null +++ b/src/devices/cpu/pic17/pic17c4x.h @@ -0,0 +1,181 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/********************************************************************** + _____ _____ + Vdd 1 |* \__/ | 40 RD0/AD8 + RC0/AD0 2 | | 39 RD1/AD9 + RC1/AD1 3 | | 38 RD2/AD10 + RC2/AD2 4 | | 37 RD3/AD11 + RC3/AD3 5 | | 36 RD4/AD12 + RC4/AD4 6 | | 35 RD5/AD13 + RC5/AD5 7 | | 34 RD6/AD14 + RC6/AD6 8 | | 33 RD7/AD15 + RC7/AD7 9 | | 32 _MCLR/Vpp + Vss 10 | PIC17C4X | 31 Vss + RB0/CAP1 11 | | 30 RE0/ALE + RB1/CAP2 12 | | 29 RE1/_OE + RB2/PWM1 13 | | 28 RE2/_WR + RB3/PWM2 14 | | 27 TEST + RB4/TCLK12 15 | | 26 RA0/INT + RB5/TCLK3 16 | | 25 RA1/T0CKI + RB6 17 | | 24 RA2 + RB7 18 | | 23 RA3 + OSC1/CLKIN 19 | | 22 RA4/RX/DT + OSC2/CLKOUT 20 |______________| 21 RA5/TX/CK + +**********************************************************************/ + +#ifndef MAME_CPU_PIC17_PIC17C4X_H +#define MAME_CPU_PIC17_PIC17C4X_H + +#pragma once + +#include "pic17.h" + +class pic17c4x_device : public pic17_cpu_device +{ +public: + enum { + RA0_LINE = 0, + INT_LINE = RA0_LINE, + RA1_LINE = 1, + T0CKI_LINE = RA1_LINE, + RA2_LINE = 2, + RA3_LINE = 3, + RA4_LINE = 4, + RX_LINE = RA4_LINE, + RA5_LINE = 5 + }; + + enum { + PIC17_LATA = PIC17_PS + 1, + PIC17_DDRB, + PIC17_LATB, + PIC17_TMR1, + PIC17_TMR2, + PIC17_TMR3, + PIC17_PR1, + PIC17_PR2, + PIC17_CA1, + PIC17_CA2, + PIC17_TCON1, + PIC17_TCON2, + PIC17_RCSTA, + PIC17_TXSTA, + PIC17_SPBRG, + PIC17_PIE, + PIC17_PIR + }; + + // callback configuration + auto ra_out_cb() { return m_port_out_cb[0].bind(); } + auto rb_out_cb() { return m_port_out_cb[1].bind(); } + auto rc_out_cb() { return m_port_out_cb[2].bind(); } + auto rd_out_cb() { return m_port_out_cb[3].bind(); } + auto re_out_cb() { return m_port_out_cb[4].bind(); } + +protected: + pic17c4x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 rom_size, address_map_constructor data_map); + + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; + + // device_execute_interface overrides + virtual u32 execute_input_lines() const noexcept override { return 6; } // for now + virtual bool execute_input_edge_triggered(int linenum) const noexcept override { return linenum == INT_LINE || linenum == T0CKI_LINE; } + virtual void execute_set_input(int linenum, int state) override; + + void data_map(address_map &map); + + virtual void increment_timers() override; + +private: + u8 porta_r(); + void porta_w(u8 data); + u8 ddrb_r(); + void ddrb_w(u8 data); + u8 portb_r(); + void portb_w(u8 data); + u8 tmr1_r(); + void tmr1_w(u8 data); + u8 tmr2_r(); + void tmr2_w(u8 data); + u8 tmr3l_r(); + void tmr3l_w(u8 data); + u8 tmr3h_r(); + void tmr3h_w(u8 data); + u8 pr1_r(); + void pr1_w(u8 data); + u8 pr2_r(); + void pr2_w(u8 data); + u8 pr3l_ca1l_r(); + void pr3l_ca1l_w(u8 data); + u8 pr3h_ca1h_r(); + void pr3h_ca1h_w(u8 data); + u8 ca2l_r(); + u8 ca2h_r(); + u8 tcon1_r(); + void tcon1_w(u8 data); + u8 tcon2_r(); + void tcon2_w(u8 data); + u8 rcsta_r(); + void rcsta_w(u8 data); + u8 txsta_r(); + void txsta_w(u8 data); + void txreg_w(u8 data); + u8 spbrg_r(); + void spbrg_w(u8 data); + u8 pir_r(); + void pir_w(u8 data); + u8 pie_r(); + void pie_w(u8 data); + + // callback objects + devcb_write8::array<5> m_port_out_cb; + + // internal state + u8 m_rain; + u8 m_lata; + bool m_rbpu; + u8 m_ddrb; + u8 m_latb; + u8 m_tmr8bit[2]; + u8 m_pr8bit[2]; + u16 m_tmr3; + u16 m_ca16bit[2]; + u8 m_tcon1; + u8 m_tcon2; + u8 m_rcsta; + u8 m_txsta; + u8 m_spbrg; + u8 m_pir; + u8 m_pie; +}; + +class pic17c43_device : public pic17c4x_device +{ +public: + // device type constructor + pic17c43_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + pic17c43_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 rom_size); + +private: + void data_map(address_map &map); +}; + +class pic17c44_device : public pic17c43_device +{ +public: + // device type constructor + pic17c44_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +// device type declarations +DECLARE_DEVICE_TYPE(PIC17C43, pic17c43_device) +DECLARE_DEVICE_TYPE(PIC17C44, pic17c44_device) + +#endif // MAME_CPU_PIC17_PIC17C4X_H diff --git a/src/devices/cpu/pic17/pic17d.cpp b/src/devices/cpu/pic17/pic17d.cpp new file mode 100644 index 00000000000..016a3cfe809 --- /dev/null +++ b/src/devices/cpu/pic17/pic17d.cpp @@ -0,0 +1,239 @@ + // license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Microchip PIC17 disassembler + +***************************************************************************/ + +#include "emu.h" +#include "pic17d.h" + +const char *const pic17_disassembler::s_peripheral_regs[0x20] = +{ + "INDF0", "FSR0", "PCL", "PCLATH", "ALUSTA", "T0STA", "CPUSTA", "INTSTA", + "INDF1", "FSR1", "WREG", "TMR0L", "TMR0H", "TBLPTRL", "TBLPTRH", "BSR", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // banked + "PRODL", "PRODH", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr +}; + +const char *const pic17_disassembler::s_tb_ops[4] = +{ + "TLRD", "TLWT", "TABLRD", "TABLWT" +}; + +const char *const pic17_disassembler::s_bit_ops[4] = +{ + "BSF", "BCF", "BTFSS", "BTFSC" +}; + +const char *const pic17_disassembler::s_cp_ops[4] = +{ + "CPFSLT", "CPFSEQ", "CPFSGT", "TSTFSZ" +}; + +const char *const pic17_disassembler::s_alu_ops[0x30 / 2] = +{ + "MOVWF", "SUBWFB", "SUBWF", "DECF", "IORWF", "ANDWF", "XORWF", "ADDWF", + "ADDWFC", "COMF", "INCF", "DECFSZ", "RRCF", "RLCF", "SWAPF", "INCFSZ", + "RRNCF", "RLNCF", "INFSNZ", "DCFSNZ", "CLRF", "SETF", "NEGW", "DAW" +}; + +pic17_disassembler::pic17_disassembler() + : util::disasm_interface() +{ +} + +u32 pic17_disassembler::opcode_alignment() const +{ + return 1; +} + +void pic17_disassembler::format_register(std::ostream &stream, u8 reg) const +{ + if (reg < 0x20 && s_peripheral_regs[reg] != nullptr) + stream << s_peripheral_regs[reg]; + else + util::stream_format(stream, "R%02X", reg); +} + +void pic17_disassembler::format_literal(std::ostream &stream, u8 data) const +{ + util::stream_format(stream, "%02Xh", data); +} + +void pic17_disassembler::format_address(std::ostream &stream, u16 dst) const +{ + util::stream_format(stream, "%04Xh", dst); +} + +offs_t pic17_disassembler::disassemble(std::ostream &stream, offs_t pc, const pic17_disassembler::data_buffer &opcodes, const pic17_disassembler::data_buffer ¶ms) +{ + u16 opcode = opcodes.r16(pc); + offs_t words = 1; + + if (opcode >= 0xc000) + { + if (BIT(opcode, 13)) + { + util::stream_format(stream, "%-8s", "CALL"); + words |= STEP_OVER; + } + else + util::stream_format(stream, "%-8s", "GOTO"); + format_address(stream, ((pc + 1) & 0xe000) | (opcode & 0x1fff)); + } + else if (opcode >= 0xb000) + { + // Literal and control operations + switch (opcode & 0x0f00) + { + case 0x000: + util::stream_format(stream, "%-8s", "MOVLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x100: + util::stream_format(stream, "%-8s", "ADDLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x200: + util::stream_format(stream, "%-8s", "SUBLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x300: + util::stream_format(stream, "%-8s", "IORLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x400: + util::stream_format(stream, "%-8s", "XORLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x500: + util::stream_format(stream, "%-8s", "ANDLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x600: + util::stream_format(stream, "%-8s", "RETLW"); + format_literal(stream, opcode & 0x00ff); + words |= STEP_OUT; + break; + + case 0x700: + util::stream_format(stream, "%-8s", "LCALL"); + format_literal(stream, opcode & 0x00ff); + words |= STEP_OVER; + break; + + case 0x800: + util::stream_format(stream, "%-8s%d", "MOVLB", opcode & 0x000f); + break; + + case 0xa00: case 0xb00: + util::stream_format(stream, "%-8s%d", "MOVLR", (opcode & 0x00f0) >> 4); + break; + + case 0xc00: + util::stream_format(stream, "%-8s", "MULLW"); + format_literal(stream, opcode & 0x00ff); + break; + + default: + util::stream_format(stream, "%-8s%04Xh", "DW", opcode); + break; + } + } + else if (opcode >= 0xa000) + { + util::stream_format(stream, "%-8s%d,", s_tb_ops[BIT(opcode, 10, 2)], BIT(opcode, 9)); + if (BIT(opcode, 11)) + util::stream_format(stream, "%d,", BIT(opcode, 8)); + format_register(stream, opcode & 0x00ff); + } + else if (opcode >= 0x8000) + { + // Bit-oriented file register operations + util::stream_format(stream, "%-8s", s_bit_ops[BIT(opcode, 11, 2)]); + format_register(stream, opcode & 0x00ff); + util::stream_format(stream, ",%d", BIT(opcode, 8, 3)); + } + else if (opcode >= 0x6000) + { + // Byte-to-byte move operations + util::stream_format(stream, "%-8s", "MOVFP"); + format_register(stream, opcode & 0x00ff); + stream << ","; + format_register(stream, (opcode & 0x1f00) >> 8); + } + else if (opcode >= 0x4000) + { + util::stream_format(stream, "%-8s", "MOVPF"); + format_register(stream, (opcode & 0x1f00) >> 8); + stream << ","; + format_register(stream, opcode & 0x00ff); + } + else if (opcode >= 0x3800) + { + util::stream_format(stream, "%-8s", "BTG"); + format_register(stream, opcode & 0x00ff); + util::stream_format(stream, ",%d", BIT(opcode, 8, 3)); + } + else if (opcode >= 0x3000) + { + if (opcode < 0x3400) + { + util::stream_format(stream, "%-8s", s_cp_ops[BIT(opcode, 8, 2)]); + format_register(stream, opcode & 0x00ff); + } + else if (opcode < 0x3500) + { + util::stream_format(stream, "%-8s", "MULWF"); + format_register(stream, opcode & 0x00ff); + } + else + util::stream_format(stream, "%-8s%04Xh", "DW", opcode); + } + else if (opcode >= 0x0100) + { + // Byte-oriented file register operations + util::stream_format(stream, "%-8s", s_alu_ops[BIT(opcode, 9, 5)]); + format_register(stream, opcode & 0x00ff); + if (opcode >= 0x0200) + util::stream_format(stream, ",%c", BIT(opcode, 8) ? 'F' : 'W'); + } + else switch (opcode) + { + case 0x0000: + stream << "NOP"; + break; + + case 0x0002: + stream << "RETURN"; + words |= STEP_OUT; + break; + + case 0x0003: + stream << "SLEEP"; + break; + + case 0x0004: + stream << "CLRWDT"; + break; + + case 0x0005: + stream << "RETFIE"; + words |= STEP_OUT; + break; + + default: + util::stream_format(stream, "%-8s%04Xh", "DW", opcode); + break; + } + + return words; +} diff --git a/src/devices/cpu/pic17/pic17d.h b/src/devices/cpu/pic17/pic17d.h new file mode 100644 index 00000000000..43c074031ff --- /dev/null +++ b/src/devices/cpu/pic17/pic17d.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_PIC17_PIC17D_H +#define MAME_CPU_PIC17_PIC17D_H + +#pragma once + +class pic17_disassembler : public util::disasm_interface +{ +public: + // construction/destruction + pic17_disassembler(); + +protected: + // disassembler overrides + 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; + +private: + // register names + static const char *const s_peripheral_regs[0x20]; + + // instruction mnemonics + static const char *const s_tb_ops[4]; + static const char *const s_bit_ops[4]; + static const char *const s_cp_ops[4]; + static const char *const s_alu_ops[0x30 / 2]; + + // internal helpers + void format_register(std::ostream &stream, u8 reg) const; + void format_literal(std::ostream &stream, u8 data) const; + void format_address(std::ostream &stream, u16 dst) const; +}; + +#endif // MAME_CPU_PIC17_PIC17D_H diff --git a/src/mame/drivers/teamjocs.cpp b/src/mame/drivers/teamjocs.cpp index b9710da9dd1..cdbd7512aea 100644 --- a/src/mame/drivers/teamjocs.cpp +++ b/src/mame/drivers/teamjocs.cpp @@ -32,7 +32,7 @@ */ #include "emu.h" -#include "cpu/pic16c5x/pic16c5x.h" +#include "cpu/pic17/pic17c4x.h" #include "machine/nvram.h" #include "sound/okim6376.h" #include "speaker.h" @@ -59,7 +59,7 @@ INPUT_PORTS_END void teamjocs_state::teamjocs(machine_config &config) { - PIC16C55(config, m_maincpu, 4_MHz_XTAL); // actually PIC17C44-16 + PIC17C44(config, m_maincpu, 4_MHz_XTAL); SPEAKER(config, "mono").front_center(); diff --git a/src/mame/drivers/xbase09.cpp b/src/mame/drivers/xbase09.cpp new file mode 100644 index 00000000000..f7401397e41 --- /dev/null +++ b/src/mame/drivers/xbase09.cpp @@ -0,0 +1,197 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/**************************************************************************** + + Skeleton driver for XBase 09 drum machine by JoMoX GmbH. + +****************************************************************************/ + +#include "emu.h" +#include "cpu/pic17/pic17c4x.h" +#include "machine/nvram.h" + +class xbase09_state : public driver_device +{ +public: + xbase09_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_analog_ports(*this, "ANALOG%02X", 0U) + , m_port_select(0) + { + } + + void xbase09(machine_config &config); + +protected: + virtual void machine_start() override; + +private: + void portb_w(u8 data); + u16 ram_r(offs_t offset); + void ram_w(offs_t offset, u16 data); + void mem_map(address_map &map); + + required_device m_maincpu; + required_ioport_array<0x16> m_analog_ports; + + std::unique_ptr m_nvram_data; + u8 m_port_select; +}; + +void xbase09_state::machine_start() +{ + m_nvram_data = std::make_unique(0x8000); + subdevice("nvram")->set_base(m_nvram_data.get(), 0x8000); + + save_pointer(NAME(m_nvram_data), 0x8000); + save_item(NAME(m_port_select)); +} + + +void xbase09_state::portb_w(u8 data) +{ + m_port_select = data >> 3; +} + +u16 xbase09_state::ram_r(offs_t offset) +{ + return m_nvram_data[offset] | 0xff00; +} + +void xbase09_state::ram_w(offs_t offset, u16 data) +{ + switch (offset) + { + case 0x0007: + // Successive-approximation ADC implemented using software algorithm and LM393 comparator + if (m_port_select < 0x16 && m_analog_ports[m_port_select]->read() < (data >> 8)) + m_maincpu->set_input_line(pic17c4x_device::RA0_LINE, ASSERT_LINE); + else + m_maincpu->set_input_line(pic17c4x_device::RA0_LINE, CLEAR_LINE); + break; + + default: + if ((data & 0xff00) != 0) + logerror("%s: Writing %04X to %04X\n", machine().describe_context(), data, offset + 0x8000); + break; + } + + m_nvram_data[offset] = data & 0x00ff; +} + + +void xbase09_state::mem_map(address_map &map) +{ + map(0x0000, 0x7fff).rom().region("firmware", 0); + map(0x8000, 0xffff).rw(FUNC(xbase09_state::ram_r), FUNC(xbase09_state::ram_w)); +} + + +static INPUT_PORTS_START(xbase09) + PORT_START("ANALOG00") + PORT_BIT(0xff, 0x00, IPT_UNKNOWN) + + PORT_START("ANALOG01") + PORT_BIT(0xff, 0x01, IPT_UNKNOWN) + + PORT_START("ANALOG02") + PORT_BIT(0xff, 0x02, IPT_UNKNOWN) + + PORT_START("ANALOG03") + PORT_BIT(0xff, 0x03, IPT_UNKNOWN) + + PORT_START("ANALOG04") + PORT_BIT(0xff, 0x04, IPT_UNKNOWN) + + PORT_START("ANALOG05") + PORT_BIT(0xff, 0x05, IPT_UNKNOWN) + + PORT_START("ANALOG06") + PORT_BIT(0xff, 0x06, IPT_UNKNOWN) + + PORT_START("ANALOG07") + PORT_BIT(0xff, 0x07, IPT_UNKNOWN) + + PORT_START("ANALOG08") + PORT_BIT(0xff, 0x08, IPT_UNKNOWN) + + PORT_START("ANALOG09") + PORT_BIT(0xff, 0x09, IPT_UNKNOWN) + + PORT_START("ANALOG0A") + PORT_BIT(0xff, 0x0a, IPT_UNKNOWN) + + PORT_START("ANALOG0B") + PORT_BIT(0xff, 0x14, IPT_UNKNOWN) + + PORT_START("ANALOG0C") + PORT_BIT(0xff, 0x1e, IPT_UNKNOWN) + + PORT_START("ANALOG0D") + PORT_BIT(0xff, 0x28, IPT_UNKNOWN) + + PORT_START("ANALOG0E") + PORT_BIT(0xff, 0x32, IPT_UNKNOWN) + + PORT_START("ANALOG0F") + PORT_BIT(0xff, 0x3c, IPT_UNKNOWN) + + PORT_START("ANALOG10") + PORT_BIT(0xff, 0x46, IPT_UNKNOWN) + + PORT_START("ANALOG11") + PORT_BIT(0xff, 0x50, IPT_UNKNOWN) + + PORT_START("ANALOG12") + PORT_BIT(0xff, 0x5a, IPT_UNKNOWN) + + PORT_START("ANALOG13") + PORT_BIT(0xff, 0x64, IPT_UNKNOWN) + + PORT_START("ANALOG14") + PORT_BIT(0xff, 0xc8, IPT_UNKNOWN) + + PORT_START("ANALOG15") + PORT_BIT(0xff, 0xff, IPT_UNKNOWN) +INPUT_PORTS_END + +void xbase09_state::xbase09(machine_config &config) +{ + PIC17C43(config, m_maincpu, 16_MHz_XTAL); // PIC17C43-16/P + m_maincpu->set_mode(pic17c43_device::mode::MICROPROCESSOR); + m_maincpu->set_addrmap(AS_PROGRAM, &xbase09_state::mem_map); + m_maincpu->rb_out_cb().set(FUNC(xbase09_state::portb_w)); + + NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); // SRM2B256SLMX10, NEC D43256BGU-70LL or equivalent + battery + + //MAX509(config, "dac"); // MAX509BWCP (near top of PCB) +} + +// IC positions are not labeled on PCB except for stickered PLDs +ROM_START(xbase09) + ROM_REGION16_LE(0x10000, "firmware", 0) + ROM_DEFAULT_BIOS("v209") + ROM_SYSTEM_BIOS(0, "v132", "Version 1.32") + ROMX_LOAD("xbase_09__1.32l.bin", 0x0000, 0x8000, CRC(30dc47c6) SHA1(ee79f9e98c06edd8a5963fcd325da3490e8e5b76), ROM_BIOS(0) | ROM_SKIP(1)) + ROMX_LOAD("xbase_09__1.32h.bin", 0x0001, 0x8000, CRC(ce2df930) SHA1(56922d069b53013f2a3646dcd63fbbc9b609cf5b), ROM_BIOS(0) | ROM_SKIP(1)) + ROM_SYSTEM_BIOS(1, "v208", "Version 2.08 (without Tempo lock)") + ROMX_LOAD("xbase_09__2.08l.bin", 0x0000, 0x8000, CRC(c0f06ef6) SHA1(912f0b01cf5cfdc37ce61b3eacf933174f80171d), ROM_BIOS(1) | ROM_SKIP(1)) + ROMX_LOAD("xbase_09__2.08h.bin", 0x0001, 0x8000, CRC(f1287888) SHA1(ee162887af1cfe968004b8c2e1c5417be42b2e9f), ROM_BIOS(1) | ROM_SKIP(1)) + ROM_SYSTEM_BIOS(2, "v209", "Version 2.09 (with Tempo lock)") + ROMX_LOAD("xbase_09__2.09l.bin", 0x0000, 0x8000, CRC(60667060) SHA1(6a004934dd3f5f729f59bcbcb79e86e0e5f97fe9), ROM_BIOS(2) | ROM_SKIP(1)) + ROMX_LOAD("xbase_09__2.09h.bin", 0x0001, 0x8000, CRC(64645c77) SHA1(35cc18774d9e4cc61af0469144c49dddfabc92b7), ROM_BIOS(2) | ROM_SKIP(1)) + ROM_SYSTEM_BIOS(3, "sx209", "SX Version 2.09") // "requires hardware update," so may need to be a separate system + ROMX_LOAD("xbase09sx_2.09l.bin", 0x0000, 0x8000, CRC(7e87c30d) SHA1(2237f235749ae583327f1f8d893ceb3bb6502ae9), ROM_BIOS(3) | ROM_SKIP(1)) + ROMX_LOAD("xbase09sx_2.09h.bin", 0x0001, 0x8000, CRC(ac9ad2e3) SHA1(8977e4520072b4ef6b603bcb0574663f10ba2629), ROM_BIOS(3) | ROM_SKIP(1)) + + ROM_REGION(0x10000, "hhrom", 0) + ROM_LOAD("xbase_09__rom_0.bin", 0x00000, 0x10000, NO_DUMP) // size unknown + + ROM_REGION(0x3000, "plds", 0) + ROM_LOAD("xbase.ic17", 0x0000, 0x0a92, NO_DUMP) // next to CPU + ROM_LOAD("xbase.ic59", 0x1000, 0x0a92, NO_DUMP) // right side of HH ROM + ROM_LOAD("xbase.ic60", 0x2000, 0x0a92, NO_DUMP) // left side of HH ROM; confirmed to be a PALCE20V8H-15PC/4 +ROM_END + +SYST(1997, xbase09, 0, 0, xbase09, xbase09, xbase09_state, empty_init, "JoMoX", "XBase 09 Midi Controlled Analogue Drum Module", MACHINE_IS_SKELETON) diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 681cdae543f..2b07e1f6ca0 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -41756,6 +41756,9 @@ ltv_naru // domfitad // dombikec // +@source:xbase09.cpp +xbase09 // + @source:xbox.cpp xbox // diff --git a/src/mame/mess.flt b/src/mame/mess.flt index 377208bcedd..5f145e2fa93 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -1081,6 +1081,7 @@ x1twin.cpp x68k.cpp xavix.cpp xavix2.cpp +xbase09.cpp xbox.cpp xerox820.cpp xor100.cpp diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index 4b420b90853..06d7747b1ac 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -119,6 +119,7 @@ using util::BIT; #include "cpu/pic16/pic16d.h" #include "cpu/pic16c5x/16c5xdsm.h" #include "cpu/pic16c62x/16c62xdsm.h" +#include "cpu/pic17/pic17d.h" #include "cpu/powerpc/ppc_dasm.h" #include "cpu/pps4/pps4dasm.h" #include "cpu/psx/psxdasm.h" @@ -480,6 +481,7 @@ static const dasm_table_entry dasm_table[] = { "pic16", le, -1, []() -> util::disasm_interface * { return new pic16_disassembler; } }, { "pic16c5x", le, -1, []() -> util::disasm_interface * { return new pic16c5x_disassembler; } }, { "pic16c62x", le, -1, []() -> util::disasm_interface * { return new pic16c62x_disassembler; } }, + { "pic17", le, -1, []() -> util::disasm_interface * { return new pic17_disassembler; } }, { "powerpc", be, 0, []() -> util::disasm_interface * { return new powerpc_disassembler; } }, { "pps4", le, 0, []() -> util::disasm_interface * { return new pps4_disassembler; } }, { "psxcpu", le, 0, []() -> util::disasm_interface * { return new psxcpu_disassembler; } },