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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (11 years, 10 months ago) by dpavlin
File MIME type: text/plain
File size: 14823 byte(s)
make working copy

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2007 Christophe Fillot (cf@utc.fr)
4 *
5 * Cisco C6k-MSFC1 I/O FPGA:
6 * - Simulates a NMC93C56 Serial EEPROM.
7 * - Simulates a DALLAS DS1620 for Temperature Sensors.
8 * - Simulates console and AUX ports (SCN2681).
9 *
10 * This is very similar to c7200 platform.
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <sys/types.h>
18
19 #include <termios.h>
20 #include <fcntl.h>
21 #include <pthread.h>
22
23 #include "ptask.h"
24 #include "cpu.h"
25 #include "vm.h"
26 #include "dynamips.h"
27 #include "memory.h"
28 #include "device.h"
29 #include "dev_vtty.h"
30 #include "nmc93cX6.h"
31 #include "ds1620.h"
32 #include "dev_msfc1.h"
33
34 /* Debugging flags */
35 #define DEBUG_UNKNOWN 1
36 #define DEBUG_ACCESS 0
37 #define DEBUG_LED 0
38 #define DEBUG_IO_CTL 0
39 #define DEBUG_ENVM 0
40
41 /* DUART RX/TX status (SRA/SRB) */
42 #define DUART_RX_READY 0x01
43 #define DUART_TX_READY 0x04
44
45 /* DUART RX/TX Interrupt Status/Mask */
46 #define DUART_TXRDYA 0x01
47 #define DUART_RXRDYA 0x02
48 #define DUART_TXRDYB 0x10
49 #define DUART_RXRDYB 0x20
50
51 /* Definitions for CPU and Midplane Serial EEPROMs */
52 #define DO2_DATA_OUT_MIDPLANE 7
53 #define DO1_DATA_OUT_CPU 6
54 #define CS2_CHIP_SEL_MIDPLANE 5
55 #define SK2_CLOCK_MIDPLANE 4
56 #define DI2_DATA_IN_MIDPLANE 3
57 #define CS1_CHIP_SEL_CPU 2
58 #define SK1_CLOCK_CPU 1
59 #define DI1_DATA_IN_CPU 0
60
61 /* Pack the NVRAM */
62 #define NVRAM_PACKED 0x04
63
64 /* 2 temperature sensors in a MSFC1: chassis inlet and oulet */
65 #define MSFC1_TEMP_SENSORS 2
66 #define MSFC1_DEFAULT_TEMP 22 /* default temperature: 22°C */
67
68 /* IO FPGA structure */
69 struct iofpga_data {
70 vm_obj_t vm_obj;
71 struct vdevice dev;
72 msfc1_t *router;
73
74 /* Lock test */
75 pthread_mutex_t lock;
76
77 /* Periodic task to trigger dummy DUART IRQ */
78 ptask_id_t duart_irq_tid;
79
80 /* DUART & Console Management */
81 u_int duart_isr,duart_imr,duart_irq_seq;
82
83 /* IO control register */
84 u_int io_ctrl_reg;
85
86 /* Temperature Control */
87 u_int temp_cfg_reg[MSFC1_TEMP_SENSORS];
88 u_int temp_deg_reg[MSFC1_TEMP_SENSORS];
89 u_int temp_clk_low;
90
91 u_int temp_cmd;
92 u_int temp_cmd_pos;
93
94 u_int temp_data;
95 u_int temp_data_pos;
96
97 /* Voltages */
98 u_int mux;
99 };
100
101 #define IOFPGA_LOCK(d) pthread_mutex_lock(&(d)->lock)
102 #define IOFPGA_UNLOCK(d) pthread_mutex_unlock(&(d)->lock)
103
104 /* CPU EEPROM definition */
105 static const struct nmc93cX6_eeprom_def eeprom_cpu_def = {
106 SK1_CLOCK_CPU, CS1_CHIP_SEL_CPU,
107 DI1_DATA_IN_CPU, DO1_DATA_OUT_CPU,
108 };
109
110 /* Midplane EEPROM definition */
111 static const struct nmc93cX6_eeprom_def eeprom_midplane_def = {
112 SK2_CLOCK_MIDPLANE, CS2_CHIP_SEL_MIDPLANE,
113 DI2_DATA_IN_MIDPLANE, DO2_DATA_OUT_MIDPLANE,
114 };
115
116
117 /* IOFPGA manages simultaneously CPU and Midplane EEPROM */
118 static const struct nmc93cX6_group eeprom_cpu_midplane = {
119 EEPROM_TYPE_NMC93C56, 2, 0, "CPU and Midplane EEPROM", 0,
120 { &eeprom_cpu_def, &eeprom_midplane_def },
121 };
122
123 /* Reset DS1620 */
124 static void temp_reset(struct iofpga_data *d)
125 {
126 d->temp_cmd_pos = 0;
127 d->temp_cmd = 0;
128
129 d->temp_data_pos = 0;
130 d->temp_data = 0;
131 }
132
133 /* Write the temperature control data */
134 static void temp_write_ctrl(struct iofpga_data *d,u_char val)
135 {
136 switch(val) {
137 case DS1620_RESET_ON:
138 temp_reset(d);
139 break;
140
141 case DS1620_CLK_LOW:
142 d->temp_clk_low = 1;
143 break;
144
145 case DS1620_CLK_HIGH:
146 d->temp_clk_low = 0;
147 break;
148 }
149 }
150
151 /* Read a temperature control data */
152 static u_int temp_read_data(struct iofpga_data *d)
153 {
154 u_int i,data = 0;
155
156 switch(d->temp_cmd) {
157 case DS1620_READ_CONFIG:
158 for(i=0;i<MSFC1_TEMP_SENSORS;i++)
159 data |= ((d->temp_cfg_reg[i] >> d->temp_data_pos) & 1) << i;
160
161 d->temp_data_pos++;
162
163 if (d->temp_data_pos == DS1620_CONFIG_READ_SIZE)
164 temp_reset(d);
165
166 break;
167
168 case DS1620_READ_TEMP:
169 for(i=0;i<MSFC1_TEMP_SENSORS;i++)
170 data |= ((d->temp_deg_reg[i] >> d->temp_data_pos) & 1) << i;
171
172 d->temp_data_pos++;
173
174 if (d->temp_data_pos == DS1620_DATA_READ_SIZE)
175 temp_reset(d);
176
177 break;
178
179 default:
180 vm_log(d->router->vm,"IO_FPGA","temp_sensors: CMD = 0x%x\n",
181 d->temp_cmd);
182 }
183
184 return(data);
185 }
186
187 /* Write the temperature data write register */
188 static void temp_write_data(struct iofpga_data *d,u_char val)
189 {
190 if (val == DS1620_ENABLE_READ) {
191 d->temp_data_pos = 0;
192 return;
193 }
194
195 if (!d->temp_clk_low)
196 return;
197
198 /* Write a command */
199 if (d->temp_cmd_pos < DS1620_WRITE_SIZE)
200 {
201 if (val == DS1620_DATA_HIGH)
202 d->temp_cmd |= 1 << d->temp_cmd_pos;
203
204 d->temp_cmd_pos++;
205
206 if (d->temp_cmd_pos == DS1620_WRITE_SIZE) {
207 switch(d->temp_cmd) {
208 case DS1620_START_CONVT:
209 //printf("temp_sensors: IOS enabled continuous monitoring.\n");
210 temp_reset(d);
211 break;
212 case DS1620_READ_CONFIG:
213 case DS1620_READ_TEMP:
214 break;
215 default:
216 vm_log(d->router->vm,"IO_FPGA",
217 "temp_sensors: IOS sent command 0x%x.\n",
218 d->temp_cmd);
219 }
220 }
221 }
222 else
223 {
224 if (val == DS1620_DATA_HIGH)
225 d->temp_data |= 1 << d->temp_data_pos;
226
227 d->temp_data_pos++;
228 }
229 }
230
231 /* Console port input */
232 static void tty_con_input(vtty_t *vtty)
233 {
234 struct iofpga_data *d = vtty->priv_data;
235
236 IOFPGA_LOCK(d);
237 if (d->duart_imr & DUART_RXRDYA) {
238 d->duart_isr |= DUART_RXRDYA;
239 vm_set_irq(d->router->vm,MSFC1_DUART_IRQ);
240 }
241 IOFPGA_UNLOCK(d);
242 }
243
244 /* AUX port input */
245 static void tty_aux_input(vtty_t *vtty)
246 {
247 struct iofpga_data *d = vtty->priv_data;
248
249 IOFPGA_LOCK(d);
250 if (d->duart_imr & DUART_RXRDYB) {
251 d->duart_isr |= DUART_RXRDYB;
252 vm_set_irq(d->router->vm,MSFC1_DUART_IRQ);
253 }
254 IOFPGA_UNLOCK(d);
255 }
256
257 /* IRQ trickery for Console and AUX ports */
258 static int tty_trigger_dummy_irq(struct iofpga_data *d,void *arg)
259 {
260 u_int mask;
261
262 IOFPGA_LOCK(d);
263 d->duart_irq_seq++;
264
265 if (d->duart_irq_seq == 2) {
266 mask = DUART_TXRDYA|DUART_TXRDYB;
267 if (d->duart_imr & mask) {
268 d->duart_isr |= DUART_TXRDYA|DUART_TXRDYB;
269 vm_set_irq(d->router->vm,MSFC1_DUART_IRQ);
270 }
271
272 d->duart_irq_seq = 0;
273 }
274
275 IOFPGA_UNLOCK(d);
276 return(0);
277 }
278
279 /*
280 * dev_msfc1_iofpga_access()
281 */
282 void *dev_msfc1_iofpga_access(cpu_gen_t *cpu,struct vdevice *dev,
283 m_uint32_t offset,u_int op_size,u_int op_type,
284 m_uint64_t *data)
285 {
286 struct iofpga_data *d = dev->priv_data;
287 vm_instance_t *vm = d->router->vm;
288 u_char odata;
289
290 if (op_type == MTS_READ)
291 *data = 0x0;
292
293 #if DEBUG_ACCESS
294 if (op_type == MTS_READ) {
295 cpu_log(cpu,"IO_FPGA","reading reg 0x%x at pc=0x%llx\n",
296 offset,cpu_get_pc(cpu));
297 } else {
298 cpu_log(cpu,"IO_FPGA","writing reg 0x%x at pc=0x%llx, data=0x%llx\n",
299 offset,cpu_get_pc(cpu),*data);
300 }
301 #endif
302
303 IOFPGA_LOCK(d);
304
305 switch(offset) {
306 case 0x294:
307 /*
308 * Unknown, seen in 12.4(6)T, and seems to be read at each
309 * network interrupt.
310 */
311 if (op_type == MTS_READ)
312 *data = 0x0;
313 break;
314
315 /* I/O control register */
316 case 0x204:
317 if (op_type == MTS_WRITE) {
318 #if DEBUG_IO_CTL
319 vm_log(vm,"IO_FPGA","setting value 0x%llx in io_ctrl_reg\n",*data);
320 #endif
321 d->io_ctrl_reg = *data;
322 } else {
323 *data = d->io_ctrl_reg;
324 *data |= NVRAM_PACKED; /* Packed NVRAM */
325 }
326 break;
327
328 /* CPU/Midplane EEPROMs */
329 case 0x21c:
330 if (op_type == MTS_WRITE)
331 nmc93cX6_write(&d->router->sys_eeprom_g1,(u_int)(*data));
332 else
333 *data = nmc93cX6_read(&d->router->sys_eeprom_g1);
334 break;
335
336 /* Watchdog */
337 case 0x234:
338 break;
339
340 /*
341 * FPGA release/presence ? Flash SIMM size:
342 * 0x0001: 2048K Flash (2 banks)
343 * 0x0504: 8192K Flash (2 banks)
344 * 0x0704: 16384K Flash (2 banks)
345 * 0x0904: 32768K Flash (2 banks)
346 * 0x0B04: 65536K Flash (2 banks)
347 * 0x2001: 1024K Flash (1 bank)
348 * 0x2504: 4096K Flash (1 bank)
349 * 0x2704: 8192K Flash (1 bank)
350 * 0x2904: 16384K Flash (1 bank)
351 * 0x2B04: 32768K Flash (1 bank)
352 *
353 * Number of Flash SIMM banks + size.
354 * Touching some lower bits causes problems with environmental monitor.
355 *
356 * It is displayed by command "sh bootflash: chips"
357 */
358 case 0x23c:
359 if (op_type == MTS_READ)
360 *data = 0x2704;
361 break;
362
363 /* LEDs */
364 case 0x244:
365 #if DEBUG_LED
366 vm_log(vm,"IO_FPGA","LED register is now 0x%x (0x%x)\n",
367 *data,(~*data) & 0x0F);
368 #endif
369 break;
370
371 /* ==== DUART SCN2681 (console/aux) ==== */
372 case 0x404: /* Mode Register A (MRA) */
373 break;
374
375 case 0x40c: /* Status Register A (SRA) */
376 if (op_type == MTS_READ) {
377 odata = 0;
378
379 if (vtty_is_char_avail(vm->vtty_con))
380 odata |= DUART_RX_READY;
381
382 odata |= DUART_TX_READY;
383
384 vm_clear_irq(vm,MSFC1_DUART_IRQ);
385 *data = odata;
386 }
387 break;
388
389 case 0x414: /* Command Register A (CRA) */
390 /* Disable TX = High */
391 if ((op_type == MTS_WRITE) && (*data & 0x8)) {
392 vm->vtty_con->managed_flush = TRUE;
393 vtty_flush(vm->vtty_con);
394 }
395 break;
396
397 case 0x41c: /* RX/TX Holding Register A (RHRA/THRA) */
398 if (op_type == MTS_WRITE) {
399 vtty_put_char(vm->vtty_con,(char)*data);
400 d->duart_isr &= ~DUART_TXRDYA;
401 } else {
402 *data = vtty_get_char(vm->vtty_con);
403 d->duart_isr &= ~DUART_RXRDYA;
404 }
405 break;
406
407 case 0x424: /* WRITE: Aux Control Register (ACR) */
408 break;
409
410 case 0x42c: /* Interrupt Status/Mask Register (ISR/IMR) */
411 if (op_type == MTS_WRITE) {
412 d->duart_imr = *data;
413 } else
414 *data = d->duart_isr;
415 break;
416
417 case 0x434: /* Counter/Timer Upper Value (CTU) */
418 case 0x43c: /* Counter/Timer Lower Value (CTL) */
419 case 0x444: /* Mode Register B (MRB) */
420 break;
421
422 case 0x44c: /* Status Register B (SRB) */
423 if (op_type == MTS_READ) {
424 odata = 0;
425
426 if (vtty_is_char_avail(vm->vtty_aux))
427 odata |= DUART_RX_READY;
428
429 odata |= DUART_TX_READY;
430
431 //vm_clear_irq(vm,MSFC1_DUART_IRQ);
432 *data = odata;
433 }
434 break;
435
436 case 0x454: /* Command Register B (CRB) */
437 /* Disable TX = High */
438 if ((op_type == MTS_WRITE) && (*data & 0x8)) {
439 vm->vtty_aux->managed_flush = TRUE;
440 vtty_flush(vm->vtty_aux);
441 }
442 break;
443
444 case 0x45c: /* RX/TX Holding Register B (RHRB/THRB) */
445 if (op_type == MTS_WRITE) {
446 vtty_put_char(vm->vtty_aux,(char)*data);
447 d->duart_isr &= ~DUART_TXRDYA;
448 } else {
449 *data = vtty_get_char(vm->vtty_aux);
450 d->duart_isr &= ~DUART_RXRDYB;
451 }
452 break;
453
454 case 0x46c: /* WRITE: Output Port Configuration Register (OPCR) */
455 case 0x474: /* READ: Start Counter Command; */
456 /* WRITE: Set Output Port Bits Command */
457 case 0x47c: /* WRITE: Reset Output Port Bits Command */
458 break;
459
460 /* ==== DS 1620 (temp sensors) ==== */
461 case 0x20c: /* Temperature Control */
462 if (op_type == MTS_WRITE)
463 temp_write_ctrl(d,*data);
464 break;
465
466 case 0x214: /* Temperature data write */
467 if (op_type == MTS_WRITE) {
468 temp_write_data(d,*data);
469 d->mux = *data;
470 }
471 break;
472
473 case 0x22c: /* Temperature data read */
474 if (op_type == MTS_READ)
475 *data = temp_read_data(d);
476 break;
477
478 #if DEBUG_UNKNOWN
479 default:
480 if (op_type == MTS_READ) {
481 cpu_log(cpu,"IO_FPGA","read from addr 0x%x, pc=0x%llx (size=%u)\n",
482 offset,cpu_get_pc(cpu),op_size);
483 } else {
484 cpu_log(cpu,"IO_FPGA","write to addr 0x%x, value=0x%llx, "
485 "pc=0x%llx (size=%u)\n",
486 offset,*data,cpu_get_pc(cpu),op_size);
487 }
488 #endif
489 }
490
491 IOFPGA_UNLOCK(d);
492 return NULL;
493 }
494
495 /* Initialize EEPROM groups */
496 void msfc1_init_eeprom_groups(msfc1_t *router)
497 {
498 router->sys_eeprom_g1 = eeprom_cpu_midplane;
499 router->sys_eeprom_g1.eeprom[0] = &router->cpu_eeprom;
500 router->sys_eeprom_g1.eeprom[1] = &router->mp_eeprom;
501 }
502
503 /* Shutdown the IO FPGA device */
504 void dev_msfc1_iofpga_shutdown(vm_instance_t *vm,struct iofpga_data *d)
505 {
506 if (d != NULL) {
507 IOFPGA_LOCK(d);
508 vm->vtty_con->read_notifier = NULL;
509 vm->vtty_aux->read_notifier = NULL;
510 IOFPGA_UNLOCK(d);
511
512 /* Remove the dummy IRQ periodic task */
513 ptask_remove(d->duart_irq_tid);
514
515 /* Remove the device */
516 dev_remove(vm,&d->dev);
517
518 /* Free the structure itself */
519 free(d);
520 }
521 }
522
523 /*
524 * dev_msfc1_iofpga_init()
525 */
526 int dev_msfc1_iofpga_init(msfc1_t *router,m_uint64_t paddr,m_uint32_t len)
527 {
528 vm_instance_t *vm = router->vm;
529 struct iofpga_data *d;
530 u_int i;
531
532 /* Allocate private data structure */
533 if (!(d = malloc(sizeof(*d)))) {
534 fprintf(stderr,"IO_FPGA: out of memory\n");
535 return(-1);
536 }
537
538 memset(d,0,sizeof(*d));
539
540 pthread_mutex_init(&d->lock,NULL);
541 d->router = router;
542
543 for(i=0;i<MSFC1_TEMP_SENSORS;i++) {
544 d->temp_cfg_reg[i] = DS1620_CONFIG_STATUS_CPU;
545 d->temp_deg_reg[i] = MSFC1_DEFAULT_TEMP * 2;
546 }
547
548 vm_object_init(&d->vm_obj);
549 d->vm_obj.name = "io_fpga";
550 d->vm_obj.data = d;
551 d->vm_obj.shutdown = (vm_shutdown_t)dev_msfc1_iofpga_shutdown;
552
553 /* Set device properties */
554 dev_init(&d->dev);
555 d->dev.name = "io_fpga";
556 d->dev.phys_addr = paddr;
557 d->dev.phys_len = len;
558 d->dev.handler = dev_msfc1_iofpga_access;
559 d->dev.priv_data = d;
560
561 /* Set console and AUX port notifying functions */
562 vm->vtty_con->priv_data = d;
563 vm->vtty_aux->priv_data = d;
564 vm->vtty_con->read_notifier = tty_con_input;
565 vm->vtty_aux->read_notifier = tty_aux_input;
566
567 /* Trigger periodically a dummy IRQ to flush buffers */
568 d->duart_irq_tid = ptask_add((ptask_callback)tty_trigger_dummy_irq,
569 d,NULL);
570
571 /* Map this device to the VM */
572 vm_bind_device(vm,&d->dev);
573 vm_object_add(vm,&d->vm_obj);
574 return(0);
575 }

  ViewVC Help
Powered by ViewVC 1.1.26