1 /*
2  * Cisco router simulation platform.
3  * Copyright (c) 2007 Christophe Fillot (cf@utc.fr)
4  *
5  * MSFC1 Midplane FPGA.
6  */
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include "cpu.h"
13 #include "vm.h"
14 #include "dynamips.h"
15 #include "memory.h"
16 #include "device.h"
17 #include "nmc93cX6.h"
18 #include "dev_c6msfc1.h"
19 
20 #define DEBUG_UNKNOWN  1
21 #define DEBUG_ACCESS   1
22 #define DEBUG_NET_IRQ  1
23 
24 /* Midplane FPGA private data */
25 struct c6msfc1_mpfpga_data {
26    vm_obj_t vm_obj;
27    struct vdevice dev;
28 
29    c6msfc1_t *router;
30    m_uint32_t irq_status;
31    m_uint32_t intr_enable;
32 };
33 
34 /* Update network interrupt status */
35 static inline
dev_c6msfc1_mpfpga_net_update_irq(struct c6msfc1_mpfpga_data * d)36 void dev_c6msfc1_mpfpga_net_update_irq(struct c6msfc1_mpfpga_data *d)
37 {
38    if (d->irq_status) {
39       vm_set_irq(d->router->vm,C6MSFC1_NETIO_IRQ);
40    } else {
41       vm_clear_irq(d->router->vm,C6MSFC1_NETIO_IRQ);
42    }
43 }
44 
45 /* Trigger a Network IRQ for the specified slot/port */
dev_c6msfc1_mpfpga_net_set_irq(struct c6msfc1_mpfpga_data * d,u_int slot,u_int port)46 void dev_c6msfc1_mpfpga_net_set_irq(struct c6msfc1_mpfpga_data *d,
47                                     u_int slot,u_int port)
48 {
49 #if DEBUG_NET_IRQ
50    vm_log(d->router->vm,"MP_FPGA","setting NetIRQ for slot %u port %u\n",
51           slot,port);
52 #endif
53    d->irq_status |= 1 << slot;
54    dev_c6msfc1_mpfpga_net_update_irq(d);
55 }
56 
57 /* Clear a Network IRQ for the specified slot/port */
dev_c6msfc1_mpfpga_net_clear_irq(struct c6msfc1_mpfpga_data * d,u_int slot,u_int port)58 void dev_c6msfc1_mpfpga_net_clear_irq(struct c6msfc1_mpfpga_data *d,
59                                       u_int slot,u_int port)
60 {
61 #if DEBUG_NET_IRQ
62    vm_log(d->router->vm,"MP_FPGA","clearing NetIRQ for slot %u port %u\n",
63           slot,port);
64 #endif
65    d->irq_status &= ~(1 << slot);
66    dev_c6msfc1_mpfpga_net_update_irq(d);
67 }
68 
69 /*
70  * dev_c6msfc1_access()
71  */
dev_c6msfc1_mpfpga_access(cpu_gen_t * cpu,struct vdevice * dev,m_uint32_t offset,u_int op_size,u_int op_type,m_uint64_t * data)72 void *dev_c6msfc1_mpfpga_access(cpu_gen_t *cpu,struct vdevice *dev,
73                                 m_uint32_t offset,u_int op_size,u_int op_type,
74                                 m_uint64_t *data)
75 {
76    struct c6msfc1_mpfpga_data *d = dev->priv_data;
77 
78    if (op_type == MTS_READ)
79       *data = 0x0;
80 
81 #if DEBUG_ACCESS
82    if (op_type == MTS_READ) {
83       cpu_log(cpu,"MP_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n",
84               offset,cpu_get_pc(cpu),op_size);
85    } else {
86       cpu_log(cpu,"MP_FPGA",
87               "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n",
88               offset,cpu_get_pc(cpu),*data,op_size);
89    }
90 #endif
91 
92    switch(offset) {
93       /*
94        * Revision + Slot: just tell we're in slot 1 (and chip rev 2)
95        * Other bits are unknown.
96        */
97       case 0x00:
98          if (op_type == MTS_READ)
99             *data = 0x12;
100          break;
101 
102       /* Interrupt Control ("sh msfc") - unknown */
103       case 0x08:
104          if (op_type == MTS_READ)
105             *data = 0x1c;
106          break;
107 
108       /* Interrupt Enable ("sh msfc") */
109       case 0x10:
110          if (op_type == MTS_READ)
111             *data = d->intr_enable;
112          else
113             d->intr_enable = *data;
114          break;
115 
116       /*
117        * Read when a Network Interrupt is triggered.
118        *   Bit 0: EOBC
119        *   Bit 1: IBC
120        */
121       case 0x18:
122       case 0x1b:
123          if (op_type == MTS_READ)
124             *data = d->irq_status;
125          break;
126 
127 #if DEBUG_UNKNOWN
128       default:
129          if (op_type == MTS_READ) {
130             cpu_log(cpu,"MP_FPGA","read from unknown addr 0x%x, pc=0x%llx\n",
131                     offset,cpu_get_pc(cpu));
132          } else {
133             cpu_log(cpu,"MP_FPGA","write to unknown addr 0x%x, value=0x%llx, "
134                     "pc=0x%llx\n",offset,*data,cpu_get_pc(cpu));
135          }
136 #endif
137    }
138 
139    return NULL;
140 }
141 
142 /* Shutdown the MP FPGA device */
143 static void
dev_c6msfc1_mpfpga_shutdown(vm_instance_t * vm,struct c6msfc1_mpfpga_data * d)144 dev_c6msfc1_mpfpga_shutdown(vm_instance_t *vm,struct c6msfc1_mpfpga_data *d)
145 {
146    if (d != NULL) {
147       /* Remove the device */
148       dev_remove(vm,&d->dev);
149 
150       /* Free the structure itself */
151       free(d);
152    }
153 }
154 
155 /*
156  * dev_c6msfc1_mpfpga_init()
157  */
dev_c6msfc1_mpfpga_init(c6msfc1_t * router,m_uint64_t paddr,m_uint32_t len)158 int dev_c6msfc1_mpfpga_init(c6msfc1_t *router,m_uint64_t paddr,m_uint32_t len)
159 {
160    struct c6msfc1_mpfpga_data *d;
161 
162    /* Allocate private data structure */
163    if (!(d = malloc(sizeof(*d)))) {
164       fprintf(stderr,"MP_FPGA: out of memory\n");
165       return(-1);
166    }
167 
168    memset(d,0,sizeof(*d));
169    d->router = router;
170 
171    vm_object_init(&d->vm_obj);
172    d->vm_obj.name = "mp_fpga";
173    d->vm_obj.data = d;
174    d->vm_obj.shutdown = (vm_shutdown_t)dev_c6msfc1_mpfpga_shutdown;
175 
176    /* Set device properties */
177    dev_init(&d->dev);
178    d->dev.name      = "mp_fpga";
179    d->dev.phys_addr = paddr;
180    d->dev.phys_len  = len;
181    d->dev.handler   = dev_c6msfc1_mpfpga_access;
182    d->dev.priv_data = d;
183 
184    /* Map this device to the VM */
185    vm_bind_device(router->vm,&d->dev);
186    vm_object_add(router->vm,&d->vm_obj);
187    return(0);
188 }
189