pic16c5x: Register file cleanup

- Use member variables for core special registers, eliminating unsafe abuse of get_write_ptr and permitting watchpoints to trigger on accesses to these
- Use arrays for TRIS registers and port read/write callbacks
- Narrow the width of some variables and function parameters
This commit is contained in:
AJR 2024-02-20 22:42:59 -05:00
parent a83f6bca7f
commit 9d36a1040a
2 changed files with 403 additions and 338 deletions

View File

@ -131,14 +131,76 @@ void pic16c5x_device::rom_11(address_map &map)
map(0x000, 0x7ff).rom();
}
void pic16c5x_device::ram_5(address_map &map)
void pic16c5x_device::core_regs(address_map &map, u8 mirror)
{
map(0x00, 0x1f).ram();
map(0x00, 0x00).noprw().mirror(mirror); // Not an actual register, reading indirectly (FSR=0) returns 0
map(0x01, 0x01).rw(FUNC(pic16c5x_device::tmr0_r), FUNC(pic16c5x_device::tmr0_w)).mirror(mirror);
map(0x02, 0x02).rw(FUNC(pic16c5x_device::pcl_r), FUNC(pic16c5x_device::pcl_w)).mirror(mirror);
map(0x03, 0x03).rw(FUNC(pic16c5x_device::status_r), FUNC(pic16c5x_device::status_w)).mirror(mirror);
map(0x04, 0x04).rw(FUNC(pic16c5x_device::fsr_r), FUNC(pic16c5x_device::fsr_w)).mirror(mirror);
}
void pic16c5x_device::ram_7(address_map &map)
// PIC16C54, PIC16C56: 2 ports (12 pins) + 25 bytes of RAM
void pic16c5x_device::ram_5_2ports(address_map &map)
{
map(0x00, 0x0f).ram().mirror(0x60);
core_regs(map);
map(0x05, 0x05).rw(FUNC(pic16c5x_device::porta_r), FUNC(pic16c5x_device::porta_w));
map(0x06, 0x06).rw(FUNC(pic16c5x_device::portb_r), FUNC(pic16c5x_device::portb_w));
map(0x07, 0x1f).ram();
}
// PIC16C55: 3 ports (20 pins) + 24 bytes of RAM
void pic16c5x_device::ram_5_3ports(address_map &map)
{
core_regs(map);
map(0x05, 0x05).rw(FUNC(pic16c5x_device::porta_r), FUNC(pic16c5x_device::porta_w));
map(0x06, 0x06).rw(FUNC(pic16c5x_device::portb_r), FUNC(pic16c5x_device::portb_w));
map(0x07, 0x07).rw(FUNC(pic16c5x_device::portc_r), FUNC(pic16c5x_device::portc_w));
map(0x08, 0x1f).ram();
}
// PIC1655: 3 ports + 24 bytes of RAM
void pic16c5x_device::ram_1655_3ports(address_map &map)
{
core_regs(map);
map(0x05, 0x05).r(FUNC(pic16c5x_device::porta_r)).nopw(); // A is input-only on 1655
map(0x06, 0x06).rw(FUNC(pic16c5x_device::portb_r), FUNC(pic16c5x_device::portb_w));
map(0x07, 0x07).rw(FUNC(pic16c5x_device::portc_r), FUNC(pic16c5x_device::portc_w));
map(0x08, 0x1f).ram();
}
// PIC1650: 4 ports + 23 bytes of RAM
void pic16c5x_device::ram_5_4ports(address_map &map)
{
core_regs(map);
map(0x05, 0x05).rw(FUNC(pic16c5x_device::porta_r), FUNC(pic16c5x_device::porta_w));
map(0x06, 0x06).rw(FUNC(pic16c5x_device::portb_r), FUNC(pic16c5x_device::portb_w));
map(0x07, 0x07).rw(FUNC(pic16c5x_device::portc_r), FUNC(pic16c5x_device::portc_w));
map(0x08, 0x08).rw(FUNC(pic16c5x_device::portd_r), FUNC(pic16c5x_device::portd_w));
map(0x09, 0x1f).ram();
}
// PIC16C58: 2 ports (12 pins) + 73 bytes of RAM
void pic16c5x_device::ram_7_2ports(address_map &map)
{
core_regs(map, 0x60);
map(0x05, 0x05).rw(FUNC(pic16c5x_device::porta_r), FUNC(pic16c5x_device::porta_w)).mirror(0x60);
map(0x06, 0x06).rw(FUNC(pic16c5x_device::portb_r), FUNC(pic16c5x_device::portb_w)).mirror(0x60);
map(0x07, 0x0f).ram().mirror(0x60);
map(0x10, 0x1f).ram();
map(0x30, 0x3f).ram();
map(0x50, 0x5f).ram();
map(0x70, 0x7f).ram();
}
// PIC16C57: 3 ports (20 pins) + 72 bytes of RAM
void pic16c5x_device::ram_7_3ports(address_map &map)
{
core_regs(map, 0x60);
map(0x05, 0x05).rw(FUNC(pic16c5x_device::porta_r), FUNC(pic16c5x_device::porta_w)).mirror(0x60);
map(0x06, 0x06).rw(FUNC(pic16c5x_device::portb_r), FUNC(pic16c5x_device::portb_w)).mirror(0x60);
map(0x07, 0x07).rw(FUNC(pic16c5x_device::portc_r), FUNC(pic16c5x_device::portc_w)).mirror(0x60);
map(0x08, 0x0f).ram().mirror(0x60);
map(0x10, 0x1f).ram();
map(0x30, 0x3f).ram();
map(0x50, 0x5f).ram();
@ -146,69 +208,60 @@ void pic16c5x_device::ram_7(address_map &map)
}
pic16c5x_device::pic16c5x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int program_width, int data_width, int picmodel)
pic16c5x_device::pic16c5x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int program_width, int data_width, int picmodel, address_map_constructor data_map)
: cpu_device(mconfig, type, tag, owner, clock)
, m_program_config("program", ENDIANNESS_LITTLE, 16, program_width, -1,
((program_width == 9) ? address_map_constructor(FUNC(pic16c5x_device::rom_9), this) :
((program_width == 10) ? address_map_constructor(FUNC(pic16c5x_device::rom_10), this) :
address_map_constructor(FUNC(pic16c5x_device::rom_11), this))))
, m_data_config("data", ENDIANNESS_LITTLE, 8, data_width, 0,
((data_width == 5) ? address_map_constructor(FUNC(pic16c5x_device::ram_5), this) :
address_map_constructor(FUNC(pic16c5x_device::ram_7), this)))
, m_internalram(nullptr)
, m_data_config("data", ENDIANNESS_LITTLE, 8, data_width, 0, data_map)
, m_picmodel(picmodel)
, m_data_width(data_width)
, m_program_width(program_width)
, m_temp_config(0)
, m_read_a(*this, 0)
, m_read_b(*this, 0)
, m_read_c(*this, 0)
, m_read_d(*this, 0)
, m_write_a(*this)
, m_write_b(*this)
, m_write_c(*this)
, m_write_d(*this)
, m_read_port(*this, 0)
, m_write_port(*this)
{
}
pic16c54_device::pic16c54_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: pic16c5x_device(mconfig, PIC16C54, tag, owner, clock, 9, 5, 0x16C54)
: pic16c5x_device(mconfig, PIC16C54, tag, owner, clock, 9, 5, 0x16C54, address_map_constructor(FUNC(pic16c54_device::ram_5_2ports), this))
{
}
pic16c55_device::pic16c55_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: pic16c5x_device(mconfig, PIC16C55, tag, owner, clock, 9, 5, 0x16C55)
: pic16c5x_device(mconfig, PIC16C55, tag, owner, clock, 9, 5, 0x16C55, address_map_constructor(FUNC(pic16c55_device::ram_5_3ports), this))
{
}
pic16c56_device::pic16c56_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: pic16c5x_device(mconfig, PIC16C56, tag, owner, clock, 10, 5, 0x16C56)
: pic16c5x_device(mconfig, PIC16C56, tag, owner, clock, 10, 5, 0x16C56, address_map_constructor(FUNC(pic16c56_device::ram_5_2ports), this))
{
}
pic16c57_device::pic16c57_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: pic16c5x_device(mconfig, PIC16C57, tag, owner, clock, 11, 7, 0x16C57)
: pic16c5x_device(mconfig, PIC16C57, tag, owner, clock, 11, 7, 0x16C57, address_map_constructor(FUNC(pic16c57_device::ram_7_3ports), this))
{
}
pic16c58_device::pic16c58_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: pic16c5x_device(mconfig, PIC16C58, tag, owner, clock, 11, 7, 0x16C58)
: pic16c5x_device(mconfig, PIC16C58, tag, owner, clock, 11, 7, 0x16C58, address_map_constructor(FUNC(pic16c58_device::ram_7_2ports), this))
{
}
pic1650_device::pic1650_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: pic16c5x_device(mconfig, PIC1650, tag, owner, clock, 9, 5, 0x1650)
: pic16c5x_device(mconfig, PIC1650, tag, owner, clock, 9, 5, 0x1650, address_map_constructor(FUNC(pic1650_device::ram_5_4ports), this))
{
}
pic1654s_device::pic1654s_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: pic16c5x_device(mconfig, PIC1654S, tag, owner, clock, 9, 5, 0x1654)
: pic16c5x_device(mconfig, PIC1654S, tag, owner, clock, 9, 5, 0x1654, address_map_constructor(FUNC(pic1654s_device::ram_5_2ports), this))
{
}
pic1655_device::pic1655_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: pic16c5x_device(mconfig, PIC1655, tag, owner, clock, 9, 5, 0x1655)
: pic16c5x_device(mconfig, PIC1655, tag, owner, clock, 9, 5, 0x1655, address_map_constructor(FUNC(pic1655_device::ram_1655_3ports), this))
{
}
@ -226,22 +279,6 @@ std::unique_ptr<util::disasm_interface> pic16c5x_device::create_disassembler()
}
void pic16c5x_device::update_internalram_ptr()
{
m_internalram = (u8 *)space(AS_DATA).get_write_ptr(0x00);
}
#define TMR0 m_internalram[1]
#define PCL m_internalram[2]
#define STATUS m_internalram[3]
#define FSR m_internalram[4]
#define PORTA m_internalram[5]
#define PORTB m_internalram[6]
#define PORTC m_internalram[7]
#define PORTD m_internalram[8]
// ******** The following is the Status Flag register definition. ********
// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
@ -253,12 +290,12 @@ void pic16c5x_device::update_internalram_ptr()
#define DC_FLAG 0x02 // DC Digit Carry/Borrow flag (Nibble)
#define C_FLAG 0x01 // C Carry/Borrow Flag (Byte)
#define PA (STATUS & PA_REG)
#define TO (STATUS & TO_FLAG)
#define PD (STATUS & PD_FLAG)
#define ZERO (STATUS & Z_FLAG)
#define DC (STATUS & DC_FLAG)
#define CARRY (STATUS & C_FLAG)
#define PA (m_STATUS & PA_REG)
#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. ********
@ -290,9 +327,6 @@ void pic16c5x_device::update_internalram_ptr()
* Shortcuts
************************************************************************/
#define M_RDRAM(A) (((A) < 9) ? m_internalram[A] : m_data.read_byte(A))
#define M_WRTRAM(A,V) do { if ((A) < 9) m_internalram[A] = (V); else m_data.write_byte(A,V); } while (0)
#define CLR(flagreg, flag) (flagreg &= u8(~flag))
#define SET(flagreg, flag) (flagreg |= (flag))
@ -304,9 +338,9 @@ void pic16c5x_device::update_internalram_ptr()
void pic16c5x_device::calc_zero_flag()
{
if (m_ALU == 0)
SET(STATUS, Z_FLAG);
SET(m_STATUS, Z_FLAG);
else
CLR(STATUS, Z_FLAG);
CLR(m_STATUS, Z_FLAG);
}
void pic16c5x_device::calc_add_flags(u8 augend)
@ -314,14 +348,14 @@ void pic16c5x_device::calc_add_flags(u8 augend)
calc_zero_flag();
if (augend > m_ALU)
SET(STATUS, C_FLAG);
SET(m_STATUS, C_FLAG);
else
CLR(STATUS, C_FLAG);
CLR(m_STATUS, C_FLAG);
if ((augend & 0x0f) > (m_ALU & 0x0f))
SET(STATUS, DC_FLAG);
SET(m_STATUS, DC_FLAG);
else
CLR(STATUS, DC_FLAG);
CLR(m_STATUS, DC_FLAG);
}
void pic16c5x_device::calc_sub_flags(u8 minuend)
@ -329,22 +363,21 @@ void pic16c5x_device::calc_sub_flags(u8 minuend)
calc_zero_flag();
if (minuend < m_ALU)
CLR(STATUS, C_FLAG);
CLR(m_STATUS, C_FLAG);
else
SET(STATUS, C_FLAG);
SET(m_STATUS, C_FLAG);
if ((minuend & 0x0f) < (m_ALU & 0x0f))
CLR(STATUS, DC_FLAG);
CLR(m_STATUS, DC_FLAG);
else
SET(STATUS, DC_FLAG);
SET(m_STATUS, DC_FLAG);
}
void pic16c5x_device::set_pc(offs_t addr)
void pic16c5x_device::set_pc(u16 addr)
{
m_PC = addr & m_program_mask;
PCL = m_PC & 0xff;
}
u16 pic16c5x_device::pop_stack()
@ -362,179 +395,30 @@ void pic16c5x_device::push_stack(u16 data)
u8 pic16c5x_device::get_regfile(offs_t addr) // Read from internal memory
u8 pic16c5x_device::get_regfile(u8 addr) // Read from internal memory
{
u8 data = 0;
if (addr == 0) { // Indirect addressing
addr = FSR & m_data_mask;
addr = m_FSR & m_data_mask;
} else if (m_data_width != 5) {
addr |= (m_FSR & 0x60); // FSR bits 6-5 are used for banking in direct mode
}
if ((m_picmodel == 0x16C57) || (m_picmodel == 0x16C58)) {
addr |= (FSR & 0x60); // FSR bits 6-5 are used for banking in direct mode
}
if ((addr & 0x10) == 0) addr &= 0x0f;
switch (addr)
{
case 0:
// Not an actual register, reading indirectly (FSR=0) returns 0
data = 0;
break;
case 5:
// read port A
if ((m_picmodel == 0x1650) || (m_picmodel == 0x1654)) {
data = m_read_a(PIC16C5x_PORTA, 0xff) & PORTA;
}
else if (m_picmodel == 0x1655) {
data = m_read_a(PIC16C5x_PORTA, 0xff) & 0x0f;
}
else {
data = m_read_a(PIC16C5x_PORTA, 0xff);
data &= m_TRISA;
data |= (u8(~m_TRISA) & PORTA);
data &= 0x0f; // 4-bit port (only lower 4 bits used)
}
break;
case 6:
// read port B
if ((m_picmodel == 0x1650) || (m_picmodel == 0x1654)) {
data = m_read_b(PIC16C5x_PORTB, 0xff) & PORTB;
}
else if (m_picmodel != 0x1655) { // B is output-only on 1655
data = m_read_b(PIC16C5x_PORTB, 0xff);
data &= m_TRISB;
data |= (u8(~m_TRISB) & PORTB);
}
break;
case 7:
// read port C
if (m_picmodel == 0x1650 || m_picmodel == 0x1655) {
data = m_read_c(PIC16C5x_PORTC, 0xff) & PORTC;
}
else if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) {
data = m_read_c(PIC16C5x_PORTC, 0xff);
data &= m_TRISC;
data |= (u8(~m_TRISC) & PORTC);
}
else { // PIC16C54, PIC16C56, PIC16C58
data = M_RDRAM(addr);
}
break;
case 8:
// read port D
if (m_picmodel == 0x1650) {
data = m_read_d(PIC16C5x_PORTD, 0xff) & PORTD;
}
else {
data = M_RDRAM(addr);
}
break;
default:
data = M_RDRAM(addr);
break;
}
return data;
return m_data.read_byte(addr);
}
void pic16c5x_device::store_regfile(offs_t addr, u8 data) // Write to internal memory
void pic16c5x_device::store_regfile(u8 addr, u8 data) // Write to internal memory
{
if (addr == 0) { // Indirect addressing
addr = FSR & m_data_mask;
addr = m_FSR & m_data_mask;
} else if (m_data_width != 5) {
addr |= (m_FSR & 0x60); // FSR bits 6-5 are used for banking in direct mode
}
if ((m_picmodel == 0x16C57) || (m_picmodel == 0x16C58)) {
addr |= (FSR & 0x60); // FSR bits 6-5 are used for banking in direct mode
}
if ((addr & 0x10) == 0) addr &= 0x0f;
switch (addr)
{
case 0:
// Not an actual register, nothing to save
break;
case 1:
m_delay_timer = 2; // Timer increment is inhibited for 2 cycles
if (PSA == 0) m_prescaler = 0; // Must clear the Prescaler
TMR0 = data;
break;
case 2:
set_pc(((STATUS & PA_REG) << 4) | data);
m_inst_cycles++;
break;
case 3:
// on GI PIC165x, high bits are 1
if (m_picmodel == 0x1650 || m_picmodel == 0x1654 || m_picmodel == 0x1655)
STATUS = data | u8(~m_status_mask);
else
STATUS = (STATUS & (TO_FLAG | PD_FLAG)) | (data & u8(~(TO_FLAG | PD_FLAG)));
break;
case 4:
// high bits are 1
FSR = data | u8(~m_data_mask);
break;
case 5:
// write port A
if ((m_picmodel == 0x1650) || (m_picmodel == 0x1654)) {
m_write_a(PIC16C5x_PORTA, data, 0xff);
}
else if (m_picmodel != 0x1655) { // A is input-only on 1655
data &= 0x0f; // 4-bit port (only lower 4 bits used)
m_write_a(PIC16C5x_PORTA, data & u8(~m_TRISA) & 0x0f, u8(~m_TRISA) & 0x0f);
}
PORTA = data;
break;
case 6:
// write port B
if (m_picmodel == 0x1650 || m_picmodel == 0x1654 || m_picmodel == 0x1655) {
m_write_b(PIC16C5x_PORTB, data, 0xff);
}
else {
m_write_b(PIC16C5x_PORTB, data & u8(~m_TRISB), u8(~m_TRISB));
}
PORTB = data;
break;
case 7:
// write port C
if (m_picmodel == 0x1650 || m_picmodel == 0x1655) {
m_write_c(PIC16C5x_PORTC, data, 0xff);
}
else if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) {
m_write_c(PIC16C5x_PORTC, data & u8(~m_TRISC), u8(~m_TRISC));
}
PORTC = data; // also writes to RAM
break;
case 8:
// write port D
if (m_picmodel == 0x1650) {
m_write_d(PIC16C5x_PORTD, data, 0xff);
}
PORTD = data; // also writes to RAM
break;
default:
M_WRTRAM(addr, data);
break;
}
m_data.write_byte(addr, data);
}
void pic16c5x_device::store_result(offs_t addr, u8 data)
void pic16c5x_device::store_result(u8 addr, u8 data)
{
if (m_opcode.b.l & 0x20)
store_regfile(addr, data);
@ -543,13 +427,166 @@ void pic16c5x_device::store_result(offs_t addr, u8 data)
}
u8 pic16c5x_device::tmr0_r()
{
return m_TMR0;
}
void pic16c5x_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 pic16c5x_device::pcl_r()
{
return m_PC & 0x0ff;
}
void pic16c5x_device::pcl_w(u8 data)
{
set_pc(((m_STATUS & PA_REG) << 4) | data);
if (!machine().side_effects_disabled())
m_inst_cycles++;
}
u8 pic16c5x_device::status_r()
{
return m_STATUS;
}
void pic16c5x_device::status_w(u8 data)
{
// on GI PIC165x, high bits are 1
if (m_picmodel == 0x1650 || m_picmodel == 0x1654 || m_picmodel == 0x1655)
m_STATUS = data | u8(~m_status_mask);
else
m_STATUS = (m_STATUS & (TO_FLAG | PD_FLAG)) | (data & u8(~(TO_FLAG | PD_FLAG)));
}
u8 pic16c5x_device::fsr_r()
{
return m_FSR;
}
void pic16c5x_device::fsr_w(u8 data)
{
// high bits are 1
m_FSR = data | u8(~m_data_mask);
}
u8 pic16c5x_device::porta_r()
{
// read port A
if ((m_picmodel == 0x1650) || (m_picmodel == 0x1654)) {
return m_read_port[PORTA](PORTA, 0xff) & m_port_data[PORTA];
}
else if (m_picmodel == 0x1655) {
return m_read_port[PORTA](PORTA, 0xff) & 0x0f;
}
else {
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 & 0x0f; // 4-bit port (only lower 4 bits used)
}
}
void pic16c5x_device::porta_w(u8 data)
{
// write port A
if ((m_picmodel == 0x1650) || (m_picmodel == 0x1654)) {
m_write_port[PORTA](PORTA, data, 0xff);
}
else {
assert(m_picmodel != 0x1655);
data &= 0x0f; // 4-bit port (only lower 4 bits used)
m_write_port[PORTA](PORTA, data & u8(~m_port_tris[PORTA]) & 0x0f, u8(~m_port_tris[PORTA]) & 0x0f);
}
m_port_data[PORTA] = data;
}
u8 pic16c5x_device::portb_r()
{
// read port B
if ((m_picmodel == 0x1650) || (m_picmodel == 0x1654)) {
return m_read_port[PORTB](PORTB, 0xff) & m_port_data[PORTB];
}
else if (m_picmodel != 0x1655) { // B is output-only on 1655
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;
}
else
return m_port_data[PORTB];
}
void pic16c5x_device::portb_w(u8 data)
{
// write port B
if (m_picmodel == 0x1650 || m_picmodel == 0x1654 || m_picmodel == 0x1655) {
m_write_port[PORTB](PORTB, data, 0xff);
}
else {
m_write_port[PORTB](PORTB, data & u8(~m_port_tris[PORTB]), u8(~m_port_tris[PORTB]));
}
m_port_data[PORTB] = data;
}
u8 pic16c5x_device::portc_r()
{
// read port C
if (m_picmodel == 0x1650 || m_picmodel == 0x1655) {
return m_read_port[PORTC](PORTC, 0xff) & m_port_data[PORTC];
}
else {
assert((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57));
u8 data = m_read_port[PORTC](PORTC, 0xff);
data &= m_port_tris[PORTC];
data |= (u8(~m_port_tris[PORTC]) & m_port_data[PORTC]);
return data;
}
}
void pic16c5x_device::portc_w(u8 data)
{
// write port C
if (m_picmodel == 0x1650 || m_picmodel == 0x1655) {
m_write_port[PORTC](PORTC, data, 0xff);
}
else {
assert((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57));
m_write_port[PORTC](PORTC, data & u8(~m_port_tris[PORTC]), u8(~m_port_tris[PORTC]));
}
m_port_data[PORTC] = data;
}
u8 pic16c5x_device::portd_r()
{
// read port D
assert(m_picmodel == 0x1650);
return m_read_port[PORTD](PORTD, 0xff) & m_port_data[PORTD];
}
void pic16c5x_device::portd_w(u8 data)
{
// write port D
assert(m_picmodel == 0x1650);
m_write_port[PORTD](PORTD, data, 0xff);
m_port_data[PORTD] = data;
}
/************************************************************************
* Emulate the Instructions
************************************************************************/
void pic16c5x_device::illegal()
{
logerror("PIC16C5x: PC=%03x, Illegal opcode = %04x\n", m_PREVPC, m_opcode.w.l);
logerror("PIC16C5x: PC=%03x, Illegal opcode = %04x\n", m_PREVPC, m_opcode.w);
}
/*
@ -616,27 +653,27 @@ void pic16c5x_device::btfsc()
void pic16c5x_device::call()
{
push_stack(m_PC);
set_pc((((STATUS & PA_REG) << 4) | m_opcode.b.l) & 0x6ff);
set_pc((((m_STATUS & PA_REG) << 4) | m_opcode.b.l) & 0x6ff);
}
void pic16c5x_device::clrw()
{
m_W = 0;
SET(STATUS, Z_FLAG);
SET(m_STATUS, Z_FLAG);
}
void pic16c5x_device::clrf()
{
store_regfile(ADDR, 0);
SET(STATUS, Z_FLAG);
SET(m_STATUS, Z_FLAG);
}
void pic16c5x_device::clrwdt()
{
m_WDT = 0;
if (PSA) m_prescaler = 0;
SET(STATUS, TO_FLAG);
SET(STATUS, PD_FLAG);
SET(m_STATUS, TO_FLAG);
SET(m_STATUS, PD_FLAG);
}
void pic16c5x_device::comf()
@ -665,7 +702,7 @@ void pic16c5x_device::decfsz()
void pic16c5x_device::goto_op()
{
set_pc(((STATUS & PA_REG) << 4) | (m_opcode.w.l & 0x1ff));
set_pc(((m_STATUS & PA_REG) << 4) | (m_opcode.w & 0x1ff));
}
void pic16c5x_device::incf()
@ -737,13 +774,13 @@ void pic16c5x_device::rlf()
m_ALU = get_regfile(ADDR);
int carry = BIT(m_ALU, 7);
m_ALU <<= 1;
if (STATUS & C_FLAG) m_ALU |= 1;
if (m_STATUS & C_FLAG) m_ALU |= 1;
store_result(ADDR, m_ALU);
if (carry)
SET(STATUS, C_FLAG);
SET(m_STATUS, C_FLAG);
else
CLR(STATUS, C_FLAG);
CLR(m_STATUS, C_FLAG);
}
void pic16c5x_device::rrf()
@ -751,21 +788,21 @@ void pic16c5x_device::rrf()
m_ALU = get_regfile(ADDR);
int carry = BIT(m_ALU, 0);
m_ALU >>= 1;
if (STATUS & C_FLAG) m_ALU |= 0x80;
if (m_STATUS & C_FLAG) m_ALU |= 0x80;
store_result(ADDR, m_ALU);
if (carry)
SET(STATUS, C_FLAG);
SET(m_STATUS, C_FLAG);
else
CLR(STATUS, C_FLAG);
CLR(m_STATUS, C_FLAG);
}
void pic16c5x_device::sleepic()
{
if (WDTE) m_WDT = 0;
if (PSA) m_prescaler = 0;
SET(STATUS, TO_FLAG);
CLR(STATUS, PD_FLAG);
SET(m_STATUS, TO_FLAG);
CLR(m_STATUS, PD_FLAG);
}
void pic16c5x_device::subwf()
@ -788,24 +825,24 @@ void pic16c5x_device::tris()
switch (m_opcode.b.l & 0x7)
{
case 5:
if (m_TRISA != m_W) {
m_TRISA = m_W | 0xf0;
m_write_a(PIC16C5x_PORTA, PORTA & u8(~m_TRISA) & 0x0f, u8(~m_TRISA) & 0x0f);
if (m_port_tris[PORTA] != m_W) {
m_port_tris[PORTA] = m_W | 0xf0;
m_write_port[PORTA](PORTA, m_port_data[PORTA] & u8(~m_port_tris[PORTA]) & 0x0f, u8(~m_port_tris[PORTA]) & 0x0f);
}
break;
case 6:
if (m_TRISB != m_W) {
m_TRISB = m_W;
m_write_b(PIC16C5x_PORTB, PORTB & u8(~m_TRISB), u8(~m_TRISB));
if (m_port_tris[PORTB] != m_W) {
m_port_tris[PORTB] = m_W;
m_write_port[PORTB](PORTB, m_port_data[PORTB] & u8(~m_port_tris[PORTB]), u8(~m_port_tris[PORTB]));
}
break;
case 7:
if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) {
if (m_TRISC != m_W) {
m_TRISC = m_W;
m_write_c(PIC16C5x_PORTC, PORTC & u8(~m_TRISC), u8(~m_TRISC));
if (m_port_tris[PORTC] != m_W) {
m_port_tris[PORTC] = m_W;
m_write_port[PORTC](PORTC, m_port_data[PORTC] & u8(~m_port_tris[PORTC]), u8(~m_port_tris[PORTC]));
}
}
else {
@ -933,14 +970,14 @@ enum
void pic16c5x_device::device_start()
{
bool is_nmospic = (m_picmodel == 0x1650 || m_picmodel == 0x1654 || m_picmodel == 0x1655);
space(AS_PROGRAM).cache(m_program);
space(AS_DATA).specific(m_data);
m_program_mask = (1 << m_program_width) - 1;
m_data_mask = (1 << m_data_width) - 1;
m_status_mask = (m_picmodel == 0x1650 || m_picmodel == 0x1654 || m_picmodel == 0x1655) ? 0x07 : 0xff;
update_internalram_ptr();
m_status_mask = is_nmospic ? 0x07 : 0xff;
m_PC = 0;
m_PREVPC = 0;
@ -949,9 +986,14 @@ void pic16c5x_device::device_start()
m_CONFIG = 0;
m_ALU = 0;
m_WDT = 0;
memset(m_STACK, 0, sizeof(m_STACK));
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.d = 0;
m_opcode.w = 0;
m_delay_timer = 0;
m_rtcc = 0;
@ -967,12 +1009,15 @@ void pic16c5x_device::device_start()
save_item(NAME(m_CONFIG));
save_item(NAME(m_ALU));
save_item(NAME(m_WDT));
save_item(NAME(m_TRISA));
save_item(NAME(m_TRISB));
save_item(NAME(m_TRISC));
save_item(NAME(m_TMR0));
save_item(NAME(m_STATUS));
save_item(NAME(m_FSR));
save_item(NAME(m_port_data));
if (!is_nmospic)
save_item(NAME(m_port_tris));
save_item(NAME(m_STACK));
save_item(NAME(m_prescaler));
save_item(NAME(m_opcode.d));
save_item(NAME(m_opcode.w));
save_item(NAME(m_delay_timer));
save_item(NAME(m_temp_config));
@ -990,13 +1035,19 @@ void pic16c5x_device::device_start()
state_add( PIC16C5x_OPT, "OPT", m_OPTION).formatstr("%02X");
state_add( PIC16C5x_STK0, "STK0", m_STACK[0]).mask(0xfff).formatstr("%03X");
state_add( PIC16C5x_STK1, "STK1", m_STACK[1]).mask(0xfff).formatstr("%03X");
state_add( PIC16C5x_PRTA, "PRTA", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X");
if (m_picmodel != 0x1655)
state_add( PIC16C5x_PRTA, "PRTA", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X");
state_add( PIC16C5x_PRTB, "PRTB", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X");
state_add( PIC16C5x_PRTC, "PRTC", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X");
state_add( PIC16C5x_PRTD, "PRTD", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X");
state_add( PIC16C5x_TRSA, "TRSA", m_TRISA).mask(0xf).formatstr("%01X");
state_add( PIC16C5x_TRSB, "TRSB", m_TRISB).formatstr("%02X");
state_add( PIC16C5x_TRSC, "TRSC", m_TRISC).formatstr("%02X");
if (m_picmodel != 0x1654 && m_picmodel != 0x16C54 && m_picmodel != 0x16C56 && m_picmodel != 0x16C58)
state_add( PIC16C5x_PRTC, "PRTC", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X");
if (m_picmodel == 0x1650)
state_add( PIC16C5x_PRTD, "PRTD", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X");
if (!is_nmospic) {
state_add( PIC16C5x_TRSA, "TRSA", m_port_tris[PORTA]).mask(0xf).formatstr("%01X");
state_add( PIC16C5x_TRSB, "TRSB", m_port_tris[PORTB]).formatstr("%02X");
if (m_picmodel != 0x16C54 && m_picmodel != 0x16C56 && m_picmodel != 0x16C58)
state_add( PIC16C5x_TRSC, "TRSC", m_port_tris[PORTC]).formatstr("%02X");
}
state_add( PIC16C5x_FSR, "FSR", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X");
state_add( PIC16C5x_PSCL, "PSCL", m_debugger_temp).callimport().formatstr("%3s");
@ -1013,25 +1064,25 @@ void pic16c5x_device::state_import(const device_state_entry &entry)
switch (entry.index())
{
case PIC16C5x_STR:
STATUS = m_debugger_temp | u8(~m_status_mask);
m_STATUS = m_debugger_temp | u8(~m_status_mask);
break;
case PIC16C5x_TMR0:
TMR0 = m_debugger_temp;
m_TMR0 = m_debugger_temp;
break;
case PIC16C5x_PRTA:
PORTA = m_debugger_temp;
m_port_data[PORTA] = m_debugger_temp;
break;
case PIC16C5x_PRTB:
PORTB = m_debugger_temp;
m_port_data[PORTB] = m_debugger_temp;
break;
case PIC16C5x_PRTC:
PORTC = m_debugger_temp;
m_port_data[PORTC] = m_debugger_temp;
break;
case PIC16C5x_PRTD:
PORTD = m_debugger_temp;
m_port_data[PORTD] = m_debugger_temp;
break;
case PIC16C5x_FSR:
FSR = m_debugger_temp | u8(~m_data_mask);
m_FSR = m_debugger_temp | u8(~m_data_mask);
break;
case PIC16C5x_PSCL:
m_prescaler = m_debugger_temp;
@ -1044,25 +1095,25 @@ void pic16c5x_device::state_export(const device_state_entry &entry)
switch (entry.index())
{
case PIC16C5x_STR:
m_debugger_temp = STATUS | u8(~m_status_mask);
m_debugger_temp = m_STATUS | u8(~m_status_mask);
break;
case PIC16C5x_TMR0:
m_debugger_temp = TMR0;
m_debugger_temp = m_TMR0;
break;
case PIC16C5x_PRTA:
m_debugger_temp = PORTA;
m_debugger_temp = m_port_data[PORTA];
break;
case PIC16C5x_PRTB:
m_debugger_temp = PORTB;
m_debugger_temp = m_port_data[PORTB];
break;
case PIC16C5x_PRTC:
m_debugger_temp = PORTC;
m_debugger_temp = m_port_data[PORTC];
break;
case PIC16C5x_PRTD:
m_debugger_temp = PORTD;
m_debugger_temp = m_port_data[PORTD];
break;
case PIC16C5x_FSR:
m_debugger_temp = FSR | u8(~m_data_mask);
m_debugger_temp = m_FSR | u8(~m_data_mask);
break;
}
}
@ -1077,12 +1128,12 @@ void pic16c5x_device::state_string_export(const device_state_entry &entry, std::
case STATE_GENFLAGS:
str = string_format("%01x%c%c%c%c%c %c%c%c%03x",
(STATUS & 0xe0) >> 5,
STATUS & 0x10 ? '.':'O', // WDT Overflow
STATUS & 0x08 ? 'P':'D', // Power/Down
STATUS & 0x04 ? 'Z':'.', // Zero
STATUS & 0x02 ? 'c':'b', // Nibble Carry/Borrow
STATUS & 0x01 ? 'C':'B', // Carry/Borrow
(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
@ -1100,9 +1151,9 @@ void pic16c5x_device::state_string_export(const device_state_entry &entry, std::
void pic16c5x_device::reset_regs()
{
m_CONFIG = m_temp_config;
m_TRISA = 0xff;
m_TRISB = 0xff;
m_TRISC = 0xff;
m_port_tris[PORTA] = 0xff;
m_port_tris[PORTB] = 0xff;
m_port_tris[PORTC] = 0xff;
m_OPTION = T0CS_FLAG | T0SE_FLAG | PSA_FLAG | PS_REG;
set_pc(m_program_mask);
m_PREVPC = m_PC;
@ -1115,7 +1166,7 @@ void pic16c5x_device::reset_regs()
void pic16c5x_device::watchdog_reset()
{
SET(STATUS, TO_FLAG | PD_FLAG | Z_FLAG | DC_FLAG | C_FLAG);
SET(m_STATUS, TO_FLAG | PD_FLAG | Z_FLAG | DC_FLAG | C_FLAG);
reset_regs();
}
@ -1129,10 +1180,10 @@ void pic16c5x_device::set_config(u16 data)
void pic16c5x_device::device_reset()
{
reset_regs();
CLR(STATUS, PA_REG);
SET(STATUS, TO_FLAG | PD_FLAG);
store_regfile(3, STATUS);
store_regfile(4, FSR);
CLR(m_STATUS, PA_REG);
SET(m_STATUS, TO_FLAG | PD_FLAG);
store_regfile(3, m_STATUS);
store_regfile(4, m_FSR);
}
@ -1151,7 +1202,7 @@ void pic16c5x_device::update_watchdog(int counts)
If the current instruction is CLRWDT or SLEEP, don't update the WDT
*/
if ((m_opcode.w.l != 3) && (m_opcode.w.l != 4)) {
if ((m_opcode.w != 3) && (m_opcode.w != 4)) {
u16 old_WDT = m_WDT;
m_WDT -= counts;
@ -1165,12 +1216,12 @@ void pic16c5x_device::update_watchdog(int counts)
m_prescaler++;
if (m_prescaler >= (1 << PS)) { // Prescale values from 1 to 128
m_prescaler = 0;
CLR(STATUS, TO_FLAG);
CLR(m_STATUS, TO_FLAG);
watchdog_reset();
}
}
else {
CLR(STATUS, TO_FLAG);
CLR(m_STATUS, TO_FLAG);
watchdog_reset();
}
}
@ -1196,12 +1247,12 @@ void pic16c5x_device::update_timer(int counts)
if (PSA == 0) {
m_prescaler += counts;
if (m_prescaler >= (2 << PS)) { // Prescale values from 2 to 256
TMR0 += (m_prescaler / (2 << PS));
m_TMR0 += (m_prescaler / (2 << PS));
m_prescaler %= (2 << PS); // Overflow prescaler
}
}
else {
TMR0 += counts;
m_TMR0 += counts;
}
}
@ -1230,8 +1281,6 @@ void pic16c5x_device::execute_set_input(int line, int state)
void pic16c5x_device::execute_run()
{
update_internalram_ptr();
do {
if (PD == 0) { // Sleep Mode
m_count_cycles = 0;
@ -1243,12 +1292,12 @@ void pic16c5x_device::execute_run()
debugger_instruction_hook(m_PC);
m_opcode.d = m_program.read_word(m_PC);
m_opcode.w = m_program.read_word(m_PC);
set_pc(m_PC + 1);
if (m_picmodel == 0x1650 || m_picmodel == 0x1654 || m_picmodel == 0x1655 || (m_opcode.w.l & 0xff0) != 0x000) { // Do all opcodes except the 00? ones
m_inst_cycles = s_opcode_main[((m_opcode.w.l >> 4) & 0xff)].cycles;
(this->*s_opcode_main[((m_opcode.w.l >> 4) & 0xff)].function)();
if (m_picmodel == 0x1650 || m_picmodel == 0x1654 || m_picmodel == 0x1655 || (m_opcode.w & 0xff0) != 0x000) { // Do all opcodes except the 00? ones
m_inst_cycles = s_opcode_main[((m_opcode.w >> 4) & 0xff)].cycles;
(this->*s_opcode_main[((m_opcode.w >> 4) & 0xff)].function)();
}
else { // Opcode 0x00? has many opcodes in its minor nibble
m_inst_cycles = s_opcode_00x[(m_opcode.b.l & 0x1f)].cycles;

View File

@ -24,15 +24,6 @@ enum
#define PIC16C5x_T0CKI PIC16C5x_RTCC
// i/o ports
enum
{
PIC16C5x_PORTA = 0,
PIC16C5x_PORTB,
PIC16C5x_PORTC,
PIC16C5x_PORTD
};
DECLARE_DEVICE_TYPE(PIC16C54, pic16c54_device)
DECLARE_DEVICE_TYPE(PIC16C55, pic16c55_device)
DECLARE_DEVICE_TYPE(PIC16C56, pic16c56_device)
@ -46,22 +37,31 @@ DECLARE_DEVICE_TYPE(PIC1655, pic1655_device)
class pic16c5x_device : public cpu_device
{
// i/o ports
enum
{
PORTA = 0,
PORTB,
PORTC,
PORTD
};
public:
// port a, 4 or 8 bits, 2-way
auto read_a() { return m_read_a.bind(); }
auto write_a() { return m_write_a.bind(); }
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_b.bind(); }
auto write_b() { return m_write_b.bind(); }
auto read_b() { return m_read_port[PORTB].bind(); }
auto write_b() { return m_write_port[PORTB].bind(); }
// port c, 8 bits, 2-way
auto read_c() { return m_read_c.bind(); }
auto write_c() { return m_write_c.bind(); }
auto read_c() { return m_read_port[PORTC].bind(); }
auto write_c() { return m_write_port[PORTC].bind(); }
// port d, 8 bits, 2-way
auto read_d() { return m_read_d.bind(); }
auto write_d() { return m_write_d.bind(); }
auto read_d() { return m_read_port[PORTD].bind(); }
auto write_d() { return m_write_port[PORTD].bind(); }
/****************************************************************************
* Function to configure the CONFIG register. This is actually hard-wired
@ -70,15 +70,20 @@ public:
*/
void set_config(u16 data);
void ram_5(address_map &map);
void ram_7(address_map &map);
void core_regs(address_map &map, u8 mirror = 0);
void ram_5_2ports(address_map &map);
void ram_5_3ports(address_map &map);
void ram_1655_3ports(address_map &map);
void ram_5_4ports(address_map &map);
void ram_7_2ports(address_map &map);
void ram_7_3ports(address_map &map);
void rom_10(address_map &map);
void rom_11(address_map &map);
void rom_9(address_map &map);
protected:
// construction/destruction
pic16c5x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int program_width, int data_width, int picmodel);
pic16c5x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int program_width, int data_width, int picmodel, address_map_constructor data_map);
// device-level overrides
virtual void device_start() override;
@ -124,13 +129,14 @@ private:
u16 m_CONFIG;
u8 m_ALU;
u16 m_WDT;
u8 m_TRISA;
u8 m_TRISB;
u8 m_TRISC;
u8 m_TMR0;
u8 m_STATUS;
u8 m_FSR;
u8 m_port_data[4];
u8 m_port_tris[3];
u16 m_STACK[2];
u16 m_prescaler; // Note: this is really an 8-bit register
PAIR m_opcode;
u8 *m_internalram;
PAIR16 m_opcode;
int m_icount;
int m_picmodel;
@ -149,14 +155,8 @@ private:
memory_access< 7, 0, 0, ENDIANNESS_LITTLE>::specific m_data;
// i/o handlers
devcb_read8 m_read_a;
devcb_read8 m_read_b;
devcb_read8 m_read_c;
devcb_read8 m_read_d;
devcb_write8 m_write_a;
devcb_write8 m_write_b;
devcb_write8 m_write_c;
devcb_write8 m_write_d;
devcb_read8::array<4> m_read_port;
devcb_write8::array<4> m_write_port;
// For debugger
int m_debugger_temp;
@ -171,16 +171,32 @@ private:
static const pic16c5x_opcode s_opcode_main[256];
static const pic16c5x_opcode s_opcode_00x[16];
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(offs_t addr);
u8 get_regfile(offs_t addr);
void store_regfile(offs_t addr, u8 data);
void store_result(offs_t addr, u8 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 portc_r();
void portc_w(u8 data);
u8 portd_r();
void portd_w(u8 data);
void reset_regs();
void watchdog_reset();