intel_8254_timer.cc revision 11321:02e930db812d
111251Sradhika.jagtap@ARM.com/* 211251Sradhika.jagtap@ARM.com * Copyright (c) 2004, 2005 311251Sradhika.jagtap@ARM.com * The Regents of The University of Michigan 411251Sradhika.jagtap@ARM.com * All Rights Reserved 511251Sradhika.jagtap@ARM.com * 611251Sradhika.jagtap@ARM.com * This code is part of the M5 simulator. 711251Sradhika.jagtap@ARM.com * 811251Sradhika.jagtap@ARM.com * Permission is granted to use, copy, create derivative works and 911251Sradhika.jagtap@ARM.com * redistribute this software and such derivative works for any 1011251Sradhika.jagtap@ARM.com * purpose, so long as the copyright notice above, this grant of 1111251Sradhika.jagtap@ARM.com * permission, and the disclaimer below appear in all copies made; and 1211251Sradhika.jagtap@ARM.com * so long as the name of The University of Michigan is not used in 1311251Sradhika.jagtap@ARM.com * any advertising or publicity pertaining to the use or distribution 1411251Sradhika.jagtap@ARM.com * of this software without specific, written prior authorization. 1511251Sradhika.jagtap@ARM.com * 1611251Sradhika.jagtap@ARM.com * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE 1711251Sradhika.jagtap@ARM.com * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND 1811251Sradhika.jagtap@ARM.com * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER 1911251Sradhika.jagtap@ARM.com * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 2011251Sradhika.jagtap@ARM.com * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2111251Sradhika.jagtap@ARM.com * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE 2211251Sradhika.jagtap@ARM.com * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, 2311251Sradhika.jagtap@ARM.com * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM 2411251Sradhika.jagtap@ARM.com * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN 2511251Sradhika.jagtap@ARM.com * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH 2611251Sradhika.jagtap@ARM.com * DAMAGES. 2711251Sradhika.jagtap@ARM.com * 2811251Sradhika.jagtap@ARM.com * Authors: Ali G. Saidi 2911251Sradhika.jagtap@ARM.com * Andrew L. Schultz 3011251Sradhika.jagtap@ARM.com * Miguel J. Serrano 3111251Sradhika.jagtap@ARM.com */ 3211251Sradhika.jagtap@ARM.com 3311251Sradhika.jagtap@ARM.com#include "base/misc.hh" 3411251Sradhika.jagtap@ARM.com#include "debug/Intel8254Timer.hh" 3511251Sradhika.jagtap@ARM.com#include "dev/intel_8254_timer.hh" 3611251Sradhika.jagtap@ARM.com 3711251Sradhika.jagtap@ARM.comusing namespace std; 3811251Sradhika.jagtap@ARM.com 3911251Sradhika.jagtap@ARM.comIntel8254Timer::Intel8254Timer(EventManager *em, const string &name, 4011251Sradhika.jagtap@ARM.com Counter *counter0, Counter *counter1, Counter *counter2) : 4111251Sradhika.jagtap@ARM.com EventManager(em), _name(name) 4211251Sradhika.jagtap@ARM.com{ 4311251Sradhika.jagtap@ARM.com counter[0] = counter0; 4411251Sradhika.jagtap@ARM.com counter[1] = counter1; 4511251Sradhika.jagtap@ARM.com counter[2] = counter2; 4611251Sradhika.jagtap@ARM.com} 4711251Sradhika.jagtap@ARM.com 4811251Sradhika.jagtap@ARM.comIntel8254Timer::Intel8254Timer(EventManager *em, const string &name) : 4911251Sradhika.jagtap@ARM.com EventManager(em), _name(name) 5011251Sradhika.jagtap@ARM.com{ 5111251Sradhika.jagtap@ARM.com counter[0] = new Counter(this, name + ".counter0", 0); 5211251Sradhika.jagtap@ARM.com counter[1] = new Counter(this, name + ".counter1", 1); 5311251Sradhika.jagtap@ARM.com counter[2] = new Counter(this, name + ".counter2", 2); 5411251Sradhika.jagtap@ARM.com} 5511251Sradhika.jagtap@ARM.com 5611251Sradhika.jagtap@ARM.comvoid 5711251Sradhika.jagtap@ARM.comIntel8254Timer::writeControl(const CtrlReg data) 5811251Sradhika.jagtap@ARM.com{ 5911251Sradhika.jagtap@ARM.com int sel = data.sel; 6011251Sradhika.jagtap@ARM.com 6111251Sradhika.jagtap@ARM.com if (sel == ReadBackCommand) 6211251Sradhika.jagtap@ARM.com panic("PITimer Read-Back Command is not implemented.\n"); 6311251Sradhika.jagtap@ARM.com 6411251Sradhika.jagtap@ARM.com if (data.rw == LatchCommand) 6511251Sradhika.jagtap@ARM.com counter[sel]->latchCount(); 6611251Sradhika.jagtap@ARM.com else { 6711251Sradhika.jagtap@ARM.com counter[sel]->setRW(data.rw); 6811251Sradhika.jagtap@ARM.com counter[sel]->setMode(data.mode); 6911251Sradhika.jagtap@ARM.com counter[sel]->setBCD(data.bcd); 7011251Sradhika.jagtap@ARM.com } 7111251Sradhika.jagtap@ARM.com} 7211251Sradhika.jagtap@ARM.com 7311251Sradhika.jagtap@ARM.comvoid 7411251Sradhika.jagtap@ARM.comIntel8254Timer::serialize(const string &base, CheckpointOut &cp) const 7511251Sradhika.jagtap@ARM.com{ 7611251Sradhika.jagtap@ARM.com // serialize the counters 7711251Sradhika.jagtap@ARM.com counter[0]->serialize(base + ".counter0", cp); 7811251Sradhika.jagtap@ARM.com counter[1]->serialize(base + ".counter1", cp); 7911251Sradhika.jagtap@ARM.com counter[2]->serialize(base + ".counter2", cp); 8011251Sradhika.jagtap@ARM.com} 8111251Sradhika.jagtap@ARM.com 8211251Sradhika.jagtap@ARM.comvoid 8311251Sradhika.jagtap@ARM.comIntel8254Timer::unserialize(const string &base, CheckpointIn &cp) 8411251Sradhika.jagtap@ARM.com{ 8511251Sradhika.jagtap@ARM.com // unserialze the counters 8611251Sradhika.jagtap@ARM.com counter[0]->unserialize(base + ".counter0", cp); 8711251Sradhika.jagtap@ARM.com counter[1]->unserialize(base + ".counter1", cp); 8811251Sradhika.jagtap@ARM.com counter[2]->unserialize(base + ".counter2", cp); 8911251Sradhika.jagtap@ARM.com} 9011251Sradhika.jagtap@ARM.com 9111251Sradhika.jagtap@ARM.comvoid 9211251Sradhika.jagtap@ARM.comIntel8254Timer::startup() 9311251Sradhika.jagtap@ARM.com{ 9411251Sradhika.jagtap@ARM.com counter[0]->startup(); 9511251Sradhika.jagtap@ARM.com counter[1]->startup(); 9611251Sradhika.jagtap@ARM.com counter[2]->startup(); 9711251Sradhika.jagtap@ARM.com} 9811251Sradhika.jagtap@ARM.com 9911251Sradhika.jagtap@ARM.comIntel8254Timer::Counter::Counter(Intel8254Timer *p, 10011251Sradhika.jagtap@ARM.com const string &name, unsigned int _num) 10111251Sradhika.jagtap@ARM.com : _name(name), num(_num), event(this), running(false), 10211251Sradhika.jagtap@ARM.com initial_count(0), latched_count(0), period(0), mode(0), 10311251Sradhika.jagtap@ARM.com output_high(false), latch_on(false), read_byte(LSB), 10411251Sradhika.jagtap@ARM.com write_byte(LSB), parent(p) 10511251Sradhika.jagtap@ARM.com{ 10611251Sradhika.jagtap@ARM.com offset = period * event.getInterval(); 10711251Sradhika.jagtap@ARM.com} 10811251Sradhika.jagtap@ARM.com 10911251Sradhika.jagtap@ARM.comvoid 11011251Sradhika.jagtap@ARM.comIntel8254Timer::Counter::latchCount() 11111251Sradhika.jagtap@ARM.com{ 11211251Sradhika.jagtap@ARM.com // behave like a real latch 11311251Sradhika.jagtap@ARM.com if (!latch_on) { 11411251Sradhika.jagtap@ARM.com latch_on = true; 11511251Sradhika.jagtap@ARM.com read_byte = LSB; 11611251Sradhika.jagtap@ARM.com latched_count = currentCount(); 11711251Sradhika.jagtap@ARM.com } 11811251Sradhika.jagtap@ARM.com} 11911251Sradhika.jagtap@ARM.com 120int 121Intel8254Timer::Counter::currentCount() 122{ 123 int clocks = event.clocksLeft(); 124 if (clocks == -1) { 125 warn_once("Reading current count from inactive timer.\n"); 126 return 0; 127 } 128 if (mode == RateGen || mode == SquareWave) 129 return clocks + 1; 130 else 131 return clocks; 132} 133 134uint8_t 135Intel8254Timer::Counter::read() 136{ 137 if (latch_on) { 138 switch (read_byte) { 139 case LSB: 140 read_byte = MSB; 141 return (uint8_t)latched_count; 142 break; 143 case MSB: 144 read_byte = LSB; 145 latch_on = false; 146 return latched_count >> 8; 147 break; 148 default: 149 panic("Shouldn't be here"); 150 } 151 } else { 152 uint16_t count = currentCount(); 153 switch (read_byte) { 154 case LSB: 155 read_byte = MSB; 156 return (uint8_t)count; 157 break; 158 case MSB: 159 read_byte = LSB; 160 return count >> 8; 161 break; 162 default: 163 panic("Shouldn't be here"); 164 } 165 } 166} 167 168void 169Intel8254Timer::Counter::write(const uint8_t data) 170{ 171 switch (write_byte) { 172 case LSB: 173 initial_count = (initial_count & 0xFF00) | data; 174 175 if (event.scheduled()) 176 parent->deschedule(event); 177 output_high = false; 178 write_byte = MSB; 179 break; 180 181 case MSB: 182 initial_count = (initial_count & 0x00FF) | (data << 8); 183 // In the RateGen or SquareWave modes, the timer wraps around and 184 // triggers on a value of 1, not 0. 185 if (mode == RateGen || mode == SquareWave) 186 period = initial_count - 1; 187 else 188 period = initial_count; 189 190 offset = period * event.getInterval(); 191 192 if (running && (period > 0)) 193 event.setTo(period); 194 195 write_byte = LSB; 196 break; 197 } 198} 199 200void 201Intel8254Timer::Counter::setRW(int rw_val) 202{ 203 if (rw_val != TwoPhase) 204 panic("Only LSB/MSB read/write is implemented.\n"); 205} 206 207void 208Intel8254Timer::Counter::setMode(int mode_val) 209{ 210 if (mode_val != InitTc && mode_val != RateGen && 211 mode_val != SquareWave) 212 panic("PIT mode %#x is not implemented: \n", mode_val); 213 214 mode = mode_val; 215} 216 217void 218Intel8254Timer::Counter::setBCD(int bcd_val) 219{ 220 if (bcd_val) 221 panic("PITimer does not implement BCD counts.\n"); 222} 223 224bool 225Intel8254Timer::Counter::outputHigh() 226{ 227 return output_high; 228} 229 230void 231Intel8254Timer::Counter::serialize(const string &base, CheckpointOut &cp) const 232{ 233 paramOut(cp, base + ".initial_count", initial_count); 234 paramOut(cp, base + ".latched_count", latched_count); 235 paramOut(cp, base + ".period", period); 236 paramOut(cp, base + ".mode", mode); 237 paramOut(cp, base + ".output_high", output_high); 238 paramOut(cp, base + ".latch_on", latch_on); 239 paramOut(cp, base + ".read_byte", read_byte); 240 paramOut(cp, base + ".write_byte", write_byte); 241 242 Tick event_tick_offset = 0; 243 if (event.scheduled()) 244 event_tick_offset = event.when() - curTick(); 245 paramOut(cp, base + ".event_tick_offset", event_tick_offset); 246} 247 248void 249Intel8254Timer::Counter::unserialize(const string &base, CheckpointIn &cp) 250{ 251 paramIn(cp, base + ".initial_count", initial_count); 252 paramIn(cp, base + ".latched_count", latched_count); 253 paramIn(cp, base + ".period", period); 254 paramIn(cp, base + ".mode", mode); 255 paramIn(cp, base + ".output_high", output_high); 256 paramIn(cp, base + ".latch_on", latch_on); 257 paramIn(cp, base + ".read_byte", read_byte); 258 paramIn(cp, base + ".write_byte", write_byte); 259 260 Tick event_tick_offset = 0; 261 assert(!event.scheduled()); 262 paramIn(cp, base + ".event_tick_offset", event_tick_offset); 263 offset = event_tick_offset; 264} 265 266void 267Intel8254Timer::Counter::startup() 268{ 269 running = true; 270 if ((period > 0) && (offset > 0)) 271 { 272 parent->schedule(event, curTick() + offset); 273 } 274} 275 276Intel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr) 277{ 278 interval = (Tick)(SimClock::Float::s / 1193180.0); 279 counter = c_ptr; 280} 281 282void 283Intel8254Timer::Counter::CounterEvent::process() 284{ 285 switch (counter->mode) { 286 case InitTc: 287 counter->output_high = true; 288 break; 289 case RateGen: 290 case SquareWave: 291 setTo(counter->period); 292 break; 293 default: 294 panic("Unimplemented PITimer mode.\n"); 295 } 296 counter->parent->counterInterrupt(counter->num); 297} 298 299void 300Intel8254Timer::Counter::CounterEvent::setTo(int clocks) 301{ 302 if (clocks == 0) 303 panic("Timer can't be set to go off instantly.\n"); 304 DPRINTF(Intel8254Timer, "Timer set to curTick() + %d\n", 305 clocks * interval); 306 counter->parent->schedule(this, curTick() + clocks * interval); 307} 308 309int 310Intel8254Timer::Counter::CounterEvent::clocksLeft() 311{ 312 if (!scheduled()) 313 return -1; 314 return (when() - curTick() + interval - 1) / interval; 315} 316 317const char * 318Intel8254Timer::Counter::CounterEvent::description() const 319{ 320 return "Intel 8254 Interval timer"; 321} 322 323Tick 324Intel8254Timer::Counter::CounterEvent::getInterval() 325{ 326 return interval; 327} 328 329