Allow gdb to request reads on invalid memory, reply with 0's
[avr-sim.git] / src / Trace.cpp
blobd505fe8d5eea03176e74e1260bb135da59080e19
1 /*
2 * avr-sim: An atmel AVR simulator
3 * Copyright (C) 2008 Tom Haber
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "Trace.h"
20 #include "Core.h"
21 #include "VerboseInfo.h"
22 #include "DebugInterface.h"
24 namespace avr {
26 Trace Trace::trace;
28 Trace::Trace() {
29 for (traceIndex = 0; traceIndex < traceBufferSize; traceIndex++)
30 traceBuffer[traceIndex] = NOTHING;
32 traceIndex = 0;
35 Trace::~Trace() {
36 if( fout.is_open() )
37 fout.close();
40 // type() - return the trace type at 'index'
41 unsigned int Trace::type(unsigned int index) const {
42 unsigned int traceType = get(index) & TYPE_MASK;
43 unsigned int cycleType = traceType & (CYCLE_COUNTER_LO
44 | CYCLE_COUNTER_HI);
45 return cycleType ? cycleType : traceType;
48 // When logging is enabled, the entire trace buffer will be copied to a file.
49 void Trace::enableLogging(const char *fname) {
50 fout.open( fname, std::ios::out | std::ios::binary );
53 void Trace::disableLogging() {
54 fout.close();
57 int Trace::isCycleTrace(unsigned int index, lword *cycle) const {
58 if ( (get(index) & (CYCLE_COUNTER_LO | CYCLE_COUNTER_HI)) == 0)
59 return 0;
61 // Cycle counter
63 // A cycle counter occupies two consecutive trace buffer entries.
64 // We have to determine if the current entry (pointed to by index) is
65 // the high or low integer of the cycle counter.
67 // The upper two bits of the trace are used to decode the two 32-bit
68 // integers that comprise the cycle counter. The encoding algorithm is
69 // optimized for speed:
70 // CYCLE_COUNTER_LO is defined as 1<<31
71 // CYCLE_COUNTER_HI is defined as 1<<30
73 // trace[i] = low 32 bits of cycle counter | CYCLE_COUNTER_LO
74 // trace[i+1] = upper 32 bits of " " | CYCLE_COUNTER_HI | bit 31 of cycle counter
76 // The low 32-bits are always saved in the trace buffer with the msb (CYCLE_COUNTER_LO)
77 // set. However, notice that this bit may've already been set prior to calling trace().
78 // So we need to make sure that we don't lose it. This is done by copying it along
79 // with the high 32-bits of the cycle counter into the next trace buffer location. The
80 // upper 2 bits of the cycle counter are assumed to always be zero (if they're not, gpsim
81 // has been running for a loooonnnggg time!). Bit 30 (CYCLE_COUNTER_HIGH) is always
82 // set in the high 32 bit trace. While bit 31 gets the copy of bit 31 that was over
83 // written in the low 32 bit trace.
85 // Here are some examples:
86 // upper 2 bits
87 // cycle counter | trace[i] trace[i+1] [i] [i+1]
88 //---------------------+----------------------------------------
89 // 0x12345678 | 0x92345678 0x40000000 10 01
90 // 0x44445555 | 0xc4445555 0x40000000 11 01
91 // 0x1111222233334444 | 0xb3334444 0x51112222 10 01
92 // 0x9999aaaa | 0x9999aaaa 0xc0000000 10 11
93 // 0xccccdddd | 0xccccdddd 0xc0000000 11 11
94 // 0xccccddde | 0xccccddde 0xc0000000 11 11
96 // Looking at the upper two bits of trace buffer, we can make these
97 // observations:
99 // 00 - not a cycle counter trace
100 // 10 - current index points at the low int of a cycle counter
101 // 01 - current index points at the high int of a cycle counter
102 // 11 - if traces on either side of the current index are the same
103 // then the current index points to a low int else it points to a high int
105 int j = index; // Assume that the index is pointing to the low int.
106 int k = (j + 1) & traceBufferMask; // and that the next entry is the high int.
108 if ( ((get(j) & CYCLE_COUNTER_LO) != 0)&& ((get(k) & CYCLE_COUNTER_HI))
109 != 0) {
110 if ( (get(j) & CYCLE_COUNTER_HI) != 0) {
111 // The upper two bits of the current trace are set. This means that
112 // the trace is either the high 32 bits or the low 32 bits of the cycle
113 // counter. This ambiguity is resolved by examining the trace buffer on
114 // either side of the current index. If the entry immediately proceeding
115 // this one is not a cycle counter trace, then we know that we're pointing
116 // at the low 32 bits. If the proceeding entry IS a cycle counter trace then
117 // we have two consecutive cycle traces (we already know that the entry
118 // immediately following the current trace index is a cycle counter trace).
119 // Now we know that if have consecutive cycle traces, then they differ by one
120 // count. We only need to look at the low 32 bits of these consecutive
121 // traces to ascertain this.
122 int i = (index - 1) & traceBufferMask; // previous index
123 if ( ((get(i) & (CYCLE_COUNTER_HI | CYCLE_COUNTER_LO)) != 0)
124 &&( ((get(k) - get(i)) & 0x7fffffff) == 1))
125 return 1;
128 // The current index points to the low int and the next entry is
129 // the high int.
130 // extract the ~64bit cycle counter from the trace buffer.
131 if (cycle != 0) {
132 *cycle = get(k) & 0x3fffffff;
133 *cycle = (*cycle << 32) | ((get(j) & 0x7fffffff) | (get(k)
134 & 0x80000000));
137 return 2;
141 return 1;
144 #define hexchar(a) std::hex << int(a) << std::dec
145 void Trace::print(unsigned index, std::ostream & ostr,
146 DebugInterface & dbgi, int /*verbose*/) const {
147 lword cycle;
148 if( isCycleTrace(index, &cycle) == 2 )
149 return;
151 switch( type(index) ) {
152 case NOTHING:
153 ostr << "empty trace cycle"<< std::endl;
154 break;
156 case CYCLE_COUNTER_HI:
157 info(DBG, ostr) << "Cycle: " << cycle << std::endl;
158 break;
160 case RESET: {
161 switch (get(index) & 0xff) {
162 case POR_RESET:
163 ostr << "Power-on reset"<< std::endl;
164 break;
166 case WDT_RESET:
167 ostr << "WDT reset"<< std::endl;
168 break;
170 case JTAG_RESET:
171 ostr << "JTAG reset"<< std::endl;
172 break;
174 case EXT_RESET:
175 ostr << "External reset"<< std::endl;
176 break;
178 case SOFT_RESET:
179 ostr << "Software initiated reset"<< std::endl;
180 break;
182 case BOD_RESET:
183 ostr << "Brown out detection reset"<< std::endl;
184 break;
186 case SIM_RESET:
187 ostr << "Simulation Reset"<< std::endl;
188 break;
190 default:
191 ostr << "unknown reset"<< std::endl;
194 break;
196 case OPCODE_WRITE: {
197 if (type(index-1) == OPCODE_WRITE )
198 ostr << "wrote opcode: " << std::hex << (get(index)&0xffff)
199 << "to pgm memory: "<< (get(index - 1) & 0xffffff)
200 << std::dec << std::endl;
202 break;
204 case REG_WRITE: {
205 byte reg = ((get(index)&0xffff00) >> 8);
206 ostr << "Registers write: address "
207 << dbgi.registerName( reg )
208 << " value = " << hexchar(get(index)&0xff)
209 << std::endl;
211 break;
213 case REG_READ: {
214 byte reg = ((get(index)&0xffff00) >> 8);
215 ostr << "Registers read: address "
216 << dbgi.registerName( reg )
217 << " value = " << hexchar(get(index)&0xff)
218 << std::endl;
220 break;
222 case PC_TRACE: {
223 dword addr = (get(index)&0xffffff);
224 ostr << "PC trace: address "
225 << std::hex << addr << std::dec << ": ";
226 dbgi.trace( ostr, addr );
227 ostr << std::endl;
229 break;
231 default:
236 void Trace::printFrom(unsigned index, std::ostream & ostr, Device & dev, int verbose) const {
237 DebugInterface *dbgi = dev.debugInterface();
238 while( index < traceIndex ) {
239 print( index, ostr, *dbgi, verbose );
240 index++;
243 delete dbgi;
246 void Trace::print(std::ostream & ostr, Device & dev, int verbose) const {
247 DebugInterface *dbgi = dev.debugInterface();
248 unsigned int i = tbi(traceIndex-2);
249 unsigned int k = tbi(traceIndex-1);
251 if( isCycleTrace(i, 0) != 2 )
252 return;
254 unsigned int frame_start = tbi(traceIndex-2);
255 unsigned int frame_end = traceIndex;
257 while( inRange(k,frame_end,frame_start) ) {
258 print(k, ostr, *dbgi, verbose);
259 k = tbi(k-1);
262 delete dbgi;
265 void Trace::list(const char *filename, std::ostream & ostr, Device & dev, int verbose) {
266 std::ifstream f( filename, std::ios::in | std::ios::binary );
267 if( ! f.is_open() )
268 return;
270 DebugInterface *dbgi = dev.debugInterface();
271 traceIndex = traceBufferSize;
272 bool done = false;
273 while( !done ) {
274 f.read( (char*)traceBuffer, traceBufferSize * sizeof(unsigned int) );
275 if( ! f ) {
276 traceIndex = f.gcount() / sizeof(unsigned int);
277 done = true;
280 for(unsigned int index = 0; index < traceIndex; ++index)
281 print( index, ostr, *dbgi, verbose );
284 delete dbgi;