Add cpu device PIC16x8x - Add PIC16F84 to magicle into misc/magicard.cpp (#12092)

This commit is contained in:
grullosgo 2024-06-03 08:21:59 -03:00 committed by GitHub
parent ee9c41d71e
commit 1efb9a831c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 2074 additions and 0 deletions

View File

@ -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

View File

@ -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 <cctype>
#include <stdexcept>
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<<bit; bits |= 1<<bit; bit--; break;
case '0': mask |= 1<<bit; bit--; break;
case ' ': break;
case 'a':
case 'b':
case 'd':
case 'f':
case 'k':
bit--;
break;
default:
throw std::logic_error(util::string_format("Invalid instruction encoding '%s %s'\n", ops[0],ops[1]));
}
}
if (bit != -1)
{
throw std::logic_error(util::string_format("not enough bits in encoding '%s %s' %d\n", ops[0],ops[1],bit));
}
while (isspace((u8)*p)) p++;
Op.emplace_back(mask, bits, *p, ops[0], ops[1]);
ops += 2;
}
}
offs_t pic16x8x_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
{
int a, b, d, f, k; // these can all be filled in by parsing an instruction
int i;
int op;
int cnt = 1;
int code;
int bit;
const char *cp; // character pointer in OpFormats
u32 flags = 0;
bool bit_option = false;
op = -1; // no matching opcode
code = opcodes.r16(pc);
for (i = 0; i < int(Op.size()); i++)
{
if ((code & Op[i].mask) == Op[i].bits)
{
if (op != -1)
{
osd_printf_debug("Error: opcode %04Xh matches %d (%s) and %d (%s)\n",
code,i,Op[i].fmt,op,Op[op].fmt);
}
op = i;
}
}
if (op == -1)
{
util::stream_format(stream, "???? dw %04Xh",code);
return cnt | SUPPORTED;
}
// shift out operands
cp = Op[op].parse;
a = b = d = f = k = 0;
bit = 13;
while (bit >= 0)
{
osd_printf_debug("{%c/%d}",*cp,bit);
switch (*cp)
{
case 'a': a <<=1; a |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
case 'b': b <<=1; b |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
case 'd': d <<=1; d |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
case 'f': f <<=1; f |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
case 'k': k <<=1; k |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
case ' ': break;
case '1': case '0': bit--; break;
case '\0': throw std::logic_error(util::string_format("premature end of parse string, opcode %x, bit = %d\n",code,bit));
}
cp++;
}
// now traverse format string
cp = Op[op].fmt;
if (!strncmp(cp, "call", 4))
flags = STEP_OVER;
else if (!strncmp(cp, "ret", 3))
flags = STEP_OUT;
else if (!strncmp(cp, "btfs", 4) || !strncmp(cp + 2, "cfsz", 4))
flags = STEP_COND;
// bit oriented instructions
switch (f)
{
case 0x03:
case 0x05:
case 0x06:
case 0x0b:
case 0x81:
case 0x85:
case 0x86:
bit_option = true;
break;
default:
bit_option = false;
break;
}
while (*cp)
{
if (*cp == '%')
{
cp++;
switch (*cp++)
{
case 'A': util::stream_format(stream, "$%03X", a); break;
case 'D': util::stream_format(stream, "%s", dest[d]); break;
case 'F': (f < 0xc) ? util::stream_format(stream, "%s", sfregs[f]) : util::stream_format(stream, "byte_DATA_$%02X", f); break;
case 'B':
{
if (bit_option)
util::stream_format(stream, "%s", reg_flags[sfr_bank0[f & 0x0f]][b]);
else
util::stream_format(stream, "%d", b);
}
break;
case 'K': util::stream_format(stream, "%02xh", k); break;
default:
throw std::logic_error(util::string_format("illegal escape character in format '%s'\n",Op[op].fmt));
}
}
else
{
stream << *cp++;
}
}
return cnt | flags | SUPPORTED;
}
u32 pic16x8x_disassembler::opcode_alignment() const
{
return 1;
}

View File

@ -0,0 +1,46 @@
// license:BSD-3-Clause
// copyright-holders: Grull Osgo
/*
Microchip PIC16X8x Emulator
Based on MAME's PIC16C5x cpu_device dissasm developed by Tony La Porta.
*/
#ifndef MAME_CPU_PIC16X8X_16X8XDSM_H
#define MAME_CPU_PIC16X8X_16X8XDSM_H
#pragma once
class pic16x8x_disassembler : public util::disasm_interface
{
public:
pic16x8x_disassembler();
virtual ~pic16x8x_disassembler() = default;
virtual u32 opcode_alignment() const override;
virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
private:
struct PIC16X8xOpcode {
u16 mask; // instruction mask
u16 bits; // constant bits
u16 extcode; // value that gets extension code
const char *parse; // how to parse bits
const char *fmt; // instruction format
PIC16X8xOpcode(u16 m, u16 b, u16 e, const char *p, const char *f) : mask(m), bits(b), extcode(e), parse(p), fmt(f) {}
};
static const u8 sfr_bank0[16];
static const char *const sfregs[12];
static const char *const dest[2];
static const char *const reg_flags[9][8];
static const char *const PIC16X8xFormats[];
std::vector<PIC16X8xOpcode> Op;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -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<util::disasm_interface> 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

View File

@ -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
/*