intel_8254_timer.cc (5443:394d180e8c04) intel_8254_timer.cc (5444:d5d0ac0b6d58)
1/*
2 * Copyright (c) 2004, 2005
3 * The Regents of The University of Michigan
4 * All Rights Reserved
5 *
6 * This code is part of the M5 simulator.
7 *
8 * Permission is granted to use, copy, create derivative works and
9 * redistribute this software and such derivative works for any
10 * purpose, so long as the copyright notice above, this grant of
11 * permission, and the disclaimer below appear in all copies made; and
12 * so long as the name of The University of Michigan is not used in
13 * any advertising or publicity pertaining to the use or distribution
14 * of this software without specific, written prior authorization.
15 *
16 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
17 * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
18 * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
19 * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
22 * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
23 * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
24 * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
25 * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
26 * DAMAGES.
27 *
28 * Authors: Ali G. Saidi
29 * Andrew L. Schultz
30 * Miguel J. Serrano
31 */
32
33#include "base/misc.hh"
34#include "dev/intel_8254_timer.hh"
35
36using namespace std;
37
38Intel8254Timer::Intel8254Timer(const string &name)
39 : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"),
40 counter2(name + ".counter2")
41{
42 counter[0] = &counter0;
43 counter[1] = &counter0;
44 counter[2] = &counter0;
45}
46
47void
48Intel8254Timer::writeControl(const CtrlReg data)
49{
50 int sel = data.sel;
51
52 if (sel == ReadBackCommand)
53 panic("PITimer Read-Back Command is not implemented.\n");
54
55 if (data.rw == LatchCommand)
56 counter[sel]->latchCount();
57 else {
58 counter[sel]->setRW(data.rw);
59 counter[sel]->setMode(data.mode);
60 counter[sel]->setBCD(data.bcd);
61 }
62}
63
64void
65Intel8254Timer::serialize(const string &base, ostream &os)
66{
67 // serialize the counters
68 counter0.serialize(base + ".counter0", os);
69 counter1.serialize(base + ".counter1", os);
70 counter2.serialize(base + ".counter2", os);
71}
72
73void
74Intel8254Timer::unserialize(const string &base, Checkpoint *cp,
75 const string &section)
76{
77 // unserialze the counters
78 counter0.unserialize(base + ".counter0", cp, section);
79 counter1.unserialize(base + ".counter1", cp, section);
80 counter2.unserialize(base + ".counter2", cp, section);
81}
82
83Intel8254Timer::Counter::Counter(const string &name)
84 : _name(name), event(this), count(0), latched_count(0), period(0),
85 mode(0), output_high(false), latch_on(false), read_byte(LSB),
86 write_byte(LSB)
87{
88
89}
90
91void
92Intel8254Timer::Counter::latchCount()
93{
94 // behave like a real latch
95 if(!latch_on) {
96 latch_on = true;
97 read_byte = LSB;
98 latched_count = count;
99 }
100}
101
102uint8_t
103Intel8254Timer::Counter::read()
104{
105 if (latch_on) {
106 switch (read_byte) {
107 case LSB:
108 read_byte = MSB;
109 return (uint8_t)latched_count;
110 break;
111 case MSB:
112 read_byte = LSB;
113 latch_on = false;
114 return latched_count >> 8;
115 break;
116 default:
117 panic("Shouldn't be here");
118 }
119 } else {
120 switch (read_byte) {
121 case LSB:
122 read_byte = MSB;
123 return (uint8_t)count;
124 break;
125 case MSB:
126 read_byte = LSB;
127 return count >> 8;
128 break;
129 default:
130 panic("Shouldn't be here");
131 }
132 }
133}
134
135void
136Intel8254Timer::Counter::write(const uint8_t data)
137{
138 switch (write_byte) {
139 case LSB:
140 count = (count & 0xFF00) | data;
141
142 if (event.scheduled())
143 event.deschedule();
144 output_high = false;
145 write_byte = MSB;
146 break;
147
148 case MSB:
149 count = (count & 0x00FF) | (data << 8);
1/*
2 * Copyright (c) 2004, 2005
3 * The Regents of The University of Michigan
4 * All Rights Reserved
5 *
6 * This code is part of the M5 simulator.
7 *
8 * Permission is granted to use, copy, create derivative works and
9 * redistribute this software and such derivative works for any
10 * purpose, so long as the copyright notice above, this grant of
11 * permission, and the disclaimer below appear in all copies made; and
12 * so long as the name of The University of Michigan is not used in
13 * any advertising or publicity pertaining to the use or distribution
14 * of this software without specific, written prior authorization.
15 *
16 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
17 * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
18 * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
19 * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
22 * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
23 * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
24 * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
25 * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
26 * DAMAGES.
27 *
28 * Authors: Ali G. Saidi
29 * Andrew L. Schultz
30 * Miguel J. Serrano
31 */
32
33#include "base/misc.hh"
34#include "dev/intel_8254_timer.hh"
35
36using namespace std;
37
38Intel8254Timer::Intel8254Timer(const string &name)
39 : _name(name), counter0(name + ".counter0"), counter1(name + ".counter1"),
40 counter2(name + ".counter2")
41{
42 counter[0] = &counter0;
43 counter[1] = &counter0;
44 counter[2] = &counter0;
45}
46
47void
48Intel8254Timer::writeControl(const CtrlReg data)
49{
50 int sel = data.sel;
51
52 if (sel == ReadBackCommand)
53 panic("PITimer Read-Back Command is not implemented.\n");
54
55 if (data.rw == LatchCommand)
56 counter[sel]->latchCount();
57 else {
58 counter[sel]->setRW(data.rw);
59 counter[sel]->setMode(data.mode);
60 counter[sel]->setBCD(data.bcd);
61 }
62}
63
64void
65Intel8254Timer::serialize(const string &base, ostream &os)
66{
67 // serialize the counters
68 counter0.serialize(base + ".counter0", os);
69 counter1.serialize(base + ".counter1", os);
70 counter2.serialize(base + ".counter2", os);
71}
72
73void
74Intel8254Timer::unserialize(const string &base, Checkpoint *cp,
75 const string &section)
76{
77 // unserialze the counters
78 counter0.unserialize(base + ".counter0", cp, section);
79 counter1.unserialize(base + ".counter1", cp, section);
80 counter2.unserialize(base + ".counter2", cp, section);
81}
82
83Intel8254Timer::Counter::Counter(const string &name)
84 : _name(name), event(this), count(0), latched_count(0), period(0),
85 mode(0), output_high(false), latch_on(false), read_byte(LSB),
86 write_byte(LSB)
87{
88
89}
90
91void
92Intel8254Timer::Counter::latchCount()
93{
94 // behave like a real latch
95 if(!latch_on) {
96 latch_on = true;
97 read_byte = LSB;
98 latched_count = count;
99 }
100}
101
102uint8_t
103Intel8254Timer::Counter::read()
104{
105 if (latch_on) {
106 switch (read_byte) {
107 case LSB:
108 read_byte = MSB;
109 return (uint8_t)latched_count;
110 break;
111 case MSB:
112 read_byte = LSB;
113 latch_on = false;
114 return latched_count >> 8;
115 break;
116 default:
117 panic("Shouldn't be here");
118 }
119 } else {
120 switch (read_byte) {
121 case LSB:
122 read_byte = MSB;
123 return (uint8_t)count;
124 break;
125 case MSB:
126 read_byte = LSB;
127 return count >> 8;
128 break;
129 default:
130 panic("Shouldn't be here");
131 }
132 }
133}
134
135void
136Intel8254Timer::Counter::write(const uint8_t data)
137{
138 switch (write_byte) {
139 case LSB:
140 count = (count & 0xFF00) | data;
141
142 if (event.scheduled())
143 event.deschedule();
144 output_high = false;
145 write_byte = MSB;
146 break;
147
148 case MSB:
149 count = (count & 0x00FF) | (data << 8);
150 period = count;
150 // In the RateGen or SquareWave modes, the timer wraps around and
151 // triggers on a value of 1, not 0.
152 if (mode == RateGen || mode == SquareWave)
153 period = count - 1;
154 else
155 period = count;
151
156
152 if (period > 0) {
153 DPRINTF(Intel8254Timer, "Timer set to curTick + %d\n",
154 count * event.interval);
155 event.schedule(curTick + count * event.interval);
156 }
157 if (period > 0)
158 event.setTo(period);
159
157 write_byte = LSB;
158 break;
159 }
160}
161
162void
163Intel8254Timer::Counter::setRW(int rw_val)
164{
165 if (rw_val != TwoPhase)
166 panic("Only LSB/MSB read/write is implemented.\n");
167}
168
169void
170Intel8254Timer::Counter::setMode(int mode_val)
171{
172 if(mode_val != InitTc && mode_val != RateGen &&
173 mode_val != SquareWave)
174 panic("PIT mode %#x is not implemented: \n", mode_val);
175
176 mode = mode_val;
177}
178
179void
180Intel8254Timer::Counter::setBCD(int bcd_val)
181{
182 if (bcd_val)
183 panic("PITimer does not implement BCD counts.\n");
184}
185
186bool
187Intel8254Timer::Counter::outputHigh()
188{
189 return output_high;
190}
191
192void
193Intel8254Timer::Counter::serialize(const string &base, ostream &os)
194{
195 paramOut(os, base + ".count", count);
196 paramOut(os, base + ".latched_count", latched_count);
197 paramOut(os, base + ".period", period);
198 paramOut(os, base + ".mode", mode);
199 paramOut(os, base + ".output_high", output_high);
200 paramOut(os, base + ".latch_on", latch_on);
201 paramOut(os, base + ".read_byte", read_byte);
202 paramOut(os, base + ".write_byte", write_byte);
203
204 Tick event_tick = 0;
205 if (event.scheduled())
206 event_tick = event.when();
207 paramOut(os, base + ".event_tick", event_tick);
208}
209
210void
211Intel8254Timer::Counter::unserialize(const string &base, Checkpoint *cp,
212 const string &section)
213{
214 paramIn(cp, section, base + ".count", count);
215 paramIn(cp, section, base + ".latched_count", latched_count);
216 paramIn(cp, section, base + ".period", period);
217 paramIn(cp, section, base + ".mode", mode);
218 paramIn(cp, section, base + ".output_high", output_high);
219 paramIn(cp, section, base + ".latch_on", latch_on);
220 paramIn(cp, section, base + ".read_byte", read_byte);
221 paramIn(cp, section, base + ".write_byte", write_byte);
222
223 Tick event_tick;
224 paramIn(cp, section, base + ".event_tick", event_tick);
225 if (event_tick)
226 event.schedule(event_tick);
227}
228
229Intel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
230 : Event(&mainEventQueue)
231{
232 interval = (Tick)(Clock::Float::s / 1193180.0);
233 counter = c_ptr;
234}
235
236void
237Intel8254Timer::Counter::CounterEvent::process()
238{
239 DPRINTF(Intel8254Timer, "Timer Interrupt\n");
240 switch (counter->mode) {
241 case InitTc:
242 counter->output_high = true;
160 write_byte = LSB;
161 break;
162 }
163}
164
165void
166Intel8254Timer::Counter::setRW(int rw_val)
167{
168 if (rw_val != TwoPhase)
169 panic("Only LSB/MSB read/write is implemented.\n");
170}
171
172void
173Intel8254Timer::Counter::setMode(int mode_val)
174{
175 if(mode_val != InitTc && mode_val != RateGen &&
176 mode_val != SquareWave)
177 panic("PIT mode %#x is not implemented: \n", mode_val);
178
179 mode = mode_val;
180}
181
182void
183Intel8254Timer::Counter::setBCD(int bcd_val)
184{
185 if (bcd_val)
186 panic("PITimer does not implement BCD counts.\n");
187}
188
189bool
190Intel8254Timer::Counter::outputHigh()
191{
192 return output_high;
193}
194
195void
196Intel8254Timer::Counter::serialize(const string &base, ostream &os)
197{
198 paramOut(os, base + ".count", count);
199 paramOut(os, base + ".latched_count", latched_count);
200 paramOut(os, base + ".period", period);
201 paramOut(os, base + ".mode", mode);
202 paramOut(os, base + ".output_high", output_high);
203 paramOut(os, base + ".latch_on", latch_on);
204 paramOut(os, base + ".read_byte", read_byte);
205 paramOut(os, base + ".write_byte", write_byte);
206
207 Tick event_tick = 0;
208 if (event.scheduled())
209 event_tick = event.when();
210 paramOut(os, base + ".event_tick", event_tick);
211}
212
213void
214Intel8254Timer::Counter::unserialize(const string &base, Checkpoint *cp,
215 const string &section)
216{
217 paramIn(cp, section, base + ".count", count);
218 paramIn(cp, section, base + ".latched_count", latched_count);
219 paramIn(cp, section, base + ".period", period);
220 paramIn(cp, section, base + ".mode", mode);
221 paramIn(cp, section, base + ".output_high", output_high);
222 paramIn(cp, section, base + ".latch_on", latch_on);
223 paramIn(cp, section, base + ".read_byte", read_byte);
224 paramIn(cp, section, base + ".write_byte", write_byte);
225
226 Tick event_tick;
227 paramIn(cp, section, base + ".event_tick", event_tick);
228 if (event_tick)
229 event.schedule(event_tick);
230}
231
232Intel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
233 : Event(&mainEventQueue)
234{
235 interval = (Tick)(Clock::Float::s / 1193180.0);
236 counter = c_ptr;
237}
238
239void
240Intel8254Timer::Counter::CounterEvent::process()
241{
242 DPRINTF(Intel8254Timer, "Timer Interrupt\n");
243 switch (counter->mode) {
244 case InitTc:
245 counter->output_high = true;
246 break;
243 case RateGen:
244 case SquareWave:
247 case RateGen:
248 case SquareWave:
249 setTo(counter->period);
245 break;
246 default:
247 panic("Unimplemented PITimer mode.\n");
248 }
249}
250
250 break;
251 default:
252 panic("Unimplemented PITimer mode.\n");
253 }
254}
255
256void
257Intel8254Timer::Counter::CounterEvent::setTo(int clocks)
258{
259 if (clocks == 0)
260 panic("Timer can't be set to go off instantly.\n");
261 DPRINTF(Intel8254Timer, "Timer set to curTick + %d\n",
262 clocks * interval);
263 schedule(curTick + clocks * interval);
264}
265
251const char *
252Intel8254Timer::Counter::CounterEvent::description() const
253{
254 return "tsunami 8254 Interval timer";
255}
266const char *
267Intel8254Timer::Counter::CounterEvent::description() const
268{
269 return "tsunami 8254 Interval timer";
270}