rename AlphaConsole to AlphaBackdoor
[gem5.git] / src / dev / intel_8254_timer.cc
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
36 using namespace std;
37
38 Intel8254Timer::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
47 void
48 Intel8254Timer::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
64 void
65 Intel8254Timer::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
73 void
74 Intel8254Timer::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
83 Intel8254Timer::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
91 void
92 Intel8254Timer::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
102 uint8_t
103 Intel8254Timer::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
135 void
136 Intel8254Timer::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 // 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;
156
157 if (period > 0)
158 event.setTo(period);
159
160 write_byte = LSB;
161 break;
162 }
163 }
164
165 void
166 Intel8254Timer::Counter::setRW(int rw_val)
167 {
168 if (rw_val != TwoPhase)
169 panic("Only LSB/MSB read/write is implemented.\n");
170 }
171
172 void
173 Intel8254Timer::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
182 void
183 Intel8254Timer::Counter::setBCD(int bcd_val)
184 {
185 if (bcd_val)
186 panic("PITimer does not implement BCD counts.\n");
187 }
188
189 bool
190 Intel8254Timer::Counter::outputHigh()
191 {
192 return output_high;
193 }
194
195 void
196 Intel8254Timer::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
213 void
214 Intel8254Timer::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
232 Intel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
233 : Event(&mainEventQueue)
234 {
235 interval = (Tick)(Clock::Float::s / 1193180.0);
236 counter = c_ptr;
237 }
238
239 void
240 Intel8254Timer::Counter::CounterEvent::process()
241 {
242 DPRINTF(Intel8254Timer, "Timer Interrupt\n");
243 switch (counter->mode) {
244 case InitTc:
245 counter->output_high = true;
246 break;
247 case RateGen:
248 case SquareWave:
249 setTo(counter->period);
250 break;
251 default:
252 panic("Unimplemented PITimer mode.\n");
253 }
254 }
255
256 void
257 Intel8254Timer::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
266 const char *
267 Intel8254Timer::Counter::CounterEvent::description() const
268 {
269 return "tsunami 8254 Interval timer";
270 }