~jderose/ubuntu/raring/qemu/vde-again

« back to all changes in this revision

Viewing changes to hw/slavio_timer.c

Tags: upstream-0.9.0+20070816
ImportĀ upstreamĀ versionĀ 0.9.0+20070816

Show diffs side-by-side

added added

removed removed

Lines of Context:
48
48
 */
49
49
 
50
50
typedef struct SLAVIO_TIMERState {
51
 
    uint32_t limit, count, counthigh;
52
 
    int64_t count_load_time;
53
 
    int64_t expire_time;
54
 
    int64_t stop_time, tick_offset;
55
 
    QEMUTimer *irq_timer;
56
 
    int irq;
57
 
    int reached, stopped;
 
51
    qemu_irq irq;
 
52
    ptimer_state *timer;
 
53
    uint32_t count, counthigh, reached;
 
54
    uint64_t limit;
 
55
    int stopped;
58
56
    int mode; // 0 = processor, 1 = user, 2 = system
59
 
    unsigned int cpu;
60
57
} SLAVIO_TIMERState;
61
58
 
62
59
#define TIMER_MAXADDR 0x1f
63
 
#define CNT_FREQ 2000000
 
60
#define TIMER_SIZE (TIMER_MAXADDR + 1)
64
61
 
65
62
// Update count, set irq, update expire_time
 
63
// Convert from ptimer countdown units
66
64
static void slavio_timer_get_out(SLAVIO_TIMERState *s)
67
65
{
68
 
    int out;
69
 
    int64_t diff, ticks, count;
70
 
    uint32_t limit;
71
 
 
72
 
    // There are three clock tick units: CPU ticks, register units
73
 
    // (nanoseconds), and counter ticks (500 ns).
74
 
    if (s->mode == 1 && s->stopped)
75
 
        ticks = s->stop_time;
76
 
    else
77
 
        ticks = qemu_get_clock(vm_clock) - s->tick_offset;
78
 
 
79
 
    out = (ticks > s->expire_time);
80
 
    if (out)
81
 
        s->reached = 0x80000000;
82
 
    if (!s->limit)
83
 
        limit = 0x7fffffff;
84
 
    else
85
 
        limit = s->limit;
86
 
 
87
 
    // Convert register units to counter ticks
88
 
    limit = limit >> 9;
89
 
 
90
 
    // Convert cpu ticks to counter ticks
91
 
    diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec);
92
 
 
93
 
    // Calculate what the counter should be, convert to register
94
 
    // units
95
 
    count = diff % limit;
96
 
    s->count = count << 9;
97
 
    s->counthigh = count >> 22;
98
 
 
99
 
    // Expire time: CPU ticks left to next interrupt
100
 
    // Convert remaining counter ticks to CPU ticks
101
 
    s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ);
102
 
 
103
 
    DPRINTF("irq %d limit %d reached %d d %" PRId64 " count %d s->c %x diff %" PRId64 " 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);
104
 
 
105
 
    if (s->mode != 1)
106
 
        pic_set_irq_cpu(s->irq, out, s->cpu);
 
66
    uint64_t count;
 
67
 
 
68
    count = s->limit - (ptimer_get_count(s->timer) << 9);
 
69
    DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit, s->counthigh,
 
70
            s->count);
 
71
    s->count = count & 0xfffffe00;
 
72
    s->counthigh = count >> 32;
107
73
}
108
74
 
109
75
// timer callback
111
77
{
112
78
    SLAVIO_TIMERState *s = opaque;
113
79
 
114
 
    if (!s->irq_timer)
115
 
        return;
116
80
    slavio_timer_get_out(s);
 
81
    DPRINTF("callback: count %x%08x\n", s->counthigh, s->count);
 
82
    s->reached = 0x80000000;
117
83
    if (s->mode != 1)
118
 
        qemu_mod_timer(s->irq_timer, s->expire_time);
 
84
        qemu_irq_raise(s->irq);
119
85
}
120
86
 
121
87
static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
122
88
{
123
89
    SLAVIO_TIMERState *s = opaque;
124
 
    uint32_t saddr;
 
90
    uint32_t saddr, ret;
125
91
 
126
92
    saddr = (addr & TIMER_MAXADDR) >> 2;
127
93
    switch (saddr) {
130
96
        // part of counter (user mode)
131
97
        if (s->mode != 1) {
132
98
            // clear irq
133
 
            pic_set_irq_cpu(s->irq, 0, s->cpu);
134
 
            s->count_load_time = qemu_get_clock(vm_clock);
 
99
            qemu_irq_lower(s->irq);
135
100
            s->reached = 0;
136
 
            return s->limit;
 
101
            ret = s->limit & 0x7fffffff;
137
102
        }
138
103
        else {
139
104
            slavio_timer_get_out(s);
140
 
            return s->counthigh & 0x7fffffff;
 
105
            ret = s->counthigh & 0x7fffffff;
141
106
        }
 
107
        break;
142
108
    case 1:
143
109
        // read counter and reached bit (system mode) or read lsbits
144
110
        // of counter (user mode)
145
111
        slavio_timer_get_out(s);
146
112
        if (s->mode != 1)
147
 
            return (s->count & 0x7fffffff) | s->reached;
 
113
            ret = (s->count & 0x7fffffff) | s->reached;
148
114
        else
149
 
            return s->count;
 
115
            ret = s->count;
 
116
        break;
150
117
    case 3:
151
118
        // read start/stop status
152
 
        return s->stopped;
 
119
        ret = s->stopped;
 
120
        break;
153
121
    case 4:
154
122
        // read user/system mode
155
 
        return s->mode & 1;
 
123
        ret = s->mode & 1;
 
124
        break;
156
125
    default:
157
 
        return 0;
 
126
        ret = 0;
 
127
        break;
158
128
    }
 
129
    DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret);
 
130
 
 
131
    return ret;
159
132
}
160
133
 
161
134
static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
162
135
{
163
136
    SLAVIO_TIMERState *s = opaque;
164
137
    uint32_t saddr;
 
138
    int reload = 0;
165
139
 
 
140
    DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val);
166
141
    saddr = (addr & TIMER_MAXADDR) >> 2;
167
142
    switch (saddr) {
168
143
    case 0:
169
144
        // set limit, reset counter
170
 
        s->count_load_time = qemu_get_clock(vm_clock);
 
145
        reload = 1;
 
146
        qemu_irq_lower(s->irq);
171
147
        // fall through
172
148
    case 2:
173
149
        // set limit without resetting counter
174
 
        if (!val)
175
 
            s->limit = 0x7fffffff;
176
 
        else
177
 
            s->limit = val & 0x7fffffff;
178
 
        slavio_timer_irq(s);
 
150
        s->limit = val & 0x7ffffe00ULL;
 
151
        if (!s->limit)
 
152
            s->limit = 0x7ffffe00ULL;
 
153
        ptimer_set_limit(s->timer, s->limit >> 9, reload);
179
154
        break;
180
155
    case 3:
181
156
        // start/stop user counter
182
157
        if (s->mode == 1) {
183
158
            if (val & 1) {
184
 
                s->stop_time = qemu_get_clock(vm_clock);
 
159
                ptimer_stop(s->timer);
185
160
                s->stopped = 1;
186
161
            }
187
162
            else {
188
 
                if (s->stopped)
189
 
                    s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time;
 
163
                ptimer_run(s->timer, 0);
190
164
                s->stopped = 0;
191
165
            }
192
166
        }
195
169
        // bit 0: user (1) or system (0) counter mode
196
170
        if (s->mode == 0 || s->mode == 1)
197
171
            s->mode = val & 1;
 
172
        if (s->mode == 1) {
 
173
            qemu_irq_lower(s->irq);
 
174
            s->limit = -1ULL;
 
175
        }
 
176
        ptimer_set_limit(s->timer, s->limit >> 9, 1);
198
177
        break;
199
178
    default:
200
179
        break;
217
196
{
218
197
    SLAVIO_TIMERState *s = opaque;
219
198
 
220
 
    qemu_put_be32s(f, &s->limit);
 
199
    qemu_put_be64s(f, &s->limit);
221
200
    qemu_put_be32s(f, &s->count);
222
201
    qemu_put_be32s(f, &s->counthigh);
223
 
    qemu_put_be64s(f, &s->count_load_time);
224
 
    qemu_put_be64s(f, &s->expire_time);
225
 
    qemu_put_be64s(f, &s->stop_time);
226
 
    qemu_put_be64s(f, &s->tick_offset);
227
 
    qemu_put_be32s(f, &s->irq);
 
202
    qemu_put_be32(f, 0); // Was irq
228
203
    qemu_put_be32s(f, &s->reached);
229
204
    qemu_put_be32s(f, &s->stopped);
230
205
    qemu_put_be32s(f, &s->mode);
 
206
    qemu_put_ptimer(f, s->timer);
231
207
}
232
208
 
233
209
static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
234
210
{
235
211
    SLAVIO_TIMERState *s = opaque;
 
212
    uint32_t tmp;
236
213
    
237
 
    if (version_id != 1)
 
214
    if (version_id != 2)
238
215
        return -EINVAL;
239
216
 
240
 
    qemu_get_be32s(f, &s->limit);
 
217
    qemu_get_be64s(f, &s->limit);
241
218
    qemu_get_be32s(f, &s->count);
242
219
    qemu_get_be32s(f, &s->counthigh);
243
 
    qemu_get_be64s(f, &s->count_load_time);
244
 
    qemu_get_be64s(f, &s->expire_time);
245
 
    qemu_get_be64s(f, &s->stop_time);
246
 
    qemu_get_be64s(f, &s->tick_offset);
247
 
    qemu_get_be32s(f, &s->irq);
 
220
    qemu_get_be32s(f, &tmp); // Was irq
248
221
    qemu_get_be32s(f, &s->reached);
249
222
    qemu_get_be32s(f, &s->stopped);
250
223
    qemu_get_be32s(f, &s->mode);
 
224
    qemu_get_ptimer(f, s->timer);
 
225
 
251
226
    return 0;
252
227
}
253
228
 
255
230
{
256
231
    SLAVIO_TIMERState *s = opaque;
257
232
 
258
 
    s->limit = 0;
 
233
    s->limit = 0x7ffffe00ULL;
259
234
    s->count = 0;
260
 
    s->count_load_time = qemu_get_clock(vm_clock);;
261
 
    s->stop_time = s->count_load_time;
262
 
    s->tick_offset = 0;
263
235
    s->reached = 0;
264
236
    s->mode &= 2;
 
237
    ptimer_set_limit(s->timer, s->limit >> 9, 1);
 
238
    ptimer_run(s->timer, 0);
265
239
    s->stopped = 1;
266
 
    slavio_timer_get_out(s);
 
240
    qemu_irq_lower(s->irq);
267
241
}
268
242
 
269
 
void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu)
 
243
void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode)
270
244
{
271
245
    int slavio_timer_io_memory;
272
246
    SLAVIO_TIMERState *s;
 
247
    QEMUBH *bh;
273
248
 
274
249
    s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
275
250
    if (!s)
276
251
        return;
277
252
    s->irq = irq;
278
253
    s->mode = mode;
279
 
    s->cpu = cpu;
280
 
    s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s);
 
254
    bh = qemu_bh_new(slavio_timer_irq, s);
 
255
    s->timer = ptimer_init(bh);
 
256
    ptimer_set_period(s->timer, 500ULL);
281
257
 
282
258
    slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
283
259
                                                    slavio_timer_mem_write, s);
284
 
    cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory);
285
 
    register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s);
 
260
    cpu_register_physical_memory(addr, TIMER_SIZE, slavio_timer_io_memory);
 
261
    register_savevm("slavio_timer", addr, 2, slavio_timer_save, slavio_timer_load, s);
286
262
    qemu_register_reset(slavio_timer_reset, s);
287
263
    slavio_timer_reset(s);
288
264
}