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