/[dynamips]/trunk/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

Annotation of /trunk/dev_mpc860.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (hide annotations)
Sat Oct 6 16:26:06 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC3/dev_mpc860.c
File MIME type: text/plain
File size: 13704 byte(s)
dynamips-0.2.7-RC3

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    

  ViewVC Help
Powered by ViewVC 1.1.26