14e98e3e1Schristos /* Lattice Mico32 CPU model. 24e98e3e1Schristos Contributed by Jon Beniston <jon@beniston.com> 34e98e3e1Schristos 4*71f62182Schristos Copyright (C) 2009-2024 Free Software Foundation, Inc. 54e98e3e1Schristos 64e98e3e1Schristos This file is part of GDB. 74e98e3e1Schristos 84e98e3e1Schristos This program is free software; you can redistribute it and/or modify 94e98e3e1Schristos it under the terms of the GNU General Public License as published by 104e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 114e98e3e1Schristos (at your option) any later version. 124e98e3e1Schristos 134e98e3e1Schristos This program is distributed in the hope that it will be useful, 144e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 154e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 164e98e3e1Schristos GNU General Public License for more details. 174e98e3e1Schristos 184e98e3e1Schristos You should have received a copy of the GNU General Public License 194e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 204e98e3e1Schristos 214b169a6bSchristos #define WANT_CPU lm32bf 224b169a6bSchristos #define WANT_CPU_LM32BF 234b169a6bSchristos 244b169a6bSchristos /* This must come before any other includes. */ 254b169a6bSchristos #include "defs.h" 264b169a6bSchristos 274e98e3e1Schristos #include "hw-main.h" 284e98e3e1Schristos #include "sim-main.h" 294e98e3e1Schristos 304e98e3e1Schristos 314e98e3e1Schristos struct lm32cpu 324e98e3e1Schristos { 334e98e3e1Schristos struct hw_event *event; 344e98e3e1Schristos }; 354e98e3e1Schristos 364e98e3e1Schristos /* input port ID's. */ 374e98e3e1Schristos 384e98e3e1Schristos enum 394e98e3e1Schristos { 404e98e3e1Schristos INT0_PORT, 414e98e3e1Schristos INT1_PORT, 424e98e3e1Schristos INT2_PORT, 434e98e3e1Schristos INT3_PORT, 444e98e3e1Schristos INT4_PORT, 454e98e3e1Schristos INT5_PORT, 464e98e3e1Schristos INT6_PORT, 474e98e3e1Schristos INT7_PORT, 484e98e3e1Schristos INT8_PORT, 494e98e3e1Schristos INT9_PORT, 504e98e3e1Schristos INT10_PORT, 514e98e3e1Schristos INT11_PORT, 524e98e3e1Schristos INT12_PORT, 534e98e3e1Schristos INT13_PORT, 544e98e3e1Schristos INT14_PORT, 554e98e3e1Schristos INT15_PORT, 564e98e3e1Schristos INT16_PORT, 574e98e3e1Schristos INT17_PORT, 584e98e3e1Schristos INT18_PORT, 594e98e3e1Schristos INT19_PORT, 604e98e3e1Schristos INT20_PORT, 614e98e3e1Schristos INT21_PORT, 624e98e3e1Schristos INT22_PORT, 634e98e3e1Schristos INT23_PORT, 644e98e3e1Schristos INT24_PORT, 654e98e3e1Schristos INT25_PORT, 664e98e3e1Schristos INT26_PORT, 674e98e3e1Schristos INT27_PORT, 684e98e3e1Schristos INT28_PORT, 694e98e3e1Schristos INT29_PORT, 704e98e3e1Schristos INT30_PORT, 714e98e3e1Schristos INT31_PORT, 724e98e3e1Schristos }; 734e98e3e1Schristos 744e98e3e1Schristos static const struct hw_port_descriptor lm32cpu_ports[] = { 754e98e3e1Schristos /* interrupt inputs. */ 764e98e3e1Schristos {"int0", INT0_PORT, 0, input_port,}, 774e98e3e1Schristos {"int1", INT1_PORT, 0, input_port,}, 784e98e3e1Schristos {"int2", INT2_PORT, 0, input_port,}, 794e98e3e1Schristos {"int3", INT3_PORT, 0, input_port,}, 804e98e3e1Schristos {"int4", INT4_PORT, 0, input_port,}, 814e98e3e1Schristos {"int5", INT5_PORT, 0, input_port,}, 824e98e3e1Schristos {"int6", INT6_PORT, 0, input_port,}, 834e98e3e1Schristos {"int7", INT7_PORT, 0, input_port,}, 844e98e3e1Schristos {"int8", INT8_PORT, 0, input_port,}, 854e98e3e1Schristos {"int9", INT9_PORT, 0, input_port,}, 864e98e3e1Schristos {"int10", INT10_PORT, 0, input_port,}, 874e98e3e1Schristos {"int11", INT11_PORT, 0, input_port,}, 884e98e3e1Schristos {"int12", INT12_PORT, 0, input_port,}, 894e98e3e1Schristos {"int13", INT13_PORT, 0, input_port,}, 904e98e3e1Schristos {"int14", INT14_PORT, 0, input_port,}, 914e98e3e1Schristos {"int15", INT15_PORT, 0, input_port,}, 924e98e3e1Schristos {"int16", INT16_PORT, 0, input_port,}, 934e98e3e1Schristos {"int17", INT17_PORT, 0, input_port,}, 944e98e3e1Schristos {"int18", INT18_PORT, 0, input_port,}, 954e98e3e1Schristos {"int19", INT19_PORT, 0, input_port,}, 964e98e3e1Schristos {"int20", INT20_PORT, 0, input_port,}, 974e98e3e1Schristos {"int21", INT21_PORT, 0, input_port,}, 984e98e3e1Schristos {"int22", INT22_PORT, 0, input_port,}, 994e98e3e1Schristos {"int23", INT23_PORT, 0, input_port,}, 1004e98e3e1Schristos {"int24", INT24_PORT, 0, input_port,}, 1014e98e3e1Schristos {"int25", INT25_PORT, 0, input_port,}, 1024e98e3e1Schristos {"int26", INT26_PORT, 0, input_port,}, 1034e98e3e1Schristos {"int27", INT27_PORT, 0, input_port,}, 1044e98e3e1Schristos {"int28", INT28_PORT, 0, input_port,}, 1054e98e3e1Schristos {"int29", INT29_PORT, 0, input_port,}, 1064e98e3e1Schristos {"int30", INT30_PORT, 0, input_port,}, 1074e98e3e1Schristos {"int31", INT31_PORT, 0, input_port,}, 1084e98e3e1Schristos {NULL,}, 1094e98e3e1Schristos }; 1104e98e3e1Schristos 1114e98e3e1Schristos 1124e98e3e1Schristos 1134e98e3e1Schristos /* 1144e98e3e1Schristos * Finish off the partially created hw device. Attach our local 1154e98e3e1Schristos * callbacks. Wire up our port names etc. 1164e98e3e1Schristos */ 1174e98e3e1Schristos static hw_port_event_method lm32cpu_port_event; 1184e98e3e1Schristos 1194e98e3e1Schristos 1204e98e3e1Schristos static void 1214e98e3e1Schristos lm32cpu_finish (struct hw *me) 1224e98e3e1Schristos { 1234e98e3e1Schristos struct lm32cpu *controller; 1244e98e3e1Schristos 1254e98e3e1Schristos controller = HW_ZALLOC (me, struct lm32cpu); 1264e98e3e1Schristos set_hw_data (me, controller); 1274e98e3e1Schristos set_hw_ports (me, lm32cpu_ports); 1284e98e3e1Schristos set_hw_port_event (me, lm32cpu_port_event); 1294e98e3e1Schristos 1304e98e3e1Schristos /* Initialize the pending interrupt flags. */ 1314e98e3e1Schristos controller->event = NULL; 1324e98e3e1Schristos } 1334e98e3e1Schristos 1344e98e3e1Schristos 1354e98e3e1Schristos /* An event arrives on an interrupt port. */ 1364e98e3e1Schristos static unsigned int s_ui_ExtIntrs = 0; 1374e98e3e1Schristos 1384e98e3e1Schristos 1394e98e3e1Schristos static void 1404e98e3e1Schristos deliver_lm32cpu_interrupt (struct hw *me, void *data) 1414e98e3e1Schristos { 1424e98e3e1Schristos static unsigned int ip, im, im_and_ip_result; 1434e98e3e1Schristos struct lm32cpu *controller = hw_data (me); 1444e98e3e1Schristos SIM_DESC sd = hw_system (me); 1454e98e3e1Schristos sim_cpu *cpu = STATE_CPU (sd, 0); /* NB: fix CPU 0. */ 1464e98e3e1Schristos 1474e98e3e1Schristos 1484e98e3e1Schristos HW_TRACE ((me, "interrupt-check event")); 1494e98e3e1Schristos 1504e98e3e1Schristos 1514e98e3e1Schristos /* 1524e98e3e1Schristos * Determine if an external interrupt is active 1534e98e3e1Schristos * and needs to cause an exception. 1544e98e3e1Schristos */ 1554e98e3e1Schristos im = lm32bf_h_csr_get (cpu, LM32_CSR_IM); 1564e98e3e1Schristos ip = lm32bf_h_csr_get (cpu, LM32_CSR_IP); 1574e98e3e1Schristos im_and_ip_result = im & ip; 1584e98e3e1Schristos 1594e98e3e1Schristos 1604e98e3e1Schristos if ((lm32bf_h_csr_get (cpu, LM32_CSR_IE) & 1) && (im_and_ip_result != 0)) 1614e98e3e1Schristos { 1624e98e3e1Schristos /* Save PC in exception address register. */ 1634e98e3e1Schristos lm32bf_h_gr_set (cpu, 30, lm32bf_h_pc_get (cpu)); 1644e98e3e1Schristos /* Restart at interrupt offset in handler exception table. */ 1654e98e3e1Schristos lm32bf_h_pc_set (cpu, 1664e98e3e1Schristos lm32bf_h_csr_get (cpu, 1674e98e3e1Schristos LM32_CSR_EBA) + 1684e98e3e1Schristos LM32_EID_INTERRUPT * 32); 1694e98e3e1Schristos /* Save interrupt enable and then clear. */ 1704e98e3e1Schristos lm32bf_h_csr_set (cpu, LM32_CSR_IE, 0x2); 1714e98e3e1Schristos } 1724e98e3e1Schristos 1734e98e3e1Schristos /* reschedule soon. */ 1744e98e3e1Schristos if (controller->event != NULL) 1754e98e3e1Schristos hw_event_queue_deschedule (me, controller->event); 1764e98e3e1Schristos controller->event = NULL; 1774e98e3e1Schristos 1784e98e3e1Schristos 1794e98e3e1Schristos /* if there are external interrupts, schedule an interrupt-check again. 1804e98e3e1Schristos * NOTE: THIS MAKES IT VERY INEFFICIENT. INSTEAD, TRIGGER THIS 1814e98e3e1Schristos * CHECk_EVENT WHEN THE USER ENABLES IE OR USER MODIFIES IM REGISTERS. 1824e98e3e1Schristos */ 1834e98e3e1Schristos if (s_ui_ExtIntrs != 0) 1844e98e3e1Schristos controller->event = 1854e98e3e1Schristos hw_event_queue_schedule (me, 1, deliver_lm32cpu_interrupt, data); 1864e98e3e1Schristos } 1874e98e3e1Schristos 1884e98e3e1Schristos 1894e98e3e1Schristos 1904e98e3e1Schristos /* Handle an event on one of the CPU's ports. */ 1914e98e3e1Schristos static void 1924e98e3e1Schristos lm32cpu_port_event (struct hw *me, 1934e98e3e1Schristos int my_port, 1944e98e3e1Schristos struct hw *source, int source_port, int level) 1954e98e3e1Schristos { 1964e98e3e1Schristos struct lm32cpu *controller = hw_data (me); 1974e98e3e1Schristos SIM_DESC sd = hw_system (me); 1984e98e3e1Schristos sim_cpu *cpu = STATE_CPU (sd, 0); /* NB: fix CPU 0. */ 1994e98e3e1Schristos 2004e98e3e1Schristos 2014e98e3e1Schristos HW_TRACE ((me, "interrupt event on port %d, level %d", my_port, level)); 2024e98e3e1Schristos 2034e98e3e1Schristos 2044e98e3e1Schristos 2054e98e3e1Schristos /* 2064e98e3e1Schristos * Activate IP if the interrupt's activated; don't do anything if 2074e98e3e1Schristos * the interrupt's deactivated. 2084e98e3e1Schristos */ 2094e98e3e1Schristos if (level == 1) 2104e98e3e1Schristos { 2114e98e3e1Schristos /* 2124e98e3e1Schristos * save state of external interrupt. 2134e98e3e1Schristos */ 2144e98e3e1Schristos s_ui_ExtIntrs |= (1 << my_port); 2154e98e3e1Schristos 2164e98e3e1Schristos /* interrupt-activated so set IP. */ 2174e98e3e1Schristos lm32bf_h_csr_set (cpu, LM32_CSR_IP, 2184e98e3e1Schristos lm32bf_h_csr_get (cpu, LM32_CSR_IP) | (1 << my_port)); 2194e98e3e1Schristos 2204e98e3e1Schristos /* 2214e98e3e1Schristos * Since interrupt is activated, queue an immediate event 2224e98e3e1Schristos * to check if this interrupt is serviceable. 2234e98e3e1Schristos */ 2244e98e3e1Schristos if (controller->event != NULL) 2254e98e3e1Schristos hw_event_queue_deschedule (me, controller->event); 2264e98e3e1Schristos 2274e98e3e1Schristos 2284e98e3e1Schristos /* 2294e98e3e1Schristos * Queue an immediate event to check if this interrupt must be serviced; 2304e98e3e1Schristos * this will happen after the current instruction is complete. 2314e98e3e1Schristos */ 2324e98e3e1Schristos controller->event = hw_event_queue_schedule (me, 2334e98e3e1Schristos 0, 2344e98e3e1Schristos deliver_lm32cpu_interrupt, 2354e98e3e1Schristos 0); 2364e98e3e1Schristos } 2374e98e3e1Schristos else 2384e98e3e1Schristos { 2394e98e3e1Schristos /* 2404e98e3e1Schristos * save state of external interrupt. 2414e98e3e1Schristos */ 2424e98e3e1Schristos s_ui_ExtIntrs &= ~(1 << my_port); 2434e98e3e1Schristos } 2444e98e3e1Schristos } 2454e98e3e1Schristos 2464e98e3e1Schristos 2474e98e3e1Schristos const struct hw_descriptor dv_lm32cpu_descriptor[] = { 2484e98e3e1Schristos {"lm32cpu", lm32cpu_finish,}, 2494e98e3e1Schristos {NULL}, 2504e98e3e1Schristos }; 251