|  | /*  This file is part of the program psim. | 
|  |  | 
|  | Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program; if not, see <http://www.gnu.org/licenses/>. | 
|  |  | 
|  | */ | 
|  |  | 
|  |  | 
|  | #ifndef _HW_CPU_C_ | 
|  | #define _HW_CPU_C_ | 
|  |  | 
|  | #ifndef STATIC_INLINE_HW_CPU | 
|  | #define STATIC_INLINE_HW_CPU STATIC_INLINE | 
|  | #endif | 
|  |  | 
|  | #include "device_table.h" | 
|  | #include "hw_cpu.h" | 
|  |  | 
|  | #include "interrupts.h" | 
|  | #include "cpu.h" | 
|  |  | 
|  |  | 
|  | /* DEVICE | 
|  |  | 
|  |  | 
|  | cpu - Interface to a Processor | 
|  |  | 
|  |  | 
|  | DESCRIPTION | 
|  |  | 
|  |  | 
|  | The CPU device provides the connection between the interrupt net | 
|  | (linking the devices and the interrupt controller) and the | 
|  | simulated model of each processor.  This device contains interrupt | 
|  | ports that correspond directly to the external interrupt stimulus | 
|  | that can be sent to a given processor.  Sending an interrupt to one | 
|  | of the ports results in an interrupt being delivered to the | 
|  | corresponding processor. | 
|  |  | 
|  | Typically, an interrupt controller would have its inputs connected | 
|  | to device interrupt sources and its outputs (sreset, int, et.al.) | 
|  | connected to this device. | 
|  |  | 
|  |  | 
|  | PROPERTIES | 
|  |  | 
|  |  | 
|  | cpu-nr = <integer> (required) | 
|  |  | 
|  |  | 
|  | Specify the processor (1..N) that this cpu device node should | 
|  | control. | 
|  |  | 
|  |  | 
|  | EXAMPLES | 
|  |  | 
|  |  | 
|  | Connect an OpenPIC interrupt controller interrupt ports to | 
|  | processor zero. | 
|  |  | 
|  | | -o '/phb/opic@0 > irq0 int /cpus/cpu@0' \ | 
|  | | -o '/phb/opic@0 > init hreset /cpus/cpu@0' \ | 
|  |  | 
|  |  | 
|  | */ | 
|  |  | 
|  | typedef struct _hw_cpu_device { | 
|  | int cpu_nr; | 
|  | cpu *processor; | 
|  | } hw_cpu_device; | 
|  |  | 
|  | static const device_interrupt_port_descriptor hw_cpu_interrupt_ports[] = { | 
|  | { "hreset", hw_cpu_hard_reset }, | 
|  | { "sreset", hw_cpu_soft_reset }, | 
|  | { "int", hw_cpu_external_interrupt }, | 
|  | { "mci", hw_cpu_machine_check_interrupt }, | 
|  | { "smi", hw_cpu_system_management_interrupt }, | 
|  | { NULL } | 
|  | }; | 
|  |  | 
|  |  | 
|  | static void * | 
|  | hw_cpu_create(const char *name, | 
|  | const device_unit *unit_address, | 
|  | const char *args) | 
|  | { | 
|  | hw_cpu_device *hw_cpu = ZALLOC(hw_cpu_device); | 
|  | return hw_cpu; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* during address initialization ensure that any missing cpu | 
|  | properties are added to this devices node */ | 
|  |  | 
|  | static void | 
|  | hw_cpu_init_address(device *me) | 
|  | { | 
|  | hw_cpu_device *hw_cpu = (hw_cpu_device*)device_data(me); | 
|  | /* populate the node with properties */ | 
|  | /* clear our data */ | 
|  | memset(hw_cpu, 0x0, sizeof(hw_cpu_device)); | 
|  | hw_cpu->cpu_nr = device_find_integer_property(me, "cpu-nr"); | 
|  | hw_cpu->processor = psim_cpu(device_system(me), hw_cpu->cpu_nr); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Take the interrupt and synchronize its delivery with the clock.  If | 
|  | we've not yet scheduled an interrupt for the next clock tick, take | 
|  | the oportunity to do it now */ | 
|  |  | 
|  | static void | 
|  | hw_cpu_interrupt_event(device *me, | 
|  | int my_port, | 
|  | device *source, | 
|  | int source_port, | 
|  | int level, | 
|  | cpu *processor, | 
|  | unsigned_word cia) | 
|  | { | 
|  | hw_cpu_device *hw_cpu = (hw_cpu_device*)device_data(me); | 
|  | if (my_port < 0 || my_port >= hw_cpu_nr_interrupt_ports) | 
|  | error("hw_cpu_interrupt_event_callback: interrupt port out of range %d\n", | 
|  | my_port); | 
|  | switch (my_port) { | 
|  | /*case hw_cpu_hard_reset:*/ | 
|  | /*case hw_cpu_soft_reset:*/ | 
|  | case hw_cpu_external_interrupt: | 
|  | external_interrupt(hw_cpu->processor, level); | 
|  | break; | 
|  | /*case hw_cpu_machine_check_interrupt:*/ | 
|  | default: | 
|  | error("hw_cpu_deliver_interrupt: unimplemented interrupt port %d\n", | 
|  | my_port); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | static device_callbacks const hw_cpu_callbacks = { | 
|  | { hw_cpu_init_address, }, /* init */ | 
|  | { NULL, }, /* address */ | 
|  | { NULL, }, /* io */ | 
|  | { NULL, }, /* DMA */ | 
|  | { hw_cpu_interrupt_event, NULL, hw_cpu_interrupt_ports }, /* interrupts */ | 
|  | { NULL, NULL, }, | 
|  | }; | 
|  |  | 
|  | const device_descriptor hw_cpu_device_descriptor[] = { | 
|  | { "hw-cpu", hw_cpu_create, &hw_cpu_callbacks }, | 
|  | { "cpu", hw_cpu_create, &hw_cpu_callbacks }, | 
|  | { NULL, }, | 
|  | }; | 
|  |  | 
|  | #endif /* _HW_CPU_C_ */ |