simulavr  1.1.0
externalirq.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 "externalirq.h"
27 #include "avrerror.h"
28 
30  HWIrqSystem* irqsys,
31  IOSpecialReg *mask,
32  IOSpecialReg *flag):
33  Hardware(c),
34  irqsystem(irqsys)
35 {
36  // connect mask and flag register to getter and setter method
37  mask_reg = mask;
39  flag_reg = flag;
41 
42  // set mask and flag values
43  reg_mask = 0;
44 
45  Reset();
46 }
47 
49  for(unsigned int idx = 0; idx < extirqs.size(); idx++)
50  delete extirqs[idx];
51 }
52 
53 void ExternalIRQHandler::registerIrq(int vector, int irqBit, ExternalIRQ* extirq) {
55  // set mask for relevant bits
56  reg_mask |= 1 << irqBit;
57  // register IRQ, mask bit and vector
58  extirqs.push_back(extirq);
59  vectors.push_back(vector);
60  irqbits.push_back(irqBit);
61  int idx = extirqs.size() - 1;
62  vector2idx[vector] = idx;
63  // communicate index to IRQ
64  extirq->setHandlerIndex(this, idx);
65 }
66 
68  int irqBit = irqbits[idx];
69  if(extirqs[idx]->mustSetFlagOnFire())
70  irq_flag |= (1 << irqBit); // must not set in case of level interrupt
72  if(irq_mask & (1 << irqBit)) // check irq mask and trigger interrupt
73  irqsystem->SetIrqFlag(this, vectors[idx]);
74 }
75 
76 void ExternalIRQHandler::ClearIrqFlag(unsigned int vector) {
77  // get index from vector
78  int idx = vector2idx[vector];
79  // reset flag
80  irq_flag &= ~(1 << irqbits[idx]);
82  // signal: irq done!
83  irqsystem->ClearIrqFlag(vector);
84  // have to trigger again?
85  if(extirqs[idx]->fireAgain()) {
86  if(irq_mask & (1 << irqbits[idx])) // check irq mask and trigger interrupt
87  irqsystem->SetIrqFlag(this, vectors[idx]);
88  }
89 }
90 
91 bool ExternalIRQHandler::IsLevelInterrupt(unsigned int vector) {
92  // get index from vector
93  int idx = vector2idx[vector];
94  return !extirqs[idx]->mustSetFlagOnFire();
95 }
96 
97 bool ExternalIRQHandler::LevelInterruptPending(unsigned int vector) {
98  // get index from vector
99  int idx = vector2idx[vector];
100  return extirqs[idx]->fireAgain() && irq_mask & (1 << irqbits[idx]);
101 }
102 
104  irq_mask = 0;
105  irq_flag = 0;
106  for(unsigned int idx = 0; idx < extirqs.size(); idx++)
107  extirqs[idx]->ResetMode();
108 }
109 
110 unsigned char ExternalIRQHandler::set_from_reg(const IOSpecialReg* reg, unsigned char nv) {
111  if(reg == mask_reg) {
112  // mask register: trigger interrupt, if mask bit is new set and flag is true or fireAgain()
113  for(unsigned int idx = 0; idx < irqbits.size(); idx++) {
114  unsigned char m = 1 << irqbits[idx];
115  if(((nv & m) != 0) &&
116  ((irq_mask & m) == 0) &&
117  (((irq_flag & m) != 0) || extirqs[idx]->fireAgain()))
118  irqsystem->SetIrqFlag(this, vectors[idx]);
119  }
120  // store value
121  irq_mask = nv & reg_mask;
122  } else {
123  // flag register
124  irq_flag ^= nv & reg_mask & irq_flag;
125  // change value
126  nv = (nv & ~reg_mask) | irq_flag;
127  }
128  return nv;
129 }
130 
131 unsigned char ExternalIRQHandler::get_from_client(const IOSpecialReg* reg, unsigned char v) {
132  if(reg == mask_reg)
133  // mask register
134  v = (v & ~reg_mask) | irq_mask;
135  else
136  // flag register
137  v = (v & ~reg_mask) | irq_flag;
138  return v;
139 }
140 
141 ExternalIRQ::ExternalIRQ(IOSpecialReg *ctrl, int ctrlOffset, int ctrlBits) {
142  handlerIndex = -1;
143  handler = NULL;
144  bitshift = ctrlOffset;
145  mask = ((1 << ctrlBits) - 1) << bitshift;
146 
147  ctrl->connectSRegClient(this);
148 }
149 
150 unsigned char ExternalIRQ::set_from_reg(const IOSpecialReg* reg, unsigned char nv) {
151  ChangeMode((nv & mask) >> bitshift);
152  return nv;
153 }
154 
155 unsigned char ExternalIRQ::get_from_client(const IOSpecialReg* reg, unsigned char v) {
156  return (v & ~mask) | (mode << bitshift);
157 }
158 
159 ExternalIRQSingle::ExternalIRQSingle(IOSpecialReg *ctrl, int ctrlOffset, int ctrlBits, Pin *pin, bool _8515mode):
160  ExternalIRQ(ctrl, ctrlOffset, ctrlBits)
161 {
162  state = (bool)*pin;
163  twoBitMode = (ctrlBits == 2);
164  mode8515 = _8515mode;
165  pin->RegisterCallback(this);
166  ResetMode();
167 }
168 
170  // new state
171  bool s = (bool)*pin;
172 
173  // handle changes
174  switch(mode) {
175  case MODE_LEVEL_LOW:
176  // interrupt on low level
177  if(s == false)
178  fireInterrupt();
179  break;
180  case MODE_EDGE_ALL:
181  // interrupt on any logical change
182  if(mode8515)
183  break; // do nothing, because at90s8515 don't support this mode
184  if(s != state)
185  fireInterrupt();
186  break;
187  case MODE_EDGE_FALL:
188  // interrupt on falling edge
189  if((s == false) && (state == true))
190  fireInterrupt();
191  break;
192  case MODE_EDGE_RISE:
193  // interrupt on rising edge
194  if((s == true) && (state == false))
195  fireInterrupt();
196  break;
197  }
198 
199  // store state
200  state = s;
201 }
202 
203 void ExternalIRQSingle::ChangeMode(unsigned char m) {
204  if(twoBitMode)
205  mode = m;
206  else
207  mode = m + MODE_EDGE_FALL;
208  if(mode8515 && mode == MODE_EDGE_ALL)
209  avr_warning("External irq mode ISCx1:ISCx0 = 0:1 isn't supported here");
210 }
211 
213  return (mode == MODE_LEVEL_LOW) && (state == false);
214 }
215 
217  return mode != MODE_LEVEL_LOW;
218 }
219 
221  ExternalIRQ(ctrl, 0, port->GetPortSize())
222 {
223  portSize = port->GetPortSize();
224  for(unsigned int idx = 0; idx < 8; idx++) {
225  if(idx < portSize) {
226  Pin *p = &port->GetPin((unsigned char)idx);
227  pins[idx] = p;
228  state[idx] = (bool)*p;
229  p->RegisterCallback(this);
230  } else {
231  pins[idx] = NULL;
232  state[idx] = false;
233  }
234  }
235  ResetMode();
236 }
237 
239  ExternalIRQ(ctrl, 0, 8)
240 {
241  portSize = 8;
242  for(unsigned int idx = 0; idx < 8; idx++) {
243  if(idx < portSize) {
244  Pin *p = pinList[idx];
245  pins[idx] = p;
246  state[idx] = (bool)*p;
247  p->RegisterCallback(this);
248  } else {
249  pins[idx] = NULL;
250  state[idx] = false;
251  }
252  }
253  ResetMode();
254 }
255 
257  // new state
258  bool s = (bool)*pin;
259 
260  // get bit of port
261  unsigned int idx = 0;
262  unsigned char m = 1;
263  for(; idx < portSize; idx++, m <<= 1) {
264  if(pin == pins[idx]) {
265  // is mask bit is set and logical change?
266  if(((m & mode) != 0) && (s != state[idx]))
267  fireInterrupt();
268  // store new state
269  state[idx] = s;
270  break;
271  }
272  }
273 }
274 
275 // EOF
virtual void ClearIrqFlag(unsigned int vector)
Definition: externalirq.cpp:76
Basic AVR device, contains the core functionality.
Definition: avrdevice.h:66
void PinStateHasChanged(Pin *pin)
virtual unsigned char get_from_client(const IOSpecialReg *reg, unsigned char v)
Pin * pins[8]
pins of port for identifying, which bit is changed
Definition: externalirq.h:141
void hardwareChangeMask(unsigned char val, unsigned char mask)
Definition: rwmem.h:444
ExternalIRQHandler(AvrDevice *core, HWIrqSystem *irqsys, IOSpecialReg *mask, IOSpecialReg *flag)
Definition: externalirq.cpp:29
Pin class, handles input and output to external parts.
Definition: pin.h:98
std::vector< int > irqbits
mapping index to mask bit
Definition: externalirq.h:52
std::vector< ExternalIRQ * > extirqs
list with external IRQ&#39;s
Definition: externalirq.h:47
void registerIrq(int vector, int irqBit, ExternalIRQ *extirq)
Definition: externalirq.cpp:53
Pin & GetPin(unsigned char pinNo)
returns a pin reference of pin with pin number
Definition: hwport.cpp:87
Defines a Port, e.g. a hardware device for GPIO.
Definition: hwport.h:43
void ChangeMode(unsigned char m)
Handle change of control register.
std::map< int, int > vector2idx
mapping irq vector to index
Definition: externalirq.h:53
Fire interrupt on low level.
Definition: externalirq.h:118
bool fireAgain(void)
does the interrupt source fire again? (for interrupt on level)
void setHandlerIndex(ExternalIRQHandler *h, int idx)
register handler and index for signaling interrupt
Definition: externalirq.h:87
IOSpecialReg * flag_reg
the interrupt flag register
Definition: externalirq.h:46
bool twoBitMode
IRQ is controlled by 2 mode bits.
Definition: externalirq.h:114
void connectSRegClient(IOSpecialRegClient *c)
Registers a client to this IO register to inform this client on read or write access.
Definition: rwmem.h:429
bool mode8515
at90s8515 don&#39;t support MODE_EDGE_ALL
Definition: externalirq.h:115
bool mustSetFlagOnFire(void)
does fire interrupt set the interrupt flag? (level interrupt does this not!)
virtual void ResetMode(void)
Reset mode.
Definition: externalirq.h:91
Basic handler for one external IRQ, handles control register.
Definition: externalirq.h:77
void SetIrqFlag(Hardware *, unsigned int vector_index)
Definition: irqsystem.cpp:243
void fireInterrupt(void)
fire a interrupt
Definition: externalirq.h:89
virtual unsigned char set_from_reg(const IOSpecialReg *reg, unsigned char nv)
virtual void Reset(void)
ExternalIRQPort(IOSpecialReg *ctrl, HWPort *port)
bool state
saved state from pin
Definition: externalirq.h:113
virtual unsigned char set_from_reg(const IOSpecialReg *reg, unsigned char nv)
bool state[8]
saved states from all pins
Definition: externalirq.h:140
void PinStateHasChanged(Pin *pin)
IOSpecialReg * mask_reg
the interrupt mask register
Definition: externalirq.h:45
int GetPortSize(void)
returns, how much bits this port controls
Definition: hwport.h:67
void fireInterrupt(int idx)
fire a interupt from IRQ with index
Definition: externalirq.cpp:67
void RegisterCallback(HasPinNotifyFunction *)
Definition: pin.cpp:60
Fire interrupt on falling edge.
Definition: externalirq.h:120
#define avr_warning(...)
Definition: avrerror.h:133
std::vector< int > vectors
mapping index to vector
Definition: externalirq.h:51
Fire interrupt on rising edge.
Definition: externalirq.h:121
unsigned char irq_mask
mask register value for registered IRQ&#39;s
Definition: externalirq.h:48
unsigned int portSize
how much pins the port controls
Definition: externalirq.h:142
HWIrqSystem * irqsystem
pointer to irq system
Definition: externalirq.h:44
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
unsigned char irq_flag
flag register value for registered IRQ&#39;s
Definition: externalirq.h:49
ExternalIRQ(IOSpecialReg *ctrl, int ctrlOffset, int ctrlBits)
virtual unsigned char get_from_client(const IOSpecialReg *reg, unsigned char v)
Fire interrupt on any logical change.
Definition: externalirq.h:119
unsigned char reg_mask
mask for relevant bits in flag and mask register
Definition: externalirq.h:50
virtual bool LevelInterruptPending(unsigned int vector)
Definition: externalirq.cpp:97
void ClearIrqFlag(unsigned int vector_index)
Definition: irqsystem.cpp:258
ExternalIRQSingle(IOSpecialReg *ctrl, int ctrlOffset, int ctrlBits, Pin *pin, bool _8515mode=false)
virtual bool IsLevelInterrupt(unsigned int vector)
Definition: externalirq.cpp:91
unsigned char mode
control mode from control register
Definition: externalirq.h:84