Annotation of qemu/hw/slavio_timer.c, revision 1.1.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.