1 //
2 // Copyright (C) 2010 by sinamas <sinamas at users.sourceforge.net>
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License version 2 as
6 // published by the Free Software Foundation.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License version 2 for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // version 2 along with this program; if not, write to the
15 // Free Software Foundation, Inc.,
16 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18
19 #include "interruptrequester.h"
20 #include "savestate.h"
21
22 namespace gambatte {
23
InterruptRequester()24 InterruptRequester::InterruptRequester()
25 : eventTimes_(disabled_time)
26 , minIntTime_(0)
27 , ifreg_(0)
28 , iereg_(0)
29 {
30 }
31
saveState(SaveState & state) const32 void InterruptRequester::saveState(SaveState &state) const {
33 state.mem.minIntTime = minIntTime_;
34 state.mem.IME = ime();
35 state.mem.halted = halted();
36 }
37
loadState(SaveState const & state)38 void InterruptRequester::loadState(SaveState const &state) {
39 minIntTime_ = state.mem.minIntTime;
40 ifreg_ = state.mem.ioamhram.get()[0x10F];
41 iereg_ = state.mem.ioamhram.get()[0x1FF] & 0x1F;
42 intFlags_.set(state.mem.IME, state.mem.halted);
43
44 eventTimes_.setValue<intevent_interrupts>(intFlags_.imeOrHalted() && pendingIrqs()
45 ? minIntTime_
46 : static_cast<unsigned long>(disabled_time));
47 }
48
resetCc(unsigned long oldCc,unsigned long newCc)49 void InterruptRequester::resetCc(unsigned long oldCc, unsigned long newCc) {
50 minIntTime_ = minIntTime_ < oldCc ? 0 : minIntTime_ - (oldCc - newCc);
51
52 if (eventTimes_.value(intevent_interrupts) != disabled_time)
53 eventTimes_.setValue<intevent_interrupts>(minIntTime_);
54 }
55
ei(unsigned long cc)56 void InterruptRequester::ei(unsigned long cc) {
57 intFlags_.setIme();
58 minIntTime_ = cc + 1;
59
60 if (pendingIrqs())
61 eventTimes_.setValue<intevent_interrupts>(minIntTime_);
62 }
63
di()64 void InterruptRequester::di() {
65 intFlags_.unsetIme();
66
67 if (!intFlags_.imeOrHalted())
68 eventTimes_.setValue<intevent_interrupts>(disabled_time);
69 }
70
halt()71 void InterruptRequester::halt() {
72 intFlags_.setHalted();
73
74 if (pendingIrqs())
75 eventTimes_.setValue<intevent_interrupts>(minIntTime_);
76 }
77
unhalt()78 void InterruptRequester::unhalt() {
79 intFlags_.unsetHalted();
80
81 if (!intFlags_.imeOrHalted())
82 eventTimes_.setValue<intevent_interrupts>(disabled_time);
83 }
84
flagIrq(unsigned bit)85 void InterruptRequester::flagIrq(unsigned bit) {
86 ifreg_ |= bit;
87
88 if (intFlags_.imeOrHalted() && pendingIrqs())
89 eventTimes_.setValue<intevent_interrupts>(minIntTime_);
90 }
91
ackIrq(unsigned bit)92 void InterruptRequester::ackIrq(unsigned bit) {
93 ifreg_ ^= bit;
94 di();
95 }
96
setIereg(unsigned iereg)97 void InterruptRequester::setIereg(unsigned iereg) {
98 iereg_ = iereg & 0x1F;
99
100 if (intFlags_.imeOrHalted()) {
101 eventTimes_.setValue<intevent_interrupts>(pendingIrqs()
102 ? minIntTime_
103 : static_cast<unsigned long>(disabled_time));
104 }
105 }
106
setIfreg(unsigned ifreg)107 void InterruptRequester::setIfreg(unsigned ifreg) {
108 ifreg_ = ifreg;
109
110 if (intFlags_.imeOrHalted()) {
111 eventTimes_.setValue<intevent_interrupts>(pendingIrqs()
112 ? minIntTime_
113 : static_cast<unsigned long>(disabled_time));
114 }
115 }
116
117 }
118