fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 356 lines 7.5 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/arch/simarm/timer.c * 7 * Created: 2004-11-14 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2004-2013 Hampa Hug <hampa@hampa.ch> * 9 * Copyright: (C) 2004-2006 Lukas Ruf <ruf@lpr.ch> * 10 *****************************************************************************/ 11 12/***************************************************************************** 13 * This program is free software. You can redistribute it and / or modify it * 14 * under the terms of the GNU General Public License version 2 as published * 15 * by the Free Software Foundation. * 16 * * 17 * This program is distributed in the hope that it will be useful, but * 18 * WITHOUT ANY WARRANTY, without even the implied warranty of * 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 20 * Public License for more details. * 21 *****************************************************************************/ 22 23/***************************************************************************** 24 * This software was developed at the Computer Engineering and Networks * 25 * Laboratory (TIK), Swiss Federal Institute of Technology (ETH) Zurich. * 26 *****************************************************************************/ 27 28 29#include "main.h" 30#include "timer.h" 31 32#include <stdlib.h> 33 34#include <lib/log.h> 35 36 37#define IXP_TIMER_ACT (1UL << 7) 38 39 40static unsigned char tmr_get_uint8 (ixp_timer_t *ic, unsigned long addr); 41static unsigned short tmr_get_uint16 (ixp_timer_t *ic, unsigned long addr); 42static unsigned long tmr_get_uint32 (ixp_timer_t *ic, unsigned long addr); 43static void tmr_set_uint8 (ixp_timer_t *ic, unsigned long addr, unsigned char val); 44static void tmr_set_uint16 (ixp_timer_t *ic, unsigned long addr, unsigned short val); 45static void tmr_set_uint32 (ixp_timer_t *ic, unsigned long addr, unsigned long val); 46 47 48static 49void ctr_init (ixp_timer_counter_t *ctr) 50{ 51 ctr->clock = NULL; 52 53 ctr->irq = NULL; 54 ctr->irq_ext = NULL; 55 ctr->irq_val = 0; 56 57 ctr->ctrl = 0; 58 ctr->load = 0xffffffffUL; 59 ctr->status = 0; 60 ctr->clear = 0; 61 62 ctr->clkdiv = 0; 63} 64 65static 66void ctr_set_irq (ixp_timer_counter_t *ctr, unsigned char val) 67{ 68 if (val) { 69 if ((ctr->irq != NULL) && (ctr->irq_val == 0)) { 70 ctr->irq (ctr->irq_ext, 1); 71 ctr->irq_val = 1; 72 } 73 } 74 else { 75 if ((ctr->irq != NULL) && (ctr->irq_val != 0)) { 76 ctr->irq (ctr->irq_ext, 0); 77 ctr->irq_val = 0; 78 } 79 } 80} 81 82static 83void ctr_clock_1 (ixp_timer_counter_t *ctr, unsigned long n) 84{ 85 if (ctr->status == 0) { 86 ctr->status = ctr->load; 87 } 88 89 if (n < ctr->status) { 90 ctr->status -= n; 91 return; 92 } 93 94 n -= ctr->status; 95 96 while (n > ctr->load) { 97 n -= ctr->load; 98 n -= 1; 99 } 100 101 ctr->status = ctr->load - n; 102 103 ctr_set_irq (ctr, 1); 104} 105 106static 107void ctr_clock_16 (ixp_timer_counter_t *ctr, unsigned long n) 108{ 109 n += ctr->clkdiv; 110 111 ctr->clkdiv = n % 16; 112 113 ctr_clock_1 (ctr, n / 16); 114} 115 116static 117void ctr_clock_256 (ixp_timer_counter_t *ctr, unsigned long n) 118{ 119 n += ctr->clkdiv; 120 121 ctr->clkdiv = n % 256; 122 123 ctr_clock_1 (ctr, n / 256); 124} 125 126static 127void ctr_set_ctrl (ixp_timer_counter_t *ctr, unsigned long val) 128{ 129 ctr->ctrl = val & 0x0000008cUL; 130 131 switch ((val >> 2) & 0x03) { 132 case 0x00: 133 ctr->clock = ctr_clock_1; 134 break; 135 136 case 0x01: 137 ctr->clock = ctr_clock_16; 138 break; 139 140 case 0x02: 141 ctr->clock = ctr_clock_256; 142 break; 143 144 case 0x03: 145 ctr->clock = ctr_clock_1; 146 break; 147 } 148 149 if ((ctr->ctrl & IXP_TIMER_ACT) == 0) { 150 ctr->clock = NULL; 151 } 152} 153 154static 155void ctr_set_load (ixp_timer_counter_t *ctr, unsigned long val) 156{ 157 ctr->load = val; 158 ctr->status = val; 159} 160 161static 162void ctr_set_clear (ixp_timer_counter_t *ctr, unsigned long val) 163{ 164 ctr->clear = val; 165 ctr_set_irq (ctr, 0); 166} 167 168static 169unsigned long ctr_get_ctrl (ixp_timer_counter_t *ctr) 170{ 171 return (ctr->ctrl); 172} 173 174static 175unsigned long ctr_get_load (ixp_timer_counter_t *ctr) 176{ 177 return (ctr->load); 178} 179 180static 181unsigned long ctr_get_status (ixp_timer_counter_t *ctr) 182{ 183 return (ctr->status); 184} 185 186void tmr_init (ixp_timer_t *tmr, unsigned long base) 187{ 188 unsigned i; 189 190 tmr->base = base; 191 192 mem_blk_init (&tmr->io, base, 0x00010000UL, 0); 193 tmr->io.ext = tmr; 194 tmr->io.get_uint8 = (mem_get_uint8_f) tmr_get_uint8; 195 tmr->io.set_uint8 = (mem_set_uint8_f) tmr_set_uint8; 196 tmr->io.get_uint16 = (mem_get_uint16_f) tmr_get_uint16; 197 tmr->io.set_uint16 = (mem_set_uint16_f) tmr_set_uint16; 198 tmr->io.get_uint32 = (mem_get_uint32_f) tmr_get_uint32; 199 tmr->io.set_uint32 = (mem_set_uint32_f) tmr_set_uint32; 200 201 for (i = 0; i < 4; i++) { 202 ctr_init (&tmr->cntr[i]); 203 } 204 205 tmr->twde = 0; 206} 207 208ixp_timer_t *tmr_new (unsigned long base) 209{ 210 ixp_timer_t *tmr; 211 212 tmr = malloc (sizeof (ixp_timer_t)); 213 if (tmr == NULL) { 214 return (NULL); 215 } 216 217 tmr_init (tmr, base); 218 219 return (tmr); 220} 221 222void tmr_free (ixp_timer_t *tmr) 223{ 224 mem_blk_free (&tmr->io); 225} 226 227void tmr_del (ixp_timer_t *tmr) 228{ 229 if (tmr != NULL) { 230 tmr_free (tmr); 231 free (tmr); 232 } 233} 234 235mem_blk_t *tmr_get_io (ixp_timer_t *tmr, unsigned i) 236{ 237 if (i == 0) { 238 return (&tmr->io); 239 } 240 241 return (NULL); 242} 243 244int tmr_get_active (ixp_timer_t *tmr, unsigned i) 245{ 246 if (i <= 3) { 247 if (tmr->cntr[i].ctrl & IXP_TIMER_ACT) { 248 return (1); 249 } 250 } 251 252 return (0); 253} 254 255void tmr_set_irq_f (ixp_timer_t *tmr, unsigned i, void *f, void *ext) 256{ 257 if (i < 4) { 258 tmr->cntr[i].irq = f; 259 tmr->cntr[i].irq_ext = ext; 260 } 261} 262 263static 264unsigned char tmr_get_uint8 (ixp_timer_t *tmr, unsigned long addr) 265{ 266 pce_log (MSG_DEB, "TMR: get_uint8 (%08lX)\n", addr); 267 268 return (0); 269} 270 271static 272unsigned short tmr_get_uint16 (ixp_timer_t *tmr, unsigned long addr) 273{ 274 pce_log (MSG_DEB, "TMR: get_uint16 (%08lX)\n", addr); 275 276 return (0); 277} 278 279static 280unsigned long tmr_get_uint32 (ixp_timer_t *tmr, unsigned long addr) 281{ 282 switch (addr) { 283 case 0x00: 284 case 0x04: 285 case 0x08: 286 case 0x0c: 287 return (ctr_get_ctrl (&tmr->cntr[(addr >> 2) & 0x03])); 288 289 case 0x10: 290 case 0x14: 291 case 0x18: 292 case 0x1c: 293 return (ctr_get_load (&tmr->cntr[(addr >> 2) & 0x03])); 294 295 case 0x20: 296 case 0x24: 297 case 0x28: 298 case 0x2c: 299 return (ctr_get_status (&tmr->cntr[(addr >> 2) & 0x03])); 300 } 301 302 return (0); 303} 304 305static 306void tmr_set_uint8 (ixp_timer_t *tmr, unsigned long addr, unsigned char val) 307{ 308 pce_log (MSG_DEB, "TMR: set_uint8 (%08lX, %02X)\n", addr, (unsigned) val); 309} 310 311static 312void tmr_set_uint16 (ixp_timer_t *tmr, unsigned long addr, unsigned short val) 313{ 314 pce_log (MSG_DEB, "TMR: set_uint16 (%08lX, %04X)\n", addr, (unsigned) val); 315} 316 317static 318void tmr_set_uint32 (ixp_timer_t *tmr, unsigned long addr, unsigned long val) 319{ 320 switch (addr) { 321 case 0x00: 322 case 0x04: 323 case 0x08: 324 case 0x0c: 325 ctr_set_ctrl (&tmr->cntr[(addr >> 2) & 0x03], val); 326 break; 327 328 case 0x10: 329 case 0x14: 330 case 0x18: 331 case 0x1c: 332 ctr_set_load (&tmr->cntr[(addr >> 2) & 0x03], val); 333 break; 334 335 case 0x30: 336 case 0x34: 337 case 0x38: 338 case 0x3c: 339 ctr_set_clear (&tmr->cntr[(addr >> 2) & 0x03], val); 340 break; 341 } 342} 343 344void tmr_clock (ixp_timer_t *tmr, unsigned long n) 345{ 346 unsigned i; 347 ixp_timer_counter_t *c; 348 349 for (i = 0; i < 4; i++) { 350 c = &tmr->cntr[i]; 351 352 if (c->clock != NULL) { 353 c->clock (c, n); 354 } 355 } 356}