00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "externalirq.h"
00027 #include "avrerror.h"
00028
00029 ExternalIRQHandler::ExternalIRQHandler(AvrDevice* c,
00030 HWIrqSystem* irqsys,
00031 IOSpecialReg *mask,
00032 IOSpecialReg *flag):
00033 Hardware(c),
00034 irqsystem(irqsys)
00035 {
00036
00037 mask_reg = mask;
00038 mask_reg->connectSRegClient(this);
00039 flag_reg = flag;
00040 flag_reg->connectSRegClient(this);
00041
00042
00043 reg_mask = 0;
00044
00045 Reset();
00046 }
00047
00048 ExternalIRQHandler::~ExternalIRQHandler(void) {
00049 for(int idx = 0; idx < extirqs.size(); idx++)
00050 delete extirqs[idx];
00051 }
00052
00053 void ExternalIRQHandler::registerIrq(int vector, int irqBit, ExternalIRQ* extirq) {
00054 irqsystem->DebugVerifyInterruptVector(vector, this);
00055
00056 reg_mask |= 1 << irqBit;
00057
00058 extirqs.push_back(extirq);
00059 vectors.push_back(vector);
00060 irqbits.push_back(irqBit);
00061 int idx = extirqs.size() - 1;
00062 vector2idx[vector] = idx;
00063
00064 extirq->setHandlerIndex(this, idx);
00065 }
00066
00067 void ExternalIRQHandler::fireInterrupt(int idx) {
00068 int irqBit = irqbits[idx];
00069 if(extirqs[idx]->mustSetFlagOnFire())
00070 irq_flag |= (1 << irqBit);
00071 flag_reg->hardwareChangeMask(irq_flag, reg_mask);
00072 if(irq_mask & (1 << irqBit))
00073 irqsystem->SetIrqFlag(this, vectors[idx]);
00074 }
00075
00076 void ExternalIRQHandler::ClearIrqFlag(unsigned int vector) {
00077
00078 int idx = vector2idx[vector];
00079
00080 irq_flag &= ~(1 << irqbits[idx]);
00081 flag_reg->hardwareChangeMask(irq_flag, reg_mask);
00082
00083 irqsystem->ClearIrqFlag(vector);
00084
00085 if(extirqs[idx]->fireAgain()) {
00086 if(irq_mask & (1 << irqbits[idx]))
00087 irqsystem->SetIrqFlag(this, vectors[idx]);
00088 }
00089 }
00090
00091 bool ExternalIRQHandler::IsLevelInterrupt(unsigned int vector) {
00092
00093 int idx = vector2idx[vector];
00094 return !extirqs[idx]->mustSetFlagOnFire();
00095 }
00096
00097 bool ExternalIRQHandler::LevelInterruptPending(unsigned int vector) {
00098
00099 int idx = vector2idx[vector];
00100 return extirqs[idx]->fireAgain() && irq_mask & (1 << irqbits[idx]);
00101 }
00102
00103 void ExternalIRQHandler::Reset(void) {
00104 irq_mask = 0;
00105 irq_flag = 0;
00106 for(int idx = 0; idx < extirqs.size(); idx++)
00107 extirqs[idx]->ResetMode();
00108 }
00109
00110 unsigned char ExternalIRQHandler::set_from_reg(const IOSpecialReg* reg, unsigned char nv) {
00111 if(reg == mask_reg) {
00112
00113 for(int idx = 0; idx < irqbits.size(); idx++) {
00114 unsigned char m = 1 << irqbits[idx];
00115 if(((nv & m) != 0) &&
00116 ((irq_mask & m) == 0) &&
00117 (((irq_flag & m) != 0) || extirqs[idx]->fireAgain()))
00118 irqsystem->SetIrqFlag(this, vectors[idx]);
00119 }
00120
00121 irq_mask = nv & reg_mask;
00122 } else {
00123
00124 irq_flag ^= nv & reg_mask & irq_flag;
00125
00126 nv = (nv & ~reg_mask) | irq_flag;
00127 }
00128 return nv;
00129 }
00130
00131 unsigned char ExternalIRQHandler::get_from_client(const IOSpecialReg* reg, unsigned char v) {
00132 if(reg == mask_reg)
00133
00134 v = v & ~reg_mask | irq_mask;
00135 else
00136
00137 v = v & ~reg_mask | irq_flag;
00138 return v;
00139 }
00140
00141 ExternalIRQ::ExternalIRQ(IOSpecialReg *ctrl, int ctrlOffset, int ctrlBits) {
00142 handlerIndex = -1;
00143 handler = NULL;
00144 bitshift = ctrlOffset;
00145 mask = ((1 << ctrlBits) - 1) << bitshift;
00146
00147 ctrl->connectSRegClient(this);
00148 }
00149
00150 unsigned char ExternalIRQ::set_from_reg(const IOSpecialReg* reg, unsigned char nv) {
00151 ChangeMode((nv & mask) >> bitshift);
00152 return nv;
00153 }
00154
00155 unsigned char ExternalIRQ::get_from_client(const IOSpecialReg* reg, unsigned char v) {
00156 return (v & ~mask) | (mode << bitshift);
00157 }
00158
00159 ExternalIRQSingle::ExternalIRQSingle(IOSpecialReg *ctrl, int ctrlOffset, int ctrlBits, Pin *pin, bool _8515mode):
00160 ExternalIRQ(ctrl, ctrlOffset, ctrlBits)
00161 {
00162 state = (bool)*pin;
00163 twoBitMode = (ctrlBits == 2);
00164 mode8515 = _8515mode;
00165 pin->RegisterCallback(this);
00166 ResetMode();
00167 }
00168
00169 void ExternalIRQSingle::PinStateHasChanged(Pin *pin) {
00170
00171 bool s = (bool)*pin;
00172
00173
00174 switch(mode) {
00175 case MODE_LEVEL_LOW:
00176
00177 if(s == false)
00178 fireInterrupt();
00179 break;
00180 case MODE_EDGE_ALL:
00181
00182 if(mode8515)
00183 break;
00184 if(s != state)
00185 fireInterrupt();
00186 break;
00187 case MODE_EDGE_FALL:
00188
00189 if((s == false) && (state == true))
00190 fireInterrupt();
00191 break;
00192 case MODE_EDGE_RISE:
00193
00194 if((s == true) && (state == false))
00195 fireInterrupt();
00196 break;
00197 }
00198
00199
00200 state = s;
00201 }
00202
00203 void ExternalIRQSingle::ChangeMode(unsigned char m) {
00204 if(twoBitMode)
00205 mode = m;
00206 else
00207 mode = m + MODE_EDGE_FALL;
00208 if(mode8515 && mode == MODE_EDGE_ALL)
00209 avr_warning("External irq mode ISCx1:ISCx0 = 0:1 isn't supported here");
00210 }
00211
00212 bool ExternalIRQSingle::fireAgain(void) {
00213 return (mode == MODE_LEVEL_LOW) && (state == false);
00214 }
00215
00216 bool ExternalIRQSingle::mustSetFlagOnFire(void) {
00217 return mode != MODE_LEVEL_LOW;
00218 }
00219
00220 ExternalIRQPort::ExternalIRQPort(IOSpecialReg *ctrl, HWPort *port):
00221 ExternalIRQ(ctrl, 0, port->GetPortSize())
00222 {
00223 portSize = port->GetPortSize();
00224 for(int idx = 0; idx < 8; idx++) {
00225 if(idx < portSize) {
00226 Pin *p = &port->GetPin((unsigned char)idx);
00227 pins[idx] = p;
00228 state[idx] = (bool)*p;
00229 p->RegisterCallback(this);
00230 } else {
00231 pins[idx] = NULL;
00232 state[idx] = false;
00233 }
00234 }
00235 ResetMode();
00236 }
00237
00238 void ExternalIRQPort::PinStateHasChanged(Pin *pin) {
00239
00240 bool s = (bool)*pin;
00241
00242
00243 int idx = 0;
00244 unsigned char m = 1;
00245 for(; idx < portSize; idx++, m <<= 1) {
00246 if(pin == pins[idx]) {
00247
00248 if(((m & mode) != 0) && (s != state[idx]))
00249 fireInterrupt();
00250
00251 state[idx] = s;
00252 break;
00253 }
00254 }
00255 }
00256
00257