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 |
|
|
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, |
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, |
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, |
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, "CPU and Midplane EEPROM", 0, |
155 |
{ &eeprom_cpu_def, &eeprom_midplane_def }, |
{ &eeprom_cpu_def, &eeprom_midplane_def }, |
156 |
}; |
}; |
157 |
|
|
160 |
* PEM stands for "Power Entry Module": |
* PEM stands for "Power Entry Module": |
161 |
* 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 |
162 |
*/ |
*/ |
163 |
static const struct nmc93c46_group eeprom_pem_npeb = { |
static const struct nmc93cX6_group eeprom_pem_npeb = { |
164 |
1, 0, "PEM (NPE-B) EEPROM", 0, { &eeprom_pem_def }, |
EEPROM_TYPE_NMC93C46, 1, 0, "PEM (NPE-B) EEPROM", 0, { &eeprom_pem_def }, |
165 |
}; |
}; |
166 |
|
|
167 |
/* Reset DS1620 */ |
/* Reset DS1620 */ |
272 |
} |
} |
273 |
} |
} |
274 |
|
|
275 |
|
/* NPE-G2 environmental monitor reading */ |
276 |
|
static m_uint32_t g2_envm_read(struct iofpga_data *d) |
277 |
|
{ |
278 |
|
m_uint32_t val = 0; |
279 |
|
m_uint32_t p1; |
280 |
|
|
281 |
|
p1 = ((d->envm_r2 & 0xFF) << 8) | d->envm_r0 >> 3; |
282 |
|
|
283 |
|
switch(p1) { |
284 |
|
case 0x2a00: /* CPU Die Temperature */ |
285 |
|
val = 0x3000; |
286 |
|
break; |
287 |
|
case 0x4c00: /* +3.30V */ |
288 |
|
val = 0x2a9; |
289 |
|
break; |
290 |
|
case 0x4c01: /* +1.50V */ |
291 |
|
val = 0x135; |
292 |
|
break; |
293 |
|
case 0x4c02: /* +2.50V */ |
294 |
|
val = 0x204; |
295 |
|
break; |
296 |
|
case 0x4c03: /* +1.80V */ |
297 |
|
val = 0x173; |
298 |
|
break; |
299 |
|
case 0x4c04: /* +1.20V */ |
300 |
|
val = 0xF7; |
301 |
|
break; |
302 |
|
case 0x4c05: /* VDD_CPU */ |
303 |
|
val = 0x108; |
304 |
|
break; |
305 |
|
case 0x4800: /* VDD_MEM */ |
306 |
|
val = 0x204; |
307 |
|
break; |
308 |
|
case 0x4801: /* VTT */ |
309 |
|
val = 0xF9; |
310 |
|
break; |
311 |
|
case 0x4802: /* +3.45V */ |
312 |
|
val = 0x2c8; |
313 |
|
break; |
314 |
|
case 0x4803: /* -11.95V*/ |
315 |
|
val = 0x260; |
316 |
|
break; |
317 |
|
case 0x4804: /* ? */ |
318 |
|
val = 0x111; |
319 |
|
break; |
320 |
|
case 0x4805: /* ? */ |
321 |
|
val = 0x111; |
322 |
|
break; |
323 |
|
case 0x4806: /* +5.15V */ |
324 |
|
val = 0x3F8; |
325 |
|
break; |
326 |
|
case 0x4807: /* +12.15V */ |
327 |
|
val = 0x33D; |
328 |
|
break; |
329 |
|
#if DEBUG_UNKNOWN |
330 |
|
default: |
331 |
|
vm_log(d->router->vm,"IO_FPGA","p1 = 0x%8.8x\n",p1); |
332 |
|
#endif |
333 |
|
} |
334 |
|
|
335 |
|
return(htonl(val)); |
336 |
|
} |
337 |
|
|
338 |
/* Console port input */ |
/* Console port input */ |
339 |
static void tty_con_input(vtty_t *vtty) |
static void tty_con_input(vtty_t *vtty) |
340 |
{ |
{ |
386 |
/* |
/* |
387 |
* dev_c7200_iofpga_access() |
* dev_c7200_iofpga_access() |
388 |
*/ |
*/ |
389 |
void *dev_c7200_iofpga_access(cpu_mips_t *cpu,struct vdevice *dev, |
void *dev_c7200_iofpga_access(cpu_gen_t *cpu,struct vdevice *dev, |
390 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
391 |
m_uint64_t *data) |
m_uint64_t *data) |
392 |
{ |
{ |
399 |
|
|
400 |
#if DEBUG_ACCESS |
#if DEBUG_ACCESS |
401 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
402 |
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", |
403 |
|
offset,cpu_get_pc(cpu)); |
404 |
} else { |
} else { |
405 |
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", |
406 |
offset,cpu->pc,*data); |
offset,cpu_get_pc(cpu),*data); |
407 |
} |
} |
408 |
#endif |
#endif |
409 |
|
|
423 |
case 0x338: |
case 0x338: |
424 |
break; |
break; |
425 |
|
|
426 |
/* NPE-G1 test - has influence on slot 0 / flash / pcmcia ... */ |
/* |
427 |
|
* NPE-G1/NPE-G2 - has influence on slot 0 / flash / pcmcia ... |
428 |
|
* Bit 24: 1=I/O slot present |
429 |
|
* Lower 16 bits: FPGA version (displayed by "sh c7200") |
430 |
|
*/ |
431 |
case 0x390: |
case 0x390: |
432 |
if (op_type == MTS_READ) |
if (op_type == MTS_READ) { |
433 |
*data = 0x0FFF0000; //0xFFFF0000; |
*data = 0x0102; |
434 |
|
|
435 |
|
/* If we have an I/O slot, we use the I/O slot DUART */ |
436 |
|
if (c7200_pa_check_eeprom(d->router,0)) |
437 |
|
*data |= 0x01000000; |
438 |
|
} |
439 |
break; |
break; |
440 |
|
|
441 |
/* I/O control register */ |
/* I/O control register */ |
445 |
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); |
446 |
#endif |
#endif |
447 |
d->io_ctrl_reg = *data; |
d->io_ctrl_reg = *data; |
448 |
} |
} else { |
|
else { |
|
449 |
*data = d->io_ctrl_reg; |
*data = d->io_ctrl_reg; |
450 |
*data |= NVRAM_PACKED; /* Packed NVRAM */ |
*data |= NVRAM_PACKED; /* Packed NVRAM */ |
451 |
} |
} |
454 |
/* CPU/Midplane EEPROMs */ |
/* CPU/Midplane EEPROMs */ |
455 |
case 0x21c: |
case 0x21c: |
456 |
if (op_type == MTS_WRITE) |
if (op_type == MTS_WRITE) |
457 |
nmc93c46_write(&d->router->sys_eeprom_g1,(u_int)(*data)); |
nmc93cX6_write(&d->router->sys_eeprom_g1,(u_int)(*data)); |
458 |
else |
else |
459 |
*data = nmc93c46_read(&d->router->sys_eeprom_g1); |
*data = nmc93cX6_read(&d->router->sys_eeprom_g1); |
460 |
break; |
break; |
461 |
|
|
462 |
/* PEM (NPE-B) EEPROM */ |
/* PEM (NPE-B) EEPROM */ |
463 |
case 0x388: |
case 0x388: |
464 |
if (op_type == MTS_WRITE) |
if (op_type == MTS_WRITE) |
465 |
nmc93c46_write(&d->router->sys_eeprom_g2,(u_int)(*data)); |
nmc93cX6_write(&d->router->sys_eeprom_g2,(u_int)(*data)); |
466 |
else |
else |
467 |
*data = nmc93c46_read(&d->router->sys_eeprom_g2); |
*data = nmc93cX6_read(&d->router->sys_eeprom_g2); |
468 |
break; |
break; |
469 |
|
|
470 |
/* Watchdog */ |
/* Watchdog */ |
660 |
} |
} |
661 |
break; |
break; |
662 |
|
|
663 |
|
/* NPE-G2 environmental monitor reading */ |
664 |
|
case 0x3c0: |
665 |
|
if (op_type == MTS_READ) |
666 |
|
*data = 0; |
667 |
|
break; |
668 |
|
|
669 |
|
case 0x3c4: |
670 |
|
if (op_type == MTS_WRITE) |
671 |
|
d->envm_r0 = ntohl(*data); |
672 |
|
break; |
673 |
|
|
674 |
|
case 0x3c8: |
675 |
|
if (op_type == MTS_WRITE) { |
676 |
|
d->envm_r1 = ntohl(*data); |
677 |
|
} else { |
678 |
|
*data = g2_envm_read(d); |
679 |
|
} |
680 |
|
break; |
681 |
|
|
682 |
|
case 0x3cc: |
683 |
|
if (op_type == MTS_WRITE) |
684 |
|
d->envm_r2 = ntohl(*data); |
685 |
|
break; |
686 |
|
|
687 |
|
/* PCMCIA status ? */ |
688 |
|
case 0x3d6: |
689 |
|
if (op_type == MTS_READ) |
690 |
|
*data = 0x33; |
691 |
|
break; |
692 |
|
|
693 |
#if DEBUG_UNKNOWN |
#if DEBUG_UNKNOWN |
694 |
default: |
default: |
695 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
696 |
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", |
697 |
offset,cpu->pc,op_size); |
offset,cpu_get_pc(cpu),op_size); |
698 |
} else { |
} else { |
699 |
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, " |
700 |
"pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size); |
"pc=0x%llx (size=%u)\n", |
701 |
|
offset,*data,cpu_get_pc(cpu),op_size); |
702 |
} |
} |
703 |
#endif |
#endif |
704 |
} |
} |
777 |
d->dev.handler = dev_c7200_iofpga_access; |
d->dev.handler = dev_c7200_iofpga_access; |
778 |
d->dev.priv_data = d; |
d->dev.priv_data = d; |
779 |
|
|
780 |
/* Set console and AUX port notifying functions */ |
/* If we have an I/O slot, we use the I/O slot DUART */ |
781 |
vm->vtty_con->priv_data = d; |
if (c7200_pa_check_eeprom(d->router,0)) { |
782 |
vm->vtty_aux->priv_data = d; |
vm_log(vm,"CONSOLE","console managed by I/O board\n"); |
783 |
vm->vtty_con->read_notifier = tty_con_input; |
|
784 |
vm->vtty_aux->read_notifier = tty_aux_input; |
/* Set console and AUX port notifying functions */ |
785 |
|
vm->vtty_con->priv_data = d; |
786 |
/* Trigger periodically a dummy IRQ to flush buffers */ |
vm->vtty_aux->priv_data = d; |
787 |
d->duart_irq_tid = ptask_add((ptask_callback)tty_trigger_dummy_irq,d,NULL); |
vm->vtty_con->read_notifier = tty_con_input; |
788 |
|
vm->vtty_aux->read_notifier = tty_aux_input; |
789 |
|
|
790 |
|
/* Trigger periodically a dummy IRQ to flush buffers */ |
791 |
|
d->duart_irq_tid = ptask_add((ptask_callback)tty_trigger_dummy_irq, |
792 |
|
d,NULL); |
793 |
|
} |
794 |
|
|
795 |
/* Map this device to the VM */ |
/* Map this device to the VM */ |
796 |
vm_bind_device(vm,&d->dev); |
vm_bind_device(vm,&d->dev); |