1 |
dpavlin |
7 |
/* |
2 |
|
|
* Cisco router simulation platform. |
3 |
|
|
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
4 |
|
|
* |
5 |
|
|
* MPC860 internal devices. |
6 |
|
|
*/ |
7 |
|
|
|
8 |
|
|
#include <stdio.h> |
9 |
|
|
#include <stdlib.h> |
10 |
|
|
#include <string.h> |
11 |
|
|
|
12 |
|
|
#include "utils.h" |
13 |
|
|
#include "net.h" |
14 |
|
|
#include "cpu.h" |
15 |
|
|
#include "vm.h" |
16 |
|
|
#include "dynamips.h" |
17 |
|
|
#include "memory.h" |
18 |
|
|
#include "device.h" |
19 |
|
|
#include "net_io.h" |
20 |
|
|
#include "dev_mpc860.h" |
21 |
|
|
|
22 |
|
|
/* Debugging flags */ |
23 |
|
|
#define DEBUG_ACCESS 0 |
24 |
|
|
#define DEBUG_UNKNOWN 1 |
25 |
|
|
#define DEBUG_IDMA 1 |
26 |
|
|
|
27 |
|
|
/* Dual-Port RAM */ |
28 |
|
|
#define MPC860_DPRAM_OFFSET 0x2000 |
29 |
|
|
#define MPC860_DPRAM_SIZE 0x2000 |
30 |
|
|
#define MPC860_DPRAM_END (MPC860_DPRAM_OFFSET + MPC860_DPRAM_SIZE) |
31 |
|
|
|
32 |
|
|
/* CIPR (CPM Interrupt Pending Register) */ |
33 |
|
|
#define MPC860_CIPR_PC15 0x80000000 |
34 |
|
|
#define MPC860_CIPR_SCC1 0x40000000 |
35 |
|
|
#define MPC860_CIPR_SCC2 0x20000000 |
36 |
|
|
#define MPC860_CIPR_SCC3 0x10000000 |
37 |
|
|
#define MPC860_CIPR_SCC4 0x08000000 |
38 |
|
|
#define MPC860_CIPR_PC14 0x04000000 |
39 |
|
|
#define MPC860_CIPR_TIMER1 0x02000000 |
40 |
|
|
#define MPC860_CIPR_PC13 0x01000000 |
41 |
|
|
#define MPC860_CIPR_PC12 0x00800000 |
42 |
|
|
#define MPC860_CIPR_SDMA 0x00400000 |
43 |
|
|
#define MPC860_CIPR_IDMA1 0x00200000 |
44 |
|
|
#define MPC860_CIPR_IDMA2 0x00100000 |
45 |
|
|
#define MPC860_CIPR_TIMER2 0x00040000 |
46 |
|
|
#define MPC860_CIPR_RTT 0x00020000 |
47 |
|
|
#define MPC860_CIPR_I2C 0x00010000 |
48 |
|
|
#define MPC860_CIPR_PC11 0x00008000 |
49 |
|
|
#define MPC860_CIPR_PC10 0x00004000 |
50 |
|
|
#define MPC860_CIPR_TIMER3 0x00001000 |
51 |
|
|
#define MPC860_CIPR_PC9 0x00000800 |
52 |
|
|
#define MPC860_CIPR_PC8 0x00000400 |
53 |
|
|
#define MPC860_CIPR_PC7 0x00000200 |
54 |
|
|
#define MPC860_CIPR_TIMER4 0x00000080 |
55 |
|
|
#define MPC860_CIPR_PC6 0x00000040 |
56 |
|
|
#define MPC860_CIPR_SPI 0x00000020 |
57 |
|
|
#define MPC860_CIPR_SMC1 0x00000010 |
58 |
|
|
#define MPC860_CIPR_SMC2 0x00000008 |
59 |
|
|
#define MPC860_CIPR_PC5 0x00000004 |
60 |
|
|
#define MPC860_CIPR_PC4 0x00000002 |
61 |
|
|
|
62 |
|
|
/* IDMA Status Register */ |
63 |
|
|
#define MPC860_IDSR_OB 0x0001 /* Out of Buffers */ |
64 |
|
|
#define MPC860_IDSR_DONE 0x0002 /* Buffer chain done */ |
65 |
|
|
#define MPC860_IDSR_AD 0x0004 /* Auxiliary done */ |
66 |
|
|
|
67 |
|
|
/* Offsets of IDMA channels (from DPRAM base) */ |
68 |
|
|
#define MPC860_IDMA1_BASE 0x1cc0 |
69 |
|
|
#define MPC860_IDMA2_BASE 0x1dc0 |
70 |
|
|
|
71 |
|
|
/* Size of an IDMA buffer descriptor */ |
72 |
|
|
#define MPC860_IDMA_BD_SIZE 16 |
73 |
|
|
|
74 |
|
|
/* IDMA Buffer Descriptor Control Word */ |
75 |
|
|
#define MPC860_IDMA_CTRL_V 0x8000 /* Valid Bit */ |
76 |
|
|
#define MPC860_IDMA_CTRL_W 0x2000 /* Wrap */ |
77 |
|
|
#define MPC860_IDMA_CTRL_I 0x1000 /* Interrupt for this BD */ |
78 |
|
|
#define MPC860_IDMA_CTRL_L 0x0800 /* Last buffer of chain */ |
79 |
|
|
#define MPC860_IDMA_CTRL_CM 0x0200 /* Continuous mode */ |
80 |
|
|
|
81 |
|
|
/* IDMA buffer descriptor */ |
82 |
|
|
struct mpc860_idma_bd { |
83 |
dpavlin |
8 |
m_uint16_t offset; /* Offset in DPRAM memory */ |
84 |
dpavlin |
7 |
|
85 |
|
|
m_uint16_t ctrl; /* Control Word */ |
86 |
|
|
m_uint8_t dfcr,sfcr; /* Src/Dst Function code registers */ |
87 |
|
|
m_uint32_t buf_len; /* Buffer Length */ |
88 |
|
|
m_uint32_t src_bp; /* Source buffer pointer */ |
89 |
|
|
m_uint32_t dst_bp; /* Destination buffer pointer */ |
90 |
|
|
}; |
91 |
|
|
|
92 |
|
|
/* MPC860 private data */ |
93 |
|
|
struct mpc860_data { |
94 |
|
|
char *name; |
95 |
|
|
vm_obj_t vm_obj; |
96 |
|
|
struct vdevice dev; |
97 |
|
|
struct pci_device *pci_dev; |
98 |
|
|
vm_instance_t *vm; |
99 |
|
|
|
100 |
|
|
/* SIU Interrupt Pending Register and Interrupt Mask Register */ |
101 |
|
|
m_uint32_t sipend,simask; |
102 |
|
|
|
103 |
|
|
/* CPM Interrupt Configuration Register */ |
104 |
|
|
m_uint32_t cicr; |
105 |
|
|
|
106 |
|
|
/* CPM Interrupt Pending Register and Interrupt Mask Register */ |
107 |
|
|
m_uint32_t cipr,cimr; |
108 |
|
|
|
109 |
|
|
/* IDMA status and mask registers */ |
110 |
|
|
m_uint8_t idsr[2],idmr[2]; |
111 |
|
|
|
112 |
|
|
/* Dual-Port RAM */ |
113 |
|
|
m_uint8_t dpram[MPC860_DPRAM_SIZE]; |
114 |
|
|
}; |
115 |
|
|
|
116 |
|
|
/* Log a MPC message */ |
117 |
|
|
#define MPC_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) |
118 |
|
|
|
119 |
|
|
/* ======================================================================== */ |
120 |
|
|
|
121 |
|
|
/* DPRAM access routines */ |
122 |
|
|
static inline m_uint8_t dpram_r8(struct mpc860_data *d,m_uint16_t offset) |
123 |
|
|
{ |
124 |
|
|
return(d->dpram[offset]); |
125 |
|
|
} |
126 |
|
|
|
127 |
|
|
static inline void dpram_w8(struct mpc860_data *d,m_uint16_t offset, |
128 |
|
|
m_uint8_t val) |
129 |
dpavlin |
8 |
{ |
130 |
dpavlin |
7 |
d->dpram[offset] = val; |
131 |
|
|
} |
132 |
|
|
|
133 |
|
|
static inline m_uint16_t dpram_r16(struct mpc860_data *d,m_uint16_t offset) |
134 |
|
|
{ |
135 |
|
|
m_uint16_t val; |
136 |
|
|
|
137 |
|
|
val = (m_uint16_t)d->dpram[offset] << 8; |
138 |
|
|
val |= d->dpram[offset+1]; |
139 |
|
|
return(val); |
140 |
|
|
} |
141 |
|
|
|
142 |
|
|
static inline void dpram_w16(struct mpc860_data *d,m_uint16_t offset, |
143 |
|
|
m_uint16_t val) |
144 |
dpavlin |
8 |
{ |
145 |
dpavlin |
7 |
d->dpram[offset] = val >> 8; |
146 |
|
|
d->dpram[offset+1] = val & 0xFF; |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
static inline m_uint32_t dpram_r32(struct mpc860_data *d,m_uint16_t offset) |
150 |
|
|
{ |
151 |
|
|
m_uint32_t val; |
152 |
|
|
|
153 |
|
|
val = d->dpram[offset] << 24; |
154 |
|
|
val |= d->dpram[offset+1] << 16; |
155 |
|
|
val |= d->dpram[offset+2] << 8; |
156 |
|
|
val |= d->dpram[offset+3]; |
157 |
|
|
return(val); |
158 |
|
|
} |
159 |
|
|
|
160 |
|
|
static inline void dpram_w32(struct mpc860_data *d,m_uint16_t offset, |
161 |
|
|
m_uint32_t val) |
162 |
|
|
{ |
163 |
|
|
d->dpram[offset] = val >> 24; |
164 |
|
|
d->dpram[offset+1] = val >> 16; |
165 |
|
|
d->dpram[offset+2] = val >> 8; |
166 |
|
|
d->dpram[offset+3] = val; |
167 |
|
|
} |
168 |
|
|
|
169 |
|
|
/* ======================================================================== */ |
170 |
|
|
|
171 |
|
|
/* Update interrupt status */ |
172 |
|
|
static void mpc860_update_irq_status(struct mpc860_data *d) |
173 |
|
|
{ |
174 |
|
|
cpu_ppc_t *cpu = CPU_PPC32(d->vm->boot_cpu); |
175 |
|
|
|
176 |
|
|
cpu->irq_pending = d->sipend & d->simask; |
177 |
|
|
cpu->irq_check = cpu->irq_pending; |
178 |
|
|
} |
179 |
|
|
|
180 |
|
|
/* Update CPM interrupt status */ |
181 |
|
|
static void mpc860_update_cpm_int_status(struct mpc860_data *d) |
182 |
|
|
{ |
183 |
|
|
if (d->cipr & d->cimr) |
184 |
|
|
mpc860_set_pending_irq(d,24); |
185 |
|
|
else |
186 |
|
|
mpc860_clear_pending_irq(d,24); |
187 |
|
|
} |
188 |
|
|
|
189 |
|
|
/* Update an IDMA status register */ |
190 |
|
|
static int mpc860_idma_update_idsr(struct mpc860_data *d,u_int id) |
191 |
|
|
{ |
192 |
|
|
u_int cpm_int; |
193 |
|
|
|
194 |
|
|
switch(id) { |
195 |
|
|
case 0: |
196 |
|
|
cpm_int = MPC860_CIPR_IDMA1; |
197 |
|
|
break; |
198 |
|
|
case 1: |
199 |
|
|
cpm_int = MPC860_CIPR_IDMA2; |
200 |
|
|
break; |
201 |
|
|
default: |
202 |
|
|
return(-1); |
203 |
|
|
} |
204 |
|
|
|
205 |
|
|
if (d->idsr[id] & d->idmr[id]) |
206 |
|
|
d->cipr |= cpm_int; |
207 |
|
|
else |
208 |
|
|
d->cipr &= ~cpm_int; |
209 |
|
|
|
210 |
|
|
mpc860_update_cpm_int_status(d); |
211 |
|
|
return(0); |
212 |
|
|
} |
213 |
|
|
|
214 |
|
|
/* Process to an IDMA transfer for the specified buffer descriptor */ |
215 |
|
|
static void mpc860_idma_transfer(struct mpc860_data *d, |
216 |
|
|
struct mpc860_idma_bd *bd) |
217 |
|
|
{ |
218 |
|
|
physmem_dma_transfer(d->vm,bd->src_bp,bd->dst_bp,bd->buf_len); |
219 |
|
|
} |
220 |
|
|
|
221 |
|
|
/* Fetch an IDMA descriptor from Dual-Port RAM */ |
222 |
|
|
static int mpc860_idma_fetch_bd(struct mpc860_data *d,m_uint16_t bd_addr, |
223 |
|
|
struct mpc860_idma_bd *bd) |
224 |
|
|
{ |
225 |
|
|
void *ptr; |
226 |
|
|
|
227 |
|
|
if ((bd_addr < MPC860_DPRAM_OFFSET) || (bd_addr > MPC860_DPRAM_END)) |
228 |
|
|
return(-1); |
229 |
|
|
|
230 |
|
|
bd->offset = bd_addr - MPC860_DPRAM_OFFSET; |
231 |
|
|
ptr = &d->dpram[bd->offset]; |
232 |
|
|
|
233 |
|
|
/* Fetch control word */ |
234 |
|
|
bd->ctrl = dpram_r16(d,bd->offset+0x00); |
235 |
|
|
|
236 |
|
|
/* Fetch function code registers */ |
237 |
|
|
bd->dfcr = dpram_r8(d,bd->offset+0x02); |
238 |
|
|
bd->sfcr = dpram_r8(d,bd->offset+0x03); |
239 |
|
|
|
240 |
|
|
/* Fetch buffer length, source and destination addresses */ |
241 |
|
|
bd->buf_len = dpram_r32(d,bd->offset+0x04); |
242 |
|
|
bd->src_bp = dpram_r32(d,bd->offset+0x08); |
243 |
|
|
bd->dst_bp = dpram_r32(d,bd->offset+0x0c); |
244 |
|
|
|
245 |
|
|
#if DEBUG_IDMA |
246 |
|
|
MPC_LOG(d,"fetched IDMA BD at 0x%4.4x, src_bp=0x%8.8x, dst_bp=0x%8.8x " |
247 |
|
|
"len=%d\n",bd->offset,bd->src_bp,bd->dst_bp,bd->buf_len); |
248 |
|
|
#endif |
249 |
|
|
|
250 |
|
|
return(0); |
251 |
|
|
} |
252 |
|
|
|
253 |
|
|
/* Start an IDMA channel */ |
254 |
|
|
static int mpc860_idma_start_channel(struct mpc860_data *d,u_int id) |
255 |
|
|
{ |
256 |
|
|
struct mpc860_idma_bd bd; |
257 |
|
|
m_uint16_t dma_base,ibase,bd_offset; |
258 |
|
|
|
259 |
|
|
switch(id) { |
260 |
|
|
case 0: |
261 |
|
|
dma_base = MPC860_IDMA1_BASE; |
262 |
|
|
break; |
263 |
|
|
case 1: |
264 |
|
|
dma_base = MPC860_IDMA2_BASE; |
265 |
|
|
break; |
266 |
|
|
default: |
267 |
|
|
return(-1); |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
/* Get the IBASE register (offset 0) */ |
271 |
|
|
ibase = bd_offset = dpram_r16(d,dma_base+0x00); |
272 |
|
|
|
273 |
|
|
while(1) { |
274 |
|
|
/* Fetch a descriptor */ |
275 |
|
|
if (mpc860_idma_fetch_bd(d,bd_offset,&bd) == -1) |
276 |
|
|
return(-1); |
277 |
|
|
|
278 |
|
|
if (!(bd.ctrl & MPC860_IDMA_CTRL_V)) { |
279 |
|
|
d->idsr[id] |= MPC860_IDSR_OB; |
280 |
|
|
break; |
281 |
|
|
} |
282 |
|
|
|
283 |
|
|
/* Run the DMA transfer */ |
284 |
|
|
mpc860_idma_transfer(d,&bd); |
285 |
|
|
|
286 |
|
|
/* Clear the Valid bit */ |
287 |
|
|
bd.ctrl &= ~MPC860_IDMA_CTRL_V; |
288 |
dpavlin |
8 |
dpram_w16(d,bd_offset-MPC860_DPRAM_OFFSET+0x00,bd.ctrl); |
289 |
dpavlin |
7 |
|
290 |
|
|
/* Generate an interrupt for this buffer ? */ |
291 |
|
|
if (bd.ctrl & MPC860_IDMA_CTRL_I) |
292 |
|
|
d->idsr[id] |= MPC860_IDSR_AD; |
293 |
|
|
|
294 |
|
|
/* Stop if this is the last buffer of chain */ |
295 |
|
|
if (bd.ctrl & MPC860_IDMA_CTRL_L) { |
296 |
|
|
d->idsr[id] |= MPC860_IDSR_DONE; |
297 |
|
|
break; |
298 |
|
|
} |
299 |
|
|
|
300 |
|
|
bd_offset += sizeof(MPC860_IDMA_BD_SIZE); |
301 |
|
|
} |
302 |
|
|
|
303 |
|
|
mpc860_idma_update_idsr(d,id); |
304 |
|
|
return(0); |
305 |
|
|
} |
306 |
|
|
|
307 |
|
|
/* |
308 |
|
|
* dev_mpc860_access() |
309 |
|
|
*/ |
310 |
|
|
void *dev_mpc860_access(cpu_gen_t *cpu,struct vdevice *dev,m_uint32_t offset, |
311 |
|
|
u_int op_size,u_int op_type,m_uint64_t *data) |
312 |
|
|
{ |
313 |
|
|
struct mpc860_data *d = dev->priv_data; |
314 |
|
|
|
315 |
|
|
if (op_type == MTS_READ) |
316 |
|
|
*data = 0x0; |
317 |
|
|
|
318 |
|
|
#if DEBUG_ACCESS |
319 |
|
|
if (op_type == MTS_READ) { |
320 |
|
|
cpu_log(cpu,d->name, |
321 |
|
|
"read from offset 0x%x, pc=0x%llx (size=%u)\n", |
322 |
|
|
offset,cpu_get_pc(cpu),op_size); |
323 |
|
|
} else { |
324 |
|
|
cpu_log(cpu,d->name, |
325 |
|
|
"write to offset 0x%x, value=0x%llx, pc=0x%llx (size=%u)\n", |
326 |
|
|
offset,*data,cpu_get_pc(cpu),op_size); |
327 |
|
|
} |
328 |
|
|
#endif |
329 |
|
|
|
330 |
|
|
/* Handle dual-port RAM access */ |
331 |
|
|
if ((offset >= MPC860_DPRAM_OFFSET) && (offset < MPC860_DPRAM_END)) |
332 |
|
|
return(d->dpram + (offset - MPC860_DPRAM_OFFSET)); |
333 |
|
|
|
334 |
|
|
switch(offset) { |
335 |
|
|
/* SWSR - Software Service Register (Watchdog) */ |
336 |
|
|
case 0x000e: |
337 |
|
|
break; |
338 |
|
|
|
339 |
|
|
/* SIU Interrupt Pending Register */ |
340 |
|
|
case 0x0010: |
341 |
|
|
if (op_type == MTS_READ) |
342 |
|
|
*data = d->sipend; |
343 |
|
|
break; |
344 |
|
|
|
345 |
|
|
/* SIU Interrupt Mask Register */ |
346 |
|
|
case 0x0014: |
347 |
|
|
if (op_type == MTS_READ) { |
348 |
|
|
*data = d->simask; |
349 |
|
|
} else { |
350 |
|
|
d->simask = *data; |
351 |
|
|
mpc860_update_irq_status(d); |
352 |
|
|
} |
353 |
|
|
break; |
354 |
|
|
|
355 |
|
|
/* |
356 |
|
|
* Cisco 2600: |
357 |
|
|
* Bit 30: 0=NM in slot 1 |
358 |
|
|
*/ |
359 |
|
|
case 0x00f0: |
360 |
|
|
if (op_type == MTS_READ) |
361 |
|
|
*data = 0x3F00F600; |
362 |
|
|
break; |
363 |
|
|
|
364 |
|
|
/* PISCR - Periodic Interrupt Status and Control Register */ |
365 |
|
|
case 0x0240: |
366 |
|
|
if (op_type == MTS_WRITE) { |
367 |
|
|
if (*data & 0x80) { |
368 |
|
|
d->sipend &= ~0x40000000; |
369 |
|
|
mpc860_update_irq_status(d); |
370 |
|
|
} |
371 |
|
|
} |
372 |
|
|
break; |
373 |
|
|
|
374 |
|
|
case 0x200: |
375 |
|
|
if (op_type == MTS_READ) |
376 |
|
|
*data = 0x45; |
377 |
|
|
break; |
378 |
|
|
|
379 |
|
|
/* IDMA1 Status and Mask Registers */ |
380 |
|
|
case 0x910: |
381 |
|
|
if (op_type == MTS_READ) { |
382 |
|
|
*data = d->idsr[0]; |
383 |
|
|
} else { |
384 |
|
|
d->idsr[0] &= ~(*data); |
385 |
|
|
} |
386 |
|
|
break; |
387 |
|
|
|
388 |
|
|
case 0x914: |
389 |
|
|
if (op_type == MTS_READ) |
390 |
|
|
*data = d->idmr[0]; |
391 |
|
|
else |
392 |
|
|
d->idmr[0] = *data; |
393 |
|
|
break; |
394 |
|
|
|
395 |
|
|
/* IDMA2 Status and Mask Registers */ |
396 |
|
|
case 0x918: |
397 |
|
|
if (op_type == MTS_READ) |
398 |
|
|
*data = d->idsr[1]; |
399 |
|
|
else |
400 |
|
|
d->idsr[1] &= ~(*data); |
401 |
|
|
break; |
402 |
|
|
|
403 |
|
|
case 0x91c: |
404 |
|
|
if (op_type == MTS_READ) |
405 |
|
|
*data = d->idmr[1]; |
406 |
|
|
else |
407 |
|
|
d->idmr[1] = *data; |
408 |
|
|
break; |
409 |
|
|
|
410 |
|
|
/* CIPR - CPM Interrupt Pending Register */ |
411 |
|
|
case 0x944: |
412 |
|
|
if (op_type == MTS_READ) |
413 |
|
|
*data = d->cipr; |
414 |
|
|
else { |
415 |
|
|
d->cipr &= ~(*data); |
416 |
|
|
mpc860_update_cpm_int_status(d); |
417 |
|
|
} |
418 |
|
|
break; |
419 |
|
|
|
420 |
|
|
/* CIMR - CPM Interrupt Mask Register */ |
421 |
|
|
case 0x948: |
422 |
|
|
if (op_type == MTS_READ) |
423 |
|
|
*data = d->cimr; |
424 |
|
|
else { |
425 |
|
|
d->cimr = *data; |
426 |
|
|
mpc860_update_cpm_int_status(d); |
427 |
|
|
} |
428 |
|
|
break; |
429 |
|
|
|
430 |
|
|
/* PCSO - Port C Special Options Register */ |
431 |
|
|
case 0x964: |
432 |
|
|
if (op_type == MTS_WRITE) { |
433 |
|
|
if (*data & 0x01) { |
434 |
|
|
MPC_LOG(d,"activating IDMA0\n"); |
435 |
|
|
mpc860_idma_start_channel(d,0); |
436 |
|
|
} |
437 |
|
|
} |
438 |
|
|
break; |
439 |
|
|
|
440 |
|
|
case 0x0966: |
441 |
|
|
break; |
442 |
|
|
|
443 |
|
|
case 0x9c0: |
444 |
|
|
if (op_type == MTS_WRITE) { |
445 |
|
|
printf("OPCODE=0x%llx, CHANNEL=0x%llx\n", |
446 |
|
|
(*data >> 8) & 0xF, (*data >> 4) & 0xF); |
447 |
|
|
} |
448 |
|
|
|
449 |
|
|
#if DEBUG_UNKNOWN |
450 |
|
|
default: |
451 |
|
|
if (op_type == MTS_READ) { |
452 |
|
|
cpu_log(cpu,d->name, |
453 |
|
|
"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", |
454 |
|
|
offset,cpu_get_pc(cpu),op_size); |
455 |
|
|
} else { |
456 |
|
|
cpu_log(cpu,d->name, |
457 |
|
|
"write to addr 0x%x, value=0x%llx, pc=0x%llx (size=%u)\n", |
458 |
|
|
offset,*data,cpu_get_pc(cpu),op_size); |
459 |
|
|
} |
460 |
|
|
#endif |
461 |
|
|
} |
462 |
|
|
|
463 |
|
|
return NULL; |
464 |
|
|
} |
465 |
|
|
|
466 |
|
|
/* Set IRQ pending status */ |
467 |
|
|
void mpc860_set_pending_irq(struct mpc860_data *d,m_uint32_t val) |
468 |
|
|
{ |
469 |
|
|
d->sipend |= 1 << val; |
470 |
|
|
mpc860_update_irq_status(d); |
471 |
|
|
} |
472 |
|
|
|
473 |
|
|
/* Clear a pending IRQ */ |
474 |
|
|
void mpc860_clear_pending_irq(struct mpc860_data *d,m_uint32_t val) |
475 |
|
|
{ |
476 |
|
|
d->sipend &= ~(1 << val); |
477 |
|
|
mpc860_update_irq_status(d); |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
/* Shutdown the MPC860 device */ |
481 |
|
|
void dev_mpc860_shutdown(vm_instance_t *vm,struct mpc860_data *d) |
482 |
|
|
{ |
483 |
|
|
if (d != NULL) { |
484 |
|
|
/* Remove the device */ |
485 |
|
|
dev_remove(vm,&d->dev); |
486 |
|
|
|
487 |
|
|
/* Free the structure itself */ |
488 |
|
|
free(d); |
489 |
|
|
} |
490 |
|
|
} |
491 |
|
|
|
492 |
|
|
/* Create the MPC860 device */ |
493 |
|
|
int dev_mpc860_init(vm_instance_t *vm,char *name, |
494 |
|
|
m_uint64_t paddr,m_uint32_t len) |
495 |
|
|
{ |
496 |
|
|
struct mpc860_data *d; |
497 |
|
|
|
498 |
|
|
if (!(d = malloc(sizeof(*d)))) { |
499 |
|
|
fprintf(stderr,"mpc860: unable to create device data.\n"); |
500 |
|
|
return(-1); |
501 |
|
|
} |
502 |
|
|
|
503 |
|
|
memset(d,0,sizeof(*d)); |
504 |
|
|
d->name = name; |
505 |
|
|
d->vm = vm; |
506 |
|
|
|
507 |
|
|
vm_object_init(&d->vm_obj); |
508 |
|
|
d->vm_obj.name = name; |
509 |
|
|
d->vm_obj.data = d; |
510 |
|
|
d->vm_obj.shutdown = (vm_shutdown_t)dev_mpc860_shutdown; |
511 |
|
|
|
512 |
|
|
dev_init(&d->dev); |
513 |
|
|
d->dev.name = name; |
514 |
|
|
d->dev.priv_data = d; |
515 |
|
|
d->dev.phys_addr = paddr; |
516 |
|
|
d->dev.phys_len = len; |
517 |
|
|
d->dev.handler = dev_mpc860_access; |
518 |
|
|
|
519 |
|
|
/* Map this device to the VM */ |
520 |
|
|
vm_bind_device(vm,&d->dev); |
521 |
|
|
vm_object_add(vm,&d->vm_obj); |
522 |
|
|
return(0); |
523 |
|
|
} |
524 |
|
|
|