simulavr  1.1.0
hwstack.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 "hwstack.h"
27 #include "avrerror.h"
28 #include "avrmalloc.h"
29 #include "flash.h"
30 #include <assert.h>
31 #include <cstdio> // NULL
32 
33 using namespace std;
34 
36  core(c),
37  m_ThreadList(*c)
38 {
39  Reset();
40 }
41 
43  typedef multimap<unsigned long, Funktor *>::iterator I;
44  for(I i = returnPointList.begin(); i != returnPointList.end(); ++i) {
45  delete i->second;
46  }
47 }
48 
49 void HWStack::Reset(void) {
50  returnPointList.clear();
51  stackPointer = 0;
53 }
54 
56  typedef multimap<unsigned long, Funktor *>::iterator I;
57  pair<I,I> l = returnPointList.equal_range(stackPointer);
58 
59  for(I i = l.first; i != l.second; i++) {
60  (*(i->second))(); //execute Funktor
61  delete i->second; //and delete it
62  }
63  returnPointList.erase(l.first, l.second);
64 }
65 
66 void HWStack::SetReturnPoint(unsigned long stackPointer, Funktor *f) {
67  returnPointList.insert(make_pair(stackPointer, f));
68 }
69 
70 HWStackSram::HWStackSram(AvrDevice *c, int bs, bool initRE):
71  HWStack(c),
72  TraceValueRegister(c, "STACK"),
73  initRAMEND(initRE),
74  sph_reg(this, "SPH",
75  this, &HWStackSram::GetSph, &HWStackSram::SetSph),
76  spl_reg(this, "SPL",
77  this, &HWStackSram::GetSpl, &HWStackSram::SetSpl)
78 {
79  stackCeil = 1 << bs; // TODO: The number of bits is unable to acurately represent 0x460 ceiling of ATmega8: has 1024 B RAM (0x400) and 32+64 (0x60) registers.
80  Reset();
81 }
82 
84  returnPointList.clear();
85  if(initRAMEND)
87  core->GetMemIOSize() +
88  core->GetMemRegisterSize() - 1;
89  else
90  stackPointer = 0;
92 }
93 
94 void HWStackSram::Push(unsigned char val) {
95  core->SetRWMem(stackPointer, val);
96  stackPointer--;
98 
100  sph_reg.hardwareChange((stackPointer & 0x00ff00)>>8);
101 
102  if(core->trace_on == 1)
103  traceOut << "SP=0x" << hex << stackPointer << " 0x" << int(val) << dec << " ";
106 
107  // measure stack usage, calculate lowest stack pointer
110 }
111 
112 unsigned char HWStackSram::Pop() {
113  stackPointer++;
115 
116  spl_reg.hardwareChange(stackPointer & 0x0000ff);
117  sph_reg.hardwareChange((stackPointer & 0x00ff00)>>8);
118 
119  if(core->trace_on == 1)
120  traceOut << "SP=0x" << hex << stackPointer << " 0x" << int(core->GetRWMem(stackPointer)) << dec << " ";
123  return core->GetRWMem(stackPointer);
124 }
125 
126 void HWStackSram::PushAddr(unsigned long addr) {
127  // low byte first, then high byte
128  Push(addr & 0xff);
129  addr >>= 8;
130  Push(addr & 0xff);
131  if(core->PC_size == 3) {
132  addr >>= 8;
133  Push(addr & 0xff);
134  }
135 }
136 
137 unsigned long HWStackSram::PopAddr() {
138  // high byte first, then low byte
139  unsigned long val = Pop();
140  val <<= 8;
141  val += Pop();
142  if(core->PC_size == 3) {
143  val <<= 8;
144  val += Pop();
145  }
146  return val;
147 }
148 
149 void HWStackSram::SetSpl(unsigned char val) {
150  uint32_t oldSP = stackPointer;
151  stackPointer &= ~0xff;
152  stackPointer += val;
153  stackPointer %= stackCeil; // zero the not used bits
154 
155  spl_reg.hardwareChange(stackPointer & 0x0000ff);
156 
157  if(core->trace_on == 1)
158  traceOut << "SP=0x" << hex << stackPointer << dec << " " ;
159  if(oldSP != stackPointer)
162 }
163 
164 void HWStackSram::SetSph(unsigned char val) {
165  uint32_t oldSP = stackPointer;
166  if(stackCeil <= 0x100)
167  avr_warning("assignment to non existent SPH (value=0x%x)", (unsigned int)val);
168  stackPointer &= ~0xff00;
169  stackPointer += val << 8;
170  stackPointer %= stackCeil; // zero the not used bits
171 
172  sph_reg.hardwareChange((stackPointer & 0x00ff00)>>8);
173 
174  if(core->trace_on == 1)
175  traceOut << "SP=0x" << hex << stackPointer << dec << " " ;
176  if(oldSP != stackPointer)
179 }
180 
181 unsigned char HWStackSram::GetSph() {
183  return (stackPointer & 0xff00) >> 8;
184 }
185 
186 unsigned char HWStackSram::GetSpl() {
188  return stackPointer & 0xff;
189 }
192 }
193 
195  HWStack(c),
196  TraceValueRegister(c, "STACK") {
197  stackArea = avr_new(unsigned long, 3);
198  trace_direct(this, "PTR", &stackPointer);
199  Reset();
200 }
201 
204 }
205 
207  returnPointList.clear();
208  stackPointer = 3;
210 }
211 
212 void ThreeLevelStack::Push(unsigned char val) {
213  avr_error("Push method isn't available on TreeLevelStack");
214 }
215 
216 unsigned char ThreeLevelStack::Pop() {
217  avr_error("Pop method isn't available on TreeLevelStack");
218  return 0;
219 }
220 
221 void ThreeLevelStack::PushAddr(unsigned long addr) {
222  stackArea[2] = stackArea[1];
223  stackArea[1] = stackArea[0];
224  stackArea[0] = addr;
225  if(stackPointer > 0)
226  stackPointer--;
229  if(stackPointer == 0)
230  avr_warning("stack overflow");
231 }
232 
233 unsigned long ThreeLevelStack::PopAddr() {
234  unsigned long val = stackArea[0];
235  stackArea[0] = stackArea[1];
236  stackArea[1] = stackArea[2];
237  stackPointer++;
238  if(stackPointer > 3) {
239  stackPointer = 3;
240  avr_warning("stack underflow");
241  }
242  return val;
243 }
244 
246  : m_core(core)
247 {
249  m_last_SP_read = 0x0000;
250  m_last_SP_writen = 0x0000;
251  m_cur_thread = 0; // we are running main() thread
252 
253  Thread * main_thread = new Thread;
254  main_thread->m_sp = 0; // invalid address, GDB never sees it, updated on switch
255  main_thread->m_ip = 0;
256  main_thread->m_alive = true;
257  m_threads.push_back(main_thread);
258 }
260 {
261  OnReset();
262 }
264 {
265  for(unsigned int i = 0; i < m_threads.size(); i++) {
266  Thread * p = m_threads[i];
267  delete p;
268  }
269  m_threads.resize(0);
270 }
271 
273 {
275  assert(m_on_call_sp != 0x0000);
276  m_on_call_ip = m_core.PC * 2;
277  Thread * old = m_threads[m_cur_thread];
278  for(unsigned int i = 0; i < 32; i++) {
279  old->registers[i] = m_core.GetCoreReg(i);
280  }
281 }
282 
283 void ThreadList::OnSPRead(int SP_value)
284 {
285  assert(0 <= SP_value && SP_value <= 0xFFFF);
286  assert(0 != SP_value); // SP must not point to register area
288  m_last_SP_read = SP_value;
289 }
290 
291 void ThreadList::OnSPWrite( int new_SP )
292 {
294  return;
296  m_last_SP_writen = new_SP;
297 }
298 
300 {
302  m_last_SP_read = 0x0000;
303  m_last_SP_writen = 0x0000;
304 }
305 
307 {
309  {
311  m_last_SP_read = 0x0000;
312  m_last_SP_writen = 0x0000;
313  return;
314  }
316  int addr = m_core.PC * 2;
317  assert(0 <= m_cur_thread && m_cur_thread < (int) m_threads.size());
318  Thread * old = m_threads[m_cur_thread];
319  assert(m_on_call_sp != 0x0000);
320  old->m_sp = m_on_call_sp;
321  old->m_ip = m_on_call_ip;
322  old->m_alive = true; // does not on FreeRTOS's vPortYieldFromTick: (m_last_SP_read != 0x0000);
323 
325  if(n == -1) {
326  m_threads.push_back( new Thread);
327  n = m_threads.size() - 1;
328  }
329  Thread * new_thread = m_threads[n];
330  new_thread->m_sp = 0x0000; // invalid
331  new_thread->m_ip = 0x0000;
332  new_thread->m_alive = true;
333 
334  avr_message("Context switch at PC 0x%05x from thread %d to %d\n", addr, m_cur_thread, n);
335  m_cur_thread = n;
336 }
337 
338 int ThreadList::GetThreadBySP(int sp) const
339 {
340  for(unsigned int i = 0; i < m_threads.size(); i++) {
341  Thread * p = m_threads[i];
342  if(p->m_sp == sp)
343  return i;
344  }
345  return -1; // not found
346 }
347 
349 {
350  return m_cur_thread + 1;
351 }
352 
353 const Thread * ThreadList::GetThreadFromGDB(int thread_id) const
354 {
355  assert(thread_id >= 1);
356  unsigned int index = thread_id - 1;
357  assert(index < m_threads.size());
358  return m_threads[index];
359 }
360 bool ThreadList::IsGDBThreadAlive(int thread_id) const
361 {
362  assert(thread_id >= 1);
363  unsigned int index = thread_id - 1;
364  if(index >= m_threads.size())
365  return false;
366 
367  Thread * p = m_threads[index];
368  return p->m_alive;
369 }
370 unsigned int ThreadList::GetCount() const
371 {
372  return m_threads.size();
373 }
374 
375 /* EOF */
uint32_t lowestStackPointer
marker: lowest stackpointer used by program
Definition: hwstack.h:96
AvrFlash * Flash
Definition: avrdevice.h:98
unsigned long * stackArea
Definition: hwstack.h:162
Basic AVR device, contains the core functionality.
Definition: avrdevice.h:66
unsigned long stackCeil
Definition: hwstack.h:134
enum ThreadList::@11 m_phase_of_switch
virtual void Reset()
Resets stack pointer and listener table.
Definition: hwstack.cpp:206
bool m_alive
Definition: hwstack.h:46
unsigned int GetMemIRamSize(void)
Get configured internal RAM size.
Definition: avrdevice.h:194
virtual void PushAddr(unsigned long addr)
Pushs a address to stack.
Definition: hwstack.cpp:221
void avr_free(void *ptr)
Free malloc&#39;d memory.
Definition: avrmalloc.cpp:182
void SetReturnPoint(unsigned long stackPointer, Funktor *listener)
Subscribes a Listener for a return address.
Definition: hwstack.cpp:66
Implements a stack with stack register using RAM as stackarea.
Definition: hwstack.h:131
#define avr_message(...)
Definition: avrerror.h:132
const Thread * GetThreadFromGDB(int thread_id) const
Definition: hwstack.cpp:353
virtual void Reset()
Resets stack pointer and listener table.
Definition: hwstack.cpp:49
void OnSPReadByTarget()
Definition: hwstack.cpp:190
#define traceOut
Definition: avrerror.h:121
virtual void Push(unsigned char val)
Pushs one byte to stack.
Definition: hwstack.cpp:212
virtual void Reset()
Resets stack pointer and listener table.
Definition: hwstack.cpp:83
STL namespace.
bool SetRWMem(unsigned addr, unsigned char val)
Set a value to RW memory cell.
Definition: avrdevice.cpp:452
virtual unsigned long PopAddr()
Pops a address from stack.
Definition: hwstack.cpp:233
int m_on_call_sp
Definition: hwstack.h:63
virtual void PushAddr(unsigned long addr)
Pushs a address to stack.
Definition: hwstack.cpp:126
uint32_t stackPointer
current value of stack pointer
Definition: hwstack.h:95
void SetSpl(unsigned char)
Definition: hwstack.cpp:149
Implements a stack register with stack logic.
Definition: hwstack.h:91
void OnPush()
Definition: hwstack.cpp:299
int m_last_SP_read
Definition: hwstack.h:61
#define avr_error(...)
Definition: avrerror.h:135
const unsigned int PC_size
Definition: avrdevice.h:96
AvrDevice * core
Link to device.
Definition: hwstack.h:94
unsigned char GetSph()
Definition: hwstack.cpp:181
ThreeLevelStack(AvrDevice *core)
Definition: hwstack.cpp:194
unsigned char GetRWMem(unsigned addr)
Get a value of RW memory cell.
Definition: avrdevice.cpp:446
HWStack(AvrDevice *core)
Creates a stack instance.
Definition: hwstack.cpp:35
std::vector< Thread * > m_threads
List of known threads. First addition (of main) is special.
Definition: hwstack.h:59
void OnSPRead(int SP_value)
Definition: hwstack.cpp:283
Build a register for TraceValue&#39;s.
Definition: traceval.h:442
bool initRAMEND
Definition: hwstack.h:135
void CheckReturnPoints()
Run functions registered for current stack address and delete them.
Definition: hwstack.cpp:55
virtual unsigned long PopAddr()
Pops a address from stack.
Definition: hwstack.cpp:137
unsigned int GetMemIOSize(void)
Get configured IO memory space size.
Definition: avrdevice.h:190
int m_cur_thread
Currently running thread. (Thread index used for querying by GDB is in GdbServer.) ...
Definition: hwstack.h:66
virtual unsigned char Pop()
Pops one byte from stack.
Definition: hwstack.cpp:216
std::multimap< unsigned long, Funktor * > returnPointList
Maps adresses to listeners for return addresses.
Definition: hwstack.h:97
void SetSph(unsigned char)
Definition: hwstack.cpp:164
unsigned int GetCount() const
Definition: hwstack.cpp:370
void OnPop()
Definition: hwstack.cpp:306
#define avr_new(type, count)
Macro for allocating memory.
Definition: avrmalloc.h:40
virtual void Push(unsigned char val)
Pushs one byte to stack.
Definition: hwstack.cpp:94
IOReg< HWStackSram > sph_reg
Definition: hwstack.h:154
bool LooksLikeContextSwitch(unsigned int addr) const
Definition: flash.cpp:131
unsigned char GetSpl()
Definition: hwstack.cpp:186
int m_on_call_ip
Definition: hwstack.h:64
int GetCurrentThreadForGDB() const
Get GDB-style thread ID (the first is 1)
Definition: hwstack.cpp:348
#define avr_warning(...)
Definition: avrerror.h:133
int m_last_SP_writen
Definition: hwstack.h:62
unsigned char GetCoreReg(unsigned addr)
Get a value from core register.
Definition: avrdevice.cpp:459
unsigned int GetMemRegisterSize(void)
Get configured register space size.
Definition: avrdevice.h:192
bool IsGDBThreadAlive(int thread_id) const
GDB-style thread ID (the first is 1)
Definition: hwstack.cpp:360
void hardwareChange(unsigned char val)
Definition: rwmem.h:318
Definition: hwstack.h:40
void OnCall()
Definition: hwstack.cpp:272
unsigned char registers[32]
Definition: hwstack.h:49
virtual unsigned char Pop()
Pops one byte from stack.
Definition: hwstack.cpp:112
int trace_on
Definition: avrdevice.h:90
HWStackSram(AvrDevice *core, int bitsize, bool initRAMEND=false)
Creates a stack instance.
Definition: hwstack.cpp:70
unsigned long GetStackPointer() const
Returns current stack pointer value.
Definition: hwstack.h:116
virtual ~HWStack()
Definition: hwstack.cpp:42
ThreadList(AvrDevice &core)
Definition: hwstack.cpp:245
ThreadList m_ThreadList
Definition: hwstack.h:103
HWStack * stack
Definition: avrdevice.h:131
unsigned int PC
Definition: avrdevice.h:93
int m_ip
address (in bytes, not index)
Definition: hwstack.h:45
void OnReset()
Definition: hwstack.cpp:263
IOReg< HWStackSram > spl_reg
Definition: hwstack.h:155
int GetThreadBySP(int SP) const
Search threads.
Definition: hwstack.cpp:338
int m_sp
Stack Pointer. Address 0x0000 is invalid; used for running thread. GDB never sees the 0...
Definition: hwstack.h:44
AvrDevice & m_core
Definition: hwstack.h:67
TraceValue * trace_direct(TraceValueRegister *t, const std::string &name, const bool *val)
Register a directly traced bool value.
Definition: traceval.cpp:788
void OnSPWrite(int new_SP)
Definition: hwstack.cpp:291