1 1.1 christos /* This file is part of the program GDB, the GNU debugger. 2 1.10 christos 3 1.11 christos Copyright (C) 1998-2024 Free Software Foundation, Inc. 4 1.1 christos Contributed by Cygnus Solutions. 5 1.10 christos 6 1.1 christos This program is free software; you can redistribute it and/or modify 7 1.1 christos it under the terms of the GNU General Public License as published by 8 1.1 christos the Free Software Foundation; either version 3 of the License, or 9 1.1 christos (at your option) any later version. 10 1.1 christos 11 1.1 christos This program is distributed in the hope that it will be useful, 12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 1.1 christos GNU General Public License for more details. 15 1.1 christos 16 1.1 christos You should have received a copy of the GNU General Public License 17 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. 18 1.10 christos 19 1.1 christos */ 20 1.1 christos 21 1.10 christos /* This must come before any other includes. */ 22 1.10 christos #include "defs.h" 23 1.1 christos 24 1.1 christos #include "sim-main.h" 25 1.1 christos #include "hw-main.h" 26 1.1 christos 27 1.1 christos 28 1.1 christos /* DEVICE 29 1.1 christos 30 1.10 christos 31 1.1 christos tx3904tmr - tx3904 timer 32 1.1 christos 33 1.10 christos 34 1.1 christos DESCRIPTION 35 1.1 christos 36 1.10 christos 37 1.1 christos Implements one tx3904 timer/counter described in the tx3904 38 1.1 christos user guide. Three instances are required for TMR0, TMR1, and 39 1.10 christos TMR3 within the tx3904, at different base addresses. 40 1.1 christos 41 1.1 christos Both internal and system clocks are synthesized as divided versions 42 1.1 christos of the simulator clock. 43 1.10 christos 44 1.1 christos There is no support for: 45 1.1 christos - edge sensitivity of external clock 46 1.1 christos - different mode restrictions for TMR0..2 47 1.1 christos - level interrupts (interrupts are treated as events that occur at edges) 48 1.1 christos 49 1.1 christos 50 1.1 christos 51 1.1 christos PROPERTIES 52 1.1 christos 53 1.1 christos 54 1.1 christos reg <base> <length> 55 1.1 christos 56 1.1 christos Base of TMR control register bank. <length> must equal 0x100. 57 1.1 christos Register offsets: 0: TCR: timer control register 58 1.1 christos 4: TISR: timer interrupt status register 59 1.1 christos 8: CPRA: compare register A 60 1.1 christos 12: CPRB: compare register B 61 1.1 christos 16: ITMR: interval timer mode register 62 1.1 christos 32: CCDR: divider register 63 1.1 christos 48: PMGR: pulse generator mode register 64 1.1 christos 64: WTMR: watchdog timer mode register 65 1.1 christos 240: TRR: timer read register 66 1.1 christos 67 1.1 christos 68 1.1 christos clock <ticks> 69 1.1 christos 70 1.1 christos Rate of timer clock signal. This number is the number of simulator 71 1.1 christos ticks per clock signal tick. Default 1. 72 1.1 christos 73 1.10 christos 74 1.1 christos ext <ticks> 75 1.1 christos 76 1.1 christos Rate of "external input clock signal", the other clock input of the 77 1.1 christos timer. It uses the same scale as above. Default 100. 78 1.1 christos 79 1.1 christos 80 1.1 christos 81 1.1 christos PORTS 82 1.1 christos 83 1.1 christos 84 1.1 christos int (output) 85 1.1 christos 86 1.1 christos Interrupt port. An event is generated when a timer interrupt 87 1.1 christos occurs. 88 1.1 christos 89 1.1 christos 90 1.1 christos ff (output) 91 1.1 christos 92 1.1 christos Flip-flop output, corresponds to the TMFFOUT port. An event is 93 1.1 christos generated when flip-flop changes value. The integer associated 94 1.1 christos with the event is 1/0 according to flip-flop value. 95 1.1 christos 96 1.1 christos 97 1.1 christos reset (input) 98 1.1 christos 99 1.1 christos Reset port. 100 1.1 christos 101 1.1 christos */ 102 1.1 christos 103 1.1 christos 104 1.1 christos 105 1.1 christos /* static functions */ 106 1.1 christos 107 1.1 christos static void deliver_tx3904tmr_tick (struct hw *me, void *data); 108 1.1 christos 109 1.1 christos 110 1.1 christos /* register numbers; each is one word long */ 111 1.10 christos enum 112 1.1 christos { 113 1.1 christos TCR_REG = 0, 114 1.1 christos TISR_REG = 1, 115 1.1 christos CPRA_REG = 2, 116 1.1 christos CPRB_REG = 3, 117 1.1 christos ITMR_REG = 4, 118 1.1 christos CCDR_REG = 8, 119 1.1 christos PMGR_REG = 12, 120 1.1 christos WTMR_REG = 16, 121 1.1 christos TRR_REG = 60 122 1.1 christos }; 123 1.1 christos 124 1.1 christos 125 1.1 christos 126 1.1 christos /* port ID's */ 127 1.1 christos 128 1.1 christos enum 129 1.1 christos { 130 1.1 christos RESET_PORT, 131 1.1 christos INT_PORT, 132 1.1 christos FF_PORT 133 1.1 christos }; 134 1.1 christos 135 1.1 christos 136 1.10 christos static const struct hw_port_descriptor tx3904tmr_ports[] = 137 1.1 christos { 138 1.1 christos { "int", INT_PORT, 0, output_port, }, 139 1.1 christos { "ff", FF_PORT, 0, output_port, }, 140 1.1 christos { "reset", RESET_PORT, 0, input_port, }, 141 1.1 christos { NULL, }, 142 1.1 christos }; 143 1.1 christos 144 1.1 christos 145 1.1 christos 146 1.1 christos /* The timer/counter register internal state. Note that we store 147 1.1 christos state using the control register images, in host endian order. */ 148 1.1 christos 149 1.1 christos struct tx3904tmr { 150 1.1 christos address_word base_address; /* control register base */ 151 1.1 christos unsigned_4 clock_ticks, ext_ticks; /* clock frequencies */ 152 1.1 christos signed_8 last_ticks; /* time at last deliver_*_tick call */ 153 1.1 christos signed_8 roundoff_ticks; /* sim ticks unprocessed during last tick call */ 154 1.1 christos int ff; /* pulse generator flip-flop value: 1/0 */ 155 1.1 christos struct hw_event* event; /* last scheduled event */ 156 1.1 christos 157 1.1 christos unsigned_4 tcr; 158 1.1 christos #define GET_TCR_TCE(c) (((c)->tcr & 0x80) >> 7) 159 1.1 christos #define GET_TCR_CCDE(c) (((c)->tcr & 0x40) >> 6) 160 1.1 christos #define GET_TCR_CRE(c) (((c)->tcr & 0x20) >> 5) 161 1.1 christos #define GET_TCR_CCS(c) (((c)->tcr & 0x04) >> 2) 162 1.1 christos #define GET_TCR_TMODE(c) (((c)->tcr & 0x03) >> 0) 163 1.1 christos unsigned_4 tisr; 164 1.1 christos #define SET_TISR_TWIS(c) ((c)->tisr |= 0x08) 165 1.1 christos #define SET_TISR_TPIBS(c) ((c)->tisr |= 0x04) 166 1.1 christos #define SET_TISR_TPIAS(c) ((c)->tisr |= 0x02) 167 1.1 christos #define SET_TISR_TIIS(c) ((c)->tisr |= 0x01) 168 1.1 christos unsigned_4 cpra; 169 1.1 christos unsigned_4 cprb; 170 1.1 christos unsigned_4 itmr; 171 1.1 christos #define GET_ITMR_TIIE(c) (((c)->itmr & 0x8000) >> 15) 172 1.1 christos #define SET_ITMR_TIIE(c,v) BLIT32((c)->itmr, 15, (v) ? 1 : 0) 173 1.1 christos #define GET_ITMR_TZCE(c) (((c)->itmr & 0x0001) >> 0) 174 1.1 christos #define SET_ITMR_TZCE(c,v) BLIT32((c)->itmr, 0, (v) ? 1 : 0) 175 1.1 christos unsigned_4 ccdr; 176 1.1 christos #define GET_CCDR_CDR(c) (((c)->ccdr & 0x07) >> 0) 177 1.1 christos unsigned_4 pmgr; 178 1.1 christos #define GET_PMGR_TPIBE(c) (((c)->pmgr & 0x8000) >> 15) 179 1.1 christos #define SET_PMGR_TPIBE(c,v) BLIT32((c)->pmgr, 15, (v) ? 1 : 0) 180 1.1 christos #define GET_PMGR_TPIAE(c) (((c)->pmgr & 0x4000) >> 14) 181 1.1 christos #define SET_PMGR_TPIAE(c,v) BLIT32((c)->pmgr, 14, (v) ? 1 : 0) 182 1.1 christos #define GET_PMGR_FFI(c) (((c)->pmgr & 0x0001) >> 0) 183 1.1 christos #define SET_PMGR_FFI(c,v) BLIT32((c)->pmgr, 0, (v) ? 1 : 0) 184 1.1 christos unsigned_4 wtmr; 185 1.1 christos #define GET_WTMR_TWIE(c) (((c)->wtmr & 0x8000) >> 15) 186 1.1 christos #define SET_WTMR_TWIE(c,v) BLIT32((c)->wtmr, 15, (v) ? 1 : 0) 187 1.1 christos #define GET_WTMR_WDIS(c) (((c)->wtmr & 0x0080) >> 7) 188 1.1 christos #define SET_WTMR_WDIS(c,v) BLIT32((c)->wtmr, 7, (v) ? 1 : 0) 189 1.1 christos #define GET_WTMR_TWC(c) (((c)->wtmr & 0x0001) >> 0) 190 1.1 christos #define SET_WTMR_TWC(c,v) BLIT32((c)->wtmr, 0, (v) ? 1 : 0) 191 1.1 christos unsigned_4 trr; 192 1.1 christos }; 193 1.1 christos 194 1.1 christos 195 1.1 christos 196 1.1 christos /* Finish off the partially created hw device. Attach our local 197 1.1 christos callbacks. Wire up our port names etc */ 198 1.1 christos 199 1.1 christos static hw_io_read_buffer_method tx3904tmr_io_read_buffer; 200 1.1 christos static hw_io_write_buffer_method tx3904tmr_io_write_buffer; 201 1.1 christos static hw_port_event_method tx3904tmr_port_event; 202 1.1 christos 203 1.1 christos static void 204 1.1 christos attach_tx3904tmr_regs (struct hw *me, 205 1.1 christos struct tx3904tmr *controller) 206 1.1 christos { 207 1.1 christos unsigned_word attach_address; 208 1.1 christos int attach_space; 209 1.1 christos unsigned attach_size; 210 1.1 christos reg_property_spec reg; 211 1.1 christos 212 1.1 christos if (hw_find_property (me, "reg") == NULL) 213 1.1 christos hw_abort (me, "Missing \"reg\" property"); 214 1.1 christos 215 1.1 christos if (!hw_find_reg_array_property (me, "reg", 0, ®)) 216 1.1 christos hw_abort (me, "\"reg\" property must contain one addr/size entry"); 217 1.1 christos 218 1.1 christos hw_unit_address_to_attach_address (hw_parent (me), 219 1.1 christos ®.address, 220 1.1 christos &attach_space, 221 1.1 christos &attach_address, 222 1.1 christos me); 223 1.1 christos hw_unit_size_to_attach_size (hw_parent (me), 224 1.1 christos ®.size, 225 1.1 christos &attach_size, me); 226 1.1 christos 227 1.1 christos hw_attach_address (hw_parent (me), 0, 228 1.1 christos attach_space, attach_address, attach_size, 229 1.1 christos me); 230 1.1 christos 231 1.10 christos if (hw_find_property(me, "clock") != NULL) 232 1.1 christos controller->clock_ticks = (unsigned_4) hw_find_integer_property(me, "clock"); 233 1.1 christos 234 1.10 christos if (hw_find_property(me, "ext") != NULL) 235 1.1 christos controller->ext_ticks = (unsigned_4) hw_find_integer_property(me, "ext"); 236 1.1 christos 237 1.1 christos controller->base_address = attach_address; 238 1.1 christos } 239 1.1 christos 240 1.1 christos 241 1.1 christos static void 242 1.1 christos tx3904tmr_finish (struct hw *me) 243 1.1 christos { 244 1.1 christos struct tx3904tmr *controller; 245 1.1 christos 246 1.1 christos controller = HW_ZALLOC (me, struct tx3904tmr); 247 1.1 christos set_hw_data (me, controller); 248 1.1 christos set_hw_io_read_buffer (me, tx3904tmr_io_read_buffer); 249 1.1 christos set_hw_io_write_buffer (me, tx3904tmr_io_write_buffer); 250 1.1 christos set_hw_ports (me, tx3904tmr_ports); 251 1.1 christos set_hw_port_event (me, tx3904tmr_port_event); 252 1.1 christos 253 1.1 christos /* Preset clock dividers */ 254 1.1 christos controller->clock_ticks = 1; 255 1.1 christos controller->ext_ticks = 100; 256 1.1 christos 257 1.1 christos /* Attach ourself to our parent bus */ 258 1.1 christos attach_tx3904tmr_regs (me, controller); 259 1.1 christos 260 1.1 christos /* Initialize to reset state */ 261 1.10 christos controller->tcr = 262 1.1 christos controller->itmr = 263 1.1 christos controller->ccdr = 264 1.10 christos controller->pmgr = 265 1.1 christos controller->wtmr = 266 1.10 christos controller->tisr = 267 1.1 christos controller->trr = 0; 268 1.1 christos controller->cpra = controller->cprb = 0x00FFFFFF; 269 1.1 christos controller->ff = 0; 270 1.1 christos controller->last_ticks = controller->roundoff_ticks = 0; 271 1.1 christos controller->event = NULL; 272 1.1 christos } 273 1.1 christos 274 1.1 christos 275 1.1 christos 276 1.1 christos /* An event arrives on an interrupt port */ 277 1.1 christos 278 1.1 christos static void 279 1.1 christos tx3904tmr_port_event (struct hw *me, 280 1.1 christos int my_port, 281 1.1 christos struct hw *source, 282 1.1 christos int source_port, 283 1.1 christos int level) 284 1.1 christos { 285 1.1 christos struct tx3904tmr *controller = hw_data (me); 286 1.1 christos 287 1.1 christos switch (my_port) 288 1.1 christos { 289 1.1 christos case RESET_PORT: 290 1.1 christos { 291 1.1 christos HW_TRACE ((me, "reset")); 292 1.1 christos 293 1.1 christos /* preset flip-flop to FFI value */ 294 1.1 christos controller->ff = GET_PMGR_FFI(controller); 295 1.1 christos 296 1.10 christos controller->tcr = 297 1.1 christos controller->itmr = 298 1.1 christos controller->ccdr = 299 1.10 christos controller->pmgr = 300 1.1 christos controller->wtmr = 301 1.10 christos controller->tisr = 302 1.1 christos controller->trr = 0; 303 1.1 christos controller->cpra = controller->cprb = 0x00FFFFFF; 304 1.1 christos controller->last_ticks = controller->roundoff_ticks = 0; 305 1.10 christos if (controller->event != NULL) 306 1.1 christos hw_event_queue_deschedule(me, controller->event); 307 1.1 christos controller->event = NULL; 308 1.1 christos break; 309 1.1 christos } 310 1.1 christos 311 1.1 christos default: 312 1.1 christos hw_abort (me, "Event on unknown port %d", my_port); 313 1.1 christos break; 314 1.1 christos } 315 1.1 christos } 316 1.1 christos 317 1.1 christos 318 1.1 christos /* generic read/write */ 319 1.1 christos 320 1.1 christos static unsigned 321 1.1 christos tx3904tmr_io_read_buffer (struct hw *me, 322 1.1 christos void *dest, 323 1.1 christos int space, 324 1.1 christos unsigned_word base, 325 1.1 christos unsigned nr_bytes) 326 1.1 christos { 327 1.1 christos struct tx3904tmr *controller = hw_data (me); 328 1.1 christos unsigned byte; 329 1.1 christos 330 1.1 christos HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); 331 1.1 christos for (byte = 0; byte < nr_bytes; byte++) 332 1.1 christos { 333 1.1 christos address_word address = base + byte; 334 1.1 christos int reg_number = (address - controller->base_address) / 4; 335 1.1 christos int reg_offset = 3 - (address - controller->base_address) % 4; 336 1.1 christos unsigned_4 register_value; /* in target byte order */ 337 1.1 christos 338 1.1 christos /* fill in entire register_value word */ 339 1.1 christos switch (reg_number) 340 1.1 christos { 341 1.1 christos case TCR_REG: register_value = controller->tcr; break; 342 1.1 christos case TISR_REG: register_value = controller->tisr; break; 343 1.1 christos case CPRA_REG: register_value = controller->cpra; break; 344 1.1 christos case CPRB_REG: register_value = controller->cprb; break; 345 1.1 christos case ITMR_REG: register_value = controller->itmr; break; 346 1.1 christos case CCDR_REG: register_value = controller->ccdr; break; 347 1.1 christos case PMGR_REG: register_value = controller->pmgr; break; 348 1.1 christos case WTMR_REG: register_value = controller->wtmr; break; 349 1.1 christos case TRR_REG: register_value = controller->trr; break; 350 1.1 christos default: register_value = 0; 351 1.1 christos } 352 1.1 christos 353 1.1 christos /* write requested byte out */ 354 1.1 christos memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1); 355 1.1 christos } 356 1.1 christos 357 1.1 christos return nr_bytes; 358 1.10 christos } 359 1.1 christos 360 1.1 christos 361 1.1 christos 362 1.1 christos static unsigned 363 1.1 christos tx3904tmr_io_write_buffer (struct hw *me, 364 1.1 christos const void *source, 365 1.1 christos int space, 366 1.1 christos unsigned_word base, 367 1.1 christos unsigned nr_bytes) 368 1.1 christos { 369 1.1 christos struct tx3904tmr *controller = hw_data (me); 370 1.1 christos unsigned byte; 371 1.1 christos 372 1.1 christos HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); 373 1.1 christos for (byte = 0; byte < nr_bytes; byte++) 374 1.1 christos { 375 1.1 christos address_word address = base + byte; 376 1.1 christos unsigned_1 write_byte = ((const char*) source)[byte]; 377 1.1 christos int reg_number = (address - controller->base_address) / 4; 378 1.1 christos int reg_offset = 3 - (address - controller->base_address) % 4; 379 1.1 christos 380 1.1 christos /* fill in entire register_value word */ 381 1.1 christos switch (reg_number) 382 1.1 christos { 383 1.1 christos case TCR_REG: 384 1.10 christos if (reg_offset == 0) /* first byte */ 385 1.1 christos { 386 1.1 christos /* update register, but mask out NOP bits */ 387 1.1 christos controller->tcr = (unsigned_4) (write_byte & 0xef); 388 1.1 christos 389 1.1 christos /* Reset counter value if timer suspended and CRE is set. */ 390 1.10 christos if (GET_TCR_TCE(controller) == 0 && 391 1.1 christos GET_TCR_CRE(controller) == 1) 392 1.1 christos controller->trr = 0; 393 1.1 christos } 394 1.1 christos /* HW_TRACE ((me, "tcr: %08lx", (long) controller->tcr)); */ 395 1.1 christos break; 396 1.1 christos 397 1.1 christos case ITMR_REG: 398 1.10 christos if (reg_offset == 1) /* second byte */ 399 1.1 christos { 400 1.1 christos SET_ITMR_TIIE(controller, write_byte & 0x80); 401 1.1 christos } 402 1.10 christos else if (reg_offset == 0) /* first byte */ 403 1.1 christos { 404 1.1 christos SET_ITMR_TZCE(controller, write_byte & 0x01); 405 1.1 christos } 406 1.1 christos /* HW_TRACE ((me, "itmr: %08lx", (long) controller->itmr)); */ 407 1.1 christos break; 408 1.1 christos 409 1.1 christos case CCDR_REG: 410 1.10 christos if (reg_offset == 0) /* first byte */ 411 1.1 christos { 412 1.1 christos controller->ccdr = write_byte & 0x07; 413 1.1 christos } 414 1.1 christos /* HW_TRACE ((me, "ccdr: %08lx", (long) controller->ccdr)); */ 415 1.1 christos break; 416 1.1 christos 417 1.1 christos case PMGR_REG: 418 1.10 christos if (reg_offset == 1) /* second byte */ 419 1.1 christos { 420 1.1 christos SET_PMGR_TPIBE(controller, write_byte & 0x80); 421 1.1 christos SET_PMGR_TPIAE(controller, write_byte & 0x40); 422 1.1 christos } 423 1.10 christos else if (reg_offset == 0) /* first byte */ 424 1.1 christos { 425 1.1 christos SET_PMGR_FFI(controller, write_byte & 0x01); 426 1.1 christos } 427 1.1 christos /* HW_TRACE ((me, "pmgr: %08lx", (long) controller->pmgr)); */ 428 1.1 christos break; 429 1.1 christos 430 1.1 christos case WTMR_REG: 431 1.10 christos if (reg_offset == 1) /* second byte */ 432 1.1 christos { 433 1.1 christos SET_WTMR_TWIE(controller, write_byte & 0x80); 434 1.1 christos } 435 1.10 christos else if (reg_offset == 0) /* first byte */ 436 1.1 christos { 437 1.1 christos SET_WTMR_WDIS(controller, write_byte & 0x80); 438 1.1 christos SET_WTMR_TWC(controller, write_byte & 0x01); 439 1.1 christos } 440 1.1 christos /* HW_TRACE ((me, "wtmr: %08lx", (long) controller->wtmr)); */ 441 1.1 christos break; 442 1.1 christos 443 1.1 christos case TISR_REG: 444 1.10 christos if (reg_offset == 0) /* first byte */ 445 1.1 christos { 446 1.1 christos /* All bits must be zero in given byte, according to 447 1.1 christos spec. */ 448 1.1 christos 449 1.1 christos /* Send an "interrupt off" event on the interrupt port */ 450 1.10 christos if (controller->tisr != 0) /* any interrupts active? */ 451 1.1 christos { 452 1.10 christos hw_port_event (me, INT_PORT, 0); 453 1.1 christos } 454 1.10 christos 455 1.1 christos /* clear interrupt status register */ 456 1.1 christos controller->tisr = 0; 457 1.1 christos } 458 1.1 christos /* HW_TRACE ((me, "tisr: %08lx", (long) controller->tisr)); */ 459 1.1 christos break; 460 1.1 christos 461 1.1 christos case CPRA_REG: 462 1.10 christos if (reg_offset < 3) /* first, second, or third byte */ 463 1.1 christos { 464 1.1 christos MBLIT32(controller->cpra, (reg_offset*8)+7, (reg_offset*8), write_byte); 465 1.1 christos } 466 1.1 christos /* HW_TRACE ((me, "cpra: %08lx", (long) controller->cpra)); */ 467 1.1 christos break; 468 1.1 christos 469 1.1 christos case CPRB_REG: 470 1.10 christos if (reg_offset < 3) /* first, second, or third byte */ 471 1.1 christos { 472 1.1 christos MBLIT32(controller->cprb, (reg_offset*8)+7, (reg_offset*8), write_byte); 473 1.1 christos } 474 1.1 christos /* HW_TRACE ((me, "cprb: %08lx", (long) controller->cprb)); */ 475 1.1 christos break; 476 1.1 christos 477 1.10 christos default: 478 1.1 christos HW_TRACE ((me, "write to illegal register %d", reg_number)); 479 1.1 christos } 480 1.1 christos } /* loop over bytes */ 481 1.1 christos 482 1.1 christos /* Schedule a timer event in near future, so we can increment or 483 1.1 christos stop the counter, to respond to register updates. */ 484 1.1 christos hw_event_queue_schedule(me, 1, deliver_tx3904tmr_tick, NULL); 485 1.1 christos 486 1.1 christos return nr_bytes; 487 1.10 christos } 488 1.1 christos 489 1.1 christos 490 1.1 christos 491 1.1 christos /* Deliver a clock tick to the counter. */ 492 1.1 christos static void 493 1.1 christos deliver_tx3904tmr_tick (struct hw *me, 494 1.1 christos void *data) 495 1.1 christos { 496 1.1 christos struct tx3904tmr *controller = hw_data (me); 497 1.1 christos SIM_DESC sd = hw_system (me); 498 1.1 christos signed_8 this_ticks = sim_events_time(sd); 499 1.1 christos 500 1.1 christos signed_8 warp; 501 1.1 christos signed_8 divisor; 502 1.1 christos signed_8 quotient, remainder; 503 1.1 christos 504 1.1 christos /* compute simulation ticks between last tick and this tick */ 505 1.10 christos if (controller->last_ticks != 0) 506 1.1 christos warp = this_ticks - controller->last_ticks + controller->roundoff_ticks; 507 1.1 christos else 508 1.1 christos { 509 1.1 christos controller->last_ticks = this_ticks; /* initialize */ 510 1.1 christos warp = controller->roundoff_ticks; 511 1.1 christos } 512 1.1 christos 513 1.10 christos if (controller->event != NULL) 514 1.1 christos hw_event_queue_deschedule(me, controller->event); 515 1.1 christos controller->event = NULL; 516 1.1 christos 517 1.1 christos /* Check whether the timer ticking is enabled at this moment. This 518 1.1 christos largely a function of the TCE bit, but is also slightly 519 1.1 christos mode-dependent. */ 520 1.10 christos switch ((int) GET_TCR_TMODE(controller)) 521 1.1 christos { 522 1.1 christos case 0: /* interval */ 523 1.1 christos /* do not advance counter if TCE = 0 or if holding at count = CPRA */ 524 1.10 christos if (GET_TCR_TCE(controller) == 0 || 525 1.1 christos controller->trr == controller->cpra) 526 1.1 christos return; 527 1.1 christos break; 528 1.1 christos 529 1.1 christos case 1: /* pulse generator */ 530 1.1 christos /* do not advance counter if TCE = 0 */ 531 1.10 christos if (GET_TCR_TCE(controller) == 0) 532 1.1 christos return; 533 1.1 christos break; 534 1.1 christos 535 1.1 christos case 2: /* watchdog */ 536 1.1 christos /* do not advance counter if TCE = 0 and WDIS = 1 */ 537 1.10 christos if (GET_TCR_TCE(controller) == 0 && 538 1.1 christos GET_WTMR_WDIS(controller) == 1) 539 1.1 christos return; 540 1.1 christos break; 541 1.1 christos 542 1.1 christos case 3: /* disabled */ 543 1.1 christos /* regardless of TCE, do not advance counter */ 544 1.1 christos return; 545 1.1 christos } 546 1.1 christos 547 1.1 christos /* In any of the above cases that return, a subsequent register 548 1.1 christos write will be needed to restart the timer. A tick event is 549 1.1 christos scheduled by any register write, so it is more efficient not to 550 1.1 christos reschedule dummy events here. */ 551 1.1 christos 552 1.1 christos 553 1.10 christos /* find appropriate divisor etc. */ 554 1.10 christos if (GET_TCR_CCS(controller) == 0) /* internal system clock */ 555 1.1 christos { 556 1.1 christos /* apply internal clock divider */ 557 1.10 christos if (GET_TCR_CCDE(controller)) /* divisor circuit enabled? */ 558 1.1 christos divisor = controller->clock_ticks * (1 << (1 + GET_CCDR_CDR(controller))); 559 1.1 christos else 560 1.1 christos divisor = controller->clock_ticks; 561 1.1 christos } 562 1.1 christos else 563 1.1 christos { 564 1.1 christos divisor = controller->ext_ticks; 565 1.1 christos } 566 1.1 christos 567 1.1 christos /* how many times to increase counter? */ 568 1.1 christos quotient = warp / divisor; 569 1.1 christos remainder = warp % divisor; 570 1.1 christos 571 1.1 christos /* NOTE: If the event rescheduling code works properly, the quotient 572 1.1 christos should never be larger than 1. That is, we should receive events 573 1.1 christos here at least as frequently as the simulated counter is supposed 574 1.1 christos to decrement. So the remainder (-> roundoff_ticks) will slowly 575 1.1 christos accumulate, with the quotient == 0. Once in a while, quotient 576 1.1 christos will equal 1. */ 577 1.1 christos 578 1.1 christos controller->roundoff_ticks = remainder; 579 1.1 christos controller->last_ticks = this_ticks; 580 1.1 christos while(quotient > 0) /* Is it time to increment counter? */ 581 1.1 christos { 582 1.1 christos /* next 24-bit counter value */ 583 1.1 christos unsigned_4 next_trr = (controller->trr + 1) % (1 << 24); 584 1.1 christos quotient --; 585 1.10 christos 586 1.10 christos switch ((int) GET_TCR_TMODE(controller)) 587 1.1 christos { 588 1.1 christos case 0: /* interval timer mode */ 589 1.1 christos { 590 1.1 christos /* Current or next counter value matches CPRA value? The 591 1.1 christos first case covers counter holding at maximum before 592 1.1 christos reset. The second case covers normal counting 593 1.1 christos behavior. */ 594 1.10 christos if (controller->trr == controller->cpra || 595 1.1 christos next_trr == controller->cpra) 596 1.1 christos { 597 1.1 christos /* likely hold CPRA value */ 598 1.10 christos if (controller->trr == controller->cpra) 599 1.1 christos next_trr = controller->cpra; 600 1.1 christos 601 1.1 christos SET_TISR_TIIS(controller); 602 1.1 christos 603 1.1 christos /* Signal an interrupt if it is enabled with TIIE, 604 1.1 christos and if we just arrived at CPRA. Don't repeatedly 605 1.1 christos interrupt if holding due to TZCE=0 */ 606 1.10 christos if (GET_ITMR_TIIE(controller) && 607 1.1 christos next_trr != controller->trr) 608 1.1 christos { 609 1.1 christos hw_port_event(me, INT_PORT, 1); 610 1.1 christos } 611 1.1 christos 612 1.1 christos /* Reset counter? */ 613 1.10 christos if (GET_ITMR_TZCE(controller)) 614 1.1 christos { 615 1.1 christos next_trr = 0; 616 1.1 christos } 617 1.1 christos } 618 1.1 christos } 619 1.1 christos break; 620 1.1 christos 621 1.1 christos case 1: /* pulse generator mode */ 622 1.1 christos { 623 1.1 christos /* first trip point */ 624 1.10 christos if (next_trr == controller->cpra) 625 1.1 christos { 626 1.1 christos /* flip flip-flop & report */ 627 1.1 christos controller->ff ^= 1; 628 1.1 christos hw_port_event(me, FF_PORT, controller->ff); 629 1.1 christos SET_TISR_TPIAS(controller); 630 1.1 christos 631 1.1 christos /* signal interrupt */ 632 1.10 christos if (GET_PMGR_TPIAE(controller)) 633 1.1 christos { 634 1.1 christos hw_port_event(me, INT_PORT, 1); 635 1.1 christos } 636 1.1 christos 637 1.1 christos } 638 1.1 christos /* second trip point */ 639 1.10 christos else if (next_trr == controller->cprb) 640 1.1 christos { 641 1.1 christos /* flip flip-flop & report */ 642 1.1 christos controller->ff ^= 1; 643 1.1 christos hw_port_event(me, FF_PORT, controller->ff); 644 1.1 christos SET_TISR_TPIBS(controller); 645 1.1 christos 646 1.1 christos /* signal interrupt */ 647 1.10 christos if (GET_PMGR_TPIBE(controller)) 648 1.1 christos { 649 1.1 christos hw_port_event(me, INT_PORT, 1); 650 1.1 christos } 651 1.1 christos 652 1.1 christos /* clear counter */ 653 1.1 christos next_trr = 0; 654 1.1 christos } 655 1.1 christos } 656 1.1 christos break; 657 1.1 christos 658 1.1 christos case 2: /* watchdog timer mode */ 659 1.1 christos { 660 1.1 christos /* watchdog timer expiry */ 661 1.10 christos if (next_trr == controller->cpra) 662 1.1 christos { 663 1.1 christos SET_TISR_TWIS(controller); 664 1.1 christos 665 1.1 christos /* signal interrupt */ 666 1.10 christos if (GET_WTMR_TWIE(controller)) 667 1.1 christos { 668 1.1 christos hw_port_event(me, INT_PORT, 1); 669 1.1 christos } 670 1.1 christos 671 1.1 christos /* clear counter */ 672 1.1 christos next_trr = 0; 673 1.1 christos } 674 1.1 christos } 675 1.1 christos break; 676 1.1 christos 677 1.1 christos case 3: /* disabled */ 678 1.1 christos default: 679 1.1 christos break; 680 1.1 christos } 681 1.1 christos 682 1.1 christos /* update counter and report */ 683 1.1 christos controller->trr = next_trr; 684 1.1 christos /* HW_TRACE ((me, "counter trr %ld tisr %lx", 685 1.1 christos (long) controller->trr, (long) controller->tisr)); */ 686 1.1 christos } /* end quotient loop */ 687 1.1 christos 688 1.1 christos /* Reschedule a timer event in near future, so we can increment the 689 1.1 christos counter again. Set the event about 75% of divisor time away, so 690 1.1 christos we will experience roughly 1.3 events per counter increment. */ 691 1.1 christos controller->event = hw_event_queue_schedule(me, divisor*3/4, deliver_tx3904tmr_tick, NULL); 692 1.1 christos } 693 1.1 christos 694 1.1 christos 695 1.1 christos 696 1.1 christos 697 1.1 christos const struct hw_descriptor dv_tx3904tmr_descriptor[] = { 698 1.1 christos { "tx3904tmr", tx3904tmr_finish, }, 699 1.1 christos { NULL }, 700 1.1 christos }; 701