Commit 8d05ea8a33c9d450d2a3079e967c69ea38ec28ba

Authored by blueswir1
1 parent 2dc7b602

Change ptimer API to use 64-bit values, add save and load methods

Use ptimers for Sparc32 Slavio


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2859 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -449,7 +449,7 @@ VL_OBJS+= cirrus_vga.o parallel.o
449 449 else
450 450 VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o
451 451 VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o sparc32_dma.o
452   -VL_OBJS+= cs4231.o
  452 +VL_OBJS+= cs4231.o ptimer.o
453 453 endif
454 454 endif
455 455 ifeq ($(TARGET_BASE_ARCH), arm)
... ...
hw/ptimer.c
... ... @@ -11,8 +11,8 @@
11 11 struct ptimer_state
12 12 {
13 13 int enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot. */
14   - uint32_t limit;
15   - uint32_t delta;
  14 + uint64_t limit;
  15 + uint64_t delta;
16 16 uint32_t period_frac;
17 17 int64_t period;
18 18 int64_t last_event;
... ... @@ -61,10 +61,10 @@ static void ptimer_tick(void *opaque)
61 61 }
62 62 }
63 63  
64   -uint32_t ptimer_get_count(ptimer_state *s)
  64 +uint64_t ptimer_get_count(ptimer_state *s)
65 65 {
66 66 int64_t now;
67   - uint32_t counter;
  67 + uint64_t counter;
68 68  
69 69 if (s->enabled) {
70 70 now = qemu_get_clock(vm_clock);
... ... @@ -75,8 +75,8 @@ uint32_t ptimer_get_count(ptimer_state *s)
75 75 triggered. */
76 76 counter = 0;
77 77 } else {
78   - int64_t rem;
79   - int64_t div;
  78 + uint64_t rem;
  79 + uint64_t div;
80 80  
81 81 rem = s->next_event - now;
82 82 div = s->period;
... ... @@ -88,7 +88,7 @@ uint32_t ptimer_get_count(ptimer_state *s)
88 88 return counter;
89 89 }
90 90  
91   -void ptimer_set_count(ptimer_state *s, uint32_t count)
  91 +void ptimer_set_count(ptimer_state *s, uint64_t count)
92 92 {
93 93 s->delta = count;
94 94 if (s->enabled) {
... ... @@ -108,7 +108,7 @@ void ptimer_run(ptimer_state *s, int oneshot)
108 108 ptimer_reload(s);
109 109 }
110 110  
111   -/* Pause a timer. Note that this may cause it to "loose" time, even if it
  111 +/* Pause a timer. Note that this may cause it to "lose" time, even if it
112 112 is immediately restarted. */
113 113 void ptimer_stop(ptimer_state *s)
114 114 {
... ... @@ -123,33 +123,60 @@ void ptimer_stop(ptimer_state *s)
123 123 /* Set counter increment interval in nanoseconds. */
124 124 void ptimer_set_period(ptimer_state *s, int64_t period)
125 125 {
126   - if (s->enabled) {
127   - fprintf(stderr, "FIXME: ptimer_set_period with running timer");
128   - }
129 126 s->period = period;
130 127 s->period_frac = 0;
  128 + if (s->enabled) {
  129 + s->next_event = qemu_get_clock(vm_clock);
  130 + ptimer_reload(s);
  131 + }
131 132 }
132 133  
133 134 /* Set counter frequency in Hz. */
134 135 void ptimer_set_freq(ptimer_state *s, uint32_t freq)
135 136 {
136   - if (s->enabled) {
137   - fprintf(stderr, "FIXME: ptimer_set_freq with running timer");
138   - }
139 137 s->period = 1000000000ll / freq;
140 138 s->period_frac = (1000000000ll << 32) / freq;
  139 + if (s->enabled) {
  140 + s->next_event = qemu_get_clock(vm_clock);
  141 + ptimer_reload(s);
  142 + }
141 143 }
142 144  
143 145 /* Set the initial countdown value. If reload is nonzero then also set
144 146 count = limit. */
145   -void ptimer_set_limit(ptimer_state *s, uint32_t limit, int reload)
  147 +void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
146 148 {
147   - if (s->enabled) {
148   - fprintf(stderr, "FIXME: ptimer_set_limit with running timer");
149   - }
150 149 s->limit = limit;
151 150 if (reload)
152 151 s->delta = limit;
  152 + if (s->enabled) {
  153 + s->next_event = qemu_get_clock(vm_clock);
  154 + ptimer_reload(s);
  155 + }
  156 +}
  157 +
  158 +void qemu_put_ptimer(QEMUFile *f, ptimer_state *s)
  159 +{
  160 + qemu_put_byte(f, s->enabled);
  161 + qemu_put_be64s(f, &s->limit);
  162 + qemu_put_be64s(f, &s->delta);
  163 + qemu_put_be32s(f, &s->period_frac);
  164 + qemu_put_be64s(f, &s->period);
  165 + qemu_put_be64s(f, &s->last_event);
  166 + qemu_put_be64s(f, &s->next_event);
  167 + qemu_put_timer(f, s->timer);
  168 +}
  169 +
  170 +void qemu_get_ptimer(QEMUFile *f, ptimer_state *s)
  171 +{
  172 + s->enabled = qemu_get_byte(f);
  173 + qemu_get_be64s(f, &s->limit);
  174 + qemu_get_be64s(f, &s->delta);
  175 + qemu_get_be32s(f, &s->period_frac);
  176 + qemu_get_be64s(f, &s->period);
  177 + qemu_get_be64s(f, &s->last_event);
  178 + qemu_get_be64s(f, &s->next_event);
  179 + qemu_get_timer(f, s->timer);
153 180 }
154 181  
155 182 ptimer_state *ptimer_init(QEMUBH *bh)
... ...
hw/slavio_timer.c
... ... @@ -48,61 +48,29 @@ do { printf(&quot;TIMER: &quot; fmt , ##args); } while (0)
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;
  51 + ptimer_state *timer;
  52 + uint32_t count, counthigh, reached;
  53 + uint64_t limit;
56 54 int irq;
57   - int reached, stopped;
  55 + int stopped;
58 56 int mode; // 0 = processor, 1 = user, 2 = system
59 57 unsigned int cpu;
60 58 void *intctl;
61 59 } SLAVIO_TIMERState;
62 60  
63 61 #define TIMER_MAXADDR 0x1f
64   -#define CNT_FREQ 2000000
65 62  
66 63 // Update count, set irq, update expire_time
  64 +// Convert from ptimer countdown units
67 65 static void slavio_timer_get_out(SLAVIO_TIMERState *s)
68 66 {
69   - int out;
70   - int64_t diff, ticks, count;
71   - uint32_t limit;
  67 + uint64_t count;
72 68  
73   - // There are three clock tick units: CPU ticks, register units
74   - // (nanoseconds), and counter ticks (500 ns).
75   - if (s->mode == 1 && s->stopped)
76   - ticks = s->stop_time;
77   - else
78   - ticks = qemu_get_clock(vm_clock) - s->tick_offset;
79   -
80   - out = (ticks > s->expire_time);
81   - if (out)
82   - s->reached = 0x80000000;
83   - // Convert register units to counter ticks
84   - limit = s->limit >> 9;
85   -
86   - if (!limit)
87   - limit = 0x7fffffff >> 9;
88   -
89   - // Convert cpu ticks to counter ticks
90   - diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec);
91   -
92   - // Calculate what the counter should be, convert to register
93   - // units
94   - count = diff % limit;
95   - s->count = count << 9;
96   - s->counthigh = count >> 22;
97   -
98   - // Expire time: CPU ticks left to next interrupt
99   - // Convert remaining counter ticks to CPU ticks
100   - s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ);
101   -
102   - 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);
103   -
104   - if (s->mode != 1)
105   - pic_set_irq_cpu(s->intctl, s->irq, out, s->cpu);
  69 + count = s->limit - (ptimer_get_count(s->timer) << 9);
  70 + DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit, s->counthigh,
  71 + s->count);
  72 + s->count = count & 0xfffffe00;
  73 + s->counthigh = count >> 32;
106 74 }
107 75  
108 76 // timer callback
... ... @@ -110,17 +78,17 @@ static void slavio_timer_irq(void *opaque)
110 78 {
111 79 SLAVIO_TIMERState *s = opaque;
112 80  
113   - if (!s->irq_timer)
114   - return;
115 81 slavio_timer_get_out(s);
  82 + DPRINTF("callback: count %x%08x\n", s->counthigh, s->count);
  83 + s->reached = 0x80000000;
116 84 if (s->mode != 1)
117   - qemu_mod_timer(s->irq_timer, s->expire_time);
  85 + pic_set_irq_cpu(s->intctl, s->irq, 1, s->cpu);
118 86 }
119 87  
120 88 static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
121 89 {
122 90 SLAVIO_TIMERState *s = opaque;
123   - uint32_t saddr;
  91 + uint32_t saddr, ret;
124 92  
125 93 saddr = (addr & TIMER_MAXADDR) >> 2;
126 94 switch (saddr) {
... ... @@ -131,60 +99,69 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
131 99 // clear irq
132 100 pic_set_irq_cpu(s->intctl, s->irq, 0, s->cpu);
133 101 s->reached = 0;
134   - return s->limit;
  102 + ret = s->limit & 0x7fffffff;
135 103 }
136 104 else {
137 105 slavio_timer_get_out(s);
138   - return s->counthigh & 0x7fffffff;
  106 + ret = s->counthigh & 0x7fffffff;
139 107 }
  108 + break;
140 109 case 1:
141 110 // read counter and reached bit (system mode) or read lsbits
142 111 // of counter (user mode)
143 112 slavio_timer_get_out(s);
144 113 if (s->mode != 1)
145   - return (s->count & 0x7fffffff) | s->reached;
  114 + ret = (s->count & 0x7fffffff) | s->reached;
146 115 else
147   - return s->count;
  116 + ret = s->count;
  117 + break;
148 118 case 3:
149 119 // read start/stop status
150   - return s->stopped;
  120 + ret = s->stopped;
  121 + break;
151 122 case 4:
152 123 // read user/system mode
153   - return s->mode & 1;
  124 + ret = s->mode & 1;
  125 + break;
154 126 default:
155   - return 0;
  127 + ret = 0;
  128 + break;
156 129 }
  130 + DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret);
  131 +
  132 + return ret;
157 133 }
158 134  
159 135 static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
160 136 {
161 137 SLAVIO_TIMERState *s = opaque;
162 138 uint32_t saddr;
  139 + int reload = 0;
163 140  
  141 + DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val);
164 142 saddr = (addr & TIMER_MAXADDR) >> 2;
165 143 switch (saddr) {
166 144 case 0:
167 145 // set limit, reset counter
168   - s->count_load_time = qemu_get_clock(vm_clock);
  146 + reload = 1;
  147 + pic_set_irq_cpu(s->intctl, s->irq, 0, s->cpu);
169 148 // fall through
170 149 case 2:
171 150 // set limit without resetting counter
172   - if (!val)
173   - s->limit = 0x7fffffff;
174   - else
175   - s->limit = val & 0x7fffffff;
176   - slavio_timer_irq(s);
  151 + s->limit = val & 0x7ffffe00ULL;
  152 + if (!s->limit)
  153 + s->limit = 0x7ffffe00ULL;
  154 + ptimer_set_limit(s->timer, s->limit >> 9, reload);
177 155 break;
178 156 case 3:
179 157 // start/stop user counter
180 158 if (s->mode == 1) {
181 159 if (val & 1) {
182   - s->stop_time = qemu_get_clock(vm_clock);
  160 + ptimer_stop(s->timer);
183 161 s->stopped = 1;
184 162 }
185 163 else {
186   - if (s->stopped)
187   - s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time;
  164 + ptimer_run(s->timer, 0);
188 165 s->stopped = 0;
189 166 }
190 167 }
... ... @@ -193,6 +170,11 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint3
193 170 // bit 0: user (1) or system (0) counter mode
194 171 if (s->mode == 0 || s->mode == 1)
195 172 s->mode = val & 1;
  173 + if (s->mode == 1) {
  174 + pic_set_irq_cpu(s->intctl, s->irq, 0, s->cpu);
  175 + s->limit = -1ULL;
  176 + }
  177 + ptimer_set_limit(s->timer, s->limit >> 9, 1);
196 178 break;
197 179 default:
198 180 break;
... ... @@ -215,37 +197,32 @@ static void slavio_timer_save(QEMUFile *f, void *opaque)
215 197 {
216 198 SLAVIO_TIMERState *s = opaque;
217 199  
218   - qemu_put_be32s(f, &s->limit);
  200 + qemu_put_be64s(f, &s->limit);
219 201 qemu_put_be32s(f, &s->count);
220 202 qemu_put_be32s(f, &s->counthigh);
221   - qemu_put_be64s(f, &s->count_load_time);
222   - qemu_put_be64s(f, &s->expire_time);
223   - qemu_put_be64s(f, &s->stop_time);
224   - qemu_put_be64s(f, &s->tick_offset);
225 203 qemu_put_be32s(f, &s->irq);
226 204 qemu_put_be32s(f, &s->reached);
227 205 qemu_put_be32s(f, &s->stopped);
228 206 qemu_put_be32s(f, &s->mode);
  207 + qemu_put_ptimer(f, s->timer);
229 208 }
230 209  
231 210 static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
232 211 {
233 212 SLAVIO_TIMERState *s = opaque;
234 213  
235   - if (version_id != 1)
  214 + if (version_id != 2)
236 215 return -EINVAL;
237 216  
238   - qemu_get_be32s(f, &s->limit);
  217 + qemu_get_be64s(f, &s->limit);
239 218 qemu_get_be32s(f, &s->count);
240 219 qemu_get_be32s(f, &s->counthigh);
241   - qemu_get_be64s(f, &s->count_load_time);
242   - qemu_get_be64s(f, &s->expire_time);
243   - qemu_get_be64s(f, &s->stop_time);
244   - qemu_get_be64s(f, &s->tick_offset);
245 220 qemu_get_be32s(f, &s->irq);
246 221 qemu_get_be32s(f, &s->reached);
247 222 qemu_get_be32s(f, &s->stopped);
248 223 qemu_get_be32s(f, &s->mode);
  224 + qemu_get_ptimer(f, s->timer);
  225 +
249 226 return 0;
250 227 }
251 228  
... ... @@ -253,13 +230,12 @@ static void slavio_timer_reset(void *opaque)
253 230 {
254 231 SLAVIO_TIMERState *s = opaque;
255 232  
256   - s->limit = 0;
  233 + s->limit = 0x7ffffe00ULL;
257 234 s->count = 0;
258   - s->count_load_time = qemu_get_clock(vm_clock);;
259   - s->stop_time = s->count_load_time;
260   - s->tick_offset = 0;
261 235 s->reached = 0;
262 236 s->mode &= 2;
  237 + ptimer_set_limit(s->timer, s->limit >> 9, 1);
  238 + ptimer_run(s->timer, 0);
263 239 s->stopped = 1;
264 240 slavio_timer_irq(s);
265 241 }
... ... @@ -269,6 +245,7 @@ void slavio_timer_init(target_phys_addr_t addr, int irq, int mode,
269 245 {
270 246 int slavio_timer_io_memory;
271 247 SLAVIO_TIMERState *s;
  248 + QEMUBH *bh;
272 249  
273 250 s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
274 251 if (!s)
... ... @@ -276,13 +253,15 @@ void slavio_timer_init(target_phys_addr_t addr, int irq, int mode,
276 253 s->irq = irq;
277 254 s->mode = mode;
278 255 s->cpu = cpu;
279   - s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s);
  256 + bh = qemu_bh_new(slavio_timer_irq, s);
  257 + s->timer = ptimer_init(bh);
  258 + ptimer_set_period(s->timer, 500ULL);
280 259 s->intctl = intctl;
281 260  
282 261 slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
283 262 slavio_timer_mem_write, s);
284 263 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);
  264 + register_savevm("slavio_timer", addr, 2, slavio_timer_save, slavio_timer_load, s);
286 265 qemu_register_reset(slavio_timer_reset, s);
287 266 slavio_timer_reset(s);
288 267 }
... ...
... ... @@ -1589,11 +1589,13 @@ typedef void (*ptimer_cb)(void *opaque);
1589 1589 ptimer_state *ptimer_init(QEMUBH *bh);
1590 1590 void ptimer_set_period(ptimer_state *s, int64_t period);
1591 1591 void ptimer_set_freq(ptimer_state *s, uint32_t freq);
1592   -void ptimer_set_limit(ptimer_state *s, uint32_t limit, int reload);
1593   -uint32_t ptimer_get_count(ptimer_state *s);
1594   -void ptimer_set_count(ptimer_state *s, uint32_t count);
  1592 +void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload);
  1593 +uint64_t ptimer_get_count(ptimer_state *s);
  1594 +void ptimer_set_count(ptimer_state *s, uint64_t count);
1595 1595 void ptimer_run(ptimer_state *s, int oneshot);
1596 1596 void ptimer_stop(ptimer_state *s);
  1597 +void qemu_put_ptimer(QEMUFile *f, ptimer_state *s);
  1598 +void qemu_get_ptimer(QEMUFile *f, ptimer_state *s);
1597 1599  
1598 1600 #include "hw/pxa.h"
1599 1601  
... ...