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