diff options
Diffstat (limited to 'src/devices/cpu/pic17/pic17c4x.cpp')
-rw-r--r-- | src/devices/cpu/pic17/pic17c4x.cpp | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/src/devices/cpu/pic17/pic17c4x.cpp b/src/devices/cpu/pic17/pic17c4x.cpp new file mode 100644 index 00000000000..45c2065ae86 --- /dev/null +++ b/src/devices/cpu/pic17/pic17c4x.cpp @@ -0,0 +1,531 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/********************************************************************** + + Microchip PIC17C4X microcontrollers + + Comparative list of features: + + Clock frequency 33 MHz maximum (PIC17C42: 25 MHz maximum) + EPROM (PIC17C42(A)) 2K (mask ROM on PIC17CR42) + EPROM (PIC17C43) 4K (mask ROM on PIC17CR43) + EPROM (PIC17C44) 8K + RAM (PIC17C42(A)) 232 bytes + RAM (PIC17C43/44) 454 bytes + Pin count 40 (PDIP, CERDIP) or 44 (PLCC, MQFP, TQFP) + Port pins 33 (19 shared with external bus) + Interrupt sources 11 + 8-bit timers 2 (cascadable) + 16-bit timers 16 (including TMR0) + Capture inputs 2 + PWM outputs 2 + USART 1 + + The original PIC17C42 lacks a hardware multiplier and has a few + CPU core bugs that were corrected in PIC17C42A and the rest of + the family. + +**********************************************************************/ + +#include "emu.h" +#include "pic17c4x.h" + +// device type definitions +DEFINE_DEVICE_TYPE(PIC17C43, pic17c43_device, "pic17c43", "Microchip PIC17C43") +DEFINE_DEVICE_TYPE(PIC17C44, pic17c44_device, "pic17c44", "Microchip PIC17C44") + +pic17c4x_device::pic17c4x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 rom_size, address_map_constructor data_map) + : pic17_cpu_device(mconfig, type, tag, owner, clock, rom_size, data_map) + , m_port_out_cb(*this) + , m_rain(0x3f) + , m_lata(0) + , m_rbpu(false) + , m_ddrb(0) + , m_latb(0) + , m_tmr8bit{0, 0} + , m_pr8bit{0, 0} + , m_tmr3(0) + , m_ca16bit{0, 0} + , m_tcon1(0) + , m_tcon2(0) + , m_rcsta(0) + , m_txsta(0) + , m_spbrg(0) + , m_pir(0) + , m_pie(0) +{ +} + +pic17c43_device::pic17c43_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 rom_size) + : pic17c4x_device(mconfig, type, tag, owner, clock, rom_size, address_map_constructor(FUNC(pic17c43_device::data_map), this)) +{ +} + +pic17c43_device::pic17c43_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : pic17c43_device(mconfig, PIC17C43, tag, owner, clock, 0x1000) +{ +} + +pic17c44_device::pic17c44_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : pic17c43_device(mconfig, PIC17C44, tag, owner, clock, 0x2000) +{ +} + +void pic17c4x_device::data_map(address_map &map) +{ + core_data_map(map); + + // TODO: add handlers for more of these SFRs + map(0x010, 0x010).rw(FUNC(pic17c4x_device::porta_r), FUNC(pic17c4x_device::porta_w)); + map(0x011, 0x011).rw(FUNC(pic17c4x_device::ddrb_r), FUNC(pic17c4x_device::ddrb_w)); + map(0x012, 0x012).rw(FUNC(pic17c4x_device::portb_r), FUNC(pic17c4x_device::portb_w)); + map(0x013, 0x013).rw(FUNC(pic17c4x_device::rcsta_r), FUNC(pic17c4x_device::rcsta_w)); + //map(0x014, 0x014).r(FUNC(pic17c4x_device::rcreg_r)); + map(0x015, 0x015).rw(FUNC(pic17c4x_device::txsta_r), FUNC(pic17c4x_device::txsta_w)); + map(0x016, 0x016).w(FUNC(pic17c4x_device::txreg_w)); + map(0x017, 0x017).rw(FUNC(pic17c4x_device::spbrg_r), FUNC(pic17c4x_device::spbrg_w)); + //map(0x110, 0x110).rw(FUNC(pic17c4x_device::ddrc_r), FUNC(pic17c4x_device::ddrc_w)); + //map(0x111, 0x111).rw(FUNC(pic17c4x_device::portc_r), FUNC(pic17c4x_device::portc_w)); + //map(0x112, 0x112).rw(FUNC(pic17c4x_device::ddrd_r), FUNC(pic17c4x_device::ddrd_w)); + //map(0x113, 0x113).rw(FUNC(pic17c4x_device::portd_r), FUNC(pic17c4x_device::portd_w)); + //map(0x114, 0x114).rw(FUNC(pic17c4x_device::ddre_r), FUNC(pic17c4x_device::ddre_w)); + //map(0x115, 0x115).rw(FUNC(pic17c4x_device::porte_r), FUNC(pic17c4x_device::porte_w)); + map(0x116, 0x116).rw(FUNC(pic17c4x_device::pir_r), FUNC(pic17c4x_device::pir_w)); + map(0x117, 0x117).rw(FUNC(pic17c4x_device::pie_r), FUNC(pic17c4x_device::pie_w)); + map(0x210, 0x210).rw(FUNC(pic17c4x_device::tmr1_r), FUNC(pic17c4x_device::tmr1_w)); + map(0x211, 0x211).rw(FUNC(pic17c4x_device::tmr2_r), FUNC(pic17c4x_device::tmr2_w)); + map(0x212, 0x212).rw(FUNC(pic17c4x_device::tmr3l_r), FUNC(pic17c4x_device::tmr3l_w)); + map(0x213, 0x213).rw(FUNC(pic17c4x_device::tmr3h_r), FUNC(pic17c4x_device::tmr3h_w)); + map(0x214, 0x214).rw(FUNC(pic17c4x_device::pr1_r), FUNC(pic17c4x_device::pr1_w)); + map(0x215, 0x215).rw(FUNC(pic17c4x_device::pr2_r), FUNC(pic17c4x_device::pr2_w)); + map(0x216, 0x216).rw(FUNC(pic17c4x_device::pr3l_ca1l_r), FUNC(pic17c4x_device::pr3l_ca1l_w)); + map(0x217, 0x217).rw(FUNC(pic17c4x_device::pr3h_ca1h_r), FUNC(pic17c4x_device::pr3h_ca1h_w)); + //map(0x310, 0x310).rw(FUNC(pic17c4x_device::pw1dcl_r), FUNC(pic17c4x_device::pw1dcl_w)); + //map(0x311, 0x311).rw(FUNC(pic17c4x_device::pw2dcl_r), FUNC(pic17c4x_device::pw2dcl_w)); + //map(0x312, 0x312).rw(FUNC(pic17c4x_device::pw1dch_r), FUNC(pic17c4x_device::pw1dch_w)); + //map(0x313, 0x313).rw(FUNC(pic17c4x_device::pw2dch_r), FUNC(pic17c4x_device::pw2dch_w)); + map(0x314, 0x314).r(FUNC(pic17c4x_device::ca2l_r)); + map(0x315, 0x315).r(FUNC(pic17c4x_device::ca2h_r)); + map(0x316, 0x316).rw(FUNC(pic17c4x_device::tcon1_r), FUNC(pic17c4x_device::tcon1_w)); + map(0x317, 0x317).rw(FUNC(pic17c4x_device::tcon2_r), FUNC(pic17c4x_device::tcon2_w)); +} + +void pic17c43_device::data_map(address_map &map) +{ + pic17c4x_device::data_map(map); + + // RAM: 454 bytes + map(0x01a, 0x0ff).ram(); + map(0x120, 0x1ff).ram(); +} + +u8 pic17c4x_device::porta_r() +{ + // RA2 and RA3 are open-drain I/O + // TODO: RA4 and RA5 carry USART signals + u8 porta = (m_rain & 0x33) | (m_rain & m_lata & 0x0c); + if (m_rbpu) + porta |= 0x80; + return porta; +} + +void pic17c4x_device::porta_w(u8 data) +{ + // RA0 and RA1 have no output drivers + // RA4 and RA5 can only be output from USART + m_lata = (m_lata & 0x30) | (data & 0x0c); + m_port_out_cb[0](m_lata); + + if (m_rbpu != BIT(data, 7)) + { + m_rbpu = BIT(data, 7); + if (m_ddrb != 0) + m_port_out_cb[1](m_rbpu ? (m_latb | m_ddrb) : (m_latb & m_ddrb)); + } +} + +u8 pic17c4x_device::ddrb_r() +{ + return m_ddrb; +} + +void pic17c4x_device::ddrb_w(u8 data) +{ + if (m_ddrb != data) + { + m_ddrb = data; + m_port_out_cb[1](m_rbpu ? (m_latb | m_ddrb) : (m_latb & m_ddrb)); + } +} + +u8 pic17c4x_device::portb_r() +{ + return m_latb | (m_rbpu ? m_ddrb : 0); +} + +void pic17c4x_device::portb_w(u8 data) +{ + m_latb = data; + m_port_out_cb[1](m_rbpu ? (m_latb | m_ddrb) : (m_latb & m_ddrb)); +} + +u8 pic17c4x_device::rcsta_r() +{ + return m_rcsta; +} + +void pic17c4x_device::rcsta_w(u8 data) +{ + // FERR, OERR and RX9D are read-only; bit 3 is unimplemented + m_rcsta = (data & 0xf0) | (m_rcsta & 0x07); +} + +u8 pic17c4x_device::txsta_r() +{ + return m_txsta; +} + +void pic17c4x_device::txsta_w(u8 data) +{ + // TRMT is read-only; bits 2 & 3 are unimplemented + m_txsta = (data & 0xf1) | (m_txsta & 0x02); +} + +void pic17c4x_device::txreg_w(u8 data) +{ + logerror("%s: Writing %02X to TXREG\n", machine().describe_context(), data); + + // Clear TXIF + m_pir &= 0xfd; + if ((m_pir & m_pie) == 0) + set_peif(false); +} + +u8 pic17c4x_device::spbrg_r() +{ + return m_spbrg; +} + +void pic17c4x_device::spbrg_w(u8 data) +{ + m_spbrg = data; +} + +u8 pic17c4x_device::tmr1_r() +{ + return m_tmr8bit[0]; +} + +void pic17c4x_device::tmr1_w(u8 data) +{ + m_tmr8bit[0] = data; +} + +u8 pic17c4x_device::tmr2_r() +{ + return m_tmr8bit[1]; +} + +void pic17c4x_device::tmr2_w(u8 data) +{ + m_tmr8bit[1] = data; +} + +u8 pic17c4x_device::tmr3l_r() +{ + return m_tmr3 & 0x00ff; +} + +void pic17c4x_device::tmr3l_w(u8 data) +{ + m_tmr3 = (m_tmr3 & 0xff00) | data; +} + +u8 pic17c4x_device::tmr3h_r() +{ + return m_tmr3 >> 8; +} + +void pic17c4x_device::tmr3h_w(u8 data) +{ + m_tmr3 = u16(data) << 8 | (m_tmr3 & 0x00ff); +} + +u8 pic17c4x_device::pr1_r() +{ + return m_pr8bit[0]; +} + +void pic17c4x_device::pr1_w(u8 data) +{ + m_pr8bit[0] = data; +} + +u8 pic17c4x_device::pr2_r() +{ + return m_pr8bit[1]; +} + +void pic17c4x_device::pr2_w(u8 data) +{ + m_pr8bit[1] = data; +} + +u8 pic17c4x_device::pr3l_ca1l_r() +{ + return m_ca16bit[0] & 0x00ff; +} + +void pic17c4x_device::pr3l_ca1l_w(u8 data) +{ + m_ca16bit[0] = (m_ca16bit[0] & 0xff00) | data; +} + +u8 pic17c4x_device::pr3h_ca1h_r() +{ + return m_ca16bit[0] >> 8; +} + +void pic17c4x_device::pr3h_ca1h_w(u8 data) +{ + m_ca16bit[0] = u16(data) << 8 | (m_ca16bit[0] & 0x00ff); +} + +u8 pic17c4x_device::ca2l_r() +{ + return m_ca16bit[1] & 0x00ff; +} + +u8 pic17c4x_device::ca2h_r() +{ + return m_ca16bit[1] >> 8; +} + +u8 pic17c4x_device::tcon1_r() +{ + return m_tcon1; +} + +void pic17c4x_device::tcon1_w(u8 data) +{ + m_tcon1 = data; +} + +u8 pic17c4x_device::tcon2_r() +{ + return m_tcon2; +} + +void pic17c4x_device::tcon2_w(u8 data) +{ + // CA1OVF and CA2OVF are read-only + m_tcon2 = (m_tcon2 & 0xc0) | (data & 0x3f); +} + +u8 pic17c4x_device::pir_r() +{ + return m_pir; +} + +void pic17c4x_device::pir_w(u8 data) +{ + // TXIF and RCIF are read-only + m_pir = (data & 0xfc) | (m_pir & 0x03); + set_peif((m_pie & m_pir) != 0); +} + +u8 pic17c4x_device::pie_r() +{ + return m_pie; +} + +void pic17c4x_device::pie_w(u8 data) +{ + m_pie = data; + set_peif((m_pie & m_pir) != 0); +} + +void pic17c4x_device::increment_timers() +{ + pic17_cpu_device::increment_timers(); + + // Advance TMR1 + if (BIT(m_tcon2, 0) && !BIT(m_tcon1, 0)) + { + if (BIT(m_tcon1, 3)) + { + // T16 mode: TMR1 and TMR2 cascaded + if (m_tmr8bit[0] == m_pr8bit[0] && m_tmr8bit[1] == m_pr8bit[1]) + { + // Roll over and set TMR1IF + m_tmr8bit[0] = 0; + m_tmr8bit[1] = 0; + m_pir |= 0x10; + if (BIT(m_pie, 4)) + set_peif(true); + } + else + { + ++m_tmr8bit[0]; + if (m_tmr8bit[0] == 0 && BIT(m_tcon2, 1)) + ++m_tmr8bit[1]; + } + } + else + { + if (m_tmr8bit[0] == m_pr8bit[0]) + { + // Roll over and set TMR1IF + m_tmr8bit[0] = 0; + m_pir |= 0x10; + if (BIT(m_pie, 4)) + set_peif(true); + } + else + ++m_tmr8bit[0]; + } + } + + // Advance TMR2 (as 8-bit counter only) + if (BIT(m_tcon2, 1) && (m_tcon1 & 0x0a) == 0) + { + if (m_tmr8bit[1] == m_pr8bit[1]) + { + // Roll over and set TMR2IF + m_tmr8bit[1] = 0; + m_pir |= 0x20; + if (BIT(m_pie, 5)) + set_peif(true); + } + else + ++m_tmr8bit[1]; + } + + // Advance TMR3 + if (BIT(m_tcon2, 2) && !BIT(m_tcon1, 2)) + { + // Period register is not used to determine overflow when CA1 mode is selected + if (m_tmr3 == (BIT(m_tcon2, 3) ? 0xffff : m_ca16bit[0])) + { + // Roll over and set TMR3IF + m_tmr3 = 0; + m_pir |= 0x40; + if (BIT(m_pie, 6)) + set_peif(true); + } + else + ++m_tmr3; + } +} + +void pic17c4x_device::device_start() +{ + pic17_cpu_device::device_start(); + + // Register debug state + state_add(PIC17_LATA, "LATA", m_lata).mask(0x3c); + state_add(PIC17_DDRB, "DDRB", m_ddrb); + state_add(PIC17_LATB, "LATB", m_latb); + state_add(PIC17_TMR1, "TMR1", m_tmr8bit[0]); + state_add(PIC17_TMR2, "TMR2", m_tmr8bit[1]); + state_add(PIC17_TMR3, "TMR3", m_tmr3); + state_add(PIC17_PR1, "PR1", m_pr8bit[0]); + state_add(PIC17_PR2, "PR2", m_pr8bit[1]); + state_add(PIC17_CA1, "CA1", m_ca16bit[0]); + state_add(PIC17_CA2, "CA2", m_ca16bit[1]); + state_add(PIC17_TCON1, "TCON1", m_tcon1); + state_add(PIC17_TCON2, "TCON2", m_tcon2); + state_add(PIC17_RCSTA, "RCSTA", m_rcsta).mask(0xf7); + state_add(PIC17_TXSTA, "TXSTA", m_txsta).mask(0xf3); + state_add(PIC17_SPBRG, "SPBRG", m_spbrg); + state_add(PIC17_PIE, "PIE", m_pie); + state_add(PIC17_PIR, "PIR", m_pir); + + // Save state + save_item(NAME(m_lata)); + save_item(NAME(m_rbpu)); + save_item(NAME(m_ddrb)); + save_item(NAME(m_latb)); + save_item(NAME(m_tmr8bit)); + save_item(NAME(m_pr8bit)); + save_item(NAME(m_tmr3)); + save_item(NAME(m_ca16bit)); + save_item(NAME(m_tcon1)); + save_item(NAME(m_tcon2)); + save_item(NAME(m_rcsta)); + save_item(NAME(m_txsta)); + save_item(NAME(m_spbrg)); + save_item(NAME(m_pie)); + save_item(NAME(m_pir)); +} + +void pic17c4x_device::device_reset() +{ + pic17_cpu_device::device_reset(); + + // Reset ports + m_lata = 0x3c; + m_rbpu = false; + m_ddrb = 0xff; + m_port_out_cb[0](0x3c); + m_port_out_cb[1](0xff); + + // Reset timers + //m_pw2dcl &= 0xc0; + m_tcon1 = 0; + m_tcon2 = 0; + + // Reset USART + m_rcsta &= 0x01; + m_txsta = (m_txsta & 0x01) | 0x02; + + // Reset peripheral interrupts + m_pir = 0x02; + m_pie = 0; +} + +void pic17c4x_device::execute_set_input(int linenum, int state) +{ + switch (linenum) + { + case RA0_LINE: + if (state != CLEAR_LINE && BIT(m_rain, 0)) + { + // Falling edge + m_rain &= 0x3e; + int_edge(false); + } + else if (state == CLEAR_LINE && !BIT(m_rain, 0)) + { + // Rising edge + m_rain |= 0x01; + int_edge(true); + } + break; + + case RA1_LINE: + if (state != CLEAR_LINE && BIT(m_rain, 1)) + { + // Falling edge + m_rain &= 0x3d; + t0cki_edge(false); + } + else if (state == CLEAR_LINE && !BIT(m_rain, 1)) + { + // Rising edge + m_rain |= 0x02; + t0cki_edge(true); + } + break; + + case RA2_LINE: + case RA3_LINE: + case RA4_LINE: + case RA5_LINE: + if (state == ASSERT_LINE) + m_rain &= ~(1 << (linenum - RA0_LINE)); + else + m_rain |= 1 << (linenum - RA0_LINE); + break; + } +} |