From 1efb9a831cc47c79ccf14dd91efed9cf595ba192 Mon Sep 17 00:00:00 2001 From: grullosgo <42551661+grullosgo@users.noreply.github.com> Date: Mon, 3 Jun 2024 08:21:59 -0300 Subject: Add cpu device PIC16x8x - Add PIC16F84 to magicle into misc/magicard.cpp (#12092) --- scripts/src/cpu.lua | 17 + src/devices/cpu/pic16x8x/16x8xdsm.cpp | 258 ++++++ src/devices/cpu/pic16x8x/16x8xdsm.h | 46 ++ src/devices/cpu/pic16x8x/pic16x8x.cpp | 1418 +++++++++++++++++++++++++++++++++ src/devices/cpu/pic16x8x/pic16x8x.h | 319 ++++++++ src/mame/misc/magicard.cpp | 16 + 6 files changed, 2074 insertions(+) create mode 100644 src/devices/cpu/pic16x8x/16x8xdsm.cpp create mode 100644 src/devices/cpu/pic16x8x/16x8xdsm.h create mode 100644 src/devices/cpu/pic16x8x/pic16x8x.cpp create mode 100644 src/devices/cpu/pic16x8x/pic16x8x.h diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index f40e4815cce..ac433ad42dd 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -1474,6 +1474,23 @@ if opt_tool(CPUS, "PIC16C62X") then table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/pic16c62x/16c62xdsm.h") end +-------------------------------------------------- +-- Microchip PIC16x8x +--@src/devices/cpu/pic16x8x/pic16x8x.h,CPUS["PIC16X8X"] = true +-------------------------------------------------- + +if CPUS["PIC16X8X"] then + files { + MAME_DIR .. "src/devices/cpu/pic16x8x/pic16x8x.cpp", + MAME_DIR .. "src/devices/cpu/pic16x8x/pic16x8x.h", + } +end + +if opt_tool(CPUS, "PIC16X8X") then + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/pic16x8x/16x8xdsm.cpp") + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/pic16x8x/16x8xdsm.h") +end + -------------------------------------------------- -- Generic PIC16 - Disassembler only --@src/devices/cpu/pic16/pic16.h,CPUS["PIC16"] = true diff --git a/src/devices/cpu/pic16x8x/16x8xdsm.cpp b/src/devices/cpu/pic16x8x/16x8xdsm.cpp new file mode 100644 index 00000000000..6f20d03eaf2 --- /dev/null +++ b/src/devices/cpu/pic16x8x/16x8xdsm.cpp @@ -0,0 +1,258 @@ +// license:BSD-3-Clause +// copyright-holders: Grull Osgo +/************************************************************************ + + Microchip PIC16X8x Emulator + + Based on MAME's PIC16C5x cpu_device dissasm developed by Tony La Porta. + +A Address to jump to. +B Bit address within an 8-bit file register. +D Destination select (0 = store result in W (accumulator)) + (1 = store result in file register) +F Register file address. +K Literal field, constant data. + +Includes Flags ID's on SFR registers where possible. + +************************************************************************/ + +#include "emu.h" +#include "16x8xdsm.h" + +#include +#include + +const u8 pic16x8x_disassembler::sfr_bank0[16] = { 0, 0, 0, 1, 0, 2, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0}; + +const char *const pic16x8x_disassembler::sfregs[12] = +{ + "INDF", "TMR0", "PCL", "STATUS", "FSR", "PORTA", "PORTB", "Reg$07", "EEDATA", "EEADDR", "PCLATH", "INTCON" +}; + +const char *const pic16x8x_disassembler::dest[2] = { "W", "Reg" }; + +const char *const pic16x8x_disassembler::reg_flags[9][8] = +{ + {"0", "1", "2", "3", "4", "5", "6", "7"}, // no flags + {"C", "DC", "Z", "PD", "TO", "RP0", "RP1", "IRP"}, // status + {"RA0", "RA1", "RA2", "RA3", "RA4/T0CKI", "5", "6", "7"}, // portA + {"RB0/INT", "RB1", "RB2", "RB3", "RB4", "RB5", "RB6", "RB7"}, // portB + {"RBIF", "INTF", "T0IF", "RBIE", "INTE", "T0IE", "EEIE", "GIE"}, // intcon + {"PS0", "PS1", "PS2", "PSA", "T0SE", "T0CS", "INTEDG", "RBPU"}, // option + {"RA0", "RA1", "RA2", "RA3", "RA4", "5", "6", "7"}, // trisa + {"RB0", "RB1", "RB2", "RB3", "RB4", "RB5", "RB6", "RB7"}, // trisb + {"RD", "WR", "WREN", "WRERR", "EEIF", "5", "6", "7"} // eecon +}; + +const char *const pic16x8x_disassembler::PIC16X8xFormats[] = +{ + "00000000000000", "nop", + "00000000001000", "return", + "00000000001001", "retfie", + "00000000100000", "nop", + "00000001000000", "nop", + "00000001100000", "nop", + "00000001100011", "sleep", + "00000001100100", "clrwdt", + "0000001fffffff", "movwf %F", + "00000100000000", "clrw", + "0000011fffffff", "clrf %F", + "000010dfffffff", "subwf %F,%D", + "000011dfffffff", "decf %F,%D", + "000100dfffffff", "iorwf %F,%D", + "000101dfffffff", "andwf %F,%D", + "000110dfffffff", "xorwf %F,%D", + "000111dfffffff", "addwf %F,%D", + "001000dfffffff", "movf %F,%D", + "001001dfffffff", "comf %F,%D", + "001010dfffffff", "incf %F,%D", + "001011dfffffff", "decfsz %F,%D", + "001100dfffffff", "rrf %F,%D", + "001101dfffffff", "rlf %F,%D", + "001110dfffffff", "swapf %F,%D", + "001111dfffffff", "incfsz %F,%D", + "0100bbbfffffff", "bcf %F,%B", + "0101bbbfffffff", "bsf %F,%B", + "0110bbbfffffff", "btfsc %F,%B", + "0111bbbfffffff", "btfss %F,%B", + "110100kkkkkkkk", "retlw %K", + "110101kkkkkkkk", "retlw %K", + "110110kkkkkkkk", "retlw %K", + "110111kkkkkkkk", "retlw %K", + "100aaaaaaaaaaa", "call %A", + "101aaaaaaaaaaa", "goto %A", + "110000kkkkkkkk", "movlw %K", + "110001kkkkkkkk", "movlw %K", + "110010kkkkkkkk", "movlw %K", + "110011kkkkkkkk", "movlw %K", + "111000kkkkkkkk", "iorlw %K", + "111001kkkkkkkk", "andlw %K", + "111010kkkkkkkk", "xorlw %K", + "111100kkkkkkkk", "sublw %K", + "111101kkkkkkkk", "sublw %K", + "111110kkkkkkkk", "addlw %K", + "111111kkkkkkkk", "addlw %K", + nullptr +}; + +pic16x8x_disassembler::pic16x8x_disassembler() +{ + const char *p; + const char *const *ops; + u16 mask, bits; + int bit; + + ops = PIC16X8xFormats; + while (*ops) + { + p = *ops; + mask = 0; bits = 0; bit = 13; + while (*p && bit >= 0) + { + switch (*p++) + { + case '1': mask |= 1<= 0) + { + osd_printf_debug("{%c/%d}",*cp,bit); + switch (*cp) + { + case 'a': a <<=1; a |= ((code & (1< Op; +}; + +#endif diff --git a/src/devices/cpu/pic16x8x/pic16x8x.cpp b/src/devices/cpu/pic16x8x/pic16x8x.cpp new file mode 100644 index 00000000000..af62420bd30 --- /dev/null +++ b/src/devices/cpu/pic16x8x/pic16x8x.cpp @@ -0,0 +1,1418 @@ +// license:BSD-3-Clause +// copyright-holders:Grull Osgo +/**************************************************************************************** + + Microchip PIC16x8x Emulator + + https://ww1.microchip.com/downloads/en/DeviceDoc/30445D.pdf + + Based on MAME's PIC16C5x/62x cpu devices developed by Tony La Porta + and improvements to SFR's accesss made by ajrhacker. + + Preliminary version to give support to magicle and other games + on misc/magicard.cpp driver, providing some protection level via I2C bus. + + Coded and partially tested: + - All instruction set and disassembler. + - I/O Ports. + - WDT. + - Timer/Counter. + - All (4) interrupt sources. + - Input lines. + - Internal EEPROM with default and NVRAM functionality. + + ToDo: + - Verify if data ram addreess map mirroring is properly coded acording to datasheet description. + + - Choose wich is the best option to set the config word, if via set instruction or from dump data or some sort of combination via default options. + + - Improve the debug section. + + - Verify eeprom write sequence (see datashhet) + + Improvements: + - SFR's Flag description (bit oriented instructions) in disassembler where possible. + +****************************************************************************************/ + +#include "emu.h" +#include "pic16x8x.h" +#include "16x8xdsm.h" + +DEFINE_DEVICE_TYPE(PIC16CR83, pic16cr83_device, "pic16cr83", "Microchip PIC16CR83") +DEFINE_DEVICE_TYPE(PIC16CR84, pic16cr84_device, "pic16cr84", "Microchip PIC16CR84") +DEFINE_DEVICE_TYPE(PIC16F83, pic16f83_device, "pic16f83", "Microchip PIC16F83") +DEFINE_DEVICE_TYPE(PIC16F84, pic16f84_device, "pic16f84", "Microchip PIC16F84") +DEFINE_DEVICE_TYPE(PIC16F84A, pic16f84a_device, "pic16f84a", "Microchip PIC16F84A") + +/**************************************************************************** + * Internal Memory Maps + ****************************************************************************/ + +void pic16x8x_device::rom_9(address_map &map) +{ + map(0x000, 0x1ff).rom(); +} + +void pic16x8x_device::rom_10(address_map &map) +{ + map(0x000, 0x3ff).rom(); +} + + +/* Notes from datasheet: + The address depends on the device used. +Devices with 36 bytes ends at 2Fh, devices with +68 bytes ends at 4Fh.*/ + +void pic16x8x_device::core_regs(address_map &map, u8 mirror) +{ + map(0x00, 0x00).noprw().mirror(mirror); // Not an actual register, reading indirectly (FSR=0) returns 0 + map(0x01, 0x01).rw(FUNC(pic16x8x_device::tmr0_r), FUNC(pic16x8x_device::tmr0_w)); + map(0x02, 0x02).rw(FUNC(pic16x8x_device::pcl_r), FUNC(pic16x8x_device::pcl_w)).mirror(mirror); + map(0x03, 0x03).rw(FUNC(pic16x8x_device::status_r), FUNC(pic16x8x_device::status_w)).mirror(mirror); + map(0x04, 0x04).rw(FUNC(pic16x8x_device::fsr_r), FUNC(pic16x8x_device::fsr_w)).mirror(mirror); + map(0x05, 0x05).rw(FUNC(pic16x8x_device::porta_r), FUNC(pic16x8x_device::porta_w)); + map(0x06, 0x06).rw(FUNC(pic16x8x_device::portb_r), FUNC(pic16x8x_device::portb_w)); + map(0x07, 0x07).noprw().mirror(mirror); // Not an actual register, returns 0 + map(0x08, 0x08).rw(FUNC(pic16x8x_device::eedata_r), FUNC(pic16x8x_device::eedata_w)); + map(0x09, 0x09).rw(FUNC(pic16x8x_device::eeadr_r), FUNC(pic16x8x_device::eeadr_w)); + map(0x0a, 0x0a).rw(FUNC(pic16x8x_device::pclath_r), FUNC(pic16x8x_device::pclath_w)).mirror(mirror); + map(0x0b, 0x0b).rw(FUNC(pic16x8x_device::intcon_r), FUNC(pic16x8x_device::intcon_w)).mirror(mirror); + map(0x81, 0x81).rw(FUNC(pic16x8x_device::option_r), FUNC(pic16x8x_device::option_w)); + map(0x85, 0x85).rw(FUNC(pic16x8x_device::trisa_r), FUNC(pic16x8x_device::trisa_w)); + map(0x86, 0x86).rw(FUNC(pic16x8x_device::trisb_r), FUNC(pic16x8x_device::trisb_w)); + map(0x88, 0x88).rw(FUNC(pic16x8x_device::eecon1_r), FUNC(pic16x8x_device::eecon1_w)); + map(0x89, 0x89).rw(FUNC(pic16x8x_device::eecon2_r), FUNC(pic16x8x_device::eecon2_w)); +} + +void pic16x8x_device::ram_6(address_map &map) +{ + // 0x00 - 0x0b SFR's Bank 0 + // 0x0c - 0x2f GPR's + // 0x80 - 0x8b SFR's Bank 1 + // 0x8c - 0xaf GPR Mirrored to 0x0c - 0x2f + core_regs(map, 0x80); + map(0x0c, 0x2f).ram().mirror(0x80); +} + +void pic16x8x_device::ram_7(address_map &map) +{ + // 0x00 - 0x0b SFR's Bank 0 + // 0x0c - 0x4f GPR's + // 0x80 - 0x8b SFR's Bank 1 + // 0x8c - 0xcf GPR Mirrored to 0x0c - 0x4f + core_regs(map, 0x80); + map(0x0c, 0x4f).ram().mirror(0x80); +} + + +pic16x8x_device::pic16x8x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int program_width, address_map_constructor program_map, address_map_constructor data_map) + : cpu_device(mconfig, type, tag, owner, clock) + , device_nvram_interface(mconfig, *this) + , m_region(*this, DEVICE_SELF) + , m_program_config("program", ENDIANNESS_LITTLE, 16, program_width, -1, program_map) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 8, 0, data_map) + , m_program_width(program_width) + , m_CONFIG(0x3fff) + , m_read_port(*this, 0) + , m_write_port(*this) +{ +} + +pic16x83_device::pic16x83_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : pic16x8x_device(mconfig, type, tag, owner, clock, 9, address_map_constructor(FUNC(pic16x8x_device::rom_9), this), address_map_constructor(FUNC(pic16x8x_device::ram_6), this)) +{ +} + +pic16x84_device::pic16x84_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : pic16x8x_device(mconfig, type, tag, owner, clock, 10, address_map_constructor(FUNC(pic16x8x_device::rom_10), this), address_map_constructor(FUNC(pic16x8x_device::ram_7), this)) +{ +} + +pic16cr83_device::pic16cr83_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : pic16x83_device(mconfig, PIC16CR83, tag, owner, clock) +{ +} + +pic16cr84_device::pic16cr84_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : pic16x84_device(mconfig, PIC16CR84, tag, owner, clock) +{ +} + +pic16f83_device::pic16f83_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : pic16x83_device(mconfig, PIC16F83, tag, owner, clock) +{ +} + +pic16f84_device::pic16f84_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : pic16x84_device(mconfig, PIC16F84, tag, owner, clock) +{ +} + +pic16f84a_device::pic16f84a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : pic16x84_device(mconfig, PIC16F84A, tag, owner, clock) +{ +} + +device_memory_interface::space_config_vector pic16x8x_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) + }; +} + +std::unique_ptr pic16x8x_device::create_disassembler() +{ + return std::make_unique(); +} + + +/* Notes about NVRAM / PIC eeprom data + +Dump size is 4280 Bytes, 16 bits wide. +0000h-03ffh is program data +0400h-3fffh is dummy data +4000h-400fh is user and config data +4010h-41ffh is dummy data +4200h-4280h is eeprom data + +NVRAM saved data is 8 bits wide, in accordance with the data width +of the EEPROM memory of the PIC. +This means that we need to perform the conversion from the default +NVRAM dumped data to the NVRAM saved data. +*/ + +void pic16x8x_device::nvram_default() +{ + u16 dump_size = 0x4280; + u16 eeprom_dump = 0x4200; + + // populate from a memory region if present + if (m_region.found()) + { + if( m_region->bytes() != dump_size ) // pic memory dump total size + { + fatalerror( "Region '%s' wrong size (expected size = 0x%X)\n", tag(), dump_size ); + } + + if( m_region->bytewidth() != 2 ) // pic memory dumps are 16 bits wide + { + fatalerror( "Region '%s' needs to be an 16-bit region\n", tag() ); + } + + // Get default NVRAM data from memory region + memcpy(m_buff, m_region->base() + eeprom_dump, m_internal_eeprom_size * 2); + + // Data width conversion + for (u8 i=0; i < m_internal_eeprom_size; i++) + m_eeprom_data[i] = m_buff[i] & 0x00ff; + } + +} + +bool pic16x8x_device::nvram_read(util::read_stream &file) +{ + auto const [err, actual] = read(file, m_eeprom_data, m_internal_eeprom_size); + return !err && (actual == m_internal_eeprom_size); +} + +bool pic16x8x_device::nvram_write(util::write_stream &file) +{ + auto const [err, actual] = write(file, m_eeprom_data, m_internal_eeprom_size); + return !err && (actual == m_internal_eeprom_size); +} + + +// EEPROM data access +u8 pic16x8x_device::m_eeread(offs_t offs) +{ + return m_eeprom_data[offs]; +} + +void pic16x8x_device::m_eewrite(offs_t offs, u8 data) +{ + m_eeprom_data[offs] = data & m_data_mask; +} + + +// ******** The following is the STATUS flag register definition. ******** +// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +// | IRP | RP1 | RP0 | T0| PD| Z | DC | C | + +// IRP Register Bank Select - Unimplemented on this device +constexpr u8 RP1_FLAG = 0x40; // Register Bank Select Bit 1 +constexpr u8 RP0_FLAG = 0x20; // Register Bank Select Bit 0 + // 00 = Bank 0 (00h-7fh) + // 01 = Bank 1 (80h-ffh) + // 10 = Bank 2 (100h-17fh) + // 11 = Bank 3 (180h-1ffh) + // Each bank is 128 bytes. Only bit RP0 is used by the PIC16F8X. RP1 should be mantained clear. +constexpr u8 TO_FLAG = 0x10; // TO Time Out flag (WatchDog) +constexpr u8 PD_FLAG = 0x08; // PD Power Down flag +constexpr u8 Z_FLAG = 0x04; // Z Zero Flag +constexpr u8 DC_FLAG = 0x02; // DC Digit Carry/Borrow flag (Nibble) +constexpr u8 C_FLAG = 0x01; // C Carry/Borrow Flag (Byte) + +#define RP0 (m_STATUS & RP0_FLAG) +#define TO (m_STATUS & TO_FLAG) +#define PD (m_STATUS & PD_FLAG) +#define ZERO (m_STATUS & Z_FLAG) +#define DC (m_STATUS & DC_FLAG) +#define CARRY (m_STATUS & C_FLAG) + + +// ******** The following is the OPTION flag register definition. ******** +// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +// | RBPU | INTEDG | T0CS | T0SE | PSA | PS2 | PS1 | PS0 | +constexpr u8 RBPU_FLAG = 0x80; // RBPU PORTB Pull-up Enable bit +constexpr u8 INTEDG_FLAG = 0x40; // INTEDG Interrupt Edge Select bit + // 1 = Interrupt on rising edge of RB0/INT pin + // 0 = Interrupt on falling edge of RB0/INT pin +constexpr u8 T0CS_FLAG = 0x20; // T0CS Timer 0 clock source select + // 1 = Transition on RA4/T0CKI pin + // 0 = Internal instruction cycle clock (CLKOUT) +constexpr u8 T0SE_FLAG = 0x10; // T0SE Timer 0 clock source edge select + // 1 = Increment on high-to-low transition on RA4/T0CKI pin + // 0 = Increment on low-to-high transition on RA4/T0CKI pin +constexpr u8 PSA_FLAG = 0x08; // PSA Prescaler Assignment bit + // 1 = Prescaler is assigned to the WDT + // 0 = Prescaler is assigned to the Timer0 module +constexpr u8 PS_REG = 0x07; // PS Prescaler Rate select + +#define RBPU (m_OPTION & RBPU_FLAG) +#define INTEDG (m_OPTION & INTEDG_FLAG) +#define T0CS (m_OPTION & T0CS_FLAG) +#define T0SE (m_OPTION & T0SE_FLAG) +#define PSA (m_OPTION & PSA_FLAG) +#define PS (m_OPTION & PS_REG) + + +// ******** The following is the CONFIG Flag register definition. ******** +// | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +// | CP | WDTE | FOSC | + // CP Code Protect (ROM read protect) +constexpr u8 WDTE_FLAG = 0x04; // WDTE WatchDog Timer enable +constexpr u8 FOSC_FLAG = 0x03; // FOSC Oscillator source select + +#define WDTE (m_CONFIG & WDTE_FLAG) +#define FOSC (m_CONFIG & FOSC_FLAG) + + +// ******** The following is the INTCON flag register definition. ******** +// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +// | GIE | EEIE | T0IE | INTE | RBIE | T0IF | INTF | RBIF | + +constexpr u8 GIE_FLAG = 0x80; +constexpr u8 EEIE_FLAG = 0x40; +constexpr u8 T0IE_FLAG = 0x20; +constexpr u8 INTE_FLAG = 0x10; +constexpr u8 RBIE_FLAG = 0x08; +constexpr u8 T0IF_FLAG = 0x04; +constexpr u8 INTF_FLAG = 0x02; +constexpr u8 RBIF_FLAG = 0x01; + +#define GIE (m_INTCON & GIE_FLAG) +#define EEIE (m_INTCON & EEIE_FLAG) +#define T0IE (m_INTCON & T0IE_FLAG) +#define INTE (m_INTCON & INTE_FLAG) +#define RBIE (m_INTCON & RBIE_FLAG) +#define T0IF (m_INTCON & T0IF_FLAG) +#define INTF (m_INTCON & INTF_FLAG) +#define RBIF (m_INTCON & RBIF_FLAG) + +// ******** The following is the EECON1 Flag register definition. ******** +// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +// | | | | EEIF | WRERR | WREN | WR | RD | + +constexpr u8 EEIF_FLAG = 0x10; +constexpr u8 WRERR_FLAG = 0x08; +constexpr u8 WREN_FLAG = 0x04; +constexpr u8 EEWR_FLAG = 0x02; +constexpr u8 EERD_FLAG = 0x01; + +#define EEIF (m_EECON1 & EEIF_FLAG) +#define WRERR (m_EECON1 & WRERR_FLAG) +#define WREN (m_EECON1 & WREN_FLAG) +#define EEWR (m_EECON1 & EEWR_FLAG) +#define EERD (m_EECON1 & EERD_FLAG) + +/************************************************************************ + * Fixed Vectors + ************************************************************************/ + +constexpr u8 RESET_VECTOR = 0x00; +constexpr u8 INT_VECTOR = 0x04; + +/************************************************************************ + * Shortcuts + ************************************************************************/ + +#define RISING_EDGE_RB0 (( (int)(RB0_in - m_old_RB0) > 0) ? 1 : 0) +#define FALLING_EDGE_RB0 (( (int)(RB0_in - m_old_RB0) < 0) ? 1 : 0) + +#define M_RDEEPROM(A) m_eeread(A) +#define M_WREEPROM(A,V) m_eewrite(A, V) + +#define CLR(flagreg, flag) (flagreg &= u8(~flag)) +#define SET(flagreg, flag) (flagreg |= (flag)) + +#define ADDR ((m_opcode.b.l & 0x7f) | (RP0 << 2)) +#define BITPOS ((m_opcode.w >> 7) & 7) + + +void pic16x8x_device::calc_zero_flag() +{ + if (m_ALU == 0) + SET(m_STATUS, Z_FLAG); + else + CLR(m_STATUS, Z_FLAG); +} + +void pic16x8x_device::calc_add_flags(u8 augend) +{ + calc_zero_flag(); + + if (augend > m_ALU) + SET(m_STATUS, C_FLAG); + else + CLR(m_STATUS, C_FLAG); + + if ((augend & 0x0f) > (m_ALU & 0x0f)) + SET(m_STATUS, DC_FLAG); + else + CLR(m_STATUS, DC_FLAG); +} + +void pic16x8x_device::calc_sub_flags(u8 minuend) +{ + calc_zero_flag(); + + if (minuend < m_ALU) + CLR(m_STATUS, C_FLAG); + else + SET(m_STATUS, C_FLAG); + + if ((minuend & 0x0f) < (m_ALU & 0x0f)) + CLR(m_STATUS, DC_FLAG); + else + SET(m_STATUS, DC_FLAG); +} + +void pic16x8x_device::set_pc(u16 addr) +{ + m_PCL = addr & m_program_mask; +} + +/* +Notes about Stack (from datasheet) +After the stack has been PUSHed eight times, the ninth +push overwrites the value that was stored from the first +push. The tenth push overwrites the second push (and +so on) +*/ + +u16 pic16x8x_device::pop_stack() +{ + m_stack_pointer = (m_stack_pointer - 1) & 0x0f; + u16 data = m_STACK[m_stack_pointer]; + return data & m_program_mask; +} + +void pic16x8x_device::push_stack(u16 data) +{ + m_STACK[m_stack_pointer] = data & m_program_mask; + m_stack_pointer = (m_stack_pointer + 1) & 0x0f; +} + +void pic16x8x_device::store_result(u8 addr, u8 data) +{ + if (m_opcode.b.l & 0x80) + store_regfile(addr, data); + else + m_W = data; + +} + +// *** Special function registers (SFR's) *** + +// *** SFR Access *** +u8 pic16x8x_device::get_regfile(u8 addr) +{ + if (addr == 0) + { // Indirect addressing + addr = m_FSR & m_data_mask; + } + return m_data.read_byte(addr); +} + +void pic16x8x_device::store_regfile(u8 addr, u8 data) +{ + if (addr == 0) + { // Indirect addressing + addr = m_FSR & m_data_mask; + } + m_data.write_byte(addr, data); +} + +// *** SFR Functions *** +u8 pic16x8x_device::tmr0_r() +{ + return m_TMR0; +} + +void pic16x8x_device::tmr0_w(u8 data) +{ + m_delay_timer = 2; // Timer increment is inhibited for 2 cycles + if (PSA == 0) m_prescaler = 0; // Must clear the Prescaler + m_TMR0 = data; +} + +u8 pic16x8x_device::pcl_r() +{ + return m_PCL; +} + +void pic16x8x_device::pcl_w(u8 data) +{ + m_PCL = data; + set_pc((m_PCLATH << 8) | data); + m_inst_cycles++; +} + +u8 pic16x8x_device::status_r() +{ + return m_STATUS; +} + +void pic16x8x_device::status_w(u8 data) +{ + m_STATUS = (m_STATUS & (TO_FLAG | PD_FLAG)) | (data & u8(~(TO_FLAG | PD_FLAG))); +} + +u8 pic16x8x_device::fsr_r() +{ + return m_FSR | (uint8_t)(~m_data_mask); +} + +void pic16x8x_device::fsr_w(u8 data) +{ + m_FSR = data | u8(~m_data_mask); +} + +u8 pic16x8x_device::porta_r() +{ + u8 data = m_read_port[PORTA](PORTA, 0xff); + data &= m_port_tris[PORTA]; + data |= (u8(~m_port_tris[PORTA]) & m_port_data[PORTA]); + return data & 0x1f; // 5-bit port (only lower 5 bits used) +} + +void pic16x8x_device::porta_w(u8 data) +{ + data &= 0x1f; // 5-bit port (only lower 5 bits used) + m_write_port[PORTA](PORTA, data & u8(~m_port_tris[PORTA]) & 0x1f, u8(~m_port_tris[PORTA]) & 0x1f); + m_port_data[PORTA] = data; +} + +u8 pic16x8x_device::portb_r() +{ + u8 data = m_read_port[PORTB](PORTB, 0xff); + data &= m_port_tris[PORTB]; + data |= (u8(~m_port_tris[PORTB]) & m_port_data[PORTB]); + return data; +} + +void pic16x8x_device::portb_w(u8 data) +{ + m_write_port[PORTB](PORTB, data & u8(~m_port_tris[PORTB]), u8(~m_port_tris[PORTB])); + m_port_data[PORTB] = data; +} + +u8 pic16x8x_device::eedata_r() +{ + return m_EEDATA; +} + +void pic16x8x_device::eedata_w(u8 data) +{ + m_EEDATA = data; +} + +u8 pic16x8x_device::eeadr_r() +{ + return m_EEADR; +} + +void pic16x8x_device::eeadr_w(u8 data) +{ + m_EEADR = data; +} + +u8 pic16x8x_device::pclath_r() +{ + return m_PCLATH; +} + +void pic16x8x_device::pclath_w(u8 data) +{ + m_PCLATH = data; +} + +u8 pic16x8x_device::intcon_r() +{ + return m_INTCON; +} + +void pic16x8x_device::intcon_w(u8 data) +{ + m_INTCON = data; +} + +u8 pic16x8x_device::trisa_r() +{ + return m_port_tris[PORTA]; +} + +void pic16x8x_device::trisa_w(u8 data) +{ + if (m_port_tris[PORTA] != data) + { + m_port_tris[PORTA] = data | 0xe0; + m_write_port[PORTA](PORTA, m_port_data[PORTA] & u8(~m_port_tris[PORTA]) & 0x1f, u8(~m_port_tris[PORTA]) & 0x1f); + } +} + +u8 pic16x8x_device::trisb_r() +{ + return m_port_tris[PORTB]; +} + +void pic16x8x_device::trisb_w(u8 data) +{ + if (m_port_tris[PORTB] != data) + { + m_port_tris[PORTB] = data; + m_write_port[PORTB](PORTB, m_port_data[PORTB] & u8(~m_port_tris[PORTB]), u8(~m_port_tris[PORTB])); + } +} + +u8 pic16x8x_device::eecon1_r() +{ + return m_EECON1; +} + +void pic16x8x_device::eecon1_w(u8 data) +{ + if (!((data & WREN_FLAG) && EEWR)) // The WR bit will be inhibited from being set unless the WREN bit is set.(from datasheet) + CLR(data, EEWR); // Clear the flag if it don't meet the requirements + + m_EECON1 = data; // update register + + if (EERD) // cheack flag condition to read eeprom + { + m_EEDATA = M_RDEEPROM(m_EEADR); // do eeprom read + CLR(m_EECON1, EERD_FLAG); // clear read enable flag + } + + if (WREN && EEWR && (m_EECON2 == 0xff)) // check flags conditions to write eeprom + { + M_WREEPROM(m_EEADR, data); // do eeprom write + CLR(m_EECON1, EEWR_FLAG); // clear write enable flag + SET(m_EECON1, EEIF_FLAG); // assuming write was done, set EEIF + } +} + +u8 pic16x8x_device::eecon2_r() +{ + return m_EECON2; +} + +void pic16x8x_device::eecon2_w(u8 data) +{ + if((m_EECON2!=0x55) & (data==0x55)) + m_EECON2 = data; + else if((m_EECON2==0x55) & (data==0xAA)) + m_EECON2 = 0xff; + else + m_EECON2 = data; +} + +u8 pic16x8x_device::option_r() +{ + return m_OPTION; +} + +void pic16x8x_device::option_w(u8 data) +{ + m_OPTION = data; +} + +/************************************************************************ + * Emulate the Instructions + ************************************************************************/ + +void pic16x8x_device::illegal() +{ + logerror("PIC16x8x: PC=%03x, Illegal opcode = %04x\n", m_PREVPC, m_opcode.w); +} + +/* + Note: + According to the manual, if the STATUS register is the destination for an instruction that affects the Z, DC or C bits + then the write to these three bits is disabled. These bits are set or cleared according to the device logic. + To ensure this is correctly emulated, in instructions that write to the file registers, always change the status flags + *after* storing the result of the instruction. + e.g. CALCULATE_*, SET(STATUS,*_FLAG) and CLR(STATUS,*_FLAG) should appear as the last steps of the instruction emulation. +*/ + +void pic16x8x_device::addlw() +{ + // New + m_ALU = m_opcode.b.l + m_W; + m_W = m_ALU; + calc_zero_flag(); +} + +void pic16x8x_device::addwf() +{ + u8 augend = get_regfile(ADDR); + m_ALU = augend + m_W; + store_result(ADDR, m_ALU); + calc_add_flags(augend); +} + +void pic16x8x_device::andlw() +{ + m_ALU = m_opcode.b.l & m_W; + m_W = m_ALU; + calc_zero_flag(); +} + +void pic16x8x_device::andwf() +{ + m_ALU = get_regfile(ADDR) & m_W; + store_result(ADDR, m_ALU); + calc_zero_flag(); +} + +void pic16x8x_device::bcf() +{ + m_ALU = get_regfile(ADDR); + m_ALU &= ~(1 << BITPOS); + store_regfile(ADDR, m_ALU); +} + +void pic16x8x_device::bsf() +{ + m_ALU = get_regfile(ADDR); + m_ALU |= 1 << BITPOS; + store_regfile(ADDR, m_ALU); +} + +void pic16x8x_device::btfss() +{ + if (BIT(get_regfile(ADDR), BITPOS)) + { + set_pc(m_PCL + 1); + m_inst_cycles++; // Add NOP cycles + } +} + +void pic16x8x_device::btfsc() +{ + if (!BIT(get_regfile(ADDR), BITPOS)) + { + set_pc(m_PCL + 1); + m_inst_cycles++; // Add NOP cycles + } +} + +void pic16x8x_device::call() +{ + push_stack(m_PCL); + set_pc(((m_PCLATH & 0x18) << 8 ) | (m_opcode.w & 0x07ff)); +} + + +void pic16x8x_device::clrw() +{ + m_W = 0; + SET(m_STATUS, Z_FLAG); +} + +void pic16x8x_device::clrf() +{ + store_regfile(ADDR, 0); + SET(m_STATUS, Z_FLAG); +} + +void pic16x8x_device::clrwdt() +{ + m_WDT = 0; + if (PSA) m_prescaler = 0; + SET(m_STATUS, TO_FLAG); + SET(m_STATUS, PD_FLAG); +} + +void pic16x8x_device::comf() +{ + m_ALU = u8(~(get_regfile(ADDR))); + store_result(ADDR, m_ALU); + calc_zero_flag(); +} + +void pic16x8x_device::decf() +{ + m_ALU = get_regfile(ADDR) - 1; + store_result(ADDR, m_ALU); + calc_zero_flag(); +} + +void pic16x8x_device::decfsz() +{ + m_ALU = get_regfile(ADDR) - 1; + store_result(ADDR, m_ALU); + if (m_ALU == 0) + { + set_pc(m_PCL + 1); + m_inst_cycles++; // Add NOP cycles + } +} + +void pic16x8x_device::goto_op() +{ + set_pc(((m_PCLATH & 0x18) << 8 ) | (m_opcode.w & 0x07ff)); +} + +void pic16x8x_device::incf() +{ + m_ALU = get_regfile(ADDR) + 1; + store_result(ADDR, m_ALU); + calc_zero_flag(); +} + +void pic16x8x_device::incfsz() +{ + m_ALU = get_regfile(ADDR) + 1; + store_result(ADDR, m_ALU); + if (m_ALU == 0) + { + set_pc(m_PCL + 1); + m_inst_cycles++; // Add NOP cycles + } +} + +void pic16x8x_device::iorlw() +{ + m_ALU = m_opcode.b.l | m_W; + m_W = m_ALU; + calc_zero_flag(); +} + +void pic16x8x_device::iorwf() +{ + m_ALU = get_regfile(ADDR) | m_W; + store_result(ADDR, m_ALU); + calc_zero_flag(); +} + +void pic16x8x_device::movf() +{ + m_ALU = get_regfile(ADDR); + store_result(ADDR, m_ALU); + calc_zero_flag(); +} + +void pic16x8x_device::movlw() +{ + m_W = m_opcode.b.l; +} + +void pic16x8x_device::movwf() +{ + store_regfile(ADDR, m_W); +} + +void pic16x8x_device::nop() +{ + // Do nothing +} + +void pic16x8x_device::retfie() // new for 16x8x +{ + // New + set_pc(pop_stack()); + m_irq_in_progress = false; +} + +void pic16x8x_device::retlw() +{ + m_W = m_opcode.b.l; + set_pc(pop_stack()); +} + +void pic16x8x_device::retrn() // new for 16x8x +{ + set_pc(pop_stack()); +} + +void pic16x8x_device::rlf() +{ + m_ALU = get_regfile(ADDR); + int carry = BIT(m_ALU, 7); + m_ALU <<= 1; + if (m_STATUS & C_FLAG) m_ALU |= 1; + store_result(ADDR, m_ALU); + + if (carry) + SET(m_STATUS, C_FLAG); + else + CLR(m_STATUS, C_FLAG); +} + +void pic16x8x_device::rrf() +{ + m_ALU = get_regfile(ADDR); + int carry = BIT(m_ALU, 0); + m_ALU >>= 1; + if (m_STATUS & C_FLAG) m_ALU |= 0x80; + store_result(ADDR, m_ALU); + + if (carry) + SET(m_STATUS, C_FLAG); + else + CLR(m_STATUS, C_FLAG); +} + +void pic16x8x_device::sleepic() +{ + if (WDTE) m_WDT = 0; + if (PSA) m_prescaler = 0; + SET(m_STATUS, TO_FLAG); + CLR(m_STATUS, PD_FLAG); +} + +void pic16x8x_device::sublw() // new for 16x8x : Substract W from literal +{ + // New + u8 minuend = m_opcode.b.l; + m_ALU = minuend - m_W; + m_W = m_ALU; + calc_sub_flags(minuend); +} + +void pic16x8x_device::subwf() // Substract W from f +{ + u8 minuend = get_regfile(ADDR); + m_ALU = minuend - m_W; + store_result(ADDR, m_ALU); + calc_sub_flags(minuend); +} + +void pic16x8x_device::swapf() +{ + u8 reg = get_regfile(ADDR); + m_ALU = reg << 4 | reg >> 4; + store_result(ADDR, m_ALU); +} + +void pic16x8x_device::xorlw() +{ + m_ALU = m_W ^ m_opcode.b.l; + m_W = m_ALU; + calc_zero_flag(); +} + +void pic16x8x_device::xorwf() +{ + m_ALU = get_regfile(ADDR) ^ m_W; + store_result(ADDR, m_ALU); + calc_zero_flag(); +} + + +/*********************************************************************** + * Opcode Table (Cycles, Instruction) + ***********************************************************************/ + +const pic16x8x_device::pic16x8x_opcode pic16x8x_device::s_opcode_main[128]= +{ + {1, &pic16x8x_device::nop },{1, &pic16x8x_device::movwf },{1, &pic16x8x_device::clrw },{1, &pic16x8x_device::clrf }, // 00 + {1, &pic16x8x_device::subwf },{1, &pic16x8x_device::subwf },{1, &pic16x8x_device::decf },{1, &pic16x8x_device::decf }, // 04 + {1, &pic16x8x_device::iorwf },{1, &pic16x8x_device::iorwf },{1, &pic16x8x_device::andwf },{1, &pic16x8x_device::andwf }, // 08 + {1, &pic16x8x_device::xorwf },{1, &pic16x8x_device::xorwf },{1, &pic16x8x_device::addwf },{1, &pic16x8x_device::addwf }, // 0C + {1, &pic16x8x_device::movf },{1, &pic16x8x_device::movf },{1, &pic16x8x_device::comf },{1, &pic16x8x_device::comf }, // 10 + {1, &pic16x8x_device::incf },{1, &pic16x8x_device::incf },{1, &pic16x8x_device::decfsz },{1, &pic16x8x_device::decfsz }, // 14 + {1, &pic16x8x_device::rrf },{1, &pic16x8x_device::rrf },{1, &pic16x8x_device::rlf },{1, &pic16x8x_device::rlf }, // 18 + {1, &pic16x8x_device::swapf },{1, &pic16x8x_device::swapf },{1, &pic16x8x_device::incfsz },{1, &pic16x8x_device::incfsz }, // 1C + {1, &pic16x8x_device::bcf },{1, &pic16x8x_device::bcf },{1, &pic16x8x_device::bcf },{1, &pic16x8x_device::bcf }, // 20 + {1, &pic16x8x_device::bcf },{1, &pic16x8x_device::bcf },{1, &pic16x8x_device::bcf },{1, &pic16x8x_device::bcf }, + {1, &pic16x8x_device::bsf },{1, &pic16x8x_device::bsf },{1, &pic16x8x_device::bsf },{1, &pic16x8x_device::bsf }, // 28 + {1, &pic16x8x_device::bsf },{1, &pic16x8x_device::bsf },{1, &pic16x8x_device::bsf },{1, &pic16x8x_device::bsf }, + {1, &pic16x8x_device::btfsc },{1, &pic16x8x_device::btfsc },{1, &pic16x8x_device::btfsc },{1, &pic16x8x_device::btfsc }, // 30 + {1, &pic16x8x_device::btfsc },{1, &pic16x8x_device::btfsc },{1, &pic16x8x_device::btfsc },{1, &pic16x8x_device::btfsc }, + {1, &pic16x8x_device::btfss },{1, &pic16x8x_device::btfss },{1, &pic16x8x_device::btfss },{1, &pic16x8x_device::btfss }, // 38 + {1, &pic16x8x_device::btfss },{1, &pic16x8x_device::btfss },{1, &pic16x8x_device::btfss },{1, &pic16x8x_device::btfss }, + {2, &pic16x8x_device::call },{2, &pic16x8x_device::call },{2, &pic16x8x_device::call },{2, &pic16x8x_device::call }, // 40 + {2, &pic16x8x_device::call },{2, &pic16x8x_device::call },{2, &pic16x8x_device::call },{2, &pic16x8x_device::call }, + {2, &pic16x8x_device::call },{2, &pic16x8x_device::call },{2, &pic16x8x_device::call },{2, &pic16x8x_device::call }, // 48 + {2, &pic16x8x_device::call },{2, &pic16x8x_device::call },{2, &pic16x8x_device::call },{2, &pic16x8x_device::call }, + {2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op }, // 50 + {2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op }, + {2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op }, // 58 + {2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op },{2, &pic16x8x_device::goto_op }, + {1, &pic16x8x_device::movlw },{1, &pic16x8x_device::movlw },{1, &pic16x8x_device::movlw },{1, &pic16x8x_device::movlw }, // 60 + {1, &pic16x8x_device::movlw },{1, &pic16x8x_device::movlw },{1, &pic16x8x_device::movlw },{1, &pic16x8x_device::movlw }, + {2, &pic16x8x_device::retlw },{2, &pic16x8x_device::retlw },{2, &pic16x8x_device::retlw },{2, &pic16x8x_device::retlw }, // 68 + {2, &pic16x8x_device::retlw },{2, &pic16x8x_device::retlw },{2, &pic16x8x_device::retlw },{2, &pic16x8x_device::retlw }, + {1, &pic16x8x_device::iorlw },{1, &pic16x8x_device::iorlw },{1, &pic16x8x_device::andlw },{1, &pic16x8x_device::andlw }, // 70 + {1, &pic16x8x_device::xorlw },{1, &pic16x8x_device::xorlw },{1, &pic16x8x_device::xorlw },{1, &pic16x8x_device::xorlw }, // 74 + {1, &pic16x8x_device::sublw },{1, &pic16x8x_device::sublw },{1, &pic16x8x_device::sublw },{1, &pic16x8x_device::sublw }, // 78 + {1, &pic16x8x_device::addlw },{1, &pic16x8x_device::addlw },{1, &pic16x8x_device::addlw },{1, &pic16x8x_device::addlw } // 7C +}; + +const pic16x8x_device::pic16x8x_opcode pic16x8x_device::s_opcode_00x[128]= +{ + {1, &pic16x8x_device::nop },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 00 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {2, &pic16x8x_device::retrn },{2, &pic16x8x_device::retfie },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 08 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 10 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 18 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::nop },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 20 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 28 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 30 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 38 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::nop },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 40 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 48 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 50 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 58 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::nop },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::sleepic }, // 60 + {1, &pic16x8x_device::clrwdt },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 68 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 70 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal }, // 78 + {1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal },{1, &pic16x8x_device::illegal } +}; + + +/**************************************************************************** + * Inits CPU emulation + ****************************************************************************/ + +enum +{ + PIC16X8x_PC=1, PIC16X8x_W, PIC16X8x_ALU, PIC16X8x_WDT, PIC16X8x_PSCL, PIC16X8x_CONFIG +}; + +void pic16x8x_device::device_start() +{ + space(AS_PROGRAM).cache(m_program); + space(AS_DATA).specific(m_data); + + m_program_mask = (1 << m_program_width) - 1; + m_data_mask = 0xff; + m_status_mask = 0xff; + m_PCL = 0; + m_PREVPC = 0; + m_W = 0; + m_OPTION = 0; + m_ALU = 0; + m_WDT = 0; + m_TMR0 = 0; + m_STATUS = ~m_status_mask; + m_FSR = 0; + std::fill(std::begin(m_port_data), std::end(m_port_data), 0); + std::fill(std::begin(m_port_tris), std::end(m_port_tris), 0); + std::fill(std::begin(m_STACK), std::end(m_STACK), 0); + m_prescaler = 0; + m_opcode.w = 0; + m_delay_timer = 0; + m_rtcc = 0; + m_count_cycles = 0; + m_inst_cycles = 0; + m_stack_pointer = 0; + m_debugger_temp = 0; + m_portb_chdetect_temp = 0xff; + m_irq_in_progress = false; + + // save states + save_item(NAME(m_PCL)); + save_item(NAME(m_PREVPC)); + save_item(NAME(m_CONFIG)); + save_item(NAME(m_W)); + save_item(NAME(m_OPTION)); + save_item(NAME(m_ALU)); + save_item(NAME(m_WDT)); + save_item(NAME(m_TMR0)); + save_item(NAME(m_STATUS)); + save_item(NAME(m_FSR)); + save_item(NAME(m_port_data)); + save_item(NAME(m_port_tris)); + save_item(NAME(m_EEDATA)); + save_item(NAME(m_EEADR)); + save_item(NAME(m_EECON1)); + save_item(NAME(m_EECON2)); + save_item(NAME(m_PCLATH)); + save_item(NAME(m_INTCON)); + save_item(NAME(m_STACK)); + save_item(NAME(m_prescaler)); + save_item(NAME(m_opcode.w)); + save_item(NAME(m_delay_timer)); + save_item(NAME(m_rtcc)); + save_item(NAME(m_count_cycles)); + save_item(NAME(m_inst_cycles)); + save_item(NAME(m_stack_pointer)); + save_item(NAME(m_old_RB0)); + save_item(NAME(m_irq_in_progress)); + save_item(NAME(m_eeprom_data)); + + + // debugger + state_add( PIC16X8x_PC, "PC", m_PCL).mask(0xfff).formatstr("%03X"); + state_add( PIC16X8x_W, "W", m_W).formatstr("%02X"); + state_add( PIC16X8x_ALU, "ALU", m_ALU).formatstr("%02X"); + state_add( PIC16X8x_WDT, "WDT", m_WDT).formatstr("%04X"); + state_add( PIC16X8x_CONFIG, "CNF", m_CONFIG).formatstr("%04X"); + state_add( PIC16X8x_PSCL, "PSCL", m_debugger_temp).callimport().formatstr("%3s"); + + state_add( STATE_GENPC, "GENPC", m_PCL).noshow(); + state_add( STATE_GENPCBASE, "CURPC", m_PREVPC).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_OPTION).formatstr("%13s").noshow(); + + set_icountptr(m_icount); +} + + +void pic16x8x_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case PIC16X8x_PSCL: + m_prescaler = m_debugger_temp; + break; + } +} + +void pic16x8x_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + } +} + +void pic16x8x_device::state_string_export(const device_state_entry &entry, std::string &str) const +{ + switch (entry.index()) + { + case PIC16X8x_PSCL: + str = string_format("%c%02X", ((m_OPTION & 0x08) ? 'W' : 'T'), m_prescaler); + break; + + case STATE_GENFLAGS: + str = string_format("%01x%c%c%c%c%c %c%c%c%03x", + (m_STATUS & 0xe0) >> 5, + m_STATUS & 0x10 ? '.':'O', // WDT Overflow + m_STATUS & 0x08 ? 'P':'D', // Power/Down + m_STATUS & 0x04 ? 'Z':'.', // Zero + m_STATUS & 0x02 ? 'c':'b', // Nibble Carry/Borrow + m_STATUS & 0x01 ? 'C':'B', // Carry/Borrow + + m_OPTION & 0x20 ? 'C':'T', // Counter/Timer + m_OPTION & 0x10 ? 'N':'P', // Negative/Positive + m_OPTION & 0x08 ? 'W':'T', // WatchDog/Timer + m_OPTION & 0x08 ? (1<<(m_OPTION&7)) : (2<<(m_OPTION&7))); + break; + } +} + + +/**************************************************************************** + * Reset registers to their initial values + ****************************************************************************/ + +void pic16x8x_device::reset_regs() +{ + set_pc(RESET_VECTOR); + m_port_tris[PORTA] = 0x1f; + m_port_tris[PORTB] = 0xff; + m_OPTION = T0CS_FLAG | T0SE_FLAG | PSA_FLAG | PS_REG; + m_PREVPC = m_PCL; + m_STATUS = 0x18; + m_PCL = 0; + m_prescaler = 0; + m_delay_timer = 0; + m_inst_cycles = 0; + m_count_cycles = 0; + m_stack_pointer = 0; + m_portb_chdetect_temp = 0xff; + m_old_RB0 = 0; +} + +void pic16x8x_device::set_config(u16 data) +{ + logerror("Writing %04x to the PIC16x8x configuration bits\n", data); + m_CONFIG = (data & 0x3fff); +} + +void pic16x8x_device::watchdog_reset() +{ + SET(m_STATUS, TO_FLAG | PD_FLAG | Z_FLAG | DC_FLAG | C_FLAG); + reset_regs(); +} + +void pic16x8x_device::device_reset() +{ + reset_regs(); + CLR(m_STATUS, RP0_FLAG); + CLR(m_STATUS, RP1_FLAG); + + // Setting TO_FLAG from Config Word + if(WDTE) + SET(m_STATUS, TO_FLAG); + else + CLR(m_STATUS, TO_FLAG); + + SET(m_STATUS, PD_FLAG); + store_regfile(3, m_STATUS); + store_regfile(4, m_FSR); +} + + +/**************************************************************************** + * WatchDog + ****************************************************************************/ + +void pic16x8x_device::update_watchdog(int counts) +{ + /* + WatchDog is set up to count 18,000 (0x464f hex) ticks to provide + the timeout period of 0.018ms based on a 4MHz input clock. + Note: the 4MHz clock should be divided by the PIC16C5x_CLOCK_DIVIDER + which effectively makes the PIC run at 1MHz internally. + + If the current instruction is CLRWDT or SLEEP, don't update the WDT + */ + + if ((m_opcode.w != 3) && (m_opcode.w != 4)) + { + u16 old_WDT = m_WDT; + + m_WDT -= counts; + + if (m_WDT > 0x464f) + { + m_WDT = 0x464f - (0xffff - m_WDT); + } + + if (((old_WDT != 0) && (old_WDT < m_WDT)) || (m_WDT == 0)) + { + if (PSA) + { + m_prescaler++; + if (m_prescaler >= (1 << PS)) + { // Prescale values from 1 to 128 + m_prescaler = 0; + CLR(m_STATUS, TO_FLAG); + watchdog_reset(); + } + } + else + { + CLR(m_STATUS, TO_FLAG); + watchdog_reset(); + } + } + } +} + + +/**************************************************************************** + * Update Timer + ****************************************************************************/ + +void pic16x8x_device::update_timer(int counts) +{ + if (m_delay_timer > 0) + { // Timer increment is inhibited + int dt = m_delay_timer; + m_delay_timer -= m_inst_cycles; + counts -= dt; + } + + if (m_delay_timer > 0 || counts <= 0) + return; + + if (PSA == 0) + { // if PSA is cleared, prescaler is assigned to timer + m_prescaler += counts; + if (m_prescaler >= (2 << PS)) + { // Prescale values from 2 to 256 + m_TMR0 += (m_prescaler / (2 << PS)); + if(m_TMR0 == 0) + SET(m_INTCON, T0IF_FLAG); + m_prescaler %= (2 << PS); // Overflow prescaler + } + } + else + { + m_TMR0 += counts; + if(m_TMR0 == 0) + SET(m_INTCON, T0IF_FLAG); + } +} + +void pic16x8x_device::execute_set_input(int line, int state) +{ + u8 RB0_in; + switch (line) + { + // RTCC/RA4_T0CKI pin + case PIC16x8x_T0CKI: + if (T0CS && state != m_rtcc) + { // Count mode, edge triggered + if ((T0SE && !state) || (!T0SE && state)) + m_count_cycles++; + } + m_rtcc = state; + break; + + case PIC16x8x_RB0INT: + RB0_in = state; + if (INTEDG) + { /* Interrupt on Rising edge RB0 input */ + if (RISING_EDGE_RB0) + { + SET(m_INTCON, INTF_FLAG); + } + } + else + { /* Interrupt on Falling edge RB0 input */ + if (FALLING_EDGE_RB0) + { + SET(m_INTCON, INTF_FLAG); + } + } + m_old_RB0 = RB0_in; + break; + + default: + break; + } +} + +/*------------------------------------------------- + check_irqs - check for and process IRQs +-------------------------------------------------*/ + +void pic16x8x_device::check_irqs() +{ + // if something is in progress, we do nothing + if (m_irq_in_progress) + return; + + if(m_read_port[PORTB](PORTB, 0xf0) != m_portb_chdetect_temp) + { + m_portb_chdetect_temp = m_read_port[PORTB](PORTB, 0xf0); + SET(m_INTCON, RBIF_FLAG); + } + + else if(GIE && RBIE && RBIF) + { + push_stack(m_PCL); + set_pc(INT_VECTOR); + standard_irq_callback(0, m_PCL); + m_irq_in_progress = true; + } + + else if(GIE && INTE && INTF) + { + push_stack(m_PCL); + set_pc(INT_VECTOR); + standard_irq_callback(1, m_PCL); + m_irq_in_progress = true; + } + + else if(GIE && T0IE && T0IF) + { + push_stack(m_PCL); + set_pc(INT_VECTOR); + standard_irq_callback(2, m_PCL); + m_irq_in_progress = true; + } + + else if(GIE && EEIE && EEIF) + { + push_stack(m_PCL); + set_pc(INT_VECTOR); + standard_irq_callback(3, m_PCL); + m_irq_in_progress = true; + } +} + + +/**************************************************************************** + * Execute IPeriod. Return 0 if emulation should be stopped + ****************************************************************************/ + +void pic16x8x_device::execute_run() +{ + do + { + // check interrupts + check_irqs(); + + if (PD == 0) + { // Sleep Mode + m_count_cycles = 0; + m_inst_cycles = 1; + debugger_instruction_hook(m_PCL); + } + else + { + m_PREVPC = m_PCL; + + debugger_instruction_hook(m_PCL); + + m_opcode.w = m_program.read_word(m_PCL); + set_pc(m_PCL + 1); + + if ( (m_opcode.w & 0x3f80) != 0x0000) + { // Do all opcodes except the 00? ones + m_inst_cycles = s_opcode_main[((m_opcode.w >> 7) & 0x7f)].cycles; + (this->*s_opcode_main[((m_opcode.w >> 7) & 0x7f)].function)(); + } + else + { // Opcode 0x00? has many opcodes in its minor nibble + m_inst_cycles = s_opcode_00x[(m_opcode.b.l & 0x7f)].cycles; + (this->*s_opcode_00x[(m_opcode.b.l & 0x7f)].function)(); + } + + update_timer(T0CS ? m_count_cycles : m_inst_cycles); + m_count_cycles = 0; + } + + if (WDTE) + { + update_watchdog(m_inst_cycles); + } + + m_icount -= m_inst_cycles; + + } while (m_icount > 0); +} diff --git a/src/devices/cpu/pic16x8x/pic16x8x.h b/src/devices/cpu/pic16x8x/pic16x8x.h new file mode 100644 index 00000000000..52456dbb3d6 --- /dev/null +++ b/src/devices/cpu/pic16x8x/pic16x8x.h @@ -0,0 +1,319 @@ +// license:BSD-3-Clause +// copyright-holders:Grull Osgo +/************************************************************************ + + Microchip PIC16x8x Emulator + + Based on MAME's PIC16C5x/62x cpu devices developed by Tony La Porta + and improvements to SFR's accesss made by ajrhacker. + + +************************************************************************/ + +#ifndef MAME_CPU_PIC16X8X_PIC16X8X_H +#define MAME_CPU_PIC16X8X_PIC16X8X_H + +#pragma once + +// input lines +enum +{ + PIC16x8x_T0CKI = 0, + PIC16x8x_RB0INT +}; + +DECLARE_DEVICE_TYPE(PIC16CR83, pic16cr83_device) +DECLARE_DEVICE_TYPE(PIC16CR84, pic16cr84_device) +DECLARE_DEVICE_TYPE(PIC16F83, pic16f83_device) +DECLARE_DEVICE_TYPE(PIC16F84, pic16f84_device) +DECLARE_DEVICE_TYPE(PIC16F84A, pic16f84a_device) + +class pic16x8x_device : public cpu_device, public device_nvram_interface +{ + +// i/o ports + enum + { + PORTA = 0, + PORTB + }; + +public: + // port a, 5 bits, 2-way + auto read_a() { return m_read_port[PORTA].bind(); } + auto write_a() { return m_write_port[PORTA].bind(); } + + // port b, 8 bits, 2-way + auto read_b() { return m_read_port[PORTB].bind(); } + auto write_b() { return m_write_port[PORTB].bind(); } + + /**************************************************************************** + * Function to configure the CONFIG register. This is actually hard-wired + * during ROM programming, so should be called in the driver INIT, with + * the value if known (available in HEX dumps of the ROM). + ****************************************************************************/ + void set_config(u16 data); + + void core_regs(address_map &map, u8 mirror = 0); + + void ram_6(address_map &map); + void rom_9(address_map &map); + void ram_7(address_map &map); + void rom_10(address_map &map); + +protected: + // construction/destruction + pic16x8x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int program_width, address_map_constructor program_map, address_map_constructor data_map); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_execute_interface overrides + /************************************************************************** + * Internal Clock divisor + * + * External Clock is divided internally by 4 for the instruction cycle + * times. (Each instruction cycle passes through 4 machine states). This + * is handled by the cpu execution engine. + **************************************************************************/ + virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 4 - 1) / 4; } + virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles * 4); } + virtual u32 execute_min_cycles() const noexcept override { return 1; } + virtual u32 execute_max_cycles() const noexcept override { return 2; } + virtual u32 execute_input_lines() const noexcept override { return 1; } + virtual bool execute_input_edge_triggered(int inputnum) const noexcept override { return inputnum == PIC16x8x_T0CKI; } + virtual void execute_run() override; + virtual void execute_set_input(int line, int state) override; + + // device_memory_interface overrides + virtual space_config_vector memory_space_config() const override; + + // device_nvram_interface implementation + virtual bool nvram_read(util::read_stream &file) override; + virtual bool nvram_write(util::write_stream &file) override; + virtual void nvram_default() override; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry) override; + virtual void state_export(const device_state_entry &entry) override; + virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + + // device_disasm_interface overrides + virtual std::unique_ptr create_disassembler() override; + + u8 m_eeprom_data[0x40]; + u16 m_buff[0x40]; + + optional_memory_region m_region; + + // address spaces + address_space_config m_program_config; + address_space_config m_data_config; + + int m_program_width; + +private: + + memory_access<13, 1, -1, ENDIANNESS_LITTLE>::cache m_program; + memory_access< 8, 0, 0, ENDIANNESS_LITTLE>::specific m_data; + + /******************** CPU Internal Registers *******************/ + u16 m_PCL; + u16 m_PREVPC; + u8 m_W; + u8 m_OPTION; + u16 m_CONFIG; + u8 m_ALU; + u16 m_WDT; + u8 m_TMR0; + u8 m_STATUS; + u8 m_FSR; + u8 m_EEDATA; + u8 m_EEADR; + u8 m_PCLATH; + u8 m_INTCON; + u8 m_EECON1; + u8 m_EECON2; + u8 m_port_data[2]; + u8 m_port_tris[2]; + u16 m_STACK[8]; + u16 m_prescaler; // Note: this is really an 8-bit register + PAIR16 m_opcode; + int m_icount; + int m_delay_timer; + int m_rtcc; + u8 m_count_cycles; + u8 m_data_mask; + u16 m_program_mask; + u8 m_status_mask; + u8 m_inst_cycles; + u8 m_stack_pointer; + u8 m_old_RB0; + u8 m_portb_chdetect_temp; + bool m_irq_in_progress; + + const u8 m_internal_eeprom_size = 0x40; + + // i/o handlers + devcb_read8::array<2> m_read_port; + devcb_write8::array<2> m_write_port; + + // For debugger + int m_debugger_temp; + + // opcode table entry + typedef void (pic16x8x_device::*pic16x8x_ophandler)(); + struct pic16x8x_opcode + { + u8 cycles; + pic16x8x_ophandler function; + }; + + static const pic16x8x_opcode s_opcode_main[128]; + static const pic16x8x_opcode s_opcode_00x[128]; + + void check_irqs(); + + // EEPROM data access + u8 m_eeread(offs_t offs); + void m_eewrite(offs_t offs, u8 data); + + //void update_internalram_ptr(); + void calc_zero_flag(); + void calc_add_flags(u8 augend); + void calc_sub_flags(u8 minuend); + u16 pop_stack(); + void push_stack(u16 data); + void set_pc(u16 addr); + u8 get_regfile(u8 addr); + void store_regfile(u8 addr, u8 data); + void store_result(u8 addr, u8 data); + u8 tmr0_r(); + void tmr0_w(u8 data); + u8 pcl_r(); + void pcl_w(u8 data); + u8 status_r(); + void status_w(u8 data); + u8 fsr_r(); + void fsr_w(u8 data); + u8 porta_r(); + void porta_w(u8 data); + u8 portb_r(); + void portb_w(u8 data); + u8 eedata_r(); + void eedata_w(u8 data); + u8 eeadr_r(); + void eeadr_w(u8 data); + u8 pclath_r(); + void pclath_w(u8 data); + u8 intcon_r(); + void intcon_w(u8 data); + u8 trisa_r(); + void trisa_w(u8 data); + u8 trisb_r(); + void trisb_w(u8 data); + u8 eecon1_r(); + void eecon1_w(u8 data); + u8 eecon2_r(); + void eecon2_w(u8 data); + u8 option_r(); + void option_w(u8 data); + void reset_regs(); + void watchdog_reset(); + void update_watchdog(int counts); + void update_timer(int counts); + + void illegal(); + void addlw(); // new for 16x8x + void addwf(); + void andwf(); + void andlw(); + void bcf(); + void bsf(); + void btfss(); + void btfsc(); + void call(); + void clrw(); + void clrf(); + void clrwdt(); + void comf(); + void decf(); + void decfsz(); + void goto_op(); + void incf(); + void incfsz(); + void iorlw(); + void iorwf(); + void movf(); + void movlw(); + void movwf(); + void nop(); + void retfie(); // new for 16x8x + void retlw(); + void retrn(); // new for 16x8x - canĀ“t use return as mnemonic - Others PIC's uses "returns", should I use it? + void rlf(); + void rrf(); + void sleepic(); + void sublw(); // new for 16x8x + void subwf(); + void swapf(); + void xorlw(); + void xorwf(); +}; + + +class pic16x83_device : public pic16x8x_device +{ +public: + // construction/destruction + pic16x83_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); //, int program_width); +}; + +class pic16x84_device : public pic16x8x_device +{ +public: + // construction/destruction + pic16x84_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); //, int program_width); +}; + +class pic16cr83_device : public pic16x83_device +{ +public: + // construction/destruction + pic16cr83_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + + +class pic16cr84_device : public pic16x84_device +{ +public: + // construction/destruction + pic16cr84_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + + +class pic16f83_device : public pic16x83_device +{ +public: + // construction/destruction + pic16f83_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + + +class pic16f84_device : public pic16x84_device +{ +public: + // construction/destruction + pic16f84_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + + +class pic16f84a_device : public pic16x84_device +{ +public: + // construction/destruction + pic16f84a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +#endif // MAME_CPU_PIC16X8X_PIC16X8X_H diff --git a/src/mame/misc/magicard.cpp b/src/mame/misc/magicard.cpp index 76ca3be02c7..3beab19dc5a 100644 --- a/src/mame/misc/magicard.cpp +++ b/src/mame/misc/magicard.cpp @@ -189,6 +189,7 @@ #include "emu.h" #include "cpu/pic16c5x/pic16c5x.h" +#include "cpu/pic16x8x/pic16x8x.h" #include "machine/ds1207.h" #include "machine/ds2401.h" #include "machine/i2cmem.h" @@ -552,6 +553,7 @@ void hotslots_state::hotslots_map_base(address_map &map) map(0x00416001, 0x00416001).w("ssg", FUNC(ymz284_device::data_w)); map(0x00417001, 0x00417001).w("ssg", FUNC(ymz284_device::address_w)); map(0x00418000, 0x00418020).rw("rtc", FUNC(rtc72421_device::read), FUNC(rtc72421_device::write)).umask16(0x00ff); + map(0x0041a000, 0x0041a001).nopw(); // supervisor? } void hotslots_state::hotslots_map(address_map &map) @@ -1101,6 +1103,11 @@ void hotslots_state::magicle(machine_config &config) { hotslots_base(config); + pic16f84_device &pic(PIC16F84(config, "pic16f84", 4000000)); + pic.set_config(0x3ffa); // No protect - No Watchdog - HS Clock + pic.read_b().set(FUNC(hotslots_state::pic_portb_r)); + pic.write_b().set(FUNC(hotslots_state::pic_portb_w)); + I2C_24C04(config, m_i2cmem).set_e0(1); } @@ -1650,6 +1657,9 @@ ROM_START( quingo ) ROM_REGION( 0x0200, "sereeprom", 0 ) // Serial EPROM ROM_LOAD16_WORD_SWAP("quingo_24c04a.bin", 0x0000, 0x0200, BAD_DUMP CRC(d5e82b49) SHA1(7dbdf7d539cbd59a3ac546b6f50861c4958abb3a) ) // all AA & 55 + + ROM_REGION16_LE( 0x4280, "pic16f84", 0 ) // borrowed from magicle to avoid I2C bus error + ROM_LOAD("magicle_5.03_pic16f84_code.bin", 0x0000, 0x0800, BAD_DUMP CRC(22965864) SHA1(c421a9e9fac7c9c5dc01adda620dc8f5f16d94ba) ) ROM_END /* @@ -1737,6 +1747,9 @@ ROM_START( bigdeal0 ) ROM_REGION( 0x0200, "sereeprom", 0 ) // Serial EPROM ROM_LOAD16_WORD_SWAP("big_deal_24c04a.bin", 0x0000, 0x0200, BAD_DUMP CRC(d5e82b49) SHA1(7dbdf7d539cbd59a3ac546b6f50861c4958abb3a) ) // all AA & 55 + + ROM_REGION16_LE( 0x4280, "pic16f84", 0 ) // borrowed from magicle to avoid I2C bus error + ROM_LOAD("magicle_5.03_pic16f84_code.bin", 0x0000, 0x0800, BAD_DUMP CRC(22965864) SHA1(c421a9e9fac7c9c5dc01adda620dc8f5f16d94ba) ) ROM_END /* @@ -1824,6 +1837,9 @@ ROM_START( belslots ) ROM_REGION( 0x0200, "sereeprom", 0 ) // Serial EPROM ROM_LOAD16_WORD_SWAP("bel_slots_exp_24c04a.bin", 0x0000, 0x0200, BAD_DUMP CRC(d5e82b49) SHA1(7dbdf7d539cbd59a3ac546b6f50861c4958abb3a) ) // all AA & 55 + + ROM_REGION16_LE( 0x4280, "pic16f84", 0 ) // borrowed from magicle to avoid I2C bus error + ROM_LOAD("magicle_5.03_pic16f84_code.bin", 0x0000, 0x0800, BAD_DUMP CRC(22965864) SHA1(c421a9e9fac7c9c5dc01adda620dc8f5f16d94ba) ) ROM_END /* -- cgit v1.2.3