1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz
3 /**************************************************************************
4 *
5 * Intel XScale SA1110 peripheral emulation
6 *
7 **************************************************************************/
8
9 #include "emu.h"
10 #include "sa1110.h"
11
12 #define LOG_UNKNOWN (1 << 1)
13 #define LOG_INTC (1 << 2)
14 #define LOG_POWER (1 << 3)
15 #define LOG_ALL (LOG_UNKNOWN | LOG_INTC | LOG_POWER)
16
17 #define VERBOSE (LOG_ALL)
18 #include "logmacro.h"
19
20 DEFINE_DEVICE_TYPE(SA1110_PERIPHERALS, sa1110_periphs_device, "sa1110_periphs", "Intel XScale SA1110 Peripherals")
21
sa1110_periphs_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)22 sa1110_periphs_device::sa1110_periphs_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
23 : device_t(mconfig, SA1110_PERIPHERALS, tag, owner, clock)
24 , m_maincpu(*this, finder_base::DUMMY_TAG)
25 {
26 }
27
28 /*
29
30 Intel SA-1110 Interrupt Controller
31
32 pg. 81 to 88 Intel StrongARM SA-1110 Microprocessor Developer's Manual
33
34 */
35
update_interrupts()36 void sa1110_periphs_device::update_interrupts()
37 {
38 m_intc_regs.icfp = (m_intc_regs.icpr & m_intc_regs.icmr) & m_intc_regs.iclr;
39 m_intc_regs.icip = (m_intc_regs.icpr & m_intc_regs.icmr) & (~m_intc_regs.iclr);
40 m_maincpu->set_input_line(ARM7_FIRQ_LINE, m_intc_regs.icfp ? ASSERT_LINE : CLEAR_LINE);
41 m_maincpu->set_input_line(ARM7_IRQ_LINE, m_intc_regs.icip ? ASSERT_LINE : CLEAR_LINE);
42 }
43
set_irq_line(uint32_t line,int irq_state)44 void sa1110_periphs_device::set_irq_line(uint32_t line, int irq_state)
45 {
46 m_intc_regs.icpr &= ~line;
47 m_intc_regs.icpr |= irq_state ? line : 0;
48 update_interrupts();
49 }
50
intc_r(offs_t offset,uint32_t mem_mask)51 uint32_t sa1110_periphs_device::intc_r(offs_t offset, uint32_t mem_mask)
52 {
53 switch (offset)
54 {
55 case REG_ICIP:
56 LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller IRQ Pending Register: %08x & %08x\n", m_intc_regs.icip, mem_mask);
57 return m_intc_regs.icip;
58 case REG_ICMR:
59 LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller Mask Register: %08x & %08x\n", m_intc_regs.icmr, mem_mask);
60 return m_intc_regs.icmr;
61 case REG_ICLR:
62 LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller Level Register: %08x & %08x\n", m_intc_regs.iclr, mem_mask);
63 return m_intc_regs.iclr;
64 case REG_ICFP:
65 LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller FIQ Pending Register: %08x & %08x\n", m_intc_regs.icfp, mem_mask);
66 return m_intc_regs.icfp;
67 case REG_ICPR:
68 LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller Pending Register: %08x & %08x\n", m_intc_regs.icpr, mem_mask);
69 return m_intc_regs.icpr;
70 case REG_ICCR:
71 LOGMASKED(LOG_INTC, "sa1110 intc_r: Interrupt Controller Control Register: %08x & %08x\n", m_intc_regs.iccr, mem_mask);
72 return m_intc_regs.iccr;
73 default:
74 LOGMASKED(LOG_INTC | LOG_UNKNOWN, "sa1110 intc_r: Unknown address: %08x\n", INTC_BASE_ADDR | (offset << 2));
75 break;
76 }
77 return 0;
78 }
79
intc_w(offs_t offset,uint32_t data,uint32_t mem_mask)80 void sa1110_periphs_device::intc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
81 {
82 switch (offset)
83 {
84 case REG_ICIP:
85 LOGMASKED(LOG_INTC, "sa1110 intc_w: (Invalid Write) Interrupt Controller IRQ Pending Register: %08x & %08x\n", data, mem_mask);
86 break;
87 case REG_ICMR:
88 LOGMASKED(LOG_INTC, "sa1110 intc_w: Interrupt Controller Mask Register: %08x & %08x\n", data, mem_mask);
89 COMBINE_DATA(&m_intc_regs.icmr);
90 break;
91 case REG_ICLR:
92 LOGMASKED(LOG_INTC, "sa1110 intc_w: Interrupt Controller Level Register: %08x & %08x\n", data, mem_mask);
93 COMBINE_DATA(&m_intc_regs.iclr);
94 break;
95 case REG_ICFP:
96 LOGMASKED(LOG_INTC, "sa1110 intc_w: (Invalid Write) Interrupt Controller FIQ Pending Register: %08x & %08x\n", data, mem_mask);
97 break;
98 case REG_ICPR:
99 LOGMASKED(LOG_INTC, "sa1110_intc_w: (Invalid Write) Interrupt Controller Pending Register: %08x & %08x\n", data, mem_mask);
100 break;
101 case REG_ICCR:
102 LOGMASKED(LOG_INTC, "sa1110 intc_w: Interrupt Controller Control Register: %08x & %08x\n", data, mem_mask);
103 m_intc_regs.iccr = BIT(data, 0);
104 break;
105 default:
106 LOGMASKED(LOG_INTC | LOG_UNKNOWN, "sa1110 intc_w: Unknown address: %08x = %08x & %08x\n", INTC_BASE_ADDR | (offset << 2), data, mem_mask);
107 break;
108 }
109 }
110
111 /*
112
113 Intel SA-1110 Power Controller
114
115 pg. 104 to 111 Intel StrongARM SA-1110 Microprocessor Developer's Manual
116
117 */
118
power_r(offs_t offset,uint32_t mem_mask)119 uint32_t sa1110_periphs_device::power_r(offs_t offset, uint32_t mem_mask)
120 {
121 switch (offset)
122 {
123 case REG_PMCR:
124 LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Control Register: %08x\n", machine().describe_context(), m_power_regs.pmcr);
125 return m_power_regs.pmcr;
126 case REG_PSSR:
127 LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Sleep Status Register: %08x\n", machine().describe_context(), m_power_regs.pssr);
128 return m_power_regs.pssr;
129 case REG_PSPR:
130 LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Scratch Pad Register: %08x\n", machine().describe_context(), m_power_regs.pspr);
131 return m_power_regs.pspr;
132 case REG_PWER:
133 LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Wake-up Enable Register: %08x\n", machine().describe_context(), m_power_regs.pwer);
134 return m_power_regs.pwer;
135 case REG_PCFR:
136 LOGMASKED(LOG_POWER, "%s: power_r: Power Manager General Configuration Register: %08x\n", machine().describe_context(), m_power_regs.pcfr);
137 return m_power_regs.pcfr;
138 case REG_PPCR:
139 LOGMASKED(LOG_POWER, "%s: power_r: Power Manager PLL Configuration Register: %08x\n", machine().describe_context(), m_power_regs.ppcr);
140 return m_power_regs.ppcr;
141 case REG_PGSR:
142 LOGMASKED(LOG_POWER, "%s: power_r: Power Manager GPIO Sleep State Register: %08x\n", machine().describe_context(), m_power_regs.pgsr);
143 return m_power_regs.pgsr;
144 case REG_POSR:
145 LOGMASKED(LOG_POWER, "%s: power_r: Power Manager Oscillator Status Register: %08x\n", machine().describe_context(), m_power_regs.posr);
146 return m_power_regs.posr;
147 default:
148 LOGMASKED(LOG_POWER | LOG_UNKNOWN, "%s: power_r: Unknown address: %08x\n", machine().describe_context(), POWER_BASE_ADDR | (offset << 2));
149 break;
150 }
151 return 0;
152 }
153
power_w(offs_t offset,uint32_t data,uint32_t mem_mask)154 void sa1110_periphs_device::power_w(offs_t offset, uint32_t data, uint32_t mem_mask)
155 {
156 switch (offset)
157 {
158 case REG_PMCR:
159 LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Control Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
160 COMBINE_DATA(&m_power_regs.pmcr);
161 break;
162 case REG_PSSR:
163 LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Sleep Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
164 m_power_regs.pssr &= ~(data & 0x0000001f);
165 break;
166 case REG_PSPR:
167 LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Scratch Pad Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
168 COMBINE_DATA(&m_power_regs.pspr);
169 break;
170 case REG_PWER:
171 LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Wake-Up Enable Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
172 COMBINE_DATA(&m_power_regs.pwer);
173 break;
174 case REG_PCFR:
175 LOGMASKED(LOG_POWER, "%s: power_w: Power Manager General Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
176 COMBINE_DATA(&m_power_regs.pcfr);
177 break;
178 case REG_PPCR:
179 LOGMASKED(LOG_POWER, "%s: power_w: Power Manager PLL Configuration Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
180 COMBINE_DATA(&m_power_regs.ppcr);
181 break;
182 case REG_PGSR:
183 LOGMASKED(LOG_POWER, "%s: power_w: Power Manager GPIO Sleep State Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
184 COMBINE_DATA(&m_power_regs.pgsr);
185 break;
186 case REG_POSR:
187 LOGMASKED(LOG_POWER, "%s: power_w: Power Manager Oscillator Status Register = %08x & %08x\n", machine().describe_context(), data, mem_mask);
188 break;
189 default:
190 LOGMASKED(LOG_POWER | LOG_UNKNOWN, "%s: power_w: Unknown address: %08x = %08x & %08x\n", machine().describe_context(), POWER_BASE_ADDR | (offset << 2),
191 data, mem_mask);
192 break;
193 }
194 }
195
device_start()196 void sa1110_periphs_device::device_start()
197 {
198 save_item(NAME(m_intc_regs.icip), m_intc_regs.icip);
199 save_item(NAME(m_intc_regs.icmr), m_intc_regs.icmr);
200 save_item(NAME(m_intc_regs.iclr), m_intc_regs.iclr);
201 save_item(NAME(m_intc_regs.iccr), m_intc_regs.iccr);
202 save_item(NAME(m_intc_regs.icfp), m_intc_regs.icfp);
203 save_item(NAME(m_intc_regs.icpr), m_intc_regs.icpr);
204
205 save_item(NAME(m_power_regs.pmcr), m_power_regs.pmcr);
206 save_item(NAME(m_power_regs.pssr), m_power_regs.pssr);
207 save_item(NAME(m_power_regs.pspr), m_power_regs.pspr);
208 save_item(NAME(m_power_regs.pwer), m_power_regs.pwer);
209 save_item(NAME(m_power_regs.pcfr), m_power_regs.pcfr);
210 save_item(NAME(m_power_regs.ppcr), m_power_regs.ppcr);
211 save_item(NAME(m_power_regs.pgsr), m_power_regs.pgsr);
212 save_item(NAME(m_power_regs.posr), m_power_regs.posr);
213 }
214
device_reset()215 void sa1110_periphs_device::device_reset()
216 {
217 memset(&m_intc_regs, 0, sizeof(m_intc_regs));
218 memset(&m_power_regs, 0, sizeof(m_power_regs));
219 }
220
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)221 void sa1110_periphs_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
222 {
223 }
224
device_add_mconfig(machine_config & config)225 void sa1110_periphs_device::device_add_mconfig(machine_config &config)
226 {
227 }
228