root / hw / lm32_timer.c @ 6059631c
History | View | Annotate | Download (5.1 kB)
1 | ea7924dc | Michael Walle | /*
|
---|---|---|---|
2 | ea7924dc | Michael Walle | * QEMU model of the LatticeMico32 timer block.
|
3 | ea7924dc | Michael Walle | *
|
4 | ea7924dc | Michael Walle | * Copyright (c) 2010 Michael Walle <michael@walle.cc>
|
5 | ea7924dc | Michael Walle | *
|
6 | ea7924dc | Michael Walle | * This library is free software; you can redistribute it and/or
|
7 | ea7924dc | Michael Walle | * modify it under the terms of the GNU Lesser General Public
|
8 | ea7924dc | Michael Walle | * License as published by the Free Software Foundation; either
|
9 | ea7924dc | Michael Walle | * version 2 of the License, or (at your option) any later version.
|
10 | ea7924dc | Michael Walle | *
|
11 | ea7924dc | Michael Walle | * This library is distributed in the hope that it will be useful,
|
12 | ea7924dc | Michael Walle | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | ea7924dc | Michael Walle | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | ea7924dc | Michael Walle | * Lesser General Public License for more details.
|
15 | ea7924dc | Michael Walle | *
|
16 | ea7924dc | Michael Walle | * You should have received a copy of the GNU Lesser General Public
|
17 | ea7924dc | Michael Walle | * License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
18 | ea7924dc | Michael Walle | *
|
19 | ea7924dc | Michael Walle | *
|
20 | ea7924dc | Michael Walle | * Specification available at:
|
21 | ea7924dc | Michael Walle | * http://www.latticesemi.com/documents/mico32timer.pdf
|
22 | ea7924dc | Michael Walle | */
|
23 | ea7924dc | Michael Walle | |
24 | ea7924dc | Michael Walle | #include "hw.h" |
25 | ea7924dc | Michael Walle | #include "sysbus.h" |
26 | ea7924dc | Michael Walle | #include "trace.h" |
27 | ea7924dc | Michael Walle | #include "qemu-timer.h" |
28 | ea7924dc | Michael Walle | #include "qemu-error.h" |
29 | ea7924dc | Michael Walle | |
30 | ea7924dc | Michael Walle | #define DEFAULT_FREQUENCY (50*1000000) |
31 | ea7924dc | Michael Walle | |
32 | ea7924dc | Michael Walle | enum {
|
33 | ea7924dc | Michael Walle | R_SR = 0,
|
34 | ea7924dc | Michael Walle | R_CR, |
35 | ea7924dc | Michael Walle | R_PERIOD, |
36 | ea7924dc | Michael Walle | R_SNAPSHOT, |
37 | ea7924dc | Michael Walle | R_MAX |
38 | ea7924dc | Michael Walle | }; |
39 | ea7924dc | Michael Walle | |
40 | ea7924dc | Michael Walle | enum {
|
41 | ea7924dc | Michael Walle | SR_TO = (1 << 0), |
42 | ea7924dc | Michael Walle | SR_RUN = (1 << 1), |
43 | ea7924dc | Michael Walle | }; |
44 | ea7924dc | Michael Walle | |
45 | ea7924dc | Michael Walle | enum {
|
46 | ea7924dc | Michael Walle | CR_ITO = (1 << 0), |
47 | ea7924dc | Michael Walle | CR_CONT = (1 << 1), |
48 | ea7924dc | Michael Walle | CR_START = (1 << 2), |
49 | ea7924dc | Michael Walle | CR_STOP = (1 << 3), |
50 | ea7924dc | Michael Walle | }; |
51 | ea7924dc | Michael Walle | |
52 | ea7924dc | Michael Walle | struct LM32TimerState {
|
53 | ea7924dc | Michael Walle | SysBusDevice busdev; |
54 | ea7924dc | Michael Walle | |
55 | ea7924dc | Michael Walle | QEMUBH *bh; |
56 | ea7924dc | Michael Walle | ptimer_state *ptimer; |
57 | ea7924dc | Michael Walle | |
58 | ea7924dc | Michael Walle | qemu_irq irq; |
59 | ea7924dc | Michael Walle | uint32_t freq_hz; |
60 | ea7924dc | Michael Walle | |
61 | ea7924dc | Michael Walle | uint32_t regs[R_MAX]; |
62 | ea7924dc | Michael Walle | }; |
63 | ea7924dc | Michael Walle | typedef struct LM32TimerState LM32TimerState; |
64 | ea7924dc | Michael Walle | |
65 | ea7924dc | Michael Walle | static void timer_update_irq(LM32TimerState *s) |
66 | ea7924dc | Michael Walle | { |
67 | ea7924dc | Michael Walle | int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
|
68 | ea7924dc | Michael Walle | |
69 | ea7924dc | Michael Walle | trace_lm32_timer_irq_state(state); |
70 | ea7924dc | Michael Walle | qemu_set_irq(s->irq, state); |
71 | ea7924dc | Michael Walle | } |
72 | ea7924dc | Michael Walle | |
73 | ea7924dc | Michael Walle | static uint32_t timer_read(void *opaque, target_phys_addr_t addr) |
74 | ea7924dc | Michael Walle | { |
75 | ea7924dc | Michael Walle | LM32TimerState *s = opaque; |
76 | ea7924dc | Michael Walle | uint32_t r = 0;
|
77 | ea7924dc | Michael Walle | |
78 | ea7924dc | Michael Walle | addr >>= 2;
|
79 | ea7924dc | Michael Walle | switch (addr) {
|
80 | ea7924dc | Michael Walle | case R_SR:
|
81 | ea7924dc | Michael Walle | case R_CR:
|
82 | ea7924dc | Michael Walle | case R_PERIOD:
|
83 | ea7924dc | Michael Walle | r = s->regs[addr]; |
84 | ea7924dc | Michael Walle | break;
|
85 | ea7924dc | Michael Walle | case R_SNAPSHOT:
|
86 | ea7924dc | Michael Walle | r = (uint32_t)ptimer_get_count(s->ptimer); |
87 | ea7924dc | Michael Walle | break;
|
88 | ea7924dc | Michael Walle | default:
|
89 | ea7924dc | Michael Walle | error_report("lm32_timer: read access to unkown register 0x"
|
90 | ea7924dc | Michael Walle | TARGET_FMT_plx, addr << 2);
|
91 | ea7924dc | Michael Walle | break;
|
92 | ea7924dc | Michael Walle | } |
93 | ea7924dc | Michael Walle | |
94 | ea7924dc | Michael Walle | trace_lm32_timer_memory_read(addr << 2, r);
|
95 | ea7924dc | Michael Walle | return r;
|
96 | ea7924dc | Michael Walle | } |
97 | ea7924dc | Michael Walle | |
98 | ea7924dc | Michael Walle | static void timer_write(void *opaque, target_phys_addr_t addr, uint32_t value) |
99 | ea7924dc | Michael Walle | { |
100 | ea7924dc | Michael Walle | LM32TimerState *s = opaque; |
101 | ea7924dc | Michael Walle | |
102 | ea7924dc | Michael Walle | trace_lm32_timer_memory_write(addr, value); |
103 | ea7924dc | Michael Walle | |
104 | ea7924dc | Michael Walle | addr >>= 2;
|
105 | ea7924dc | Michael Walle | switch (addr) {
|
106 | ea7924dc | Michael Walle | case R_SR:
|
107 | ea7924dc | Michael Walle | s->regs[R_SR] &= ~SR_TO; |
108 | ea7924dc | Michael Walle | break;
|
109 | ea7924dc | Michael Walle | case R_CR:
|
110 | ea7924dc | Michael Walle | s->regs[R_CR] = value; |
111 | ea7924dc | Michael Walle | if (s->regs[R_CR] & CR_START) {
|
112 | ea7924dc | Michael Walle | ptimer_run(s->ptimer, 1);
|
113 | ea7924dc | Michael Walle | } |
114 | ea7924dc | Michael Walle | if (s->regs[R_CR] & CR_STOP) {
|
115 | ea7924dc | Michael Walle | ptimer_stop(s->ptimer); |
116 | ea7924dc | Michael Walle | } |
117 | ea7924dc | Michael Walle | break;
|
118 | ea7924dc | Michael Walle | case R_PERIOD:
|
119 | ea7924dc | Michael Walle | s->regs[R_PERIOD] = value; |
120 | ea7924dc | Michael Walle | ptimer_set_count(s->ptimer, value); |
121 | ea7924dc | Michael Walle | break;
|
122 | ea7924dc | Michael Walle | case R_SNAPSHOT:
|
123 | ea7924dc | Michael Walle | error_report("lm32_timer: write access to read only register 0x"
|
124 | ea7924dc | Michael Walle | TARGET_FMT_plx, addr << 2);
|
125 | ea7924dc | Michael Walle | break;
|
126 | ea7924dc | Michael Walle | default:
|
127 | ea7924dc | Michael Walle | error_report("lm32_timer: write access to unkown register 0x"
|
128 | ea7924dc | Michael Walle | TARGET_FMT_plx, addr << 2);
|
129 | ea7924dc | Michael Walle | break;
|
130 | ea7924dc | Michael Walle | } |
131 | ea7924dc | Michael Walle | timer_update_irq(s); |
132 | ea7924dc | Michael Walle | } |
133 | ea7924dc | Michael Walle | |
134 | ea7924dc | Michael Walle | static CPUReadMemoryFunc * const timer_read_fn[] = { |
135 | ea7924dc | Michael Walle | NULL,
|
136 | ea7924dc | Michael Walle | NULL,
|
137 | ea7924dc | Michael Walle | &timer_read, |
138 | ea7924dc | Michael Walle | }; |
139 | ea7924dc | Michael Walle | |
140 | ea7924dc | Michael Walle | static CPUWriteMemoryFunc * const timer_write_fn[] = { |
141 | ea7924dc | Michael Walle | NULL,
|
142 | ea7924dc | Michael Walle | NULL,
|
143 | ea7924dc | Michael Walle | &timer_write, |
144 | ea7924dc | Michael Walle | }; |
145 | ea7924dc | Michael Walle | |
146 | ea7924dc | Michael Walle | static void timer_hit(void *opaque) |
147 | ea7924dc | Michael Walle | { |
148 | ea7924dc | Michael Walle | LM32TimerState *s = opaque; |
149 | ea7924dc | Michael Walle | |
150 | ea7924dc | Michael Walle | trace_lm32_timer_hit(); |
151 | ea7924dc | Michael Walle | |
152 | ea7924dc | Michael Walle | s->regs[R_SR] |= SR_TO; |
153 | ea7924dc | Michael Walle | |
154 | ea7924dc | Michael Walle | if (s->regs[R_CR] & CR_CONT) {
|
155 | ea7924dc | Michael Walle | ptimer_set_count(s->ptimer, s->regs[R_PERIOD]); |
156 | ea7924dc | Michael Walle | ptimer_run(s->ptimer, 1);
|
157 | ea7924dc | Michael Walle | } |
158 | ea7924dc | Michael Walle | timer_update_irq(s); |
159 | ea7924dc | Michael Walle | } |
160 | ea7924dc | Michael Walle | |
161 | ea7924dc | Michael Walle | static void timer_reset(DeviceState *d) |
162 | ea7924dc | Michael Walle | { |
163 | ea7924dc | Michael Walle | LM32TimerState *s = container_of(d, LM32TimerState, busdev.qdev); |
164 | ea7924dc | Michael Walle | int i;
|
165 | ea7924dc | Michael Walle | |
166 | ea7924dc | Michael Walle | for (i = 0; i < R_MAX; i++) { |
167 | ea7924dc | Michael Walle | s->regs[i] = 0;
|
168 | ea7924dc | Michael Walle | } |
169 | ea7924dc | Michael Walle | ptimer_stop(s->ptimer); |
170 | ea7924dc | Michael Walle | } |
171 | ea7924dc | Michael Walle | |
172 | ea7924dc | Michael Walle | static int lm32_timer_init(SysBusDevice *dev) |
173 | ea7924dc | Michael Walle | { |
174 | ea7924dc | Michael Walle | LM32TimerState *s = FROM_SYSBUS(typeof(*s), dev); |
175 | ea7924dc | Michael Walle | int timer_regs;
|
176 | ea7924dc | Michael Walle | |
177 | ea7924dc | Michael Walle | sysbus_init_irq(dev, &s->irq); |
178 | ea7924dc | Michael Walle | |
179 | ea7924dc | Michael Walle | s->bh = qemu_bh_new(timer_hit, s); |
180 | ea7924dc | Michael Walle | s->ptimer = ptimer_init(s->bh); |
181 | ea7924dc | Michael Walle | ptimer_set_freq(s->ptimer, s->freq_hz); |
182 | ea7924dc | Michael Walle | |
183 | ea7924dc | Michael Walle | timer_regs = cpu_register_io_memory(timer_read_fn, timer_write_fn, s, |
184 | ea7924dc | Michael Walle | DEVICE_NATIVE_ENDIAN); |
185 | ea7924dc | Michael Walle | sysbus_init_mmio(dev, R_MAX * 4, timer_regs);
|
186 | ea7924dc | Michael Walle | |
187 | ea7924dc | Michael Walle | return 0; |
188 | ea7924dc | Michael Walle | } |
189 | ea7924dc | Michael Walle | |
190 | ea7924dc | Michael Walle | static const VMStateDescription vmstate_lm32_timer = { |
191 | ea7924dc | Michael Walle | .name = "lm32-timer",
|
192 | ea7924dc | Michael Walle | .version_id = 1,
|
193 | ea7924dc | Michael Walle | .minimum_version_id = 1,
|
194 | ea7924dc | Michael Walle | .minimum_version_id_old = 1,
|
195 | ea7924dc | Michael Walle | .fields = (VMStateField[]) { |
196 | ea7924dc | Michael Walle | VMSTATE_PTIMER(ptimer, LM32TimerState), |
197 | ea7924dc | Michael Walle | VMSTATE_UINT32(freq_hz, LM32TimerState), |
198 | ea7924dc | Michael Walle | VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX), |
199 | ea7924dc | Michael Walle | VMSTATE_END_OF_LIST() |
200 | ea7924dc | Michael Walle | } |
201 | ea7924dc | Michael Walle | }; |
202 | ea7924dc | Michael Walle | |
203 | ea7924dc | Michael Walle | static SysBusDeviceInfo lm32_timer_info = {
|
204 | ea7924dc | Michael Walle | .init = lm32_timer_init, |
205 | ea7924dc | Michael Walle | .qdev.name = "lm32-timer",
|
206 | ea7924dc | Michael Walle | .qdev.size = sizeof(LM32TimerState),
|
207 | ea7924dc | Michael Walle | .qdev.vmsd = &vmstate_lm32_timer, |
208 | ea7924dc | Michael Walle | .qdev.reset = timer_reset, |
209 | ea7924dc | Michael Walle | .qdev.props = (Property[]) { |
210 | ea7924dc | Michael Walle | DEFINE_PROP_UINT32( |
211 | ea7924dc | Michael Walle | "frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY
|
212 | ea7924dc | Michael Walle | ), |
213 | ea7924dc | Michael Walle | DEFINE_PROP_END_OF_LIST(), |
214 | ea7924dc | Michael Walle | } |
215 | ea7924dc | Michael Walle | }; |
216 | ea7924dc | Michael Walle | |
217 | ea7924dc | Michael Walle | static void lm32_timer_register(void) |
218 | ea7924dc | Michael Walle | { |
219 | ea7924dc | Michael Walle | sysbus_register_withprop(&lm32_timer_info); |
220 | ea7924dc | Michael Walle | } |
221 | ea7924dc | Michael Walle | |
222 | ea7924dc | Michael Walle | device_init(lm32_timer_register) |