1 /* Lattice Mico32 timer model. 2 Contributed by Jon Beniston <jon@beniston.com> 3 4 Copyright (C) 2009-2019 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 #include "sim-main.h" 22 #include "hw-main.h" 23 #include "sim-assert.h" 24 25 struct lm32timer 26 { 27 unsigned base; /* Base address of this timer. */ 28 unsigned limit; /* Limit address of this timer. */ 29 unsigned int status; 30 unsigned int control; 31 unsigned int period; 32 unsigned int snapshot; 33 struct hw_event *event; 34 }; 35 36 /* Timer registers. */ 37 #define LM32_TIMER_STATUS 0x0 38 #define LM32_TIMER_CONTROL 0x4 39 #define LM32_TIMER_PERIOD 0x8 40 #define LM32_TIMER_SNAPSHOT 0xc 41 42 /* Timer ports. */ 43 44 enum 45 { 46 INT_PORT 47 }; 48 49 static const struct hw_port_descriptor lm32timer_ports[] = { 50 {"int", INT_PORT, 0, output_port}, 51 {} 52 }; 53 54 static void 55 do_timer_event (struct hw *me, void *data) 56 { 57 struct lm32timer *timer = hw_data (me); 58 59 /* Is timer started? */ 60 if (timer->control & 0x4) 61 { 62 if (timer->snapshot) 63 { 64 /* Decrement timer. */ 65 timer->snapshot--; 66 } 67 else if (timer->control & 1) 68 { 69 /* Restart timer. */ 70 timer->snapshot = timer->period; 71 } 72 } 73 /* Generate interrupt when timer is at 0, and interrupt enable is 1. */ 74 if ((timer->snapshot == 0) && (timer->control & 1)) 75 { 76 /* Generate interrupt. */ 77 hw_port_event (me, INT_PORT, 1); 78 } 79 /* If timer is started, schedule another event to decrement the timer again. */ 80 if (timer->control & 4) 81 hw_event_queue_schedule (me, 1, do_timer_event, 0); 82 } 83 84 static unsigned 85 lm32timer_io_write_buffer (struct hw *me, 86 const void *source, 87 int space, unsigned_word base, unsigned nr_bytes) 88 { 89 struct lm32timer *timers = hw_data (me); 90 int timer_reg; 91 const unsigned char *source_bytes = source; 92 int value = 0; 93 94 HW_TRACE ((me, "write to 0x%08lx length %d with 0x%x", (long) base, 95 (int) nr_bytes, value)); 96 97 if (nr_bytes == 4) 98 value = (source_bytes[0] << 24) 99 | (source_bytes[1] << 16) | (source_bytes[2] << 8) | (source_bytes[3]); 100 else 101 hw_abort (me, "write with invalid number of bytes: %d", nr_bytes); 102 103 timer_reg = base - timers->base; 104 105 switch (timer_reg) 106 { 107 case LM32_TIMER_STATUS: 108 timers->status = value; 109 break; 110 case LM32_TIMER_CONTROL: 111 timers->control = value; 112 if (timers->control & 0x4) 113 { 114 /* Timer is started. */ 115 hw_event_queue_schedule (me, 1, do_timer_event, 0); 116 } 117 break; 118 case LM32_TIMER_PERIOD: 119 timers->period = value; 120 break; 121 default: 122 hw_abort (me, "invalid register address: 0x%x.", timer_reg); 123 } 124 125 return nr_bytes; 126 } 127 128 static unsigned 129 lm32timer_io_read_buffer (struct hw *me, 130 void *dest, 131 int space, unsigned_word base, unsigned nr_bytes) 132 { 133 struct lm32timer *timers = hw_data (me); 134 int timer_reg; 135 int value; 136 unsigned char *dest_bytes = dest; 137 138 HW_TRACE ((me, "read 0x%08lx length %d", (long) base, (int) nr_bytes)); 139 140 timer_reg = base - timers->base; 141 142 switch (timer_reg) 143 { 144 case LM32_TIMER_STATUS: 145 value = timers->status; 146 break; 147 case LM32_TIMER_CONTROL: 148 value = timers->control; 149 break; 150 case LM32_TIMER_PERIOD: 151 value = timers->period; 152 break; 153 case LM32_TIMER_SNAPSHOT: 154 value = timers->snapshot; 155 break; 156 default: 157 hw_abort (me, "invalid register address: 0x%x.", timer_reg); 158 } 159 160 if (nr_bytes == 4) 161 { 162 dest_bytes[0] = value >> 24; 163 dest_bytes[1] = value >> 16; 164 dest_bytes[2] = value >> 8; 165 dest_bytes[3] = value; 166 } 167 else 168 hw_abort (me, "read of unsupported number of bytes: %d", nr_bytes); 169 170 return nr_bytes; 171 } 172 173 static void 174 attach_lm32timer_regs (struct hw *me, struct lm32timer *timers) 175 { 176 unsigned_word attach_address; 177 int attach_space; 178 unsigned attach_size; 179 reg_property_spec reg; 180 181 if (hw_find_property (me, "reg") == NULL) 182 hw_abort (me, "Missing \"reg\" property"); 183 if (!hw_find_reg_array_property (me, "reg", 0, ®)) 184 hw_abort (me, "\"reg\" property must contain three addr/size entries"); 185 hw_unit_address_to_attach_address (hw_parent (me), 186 ®.address, 187 &attach_space, &attach_address, me); 188 timers->base = attach_address; 189 hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); 190 timers->limit = attach_address + (attach_size - 1); 191 hw_attach_address (hw_parent (me), 192 0, attach_space, attach_address, attach_size, me); 193 } 194 195 static void 196 lm32timer_finish (struct hw *me) 197 { 198 struct lm32timer *timers; 199 int i; 200 201 timers = HW_ZALLOC (me, struct lm32timer); 202 set_hw_data (me, timers); 203 set_hw_io_read_buffer (me, lm32timer_io_read_buffer); 204 set_hw_io_write_buffer (me, lm32timer_io_write_buffer); 205 set_hw_ports (me, lm32timer_ports); 206 207 /* Attach ourself to our parent bus. */ 208 attach_lm32timer_regs (me, timers); 209 210 /* Initialize the timers. */ 211 timers->status = 0; 212 timers->control = 0; 213 timers->period = 0; 214 timers->snapshot = 0; 215 } 216 217 const struct hw_descriptor dv_lm32timer_descriptor[] = { 218 {"lm32timer", lm32timer_finish,}, 219 {NULL}, 220 }; 221