Annotation of qemu/hw/slavio_timer.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.