1 // -*- Mode: C++; tab-width:2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi:tw=80:et:ts=2:sts=2
3 //
4 // -----------------------------------------------------------------------
5 //
6 // This file is part of RLVM, a RealLive virtual machine clone.
7 //
8 // -----------------------------------------------------------------------
9 //
10 // Copyright (C) 2007 Elliot Glaysher
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
25 //
26 // -----------------------------------------------------------------------
27
28 #include "machine/memory.h"
29
30 #include <iostream>
31 #include <map>
32 #include <string>
33
34 #include "libreallive/gameexe.h"
35 #include "libreallive/intmemref.h"
36 #include "machine/rlmachine.h"
37 #include "utilities/exception.h"
38 #include "utilities/string_utilities.h"
39
40 using std::make_pair;
41
42 const IntegerBank_t LOCAL_INTEGER_BANKS = {
43 make_pair(libreallive::INTA_LOCATION, 'A'),
44 make_pair(libreallive::INTB_LOCATION, 'B'),
45 make_pair(libreallive::INTC_LOCATION, 'C'),
46 make_pair(libreallive::INTD_LOCATION, 'D'),
47 make_pair(libreallive::INTE_LOCATION, 'E'),
48 make_pair(libreallive::INTF_LOCATION, 'F')};
49
50 const IntegerBank_t GLOBAL_INTEGER_BANKS = {
51 make_pair(libreallive::INTG_LOCATION, 'G'),
52 make_pair(libreallive::INTZ_LOCATION, 'Z')};
53
54 // -----------------------------------------------------------------------
55 // GlobalMemory
56 // -----------------------------------------------------------------------
GlobalMemory()57 GlobalMemory::GlobalMemory() {
58 memset(intG, 0, sizeof(intG));
59 memset(intZ, 0, sizeof(intZ));
60 }
61
62 // -----------------------------------------------------------------------
63 // LocalMemory
64 // -----------------------------------------------------------------------
LocalMemory()65 LocalMemory::LocalMemory() { reset(); }
66
LocalMemory(dont_initialize)67 LocalMemory::LocalMemory(dont_initialize) {}
68
reset()69 void LocalMemory::reset() {
70 memset(intA, 0, sizeof(intA));
71 memset(intB, 0, sizeof(intB));
72 memset(intC, 0, sizeof(intC));
73 memset(intD, 0, sizeof(intD));
74 memset(intE, 0, sizeof(intE));
75 memset(intF, 0, sizeof(intF));
76
77 for (int i = 0; i < SIZE_OF_MEM_BANK; ++i)
78 strS[i].clear();
79 for (int i = 0; i < SIZE_OF_NAME_BANK; ++i)
80 local_names[i].clear();
81 }
82
83 // -----------------------------------------------------------------------
84 // Memory
85 // -----------------------------------------------------------------------
Memory(RLMachine & machine,Gameexe & gameexe)86 Memory::Memory(RLMachine& machine, Gameexe& gameexe)
87 : global_(new GlobalMemory), local_(), machine_(machine) {
88 ConnectIntVarPointers();
89
90 InitializeDefaultValues(gameexe);
91 }
92
Memory(RLMachine & machine,int slot)93 Memory::Memory(RLMachine& machine, int slot)
94 : global_(machine.memory().global_),
95 local_(dont_initialize()),
96 machine_(machine) {
97 ConnectIntVarPointers();
98 }
99
~Memory()100 Memory::~Memory() {}
101
ConnectIntVarPointers()102 void Memory::ConnectIntVarPointers() {
103 int_var[0] = local_.intA;
104 int_var[1] = local_.intB;
105 int_var[2] = local_.intC;
106 int_var[3] = local_.intD;
107 int_var[4] = local_.intE;
108 int_var[5] = local_.intF;
109 int_var[6] = global_->intG;
110 int_var[7] = global_->intZ;
111
112 original_int_var[0] = &local_.original_intA;
113 original_int_var[1] = &local_.original_intB;
114 original_int_var[2] = &local_.original_intC;
115 original_int_var[3] = &local_.original_intD;
116 original_int_var[4] = &local_.original_intE;
117 original_int_var[5] = &local_.original_intF;
118 original_int_var[6] = NULL;
119 original_int_var[7] = NULL;
120 }
121
GetStringValue(int type,int location)122 const std::string& Memory::GetStringValue(int type, int location) {
123 if (location > (SIZE_OF_MEM_BANK - 1))
124 throw rlvm::Exception(
125 "Invalid range access in RLMachine::set_string_value");
126
127 switch (type) {
128 case libreallive::STRK_LOCATION:
129 if ((location + 1) > machine_.CurrentStrKBank().size())
130 machine_.CurrentStrKBank().resize(location + 1);
131 return machine_.CurrentStrKBank()[location];
132 case libreallive::STRM_LOCATION:
133 return global_->strM[location];
134 case libreallive::STRS_LOCATION:
135 return local_.strS[location];
136 default:
137 throw rlvm::Exception("Invalid type in RLMachine::get_string_value");
138 }
139 }
140
SetStringValue(int type,int number,const std::string & value)141 void Memory::SetStringValue(int type, int number, const std::string& value) {
142 if (number > (SIZE_OF_MEM_BANK - 1))
143 throw rlvm::Exception(
144 "Invalid range access in RLMachine::set_string_value");
145
146 switch (type) {
147 case libreallive::STRK_LOCATION:
148 if ((number + 1) > machine_.CurrentStrKBank().size())
149 machine_.CurrentStrKBank().resize(number + 1);
150 machine_.CurrentStrKBank()[number] = value;
151 break;
152 case libreallive::STRM_LOCATION:
153 global_->strM[number] = value;
154 break;
155 case libreallive::STRS_LOCATION: {
156 // Possibly record the original value for a piece of local memory.
157 std::map<int, std::string>::iterator it =
158 local_.original_strS.find(number);
159 if (it == local_.original_strS.end()) {
160 local_.original_strS.insert(
161 std::make_pair(number, local_.strS[number]));
162 }
163 local_.strS[number] = value;
164 break;
165 }
166 default:
167 throw rlvm::Exception("Invalid type in RLMachine::set_string_value");
168 }
169 }
170
CheckNameIndex(int index,const std::string & name) const171 void Memory::CheckNameIndex(int index, const std::string& name) const {
172 if (index > (SIZE_OF_NAME_BANK - 1)) {
173 std::ostringstream oss;
174 oss << "Invalid index " << index << " in " << name;
175 throw rlvm::Exception(oss.str());
176 }
177 }
178
SetName(int index,const std::string & name)179 void Memory::SetName(int index, const std::string& name) {
180 CheckNameIndex(index, "Memory::set_name");
181 global_->global_names[index] = name;
182 }
183
GetName(int index) const184 const std::string& Memory::GetName(int index) const {
185 CheckNameIndex(index, "Memory::get_name");
186 return global_->global_names[index];
187 }
188
SetLocalName(int index,const std::string & name)189 void Memory::SetLocalName(int index, const std::string& name) {
190 CheckNameIndex(index, "Memory::set_local_name");
191 local_.local_names[index] = name;
192 }
193
GetLocalName(int index) const194 const std::string& Memory::GetLocalName(int index) const {
195 CheckNameIndex(index, "Memory::set_local_name");
196 return local_.local_names[index];
197 }
198
HasBeenRead(int scenario,int kidoku) const199 bool Memory::HasBeenRead(int scenario, int kidoku) const {
200 std::map<int, boost::dynamic_bitset<>>::const_iterator it =
201 global_->kidoku_data.find(scenario);
202
203 if ((it != global_->kidoku_data.end()) &&
204 (static_cast<size_t>(kidoku) < it->second.size()))
205 return it->second.test(kidoku);
206
207 return false;
208 }
209
RecordKidoku(int scenario,int kidoku)210 void Memory::RecordKidoku(int scenario, int kidoku) {
211 boost::dynamic_bitset<>& bitset = global_->kidoku_data[scenario];
212 if (bitset.size() <= static_cast<size_t>(kidoku))
213 bitset.resize(kidoku + 1, false);
214
215 bitset[kidoku] = true;
216 }
217
TakeSavepointSnapshot()218 void Memory::TakeSavepointSnapshot() {
219 local_.original_intA.clear();
220 local_.original_intB.clear();
221 local_.original_intC.clear();
222 local_.original_intD.clear();
223 local_.original_intE.clear();
224 local_.original_intF.clear();
225 local_.original_strS.clear();
226 }
227
228 // static
ConvertLetterIndexToInt(const std::string & value)229 int Memory::ConvertLetterIndexToInt(const std::string& value) {
230 int total = 0;
231
232 if (value.size() == 1) {
233 total += (value[0] - 'A');
234 } else if (value.size() == 2) {
235 total += 26 * ((value[0] - 'A') + 1);
236 total += (value[1] - 'A');
237 } else {
238 throw rlvm::Exception("Invalid value in convert_name_var!");
239 }
240
241 return total;
242 }
243
InitializeDefaultValues(Gameexe & gameexe)244 void Memory::InitializeDefaultValues(Gameexe& gameexe) {
245 // Note: We ignore the \#NAME_MAXLEN variable because manual allocation is
246 // error prone and for losers.
247 GameexeFilteringIterator end = gameexe.filtering_end();
248 for (GameexeFilteringIterator it = gameexe.filtering_begin("NAME.");
249 it != end;
250 ++it) {
251 try {
252 SetName(ConvertLetterIndexToInt(it->GetKeyParts().at(1)),
253 RemoveQuotes(it->ToString()));
254 }
255 catch (...) {
256 std::cerr << "WARNING: Invalid format for key " << it->key() << std::endl;
257 }
258 }
259
260 for (GameexeFilteringIterator it = gameexe.filtering_begin("LOCALNAME.");
261 it != end;
262 ++it) {
263 try {
264 SetLocalName(ConvertLetterIndexToInt(it->GetKeyParts().at(1)),
265 RemoveQuotes(it->ToString()));
266 }
267 catch (...) {
268 std::cerr << "WARNING: Invalid format for key " << it->key() << std::endl;
269 }
270 }
271 }
272