View Javadoc

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              // Carry should be set if the (unsigned) result is not true.
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     // Aliases for non-storing versions.
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) { // This is a non-storing instruction with PC destination
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); // Do not flush pipeline if we only set the flags
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 }