/[dynamips]/upstream/dynamips-0.2.7-RC2/dev_mpc860.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/dynamips-0.2.7-RC2/dev_mpc860.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8 - (show annotations)
Sat Oct 6 16:24:54 2007 UTC (12 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 13704 byte(s)
dynamips-0.2.7-RC2

1 /*
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 m_uint16_t offset; /* Offset in DPRAM memory */
84
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 {
130 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 {
145 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 dpram_w16(d,bd_offset-MPC860_DPRAM_OFFSET+0x00,bd.ctrl);
289
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

  ViewVC Help
Powered by ViewVC 1.1.26