|
|
1.1 ! root 1: /* ! 2: * QEMU Sparc SLAVIO timer controller emulation ! 3: * ! 4: * Copyright (c) 2003-2005 Fabrice Bellard ! 5: * ! 6: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 7: * of this software and associated documentation files (the "Software"), to deal ! 8: * in the Software without restriction, including without limitation the rights ! 9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 10: * copies of the Software, and to permit persons to whom the Software is ! 11: * furnished to do so, subject to the following conditions: ! 12: * ! 13: * The above copyright notice and this permission notice shall be included in ! 14: * all copies or substantial portions of the Software. ! 15: * ! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 22: * THE SOFTWARE. ! 23: */ ! 24: #include "vl.h" ! 25: ! 26: //#define DEBUG_TIMER ! 27: ! 28: #ifdef DEBUG_TIMER ! 29: #define DPRINTF(fmt, args...) \ ! 30: do { printf("TIMER: " fmt , ##args); } while (0) ! 31: #else ! 32: #define DPRINTF(fmt, args...) ! 33: #endif ! 34: ! 35: /* ! 36: * Registers of hardware timer in sun4m. ! 37: * ! 38: * This is the timer/counter part of chip STP2001 (Slave I/O), also ! 39: * produced as NCR89C105. See ! 40: * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt ! 41: * ! 42: * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 ! 43: * are zero. Bit 31 is 1 when count has been reached. ! 44: * ! 45: */ ! 46: ! 47: typedef struct SLAVIO_TIMERState { ! 48: uint32_t limit, count, counthigh; ! 49: int64_t count_load_time; ! 50: int64_t expire_time; ! 51: int64_t stop_time, tick_offset; ! 52: QEMUTimer *irq_timer; ! 53: int irq; ! 54: int reached, stopped; ! 55: int mode; // 0 = processor, 1 = user, 2 = system ! 56: } SLAVIO_TIMERState; ! 57: ! 58: #define TIMER_MAXADDR 0x1f ! 59: #define CNT_FREQ 2000000 ! 60: #define MAX_CPUS 16 ! 61: ! 62: // Update count, set irq, update expire_time ! 63: static void slavio_timer_get_out(SLAVIO_TIMERState *s) ! 64: { ! 65: int out; ! 66: int64_t diff, ticks, count; ! 67: uint32_t limit; ! 68: ! 69: // There are three clock tick units: CPU ticks, register units ! 70: // (nanoseconds), and counter ticks (500 ns). ! 71: if (s->mode == 1 && s->stopped) ! 72: ticks = s->stop_time; ! 73: else ! 74: ticks = qemu_get_clock(vm_clock) - s->tick_offset; ! 75: ! 76: out = (ticks >= s->expire_time); ! 77: if (out) ! 78: s->reached = 0x80000000; ! 79: if (!s->limit) ! 80: limit = 0x7fffffff; ! 81: else ! 82: limit = s->limit; ! 83: ! 84: // Convert register units to counter ticks ! 85: limit = limit >> 9; ! 86: ! 87: // Convert cpu ticks to counter ticks ! 88: diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec); ! 89: ! 90: // Calculate what the counter should be, convert to register ! 91: // units ! 92: count = diff % limit; ! 93: s->count = count << 9; ! 94: s->counthigh = count >> 22; ! 95: ! 96: // Expire time: CPU ticks left to next interrupt ! 97: // Convert remaining counter ticks to CPU ticks ! 98: s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ); ! 99: ! 100: DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); ! 101: ! 102: if (s->mode != 1) ! 103: pic_set_irq(s->irq, out); ! 104: } ! 105: ! 106: // timer callback ! 107: static void slavio_timer_irq(void *opaque) ! 108: { ! 109: SLAVIO_TIMERState *s = opaque; ! 110: ! 111: if (!s->irq_timer) ! 112: return; ! 113: slavio_timer_get_out(s); ! 114: if (s->mode != 1) ! 115: qemu_mod_timer(s->irq_timer, s->expire_time); ! 116: } ! 117: ! 118: static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) ! 119: { ! 120: SLAVIO_TIMERState *s = opaque; ! 121: uint32_t saddr; ! 122: ! 123: saddr = (addr & TIMER_MAXADDR) >> 2; ! 124: switch (saddr) { ! 125: case 0: ! 126: // read limit (system counter mode) or read most signifying ! 127: // part of counter (user mode) ! 128: if (s->mode != 1) { ! 129: // clear irq ! 130: pic_set_irq(s->irq, 0); ! 131: s->count_load_time = qemu_get_clock(vm_clock); ! 132: s->reached = 0; ! 133: return s->limit; ! 134: } ! 135: else { ! 136: slavio_timer_get_out(s); ! 137: return s->counthigh & 0x7fffffff; ! 138: } ! 139: case 1: ! 140: // read counter and reached bit (system mode) or read lsbits ! 141: // of counter (user mode) ! 142: slavio_timer_get_out(s); ! 143: if (s->mode != 1) ! 144: return (s->count & 0x7fffffff) | s->reached; ! 145: else ! 146: return s->count; ! 147: case 3: ! 148: // read start/stop status ! 149: return s->stopped; ! 150: case 4: ! 151: // read user/system mode ! 152: return s->mode & 1; ! 153: default: ! 154: return 0; ! 155: } ! 156: } ! 157: ! 158: static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) ! 159: { ! 160: SLAVIO_TIMERState *s = opaque; ! 161: uint32_t saddr; ! 162: ! 163: saddr = (addr & TIMER_MAXADDR) >> 2; ! 164: switch (saddr) { ! 165: case 0: ! 166: // set limit, reset counter ! 167: s->count_load_time = qemu_get_clock(vm_clock); ! 168: // fall through ! 169: case 2: ! 170: // set limit without resetting counter ! 171: if (!val) ! 172: s->limit = 0x7fffffff; ! 173: else ! 174: s->limit = val & 0x7fffffff; ! 175: slavio_timer_irq(s); ! 176: break; ! 177: case 3: ! 178: // start/stop user counter ! 179: if (s->mode == 1) { ! 180: if (val & 1) { ! 181: s->stop_time = qemu_get_clock(vm_clock); ! 182: s->stopped = 1; ! 183: } ! 184: else { ! 185: if (s->stopped) ! 186: s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time; ! 187: s->stopped = 0; ! 188: } ! 189: } ! 190: break; ! 191: case 4: ! 192: // bit 0: user (1) or system (0) counter mode ! 193: if (s->mode == 0 || s->mode == 1) ! 194: s->mode = val & 1; ! 195: break; ! 196: default: ! 197: break; ! 198: } ! 199: } ! 200: ! 201: static CPUReadMemoryFunc *slavio_timer_mem_read[3] = { ! 202: slavio_timer_mem_readl, ! 203: slavio_timer_mem_readl, ! 204: slavio_timer_mem_readl, ! 205: }; ! 206: ! 207: static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = { ! 208: slavio_timer_mem_writel, ! 209: slavio_timer_mem_writel, ! 210: slavio_timer_mem_writel, ! 211: }; ! 212: ! 213: static void slavio_timer_save(QEMUFile *f, void *opaque) ! 214: { ! 215: SLAVIO_TIMERState *s = opaque; ! 216: ! 217: qemu_put_be32s(f, &s->limit); ! 218: qemu_put_be32s(f, &s->count); ! 219: qemu_put_be32s(f, &s->counthigh); ! 220: qemu_put_be64s(f, &s->count_load_time); ! 221: qemu_put_be64s(f, &s->expire_time); ! 222: qemu_put_be64s(f, &s->stop_time); ! 223: qemu_put_be64s(f, &s->tick_offset); ! 224: qemu_put_be32s(f, &s->irq); ! 225: qemu_put_be32s(f, &s->reached); ! 226: qemu_put_be32s(f, &s->stopped); ! 227: qemu_put_be32s(f, &s->mode); ! 228: } ! 229: ! 230: static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) ! 231: { ! 232: SLAVIO_TIMERState *s = opaque; ! 233: ! 234: if (version_id != 1) ! 235: return -EINVAL; ! 236: ! 237: qemu_get_be32s(f, &s->limit); ! 238: qemu_get_be32s(f, &s->count); ! 239: qemu_get_be32s(f, &s->counthigh); ! 240: qemu_get_be64s(f, &s->count_load_time); ! 241: qemu_get_be64s(f, &s->expire_time); ! 242: qemu_get_be64s(f, &s->stop_time); ! 243: qemu_get_be64s(f, &s->tick_offset); ! 244: qemu_get_be32s(f, &s->irq); ! 245: qemu_get_be32s(f, &s->reached); ! 246: qemu_get_be32s(f, &s->stopped); ! 247: qemu_get_be32s(f, &s->mode); ! 248: return 0; ! 249: } ! 250: ! 251: static void slavio_timer_reset(void *opaque) ! 252: { ! 253: SLAVIO_TIMERState *s = opaque; ! 254: ! 255: s->limit = 0; ! 256: s->count = 0; ! 257: s->count_load_time = qemu_get_clock(vm_clock);; ! 258: s->stop_time = s->count_load_time; ! 259: s->tick_offset = 0; ! 260: s->reached = 0; ! 261: s->mode &= 2; ! 262: s->stopped = 1; ! 263: slavio_timer_get_out(s); ! 264: } ! 265: ! 266: static void slavio_timer_init_internal(uint32_t addr, int irq, int mode) ! 267: { ! 268: int slavio_timer_io_memory; ! 269: SLAVIO_TIMERState *s; ! 270: ! 271: s = qemu_mallocz(sizeof(SLAVIO_TIMERState)); ! 272: if (!s) ! 273: return; ! 274: s->irq = irq; ! 275: s->mode = mode; ! 276: s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s); ! 277: ! 278: slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, ! 279: slavio_timer_mem_write, s); ! 280: cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory); ! 281: register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s); ! 282: qemu_register_reset(slavio_timer_reset, s); ! 283: slavio_timer_reset(s); ! 284: } ! 285: ! 286: void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2) ! 287: { ! 288: int i; ! 289: ! 290: for (i = 0; i < MAX_CPUS; i++) { ! 291: slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0); ! 292: } ! 293: ! 294: slavio_timer_init_internal(addr2, irq2, 2); ! 295: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.