1a5a4af3bSchristos /* Lattice Mico32 timer model. 2a5a4af3bSchristos Contributed by Jon Beniston <jon@beniston.com> 3a5a4af3bSchristos 4*8b657b07Schristos Copyright (C) 2009-2023 Free Software Foundation, Inc. 5a5a4af3bSchristos 6a5a4af3bSchristos This file is part of GDB. 7a5a4af3bSchristos 8a5a4af3bSchristos This program is free software; you can redistribute it and/or modify 9a5a4af3bSchristos it under the terms of the GNU General Public License as published by 10a5a4af3bSchristos the Free Software Foundation; either version 3 of the License, or 11a5a4af3bSchristos (at your option) any later version. 12a5a4af3bSchristos 13a5a4af3bSchristos This program is distributed in the hope that it will be useful, 14a5a4af3bSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 15a5a4af3bSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16a5a4af3bSchristos GNU General Public License for more details. 17a5a4af3bSchristos 18a5a4af3bSchristos You should have received a copy of the GNU General Public License 19a5a4af3bSchristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20a5a4af3bSchristos 21*8b657b07Schristos /* This must come before any other includes. */ 22*8b657b07Schristos #include "defs.h" 23*8b657b07Schristos 24a5a4af3bSchristos #include "sim-main.h" 25a5a4af3bSchristos #include "hw-main.h" 26a5a4af3bSchristos #include "sim-assert.h" 27a5a4af3bSchristos 28a5a4af3bSchristos struct lm32timer 29a5a4af3bSchristos { 30a5a4af3bSchristos unsigned base; /* Base address of this timer. */ 31a5a4af3bSchristos unsigned limit; /* Limit address of this timer. */ 32a5a4af3bSchristos unsigned int status; 33a5a4af3bSchristos unsigned int control; 34a5a4af3bSchristos unsigned int period; 35a5a4af3bSchristos unsigned int snapshot; 36a5a4af3bSchristos struct hw_event *event; 37a5a4af3bSchristos }; 38a5a4af3bSchristos 39a5a4af3bSchristos /* Timer registers. */ 40a5a4af3bSchristos #define LM32_TIMER_STATUS 0x0 41a5a4af3bSchristos #define LM32_TIMER_CONTROL 0x4 42a5a4af3bSchristos #define LM32_TIMER_PERIOD 0x8 43a5a4af3bSchristos #define LM32_TIMER_SNAPSHOT 0xc 44a5a4af3bSchristos 45a5a4af3bSchristos /* Timer ports. */ 46a5a4af3bSchristos 47a5a4af3bSchristos enum 48a5a4af3bSchristos { 49a5a4af3bSchristos INT_PORT 50a5a4af3bSchristos }; 51a5a4af3bSchristos 52a5a4af3bSchristos static const struct hw_port_descriptor lm32timer_ports[] = { 53a5a4af3bSchristos {"int", INT_PORT, 0, output_port}, 54a5a4af3bSchristos {} 55a5a4af3bSchristos }; 56a5a4af3bSchristos 57a5a4af3bSchristos static void 58a5a4af3bSchristos do_timer_event (struct hw *me, void *data) 59a5a4af3bSchristos { 60a5a4af3bSchristos struct lm32timer *timer = hw_data (me); 61a5a4af3bSchristos 62a5a4af3bSchristos /* Is timer started? */ 63a5a4af3bSchristos if (timer->control & 0x4) 64a5a4af3bSchristos { 65a5a4af3bSchristos if (timer->snapshot) 66a5a4af3bSchristos { 67a5a4af3bSchristos /* Decrement timer. */ 68a5a4af3bSchristos timer->snapshot--; 69a5a4af3bSchristos } 70a5a4af3bSchristos else if (timer->control & 1) 71a5a4af3bSchristos { 72a5a4af3bSchristos /* Restart timer. */ 73a5a4af3bSchristos timer->snapshot = timer->period; 74a5a4af3bSchristos } 75a5a4af3bSchristos } 76a5a4af3bSchristos /* Generate interrupt when timer is at 0, and interrupt enable is 1. */ 77a5a4af3bSchristos if ((timer->snapshot == 0) && (timer->control & 1)) 78a5a4af3bSchristos { 79a5a4af3bSchristos /* Generate interrupt. */ 80a5a4af3bSchristos hw_port_event (me, INT_PORT, 1); 81a5a4af3bSchristos } 82a5a4af3bSchristos /* If timer is started, schedule another event to decrement the timer again. */ 83a5a4af3bSchristos if (timer->control & 4) 84a5a4af3bSchristos hw_event_queue_schedule (me, 1, do_timer_event, 0); 85a5a4af3bSchristos } 86a5a4af3bSchristos 87a5a4af3bSchristos static unsigned 88a5a4af3bSchristos lm32timer_io_write_buffer (struct hw *me, 89a5a4af3bSchristos const void *source, 90a5a4af3bSchristos int space, unsigned_word base, unsigned nr_bytes) 91a5a4af3bSchristos { 92a5a4af3bSchristos struct lm32timer *timers = hw_data (me); 93a5a4af3bSchristos int timer_reg; 94a5a4af3bSchristos const unsigned char *source_bytes = source; 95a5a4af3bSchristos int value = 0; 96a5a4af3bSchristos 97a5a4af3bSchristos HW_TRACE ((me, "write to 0x%08lx length %d with 0x%x", (long) base, 98a5a4af3bSchristos (int) nr_bytes, value)); 99a5a4af3bSchristos 100a5a4af3bSchristos if (nr_bytes == 4) 101a5a4af3bSchristos value = (source_bytes[0] << 24) 102a5a4af3bSchristos | (source_bytes[1] << 16) | (source_bytes[2] << 8) | (source_bytes[3]); 103a5a4af3bSchristos else 104a5a4af3bSchristos hw_abort (me, "write with invalid number of bytes: %d", nr_bytes); 105a5a4af3bSchristos 106a5a4af3bSchristos timer_reg = base - timers->base; 107a5a4af3bSchristos 108a5a4af3bSchristos switch (timer_reg) 109a5a4af3bSchristos { 110a5a4af3bSchristos case LM32_TIMER_STATUS: 111a5a4af3bSchristos timers->status = value; 112a5a4af3bSchristos break; 113a5a4af3bSchristos case LM32_TIMER_CONTROL: 114a5a4af3bSchristos timers->control = value; 115a5a4af3bSchristos if (timers->control & 0x4) 116a5a4af3bSchristos { 117a5a4af3bSchristos /* Timer is started. */ 118a5a4af3bSchristos hw_event_queue_schedule (me, 1, do_timer_event, 0); 119a5a4af3bSchristos } 120a5a4af3bSchristos break; 121a5a4af3bSchristos case LM32_TIMER_PERIOD: 122a5a4af3bSchristos timers->period = value; 123a5a4af3bSchristos break; 124a5a4af3bSchristos default: 125a5a4af3bSchristos hw_abort (me, "invalid register address: 0x%x.", timer_reg); 126a5a4af3bSchristos } 127a5a4af3bSchristos 128a5a4af3bSchristos return nr_bytes; 129a5a4af3bSchristos } 130a5a4af3bSchristos 131a5a4af3bSchristos static unsigned 132a5a4af3bSchristos lm32timer_io_read_buffer (struct hw *me, 133a5a4af3bSchristos void *dest, 134a5a4af3bSchristos int space, unsigned_word base, unsigned nr_bytes) 135a5a4af3bSchristos { 136a5a4af3bSchristos struct lm32timer *timers = hw_data (me); 137a5a4af3bSchristos int timer_reg; 138a5a4af3bSchristos int value; 139a5a4af3bSchristos unsigned char *dest_bytes = dest; 140a5a4af3bSchristos 141a5a4af3bSchristos HW_TRACE ((me, "read 0x%08lx length %d", (long) base, (int) nr_bytes)); 142a5a4af3bSchristos 143a5a4af3bSchristos timer_reg = base - timers->base; 144a5a4af3bSchristos 145a5a4af3bSchristos switch (timer_reg) 146a5a4af3bSchristos { 147a5a4af3bSchristos case LM32_TIMER_STATUS: 148a5a4af3bSchristos value = timers->status; 149a5a4af3bSchristos break; 150a5a4af3bSchristos case LM32_TIMER_CONTROL: 151a5a4af3bSchristos value = timers->control; 152a5a4af3bSchristos break; 153a5a4af3bSchristos case LM32_TIMER_PERIOD: 154a5a4af3bSchristos value = timers->period; 155a5a4af3bSchristos break; 156a5a4af3bSchristos case LM32_TIMER_SNAPSHOT: 157a5a4af3bSchristos value = timers->snapshot; 158a5a4af3bSchristos break; 159a5a4af3bSchristos default: 160a5a4af3bSchristos hw_abort (me, "invalid register address: 0x%x.", timer_reg); 161a5a4af3bSchristos } 162a5a4af3bSchristos 163a5a4af3bSchristos if (nr_bytes == 4) 164a5a4af3bSchristos { 165a5a4af3bSchristos dest_bytes[0] = value >> 24; 166a5a4af3bSchristos dest_bytes[1] = value >> 16; 167a5a4af3bSchristos dest_bytes[2] = value >> 8; 168a5a4af3bSchristos dest_bytes[3] = value; 169a5a4af3bSchristos } 170a5a4af3bSchristos else 171a5a4af3bSchristos hw_abort (me, "read of unsupported number of bytes: %d", nr_bytes); 172a5a4af3bSchristos 173a5a4af3bSchristos return nr_bytes; 174a5a4af3bSchristos } 175a5a4af3bSchristos 176a5a4af3bSchristos static void 177a5a4af3bSchristos attach_lm32timer_regs (struct hw *me, struct lm32timer *timers) 178a5a4af3bSchristos { 179a5a4af3bSchristos unsigned_word attach_address; 180a5a4af3bSchristos int attach_space; 181a5a4af3bSchristos unsigned attach_size; 182a5a4af3bSchristos reg_property_spec reg; 183a5a4af3bSchristos 184a5a4af3bSchristos if (hw_find_property (me, "reg") == NULL) 185a5a4af3bSchristos hw_abort (me, "Missing \"reg\" property"); 186a5a4af3bSchristos if (!hw_find_reg_array_property (me, "reg", 0, ®)) 187a5a4af3bSchristos hw_abort (me, "\"reg\" property must contain three addr/size entries"); 188a5a4af3bSchristos hw_unit_address_to_attach_address (hw_parent (me), 189a5a4af3bSchristos ®.address, 190a5a4af3bSchristos &attach_space, &attach_address, me); 191a5a4af3bSchristos timers->base = attach_address; 192a5a4af3bSchristos hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); 193a5a4af3bSchristos timers->limit = attach_address + (attach_size - 1); 194a5a4af3bSchristos hw_attach_address (hw_parent (me), 195a5a4af3bSchristos 0, attach_space, attach_address, attach_size, me); 196a5a4af3bSchristos } 197a5a4af3bSchristos 198a5a4af3bSchristos static void 199a5a4af3bSchristos lm32timer_finish (struct hw *me) 200a5a4af3bSchristos { 201a5a4af3bSchristos struct lm32timer *timers; 202a5a4af3bSchristos int i; 203a5a4af3bSchristos 204a5a4af3bSchristos timers = HW_ZALLOC (me, struct lm32timer); 205a5a4af3bSchristos set_hw_data (me, timers); 206a5a4af3bSchristos set_hw_io_read_buffer (me, lm32timer_io_read_buffer); 207a5a4af3bSchristos set_hw_io_write_buffer (me, lm32timer_io_write_buffer); 208a5a4af3bSchristos set_hw_ports (me, lm32timer_ports); 209a5a4af3bSchristos 210a5a4af3bSchristos /* Attach ourself to our parent bus. */ 211a5a4af3bSchristos attach_lm32timer_regs (me, timers); 212a5a4af3bSchristos 213a5a4af3bSchristos /* Initialize the timers. */ 214a5a4af3bSchristos timers->status = 0; 215a5a4af3bSchristos timers->control = 0; 216a5a4af3bSchristos timers->period = 0; 217a5a4af3bSchristos timers->snapshot = 0; 218a5a4af3bSchristos } 219a5a4af3bSchristos 220a5a4af3bSchristos const struct hw_descriptor dv_lm32timer_descriptor[] = { 221a5a4af3bSchristos {"lm32timer", lm32timer_finish,}, 222a5a4af3bSchristos {NULL}, 223a5a4af3bSchristos }; 224