summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/pic17/pic17c4x.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/pic17/pic17c4x.cpp')
-rw-r--r--src/devices/cpu/pic17/pic17c4x.cpp531
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;
+ }
+}