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