1 |
/* |
/* |
2 |
* Cisco 7200 (Predator) simulation platform. |
* Cisco router simulation platform. |
3 |
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
4 |
* |
* |
5 |
* Cisco C7200 (Predator) I/O FPGA: |
* Cisco 7200 I/O FPGA: |
6 |
* - Simulates a NMC93C46 Serial EEPROM as CPU and Midplane EEPROM. |
* - Simulates a NMC93C46 Serial EEPROM as CPU and Midplane EEPROM. |
7 |
* - Simulates a DALLAS DS1620 for Temperature Sensors. |
* - Simulates a DALLAS DS1620 for Temperature Sensors. |
8 |
* - Simulates voltage sensors. |
* - Simulates voltage sensors. |
9 |
* - Simulates console and AUX ports. |
* - Simulates console and AUX ports (SCN2681). |
10 |
*/ |
*/ |
11 |
|
|
12 |
#include <stdio.h> |
#include <stdio.h> |
20 |
#include <pthread.h> |
#include <pthread.h> |
21 |
|
|
22 |
#include "ptask.h" |
#include "ptask.h" |
23 |
#include "mips64.h" |
#include "cpu.h" |
24 |
|
#include "vm.h" |
25 |
#include "dynamips.h" |
#include "dynamips.h" |
26 |
#include "memory.h" |
#include "memory.h" |
27 |
#include "device.h" |
#include "device.h" |
28 |
#include "dev_vtty.h" |
#include "dev_vtty.h" |
29 |
#include "nmc93c46.h" |
#include "nmc93cX6.h" |
30 |
#include "ds1620.h" |
#include "ds1620.h" |
31 |
#include "dev_c7200.h" |
#include "dev_c7200.h" |
32 |
|
|
124 |
|
|
125 |
/* Voltages */ |
/* Voltages */ |
126 |
u_int mux; |
u_int mux; |
127 |
|
|
128 |
|
/* NPE-G2 environmental part */ |
129 |
|
m_uint32_t envm_r0,envm_r1,envm_r2; |
130 |
}; |
}; |
131 |
|
|
132 |
#define IOFPGA_LOCK(d) pthread_mutex_lock(&(d)->lock) |
#define IOFPGA_LOCK(d) pthread_mutex_lock(&(d)->lock) |
133 |
#define IOFPGA_UNLOCK(d) pthread_mutex_unlock(&(d)->lock) |
#define IOFPGA_UNLOCK(d) pthread_mutex_unlock(&(d)->lock) |
134 |
|
|
|
/* Empty EEPROM */ |
|
|
static const m_uint16_t eeprom_empty_data[16] = { |
|
|
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, |
|
|
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, |
|
|
}; |
|
|
|
|
135 |
/* CPU EEPROM definition */ |
/* CPU EEPROM definition */ |
136 |
static const struct nmc93c46_eeprom_def eeprom_cpu_def = { |
static const struct nmc93cX6_eeprom_def eeprom_cpu_def = { |
137 |
SK1_CLOCK_CPU, CS1_CHIP_SEL_CPU, |
SK1_CLOCK_CPU, CS1_CHIP_SEL_CPU, |
138 |
DI1_DATA_IN_CPU, DO1_DATA_OUT_CPU, |
DI1_DATA_IN_CPU, DO1_DATA_OUT_CPU, |
|
NULL, 0, |
|
139 |
}; |
}; |
140 |
|
|
141 |
/* Midplane EEPROM definition */ |
/* Midplane EEPROM definition */ |
142 |
static const struct nmc93c46_eeprom_def eeprom_midplane_def = { |
static const struct nmc93cX6_eeprom_def eeprom_midplane_def = { |
143 |
SK2_CLOCK_MIDPLANE, CS2_CHIP_SEL_MIDPLANE, |
SK2_CLOCK_MIDPLANE, CS2_CHIP_SEL_MIDPLANE, |
144 |
DI2_DATA_IN_MIDPLANE, DO2_DATA_OUT_MIDPLANE, |
DI2_DATA_IN_MIDPLANE, DO2_DATA_OUT_MIDPLANE, |
|
NULL, 0, |
|
145 |
}; |
}; |
146 |
|
|
147 |
/* PEM (NPE-B) EEPROM definition */ |
/* PEM (NPE-B) EEPROM definition */ |
148 |
static const struct nmc93c46_eeprom_def eeprom_pem_def = { |
static const struct nmc93cX6_eeprom_def eeprom_pem_def = { |
149 |
SK1_CLOCK_PEM, CS1_CHIP_SEL_PEM, DI1_DATA_IN_PEM, DO1_DATA_OUT_PEM, |
SK1_CLOCK_PEM, CS1_CHIP_SEL_PEM, DI1_DATA_IN_PEM, DO1_DATA_OUT_PEM, |
|
(m_uint16_t *)eeprom_empty_data, (sizeof(eeprom_empty_data) / 2), |
|
150 |
}; |
}; |
151 |
|
|
152 |
/* IOFPGA manages simultaneously CPU and Midplane EEPROM */ |
/* IOFPGA manages simultaneously CPU and Midplane EEPROM */ |
153 |
static const struct nmc93c46_group eeprom_cpu_midplane = { |
static const struct nmc93cX6_group eeprom_cpu_midplane = { |
154 |
2, 0, "CPU and Midplane EEPROM", 0, |
EEPROM_TYPE_NMC93C46, 2, 0, |
155 |
{ NULL, NULL, }, { { 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0} }, |
EEPROM_DORD_NORMAL, |
156 |
|
EEPROM_DOUT_HIGH, |
157 |
|
EEPROM_DEBUG_DISABLED, |
158 |
|
"CPU and Midplane EEPROM", |
159 |
|
{ &eeprom_cpu_def, &eeprom_midplane_def }, |
160 |
}; |
}; |
161 |
|
|
162 |
/* |
/* |
164 |
* PEM stands for "Power Entry Module": |
* PEM stands for "Power Entry Module": |
165 |
* http://www.cisco.com/en/US/products/hw/routers/ps341/products_field_notice09186a00801cb26d.shtml |
* http://www.cisco.com/en/US/products/hw/routers/ps341/products_field_notice09186a00801cb26d.shtml |
166 |
*/ |
*/ |
167 |
static const struct nmc93c46_group eeprom_pem_npeb = { |
static const struct nmc93cX6_group eeprom_pem_npeb = { |
168 |
1, 0, "PEM (NPE-B) EEPROM", 0, { NULL }, { { 0, 0, 0, 0, 0} }, |
EEPROM_TYPE_NMC93C46, 1, 0, |
169 |
|
EEPROM_DORD_NORMAL, |
170 |
|
EEPROM_DOUT_HIGH, |
171 |
|
EEPROM_DEBUG_DISABLED, |
172 |
|
"PEM (NPE-B) EEPROM", |
173 |
|
{ &eeprom_pem_def }, |
174 |
}; |
}; |
175 |
|
|
176 |
/* Reset DS1620 */ |
/* Reset DS1620 */ |
281 |
} |
} |
282 |
} |
} |
283 |
|
|
284 |
|
/* NPE-G2 environmental monitor reading */ |
285 |
|
static m_uint32_t g2_envm_read(struct iofpga_data *d) |
286 |
|
{ |
287 |
|
m_uint32_t val = 0; |
288 |
|
m_uint32_t p1; |
289 |
|
|
290 |
|
p1 = ((d->envm_r2 & 0xFF) << 8) | d->envm_r0 >> 3; |
291 |
|
|
292 |
|
switch(p1) { |
293 |
|
case 0x2a00: /* CPU Die Temperature */ |
294 |
|
val = 0x3000; |
295 |
|
break; |
296 |
|
case 0x4c00: /* +3.30V */ |
297 |
|
val = 0x2a9; |
298 |
|
break; |
299 |
|
case 0x4c01: /* +1.50V */ |
300 |
|
val = 0x135; |
301 |
|
break; |
302 |
|
case 0x4c02: /* +2.50V */ |
303 |
|
val = 0x204; |
304 |
|
break; |
305 |
|
case 0x4c03: /* +1.80V */ |
306 |
|
val = 0x173; |
307 |
|
break; |
308 |
|
case 0x4c04: /* +1.20V */ |
309 |
|
val = 0xF7; |
310 |
|
break; |
311 |
|
case 0x4c05: /* VDD_CPU */ |
312 |
|
val = 0x108; |
313 |
|
break; |
314 |
|
case 0x4800: /* VDD_MEM */ |
315 |
|
val = 0x204; |
316 |
|
break; |
317 |
|
case 0x4801: /* VTT */ |
318 |
|
val = 0xF9; |
319 |
|
break; |
320 |
|
case 0x4802: /* +3.45V */ |
321 |
|
val = 0x2c8; |
322 |
|
break; |
323 |
|
case 0x4803: /* -11.95V*/ |
324 |
|
val = 0x260; |
325 |
|
break; |
326 |
|
case 0x4804: /* ? */ |
327 |
|
val = 0x111; |
328 |
|
break; |
329 |
|
case 0x4805: /* ? */ |
330 |
|
val = 0x111; |
331 |
|
break; |
332 |
|
case 0x4806: /* +5.15V */ |
333 |
|
val = 0x3F8; |
334 |
|
break; |
335 |
|
case 0x4807: /* +12.15V */ |
336 |
|
val = 0x33D; |
337 |
|
break; |
338 |
|
#if DEBUG_UNKNOWN |
339 |
|
default: |
340 |
|
vm_log(d->router->vm,"IO_FPGA","p1 = 0x%8.8x\n",p1); |
341 |
|
#endif |
342 |
|
} |
343 |
|
|
344 |
|
return(htonl(val)); |
345 |
|
} |
346 |
|
|
347 |
/* Console port input */ |
/* Console port input */ |
348 |
static void tty_con_input(vtty_t *vtty) |
static void tty_con_input(vtty_t *vtty) |
349 |
{ |
{ |
395 |
/* |
/* |
396 |
* dev_c7200_iofpga_access() |
* dev_c7200_iofpga_access() |
397 |
*/ |
*/ |
398 |
void *dev_c7200_iofpga_access(cpu_mips_t *cpu,struct vdevice *dev, |
void *dev_c7200_iofpga_access(cpu_gen_t *cpu,struct vdevice *dev, |
399 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
400 |
m_uint64_t *data) |
m_uint64_t *data) |
401 |
{ |
{ |
408 |
|
|
409 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
410 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
411 |
cpu_log(cpu,"IO_FPGA","reading reg 0x%x at pc=0x%llx\n",offset,cpu->pc); |
cpu_log(cpu,"IO_FPGA","reading reg 0x%x at pc=0x%llx\n", |
412 |
|
offset,cpu_get_pc(cpu)); |
413 |
} else { |
} else { |
414 |
cpu_log(cpu,"IO_FPGA","writing reg 0x%x at pc=0x%llx, data=0x%llx\n", |
cpu_log(cpu,"IO_FPGA","writing reg 0x%x at pc=0x%llx, data=0x%llx\n", |
415 |
offset,cpu->pc,*data); |
offset,cpu_get_pc(cpu),*data); |
416 |
} |
} |
417 |
#endif |
#endif |
418 |
|
|
432 |
case 0x338: |
case 0x338: |
433 |
break; |
break; |
434 |
|
|
435 |
/* NPE-G1 test - has influence on slot 0 / flash / pcmcia ... */ |
/* |
436 |
|
* NPE-G1/NPE-G2 - has influence on slot 0 / flash / pcmcia ... |
437 |
|
* Bit 24: 1=I/O slot present |
438 |
|
* Lower 16 bits: FPGA version (displayed by "sh c7200") |
439 |
|
*/ |
440 |
case 0x390: |
case 0x390: |
441 |
if (op_type == MTS_READ) |
if (op_type == MTS_READ) { |
442 |
*data = 0x0FFF0000; //0xFFFF0000; |
*data = 0x0102; |
443 |
|
|
444 |
|
/* If we have an I/O slot, we use the I/O slot DUART */ |
445 |
|
if (vm_slot_check_eeprom(d->router->vm,0,0)) |
446 |
|
*data |= 0x01000000; |
447 |
|
} |
448 |
break; |
break; |
449 |
|
|
450 |
/* I/O control register */ |
/* I/O control register */ |
454 |
vm_log(vm,"IO_FPGA","setting value 0x%llx in io_ctrl_reg\n",*data); |
vm_log(vm,"IO_FPGA","setting value 0x%llx in io_ctrl_reg\n",*data); |
455 |
#endif |
#endif |
456 |
d->io_ctrl_reg = *data; |
d->io_ctrl_reg = *data; |
457 |
} |
} else { |
|
else { |
|
458 |
*data = d->io_ctrl_reg; |
*data = d->io_ctrl_reg; |
459 |
*data |= NVRAM_PACKED; /* Packed NVRAM */ |
*data |= NVRAM_PACKED; /* Packed NVRAM */ |
460 |
} |
} |
463 |
/* CPU/Midplane EEPROMs */ |
/* CPU/Midplane EEPROMs */ |
464 |
case 0x21c: |
case 0x21c: |
465 |
if (op_type == MTS_WRITE) |
if (op_type == MTS_WRITE) |
466 |
nmc93c46_write(&d->router->sys_eeprom_g1,(u_int)(*data)); |
nmc93cX6_write(&d->router->sys_eeprom_g1,(u_int)(*data)); |
467 |
else |
else |
468 |
*data = nmc93c46_read(&d->router->sys_eeprom_g1); |
*data = nmc93cX6_read(&d->router->sys_eeprom_g1); |
469 |
break; |
break; |
470 |
|
|
471 |
/* PEM (NPE-B) EEPROM */ |
/* PEM (NPE-B) EEPROM */ |
472 |
case 0x388: |
case 0x388: |
473 |
if (op_type == MTS_WRITE) |
if (op_type == MTS_WRITE) |
474 |
nmc93c46_write(&d->router->sys_eeprom_g2,(u_int)(*data)); |
nmc93cX6_write(&d->router->sys_eeprom_g2,(u_int)(*data)); |
475 |
else |
else |
476 |
*data = nmc93c46_read(&d->router->sys_eeprom_g2); |
*data = nmc93cX6_read(&d->router->sys_eeprom_g2); |
477 |
break; |
break; |
478 |
|
|
479 |
/* Watchdog */ |
/* Watchdog */ |
669 |
} |
} |
670 |
break; |
break; |
671 |
|
|
672 |
|
/* NPE-G2 environmental monitor reading */ |
673 |
|
case 0x3c0: |
674 |
|
if (op_type == MTS_READ) |
675 |
|
*data = 0; |
676 |
|
break; |
677 |
|
|
678 |
|
case 0x3c4: |
679 |
|
if (op_type == MTS_WRITE) |
680 |
|
d->envm_r0 = ntohl(*data); |
681 |
|
break; |
682 |
|
|
683 |
|
case 0x3c8: |
684 |
|
if (op_type == MTS_WRITE) { |
685 |
|
d->envm_r1 = ntohl(*data); |
686 |
|
} else { |
687 |
|
*data = g2_envm_read(d); |
688 |
|
} |
689 |
|
break; |
690 |
|
|
691 |
|
case 0x3cc: |
692 |
|
if (op_type == MTS_WRITE) |
693 |
|
d->envm_r2 = ntohl(*data); |
694 |
|
break; |
695 |
|
|
696 |
|
/* PCMCIA status ? */ |
697 |
|
case 0x3d6: |
698 |
|
if (op_type == MTS_READ) |
699 |
|
*data = 0x33; |
700 |
|
break; |
701 |
|
|
702 |
#if DEBUG_UNKNOWN |
#if DEBUG_UNKNOWN |
703 |
default: |
default: |
704 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
705 |
cpu_log(cpu,"IO_FPGA","read from addr 0x%x, pc=0x%llx (size=%u)\n", |
cpu_log(cpu,"IO_FPGA","read from addr 0x%x, pc=0x%llx (size=%u)\n", |
706 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
707 |
} else { |
} else { |
708 |
cpu_log(cpu,"IO_FPGA","write to addr 0x%x, value=0x%llx, " |
cpu_log(cpu,"IO_FPGA","write to addr 0x%x, value=0x%llx, " |
709 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n", |
710 |
|
offset,*data,cpu_get_pc(cpu),op_size); |
711 |
} |
} |
712 |
#endif |
#endif |
713 |
} |
} |
716 |
return NULL; |
return NULL; |
717 |
} |
} |
718 |
|
|
719 |
/* Initialize EEPROM groups */ |
/* Initialize system EEPROM groups */ |
720 |
void c7200_init_eeprom_groups(c7200_t *router) |
void c7200_init_sys_eeprom_groups(c7200_t *router) |
721 |
{ |
{ |
722 |
struct nmc93c46_group *g; |
router->sys_eeprom_g1 = eeprom_cpu_midplane; |
723 |
|
router->sys_eeprom_g2 = eeprom_pem_npeb; |
724 |
/* Copy EEPROM definitions */ |
|
725 |
memcpy(&router->cpu_eeprom,&eeprom_cpu_def,sizeof(eeprom_cpu_def)); |
router->sys_eeprom_g1.eeprom[0] = &router->cpu_eeprom; |
726 |
memcpy(&router->mp_eeprom,&eeprom_midplane_def,sizeof(eeprom_midplane_def)); |
router->sys_eeprom_g1.eeprom[1] = &router->mp_eeprom; |
727 |
memcpy(&router->pem_eeprom,&eeprom_pem_def,sizeof(eeprom_pem_def)); |
|
728 |
|
router->sys_eeprom_g2.eeprom[0] = &router->pem_eeprom; |
|
/* Initialize groups */ |
|
|
g = &router->sys_eeprom_g1; |
|
|
memcpy(g,&eeprom_cpu_midplane,sizeof(eeprom_cpu_midplane)); |
|
|
g->def[0] = &router->cpu_eeprom; |
|
|
g->def[1] = &router->mp_eeprom; |
|
|
|
|
|
g = &router->sys_eeprom_g2; |
|
|
memcpy(g,&eeprom_pem_npeb,sizeof(eeprom_pem_npeb)); |
|
|
g->def[0] = &router->pem_eeprom; |
|
729 |
} |
} |
730 |
|
|
731 |
/* Shutdown the IO FPGA device */ |
/* Shutdown the IO FPGA device */ |
786 |
d->dev.handler = dev_c7200_iofpga_access; |
d->dev.handler = dev_c7200_iofpga_access; |
787 |
d->dev.priv_data = d; |
d->dev.priv_data = d; |
788 |
|
|
789 |
/* Set console and AUX port notifying functions */ |
/* If we have an I/O slot, we use the I/O slot DUART */ |
790 |
vm->vtty_con->priv_data = d; |
if (vm_slot_check_eeprom(vm,0,0)) { |
791 |
vm->vtty_aux->priv_data = d; |
vm_log(vm,"CONSOLE","console managed by I/O board\n"); |
792 |
vm->vtty_con->read_notifier = tty_con_input; |
|
793 |
vm->vtty_aux->read_notifier = tty_aux_input; |
/* Set console and AUX port notifying functions */ |
794 |
|
vm->vtty_con->priv_data = d; |
795 |
/* Trigger periodically a dummy IRQ to flush buffers */ |
vm->vtty_aux->priv_data = d; |
796 |
d->duart_irq_tid = ptask_add((ptask_callback)tty_trigger_dummy_irq,d,NULL); |
vm->vtty_con->read_notifier = tty_con_input; |
797 |
|
vm->vtty_aux->read_notifier = tty_aux_input; |
798 |
|
|
799 |
|
/* Trigger periodically a dummy IRQ to flush buffers */ |
800 |
|
d->duart_irq_tid = ptask_add((ptask_callback)tty_trigger_dummy_irq, |
801 |
|
d,NULL); |
802 |
|
} |
803 |
|
|
804 |
/* Map this device to the VM */ |
/* Map this device to the VM */ |
805 |
vm_bind_device(vm,&d->dev); |
vm_bind_device(vm,&d->dev); |