simulavr  1.1.0
irqsystem.cpp
Go to the documentation of this file.
1 /*
2  ****************************************************************************
3  *
4  * simulavr - A simulator for the Atmel AVR family of microcontrollers.
5  * Copyright (C) 2001, 2002, 2003 Klaus Rudolph
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  ****************************************************************************
22  *
23  * $Id$
24  */
25 
26 #include "irqsystem.h"
27 #include "avrdevice.h"
28 #include "funktor.h"
29 #include "systemclock.h"
30 #include "helper.h"
31 #include "avrerror.h"
32 
33 #include "application.h"
34 
35 #include <iostream>
36 #include <assert.h>
37 #include <typeinfo>
38 
39 using namespace std;
40 
41 // global switch to enable irq statistic (default is disabled)
42 bool enableIRQStatistic = false;
43 
44 // if HEXOUT is set the statistic output will be written in hex
45 // if not defined the output is decimal seperated with tabs for reading it with gnumeric
46 //#define HEXOUT
47 
49  setClear =flagCleared-flagSet;
50  setStarted =handlerStarted-flagSet;
51  setFinished =handlerFinished-flagSet;
52  startedFinished =handlerFinished-handlerStarted;
53 }
54 
56  // set the "short" params to the max values so that the first "not dummy" is smaller
57  // and set to the real statistic
58  IrqStatisticEntry longDummy;
59  IrqStatisticEntry shortDummy;
60 
61  longDummy.setClear=0xffffffffffffll;
62  longDummy.setStarted=0xffffffffffffll;
63  longDummy.setFinished=0xffffffffffffll;
64  longDummy.startedFinished=0xffffffffffffll;
65 
66  shortDummy.setClear=0;
67  shortDummy.setStarted=0;
68  shortDummy.setFinished=0;
69  shortDummy.startedFinished=0;
70 
71  long_SetClear=shortDummy;
72  long_SetStarted=shortDummy;
73  long_SetFinished=shortDummy;
74  long_StartedFinished=shortDummy;
75 
76  short_SetClear=longDummy;
77  short_SetStarted=longDummy;
78  short_SetFinished=longDummy;
79  short_StartedFinished=longDummy;
80 }
81 
83  actual.CalcDiffs();
84 
85  if (actual.setClear< short_SetClear.setClear) {
86  short_SetClear=actual;
87  }
88 
89  if (actual.setClear> long_SetClear.setClear) {
90  long_SetClear=actual;
91  }
92 
93  if (actual.setStarted< short_SetStarted.setStarted) {
94  short_SetStarted=actual;
95  }
96 
97  if( actual.setStarted> long_SetStarted.setStarted) {
98  long_SetStarted=actual;
99  }
100 
101  if ( actual.setFinished< short_SetFinished.setFinished) {
102  short_SetFinished= actual;
103  }
104 
105  if ( actual.setFinished > long_SetFinished.setFinished) {
106  long_SetFinished= actual;
107  }
108 
109  if (actual.startedFinished < short_StartedFinished.startedFinished) {
110  short_StartedFinished= actual;
111  }
112 
113  if (actual.startedFinished > long_StartedFinished.startedFinished) {
114  long_StartedFinished= actual;
115  }
116 }
117 
119  if ((actual.flagSet!=0) &&
120  (actual.flagCleared!=0) &&
121  (actual.handlerStarted!=0) &&
122  (actual.handlerFinished!=0))
123  {
124  CalculateStatistic();
125  IrqStatisticEntry emptyDummy;
126  actual=emptyDummy;
127 
128  }
129 }
130 
131 ostream &helpHexOut(ostream &os, unsigned long long x) {
132 #ifdef HEXOUT
133  os << "0x";
134  os.fill('0');
135  os.width(16);
136  os << hex << x << ":" ;
137 #else
138  os<< x << "\t" ;
139 #endif
140  return os;
141 }
142 
143 ostream& operator<<(ostream &os, const IrqStatisticEntry& ise) {
144  os << dec<<"\t";
145  helpHexOut(os, ise.flagSet) ;
146  helpHexOut(os, ise.flagCleared );
147  helpHexOut(os, ise.handlerStarted );
148  helpHexOut(os, ise.handlerFinished );
149  helpHexOut(os, ise.setClear );
150  helpHexOut(os, ise.setStarted );
151  helpHexOut(os, ise.setFinished );
152  helpHexOut(os, ise.startedFinished );
153 
154  return os;
155 }
156 
157 ostream& operator<<(ostream &os, const IrqStatisticPerVector &ispv) {
158  os << "Set->Clear >" << ispv.long_SetClear << endl;
159  os << "Set->Clear <" << ispv.short_SetClear << endl;
160  os << "Set->HandlerStarted >" << ispv.long_SetStarted << endl;
161  os << "Set->HandlerStarted <" << ispv.short_SetStarted << endl;
162 
163  os << "Set->HandlerFinished >" << ispv.long_SetFinished << endl;
164  os << "Set->HandlerFinished <" << ispv.short_SetFinished << endl;
165  os << "Handler Start->Finished >" << ispv.long_StartedFinished << endl;
166  os << "Handler Start->Finished <" << ispv.short_StartedFinished << endl;
167 
168  return os;
169 }
170 
171 
172 ostream& operator<<(ostream &os, const IrqStatistic& is) {
173  map<unsigned int, IrqStatisticPerVector>::const_iterator ii;
174 
175  os << "IRQ STATISTIC" << endl;
176  os << "\tFlagSet\tflagCleared\tHandlerStarted\tHandlerFinished\tSet->Clear\tSet->Started\tSet->Finished\tStarted->Finished"<<endl;
177  for (ii=is.entries.begin(); ii!= is.entries.end(); ii++) {
178  os << "Core: " << is.core->GetFname() <<endl;
179  os << "Statistic for vector: 0x" << hex << ii->first << endl;
180  os << (ii->second);
181  }
182 
183  return os;
184 }
185 
186 HWIrqSystem::HWIrqSystem(AvrDevice* _core, int bytes, int tblsize):
187  TraceValueRegister(_core, "IRQ"),
188  bytesPerVector(bytes),
189  vectorTableSize(tblsize),
190  irqTrace(tblsize),
191  irqStack(tblsize, NULL),
192  irqStackSize(0),
193  core(_core),
194  irqStatistic(_core),
195  debugInterruptTable(tblsize, (Hardware*)NULL)
196 {
197  for(unsigned int i = 0; i < vectorTableSize; i++) {
198  TraceValue* tv = new TraceValue(1, GetTraceValuePrefix() + "VECTOR" + int2str(i));
199  tv->set_written(0);
200  RegisterTraceValue(tv);
201  irqTrace[i] = tv;
202  }
203 }
204 
206  for(unsigned int i = 0; i < vectorTableSize; i++) {
208  irqTrace[i] = NULL;
209  }
210 }
211 
213  return irqStackSize > 0; // if any interrupt is in the list, return true
214 }
215 
216 unsigned int HWIrqSystem::GetNewPc(unsigned int &actualVector) {
217  unsigned int newPC = 0xffffffff;
218 
219  //this vector is implicit sorted, so the priority of the irq vector is known and handled correctly
220  for(unsigned int index = 0; index < vectorTableSize; index++) {
221  if(irqStack[index] == NULL)
222  continue;
223  Hardware* second = irqStack[index];
224 
225  if(second->IsLevelInterrupt(index)) {
226  second->ClearIrqFlag(index);
227  if(second->LevelInterruptPending(index)) {
228  actualVector = index;
229  newPC = index * (bytesPerVector / 2);
230  break;
231  }
232  } else {
233  second->ClearIrqFlag(index);
234  actualVector = index;
235  newPC = index * (bytesPerVector / 2);
236  break;
237  }
238  }
239 
240  return newPC;
241 }
242 
243 void HWIrqSystem::SetIrqFlag(Hardware *hwp, unsigned int vector) {
244  assert(vector < vectorTableSize);
245 
246  irqStack[vector] = hwp;
247  irqStackSize++;
248 
249  if (core->trace_on) {
250  traceOut << core->GetFname() << " interrupt on index " << vector << " is pending" << endl;
251  }
252 
253  if ( irqStatistic.entries[vector].actual.flagSet == 0) { // the actual entry was not used before... fine!
254  irqStatistic.entries[vector].actual.flagSet = SystemClock::Instance().GetCurrentTime();
255  }
256 }
257 
258 void HWIrqSystem::ClearIrqFlag(unsigned int vector) {
259  irqStack[vector] = NULL;
260  irqStackSize--;
261 
262  if (core->trace_on) {
263  traceOut << core->GetFname() << " interrupt on index " << vector << "cleared" << endl;
264  }
265 
266  if (irqStatistic.entries[vector].actual.flagCleared == 0) {
267  irqStatistic.entries[vector].actual.flagCleared = SystemClock::Instance().GetCurrentTime();
268  }
269 
270  irqStatistic.entries[vector].CheckComplete();
271 }
272 
273 void HWIrqSystem::IrqHandlerStarted(unsigned int vector) {
274  irqTrace[vector]->change(1);
275  if (core->trace_on) {
276  traceOut << core->GetFname() << " IrqSystem: IrqHandlerStarted Vec: " << vector << endl;
277  }
278 
279  if (irqStatistic.entries[vector].actual.handlerStarted==0) {
280  irqStatistic.entries[vector].actual.handlerStarted=SystemClock::Instance().GetCurrentTime();
281  }
282  irqStatistic.entries[vector].CheckComplete();
283 }
284 
285 void HWIrqSystem::IrqHandlerFinished(unsigned int vector) {
286  irqTrace[vector]->change(0);
287  if (core->trace_on) {
288  traceOut << core->GetFname() << " IrqSystem: IrqHandler Finished Vec: " << vector << endl;
289  }
290 
291  if (irqStatistic.entries[vector].actual.handlerFinished==0) {
292  irqStatistic.entries[vector].actual.handlerFinished=SystemClock::Instance().GetCurrentTime();
293  }
294  irqStatistic.entries[vector].CheckComplete();
295 }
296 
297 void HWIrqSystem::DebugVerifyInterruptVector(unsigned int vector, const Hardware* source) {
298  assert(vector < vectorTableSize);
299  const Hardware* existing = debugInterruptTable[vector];
300  if(existing == NULL)
301  debugInterruptTable[vector] = source;
302  else
303  assert(existing == source);
304  // The same `source' for multiple `vector' values is OK. It would be pain
305  // for ExternalIRQSingle class to inherit from Hardware just for this test.
306 }
308 {
309  avr_message("Interrupt vector table (for comparison against a datasheet)\n");
310  avr_message("Vector | Address/2 | Source Peripheral (class)\n");
311  for(unsigned i = 0; i < debugInterruptTable.size(); i++)
312  {
313  const Hardware* source = debugInterruptTable[i];
314  const char * handler = (i==0) ? "funct AvrDevice::Reset()"
315  : source ? typeid(*source).name() : "(unsupported or not registered)";
316  avr_message(" %3d | $%04x | %s\n", i+1, i*bytesPerVector/2, handler);
317  }
318 }
319 
322 }
323 
324 //the standard function object for a printable is printing to "out", so we do this here
327  out << *this;
328 }
329 
Basic AVR device, contains the core functionality.
Definition: avrdevice.h:66
SystemClockOffset handlerFinished
Definition: irqsystem.h:48
AvrDevice * core
Definition: irqsystem.h:102
virtual ~HWIrqSystem()
Definition: irqsystem.cpp:205
SystemClockOffset handlerStarted
Definition: irqsystem.h:47
SystemClockOffset flagSet
Definition: irqsystem.h:45
SystemClockOffset GetCurrentTime() const
Returns the current simulation time.
Definition: systemclock.h:95
unsigned int irqStackSize
Definition: irqsystem.h:128
virtual void ClearIrqFlag(unsigned int vector)
Definition: hardware.h:54
IrqStatisticEntry long_SetClear
Definition: irqsystem.h:71
#define avr_message(...)
Definition: avrerror.h:132
IrqStatisticEntry long_StartedFinished
Definition: irqsystem.h:80
HWIrqSystem(AvrDevice *_core, int bytes_per_vector, int number_of_vectors)
Definition: irqsystem.cpp:186
#define traceOut
Definition: avrerror.h:121
void operator()()
Definition: irqsystem.cpp:325
void DebugDumpTable()
Definition: irqsystem.cpp:307
STL namespace.
SystemClockOffset startedFinished
Definition: irqsystem.h:53
IrqStatistic irqStatistic
Definition: irqsystem.h:130
SystemClockOffset setClear
Definition: irqsystem.h:50
void set_written()
Definition: traceval.cpp:99
SystemClockOffset setStarted
Definition: irqsystem.h:51
Build a register for TraceValue&#39;s.
Definition: traceval.h:442
bool enableIRQStatistic
global switch to enable irq statistic (default is disabled)
Definition: irqsystem.cpp:42
void RegisterTraceValue(TraceValue *t)
Registers a TraceValue for this register.
Definition: traceval.cpp:217
unsigned int vectorTableSize
number of entries supported by the device, not bytes
Definition: irqsystem.h:122
static SystemClock & Instance()
Returns the central SystemClock instance for the application.
void SetIrqFlag(Hardware *, unsigned int vector_index)
Definition: irqsystem.cpp:243
IrqStatisticEntry short_StartedFinished
Definition: irqsystem.h:81
ostream & helpHexOut(ostream &os, unsigned long long x)
Definition: irqsystem.cpp:131
IrqStatistic(AvrDevice *)
Definition: irqsystem.cpp:320
void IrqHandlerStarted(unsigned int vector_index)
Definition: irqsystem.cpp:273
bool IsIrqPending()
Definition: irqsystem.cpp:212
std::string int2str(int i)
Convert an int into a string.
Definition: helper.cpp:59
const std::string & GetFname(void)
Return filename from loaded program.
Definition: avrdevice.h:179
unsigned int GetNewPc(unsigned int &vector_index)
returns a new PC pointer if interrupt occurred, -1 otherwise.
Definition: irqsystem.cpp:216
std::vector< Hardware * > irqStack
priority queue of pending interrupts (i.e. waiting to be processed)
Definition: irqsystem.h:127
void RegisterPrintable(Printable *x)
Definition: application.cpp:35
SystemClockOffset setFinished
Definition: irqsystem.h:52
IrqStatisticEntry long_SetFinished
Definition: irqsystem.h:77
IrqStatisticEntry short_SetStarted
Definition: irqsystem.h:75
ostream & operator<<(ostream &os, const IrqStatisticEntry &ise)
Definition: irqsystem.cpp:143
std::vector< TraceValue * > irqTrace
Definition: irqsystem.h:124
const std::string GetTraceValuePrefix(void)
Returns the scope prefix.
Definition: traceval.h:487
void UnregisterTraceValue(TraceValue *t)
Unregisters a TraceValue, remove it from register.
Definition: traceval.cpp:237
std::ostream & out
Definition: printable.h:36
void DebugVerifyInterruptVector(unsigned int vector_index, const Hardware *source)
In datasheets RESET vector is index 1 but we use 0! And not a byte address.
Definition: irqsystem.cpp:297
int trace_on
Definition: avrdevice.h:90
SystemClockOffset flagCleared
Definition: irqsystem.h:46
void ClearIrqFlag(unsigned int vector_index)
Definition: irqsystem.cpp:258
virtual bool LevelInterruptPending(unsigned int vector)
Definition: hardware.h:60
AvrDevice * core
Definition: irqsystem.h:129
IrqStatisticEntry long_SetStarted
Definition: irqsystem.h:74
static Application * GetInstance()
Definition: application.cpp:30
std::map< unsigned int, IrqStatisticPerVector > entries
Definition: irqsystem.h:105
void IrqHandlerFinished(unsigned int vector_index)
Definition: irqsystem.cpp:285
IrqStatisticEntry short_SetFinished
Definition: irqsystem.h:78
virtual bool IsLevelInterrupt(unsigned int vector)
Definition: hardware.h:57
IrqStatisticEntry short_SetClear
Definition: irqsystem.h:72
int bytesPerVector
Definition: irqsystem.h:121
std::vector< const Hardware * > debugInterruptTable
Definition: irqsystem.h:131