2
DrMIPS - Educational MIPS simulator
3
Copyright (C) 2013-2014 Bruno Nova <ei08109@fe.up.pt>
5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
19
package org.feup.brunonova.drmips.gui;
21
import java.io.BufferedReader;
22
import java.io.BufferedWriter;
24
import java.io.FileWriter;
25
import java.io.InputStreamReader;
27
import org.feup.brunonova.drmips.R;
28
import org.feup.brunonova.drmips.simulator.mips.CPU;
30
import android.app.Application;
31
import android.content.Context;
32
import android.content.SharedPreferences;
33
import android.content.pm.PackageInfo;
34
import android.content.pm.PackageManager.NameNotFoundException;
35
import android.os.Build;
36
import android.os.Environment;
37
import android.util.Log;
38
import android.util.TypedValue;
39
import android.widget.Toast;
42
* Global object that represents the application.
43
* <p>It also contains some global constants and parameters.</p>
47
public class DrMIPS extends Application {
48
/** The key of the preference with the version of the last app launch. */
49
public static final String LAST_VERSION_PREF = "last_version";
50
/** The key of the preference with the name of the last code file opened. */
51
public static final String LAST_FILE_PREF = "last_file";
52
/** The key of the preference with the name of the last CPU opened. */
53
public static final String LAST_CPU_PREF = "last_cpu";
54
/** The name of the default CPU to load at startup. */
55
public static final String DEFAULT_CPU = "unicycle.cpu";
56
/** The key of the registers display format preference. */
57
public static final String REGISTER_FORMAT_PREF = "reg_format";
58
/** The key of the datapath display data format preference. */
59
public static final String DATAPATH_DATA_FORMAT_PREF = "datapath_format";
60
/** The key of the assembled code display data format preference. */
61
public static final String ASSEMBLED_CODE_FORMAT_PREF = "assembled_code_format";
62
/** The key of the data memory display data format preference. */
63
public static final String DATA_MEMORY_FORMAT_PREF = "data_memory_format";
64
/** The default performance mode type. */
65
public static final int DEFAULT_PERFORMANCE_TYPE = Util.CPU_PERFORMANCE_TYPE_INDEX;
66
/** The key of the show control path preference. */
67
public static final String THEME_PREF = "theme";
68
/** The key of the show arrows preference. */
69
public static final String SHOW_CONTROL_PATH_PREF = "show_control_path";
70
/** The key of the theme preference. */
71
public static final String SHOW_ARROWS_PREF = "show_arrows";
72
/** The key of the performance mode preference. */
73
public static final String PERFORMANCE_MODE_PREF = "performance_mode";
74
/** The key of the performance mode type preference. */
75
public static final String PERFORMANCE_TYPE_PREF = "performance_type";
76
/** The key of the overlayed data preference. */
77
public static final String OVERLAYED_DATA_PREF = "overlayed_data";
78
/** The default format with which the registers are displayed. */
79
public static final int DEFAULT_REGISTER_FORMAT = Util.DECIMAL_FORMAT_INDEX;
80
/** The default format with which the datapath data is displayed. */
81
public static final int DEFAULT_DATAPATH_DATA_FORMAT = Util.DECIMAL_FORMAT_INDEX;
82
/** The default format with which the assembled code data is displayed. */
83
public static final int DEFAULT_ASSEMBLED_CODE_FORMAT = Util.DECIMAL_FORMAT_INDEX;
84
/** The default format with which the data memory values are displayed. */
85
public static final int DEFAULT_DATA_MEMORY_FORMAT = Util.DECIMAL_FORMAT_INDEX;
86
/** Whether the control path is shown by default. */
87
public static final boolean DEFAULT_SHOW_CONTROL_PATH = true;
88
/** Whether arrows are shown on the wires by default. */
89
public static final boolean DEFAULT_SHOW_ARROWS = true;
90
/** Whether the performance mode is enabled by default. */
91
public static final boolean DEFAULT_PERFORMANCE_MODE = false;
92
/** Whether the in/out tips are shown by default. */
93
public static final boolean DEFAULT_OVERLAYED_DATA = true;
95
/** The current application. */
96
private static DrMIPS app = null;
97
/** The context of the application. */
98
private Context context = null;
99
/** File representation that points to the app's files directory (preferably on the external memory). */
100
private File filesDir = null;
101
/** File representation that points to the CPU directory. */
102
private File cpuDir = null;
103
/** File representation that points to the user created assembly code files directory. */
104
private File codeDir = null;
105
/** The application's version code. */
106
private int versionCode = 0;
107
/** The application's version name. */
108
private String versionName = "";
109
/** The currently loaded CPU. */
110
private CPU cpu = null;
113
public void onCreate() {
116
context = getApplicationContext();
118
try { // Find application's version
119
PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0);
120
versionCode = info.versionCode;
121
versionName = info.versionName;
122
} catch (NameNotFoundException e) {
123
Log.e(getClass().getName(), "Failed to get app version!", e);
126
createDefaultFiles();
130
* Returns a reference to the application.
131
* @return The application.
133
public static DrMIPS getApplication() {
138
* Returns the default theme of the application
139
* <p>For Android 3.0 and higher the default theme is LightTheme.<br />
140
* For versions below 3.0 the default theme is DarkTheme.</p>
141
* @return Application's default theme.
143
public static int getDefaultTheme() {
144
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ? R.style.LightTheme : R.style.DarkTheme;
148
* Returns the currently loaded CPU.
149
* @return The currently loaded CPU.
151
public CPU getCPU() {
156
* Updates the currently loaded CPU.
157
* @param cpu New CPU.
159
public void setCPU(CPU cpu) {
164
* Returns whether there is a CPU loaded.
165
* @return <tt>True</tt> if the is a CPU loaded.
167
public boolean hasCPU() {
172
* Returns the context of the application.
173
* @return Context of the application.
175
public Context getContext() {
180
* Returns the ID of the current theme (from the preferences).
181
* @return ID of the current theme.
183
public int getCurrentTheme() {
184
return DrMIPS.getApplication().getPreferences().getInt(DrMIPS.THEME_PREF, getDefaultTheme());
188
* Converts the given size in dips to pixels.
189
* @param dip Size in dips.
190
* @return Size in pixels
192
public int dipToPx(float dip) {
193
// getResources().getDisplayMetrics().density
194
return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
198
* Returns the file representation that points to the app's files directory (preferably on the external memory).
199
* @return File representation that points to the app's files directory (preferably on the external memory).
201
public File getFilesDir() {
206
* Returns the file representation that points to the CPU directory.
207
* @return File representation that points to the CPU directory.
209
public File getCPUDir() {
214
* Returns the file representation that points to the user created assembly code files directory.
215
* @return File representation that points to the user created assembly code files directory.
217
public File getCodeDir() {
222
* Returns the application's version code.
223
* @return The application's version code.
225
public int getVersionCode() {
230
* Returns the application's preferences.
231
* @return App's preferences.
233
public SharedPreferences getPreferences() {
234
return getSharedPreferences("prefs", MODE_PRIVATE);
238
* Creates the default .cpu and .set files on the sdcard if they don't exist yet.
239
* <p>Also sets the path to the application files directory.</p>
241
private void createDefaultFiles() {
242
// Find if the (preferred) external memory is available
243
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) // external memory available?
244
filesDir = getExternalFilesDir(null);
245
else { // external memory not available! (use internal memory)
246
filesDir = context.getFilesDir(); // Apparently can return null, at least in the emulator
247
Toast.makeText(getContext(), R.string.sdcard_not_available, Toast.LENGTH_SHORT).show();
250
// Create internal directories
251
cpuDir = new File(filesDir.getAbsoluteFile() + File.separator + "cpu");
252
codeDir = new File(filesDir.getAbsolutePath()+ File.separator + "code");
253
if(!cpuDir.exists() && !cpuDir.mkdir()) Log.e(getClass().getName(), "Failed to create CPUs directory!");
254
if(!codeDir.exists() && !codeDir.mkdir()) Log.e(getClass().getName(), "Failed to create code directory!");
256
// Find if the app was upgraded (because the default files could have been upgraded too)
257
boolean upgraded = versionCode > getPreferences().getInt(LAST_VERSION_PREF, -1);
258
SharedPreferences.Editor editor = getPreferences().edit();
259
editor.putInt(LAST_VERSION_PREF, versionCode); // save new "last version"
262
// Copy default CPU files to the memory
263
File unicycleCPU = new File(cpuDir.getAbsoluteFile() + File.separator + "unicycle.cpu");
264
File unicycleNoJumpCPU = new File(cpuDir.getAbsoluteFile() + File.separator + "unicycle-no-jump.cpu");
265
File unicycleNoJumpBranchCPU = new File(cpuDir.getAbsoluteFile() + File.separator + "unicycle-no-jump-branch.cpu");
266
File unicycleExtendedCPU = new File(cpuDir.getAbsoluteFile() + File.separator + "unicycle-extended.cpu");
267
File pipelineCPU = new File(cpuDir.getAbsoluteFile() + File.separator + "pipeline.cpu");
268
File pipelineNoHazardDetectionCPU = new File(cpuDir.getAbsoluteFile() + File.separator + "pipeline-no-hazard-detection.cpu");
269
File pipelineOnlyForwardingCPU = new File(cpuDir.getAbsoluteFile() + File.separator + "pipeline-only-forwarding.cpu");
270
File pipelineExtendedCPU = new File(cpuDir.getAbsoluteFile() + File.separator + "pipeline-extended.cpu");
271
File defaultSet = new File(cpuDir.getAbsoluteFile() + File.separator + "default.set");
272
File defaultNoJumpSet = new File(cpuDir.getAbsoluteFile() + File.separator + "default-no-jump.set");
273
File defaultNoJumpBranchSet = new File(cpuDir.getAbsoluteFile() + File.separator + "default-no-jump-branch.set");
274
File defaultExtendedSet = new File(cpuDir.getAbsoluteFile() + File.separator + "default-extended.set");
275
File defaultExtendedNoJumpSet = new File(cpuDir.getAbsoluteFile() + File.separator + "default-extended-no-jump.set");
276
if(upgraded || !unicycleCPU.exists()) copyResourceFile(R.raw.unicycle_cpu, unicycleCPU);
277
if(upgraded || !unicycleNoJumpCPU.exists()) copyResourceFile(R.raw.unicycle_no_jump_cpu, unicycleNoJumpCPU);
278
if(upgraded || !unicycleNoJumpBranchCPU.exists()) copyResourceFile(R.raw.unicycle_no_jump_branch_cpu, unicycleNoJumpBranchCPU);
279
if(upgraded || !unicycleExtendedCPU.exists()) copyResourceFile(R.raw.unicycle_extended_cpu, unicycleExtendedCPU);
280
if(upgraded || !pipelineCPU.exists()) copyResourceFile(R.raw.pipeline_cpu, pipelineCPU);
281
if(upgraded || !pipelineOnlyForwardingCPU.exists()) copyResourceFile(R.raw.pipeline_only_forwarding_cpu, pipelineOnlyForwardingCPU);
282
if(upgraded || !pipelineNoHazardDetectionCPU.exists()) copyResourceFile(R.raw.pipeline_no_hazard_detection_cpu, pipelineNoHazardDetectionCPU);
283
if(upgraded || !pipelineExtendedCPU.exists()) copyResourceFile(R.raw.pipeline_extended_cpu, pipelineExtendedCPU);
284
if(upgraded || !defaultSet.exists()) copyResourceFile(R.raw.default_set, defaultSet);
285
if(upgraded || !defaultNoJumpSet.exists()) copyResourceFile(R.raw.default_no_jump_set, defaultNoJumpSet);
286
if(upgraded || !defaultNoJumpBranchSet.exists()) copyResourceFile(R.raw.default_no_jump_branch_set, defaultNoJumpBranchSet);
287
if(upgraded || !defaultExtendedSet.exists()) copyResourceFile(R.raw.default_extended_set, defaultExtendedSet);
288
if(upgraded || !defaultExtendedNoJumpSet.exists()) copyResourceFile(R.raw.default_extended_no_jump_set, defaultExtendedNoJumpSet);
292
* Copies the raw file with the given id to the specified path.
293
* @param resource The resource identifier of the file to copy.
294
* @param dest The File representation with the full path to the destination (including the file name).
296
private void copyResourceFile(int resource, File dest) {
297
BufferedReader in = null;
298
BufferedWriter out = null;
302
in = new BufferedReader(new InputStreamReader(getContext().getResources().openRawResource(resource)));
303
out = new BufferedWriter(new FileWriter(dest));
304
while((line = in.readLine()) != null)
305
out.write(line + "\n");
308
Log.e(getClass().getName(), "Failed to copy default file to " + dest.getAbsolutePath() + "!", e);
312
if(in != null) in.close();
313
if(out != null) out.close();
314
} catch(Exception ex) { }