|
|
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.