1 package com.tapina.robe.runtime.instruction;
2
3 import com.tapina.robe.runtime.*;
4
5 import java.io.Writer;
6 import java.io.IOException;
7
8 /***
9 * Created by IntelliJ IDEA.
10 * User: gareth
11 * Date: Aug 23, 2003
12 * Time: 10:52:46 PM
13 */
14 public final class DataProcessingInstruction extends Instruction {
15 private final int Rd;
16 private final Operator operator;
17 private final int Rn;
18 private final Operand op2;
19 private final boolean storeResult;
20 private final boolean setConditionCodes;
21
22 private static abstract class ArithmeticOperator extends Operator {
23 public final int addValues(int op1, int op2, CPU cpu, boolean setConditionFlags) {
24 final int result = op1 + op2;
25 if (setConditionFlags) {
26 setZNFlags(result, cpu);
27 setCVFlags(op1, op2, cpu);
28 }
29 return result;
30 }
31
32 void dumpAddition(Writer out, String varName, String arg1, String arg2, boolean setFlags) throws IOException {
33 out.write("final int " + varName + ";\n");
34 out.write("{\n");
35 out.write("final int arg1 = " + arg1 + ";\n");
36 out.write("final int arg2 = " + arg2 + ";\n");
37 out.write(varName + " = arg1 + arg2;\n");
38 if (setFlags) {
39 out.write("Operator.setZNFlags(" + varName + ", cpu);\n");
40 out.write("DataProcessingInstruction.ArithmeticOperator.setCVFlags(arg1, arg2, cpu);\n");
41 }
42 out.write("}\n");
43 }
44
45 /***
46 * Overflow occurs iff the operators are the same sign and the result is different sign.
47 * Carry occurs iff the operators are treated unsigned and the result is not true.
48 * @param op1 first operand to be added
49 * @param op2 second operand to be added
50 * @param cpu cpu on which to set flags
51 */
52 private static void setCVFlags(int op1, int op2, CPU cpu) {
53
54 long lop1 = ((long) op1) & 0x00000000ffffffffL;
55 long lop2 = ((long) op2) & 0x00000000ffffffffL;
56 int result = op1 + op2;
57 long lresult = lop1 + lop2;
58 if ((lresult & 0xffffffff00000000L) == 0) {
59 cpu.clearC();
60 } else {
61 cpu.setC();
62 }
63
64 if ((op1 > 0 && op2 > 0 && result < 0)
65 || (op1 < 0 && op2 < 0 && result >= 0)) {
66 cpu.setV();
67 } else {
68 cpu.clearV();
69 }
70 }
71 }
72
73 private static abstract class LogicalOperator extends Operator {
74 public final int getValue(int op1, int op2, CPU cpu, boolean setConditionFlags) {
75 final int result = getValue(op1, op2);
76 if (setConditionFlags) {
77 setZNFlags(result, cpu);
78 }
79 return result;
80 }
81
82 public void dumpJavaSource(String varName, boolean setFlags, Writer out) throws IOException {
83 out.write("final int " + varName + " = " + getValueExpression() + ";\n");
84 if (setFlags) {
85 out.write("Operator.setZNFlags(" + varName + ", cpu);\n");
86 }
87 }
88
89 abstract int getValue(int op1, int op2);
90 abstract String getValueExpression();
91 }
92
93 public static final Operator ADC = new ArithmeticOperator() {
94 public int getValue(int op1, int op2, CPU cpu, boolean setConditionFlags) {
95 return addValues(op1, cpu.getC()? (op2 + 1) : op2, cpu, setConditionFlags);
96 }
97
98 public void dumpJavaSource(String varName, boolean setFlags, Writer out) throws IOException {
99 dumpAddition(out, varName, "op1", "(cpu.getC()? (op2 + 1) : op2)", setFlags);
100 }
101 };
102
103 public static final Operator ADD = new ArithmeticOperator() {
104 public int getValue(int op1, int op2, CPU cpu, boolean setConditionFlags) {
105 return addValues(op1, op2, cpu, setConditionFlags);
106 }
107
108 public void dumpJavaSource(String varName, boolean setFlags, Writer out) throws IOException {
109 dumpAddition(out, varName, "op1", "op2", setFlags);
110 }
111 };
112 public static final Operator AND = new LogicalOperator() {
113 public int getValue(int op1, int op2) {
114 return op1 & op2;
115 }
116
117 String getValueExpression() {
118 return "op1 & op2";
119 }
120 };
121 public static final Operator BIC = new LogicalOperator() {
122 public int getValue(int op1, int op2) {
123 return op1 & (~op2);
124 }
125
126 String getValueExpression() {
127 return "op1 & (~op2)";
128 }
129 };
130 public static final Operator EOR = new LogicalOperator() {
131 public int getValue(int op1, int op2) {
132 return op1 ^ op2;
133 }
134
135 String getValueExpression() {
136 return "op1 ^ op2";
137 }
138 };
139 public static final Operator MOV = new LogicalOperator() {
140 public int getValue(int op1, int op2) {
141 return op2;
142 }
143
144 String getValueExpression() {
145 return "op2";
146 }
147 };
148 public static final Operator MVN = new LogicalOperator() {
149 public int getValue(int op1, int op2) {
150 return 0xffffffff ^ op2;
151 }
152
153 String getValueExpression() {
154 return "0xffffffff ^ op2";
155 }
156 };
157 public static final Operator ORR = new LogicalOperator() {
158 public int getValue(int op1, int op2) {
159 return op1 | op2;
160 }
161
162 String getValueExpression() {
163 return "op1 | op2";
164 }
165 };
166 public static final Operator RSB = new ArithmeticOperator() {
167 public int getValue(int op1, int op2, CPU cpu, boolean setConditionFlags) {
168 return addValues(op2, -op1, cpu, setConditionFlags);
169 }
170
171 public void dumpJavaSource(String varName, boolean setFlags, Writer out) throws IOException {
172 dumpAddition(out, varName, "op2", "(-op1)", setFlags);
173 }
174 };
175 public static final Operator RSC = new ArithmeticOperator() {
176 public int getValue(int op1, int op2, CPU cpu, boolean setConditionFlags) {
177 return addValues(op2, cpu.getC()? -op1 : -(op1 + 1), cpu, setConditionFlags);
178 }
179
180 public void dumpJavaSource(String varName, boolean setFlags, Writer out) throws IOException {
181 dumpAddition(out, varName, "op2", "(cpu.getC()? -op1 : -(op1 + 1))", setFlags);
182 }
183 };
184 public static final Operator SBC = new ArithmeticOperator() {
185 public int getValue(int op1, int op2, CPU cpu, boolean setConditionFlags) {
186 return addValues(op1, cpu.getC()? -op2 : -(op2 + 1), cpu, setConditionFlags);
187 }
188
189 public void dumpJavaSource(String varName, boolean setFlags, Writer out) throws IOException {
190 dumpAddition(out, varName, "op1", "(cpu.getC()? -op2 : -(op2 + 1))", setFlags);
191 }
192 };
193 public static final Operator SUB = new ArithmeticOperator() {
194 public int getValue(int op1, int op2, CPU cpu, boolean setConditionFlags) {
195 return addValues(op1, -op2, cpu, setConditionFlags);
196 }
197
198 public void dumpJavaSource(String varName, boolean setFlags, Writer out) throws IOException {
199 dumpAddition(out, varName, "op1", "(-op2)", setFlags);
200 }
201 };
202
203 public static final Operator CMN = ADD, CMP = SUB, TEQ = EOR, TST = AND;
204
205 public DataProcessingInstruction(Condition condition, Operator operator, int destinationRegister,
206 int sourceRegister, Operand op2, boolean storeResult, boolean setConditionCodes) {
207 super(condition);
208 this.op2 = op2;
209 this.operator = operator;
210 this.Rd = destinationRegister;
211 this.Rn = sourceRegister;
212 this.storeResult = storeResult;
213 this.setConditionCodes = setConditionCodes;
214 }
215
216 protected final boolean execute(Environment environment) {
217 final CPU cpu = environment.getCpu();
218 final int[] R = cpu.R;
219 final int op1 = Rn != 15? R[Rn] : cpu.getPC();
220 final boolean setFlags = setConditionCodes && Rd != 15;
221 final int result = operator.getValue(op1, op2.getValue(cpu), cpu, setFlags);
222 if (storeResult) {
223 if (Rd == 15 && !setConditionCodes) {
224 cpu.setPC(result);
225 } else {
226 R[Rd] = result;
227 }
228 } else if (Rd == 15) {
229 cpu.setFlags(result);
230 }
231 if (setFlags) {
232 if (operator instanceof LogicalOperator && op2 instanceof RegisterOperand) {
233 final RegisterOperand registerOperand = (RegisterOperand) op2;
234 if (registerOperand.isShiftPerformed()) {
235 if (registerOperand.isCarryFlagSet()) {
236 cpu.setC();
237 } else {
238 cpu.clearC();
239 }
240 }
241 }
242 }
243
244 return (Rd == 15 && storeResult);
245 }
246
247 public void dumpJavaSourceUnconditional(Writer out) throws IOException {
248 out.write("final int op1 = ");
249 if (Rn != 15) {
250 out.write("R[" + Rn + "];\n");
251 } else {
252 out.write("cpu.getPC();\n");
253 }
254 final boolean setFlags = setConditionCodes && Rd != 15;
255 op2.dumpJavaSource("op2", out);
256 operator.dumpJavaSource("result", setFlags, out);
257 if (storeResult) {
258 if (Rd == 15 && !setConditionCodes) {
259 out.write("cpu.getPC(result);\n");
260 } else {
261 out.write("R[" + Rd + "] = result;\n");
262 }
263 } else if (Rd == 15) {
264 out.write("cpu.setFlags(result);\n");
265 }
266 if (setFlags) {
267 if (operator instanceof LogicalOperator && op2 instanceof RegisterOperand) {
268 out.write("if (shiftPeformed) {\n");
269 out.write("if (carryFlag) cpu.setC(); else cpu.clearC();\n");
270 out.write("}\n");
271 }
272 }
273 if (Rd == 15 && storeResult) {
274 out.write("return;");
275 }
276 }
277 }