Scoreboard and Tomasulo
1. Parallel Computing
Parallelism, playing a role as important as Memory Hierarchy, can be implemented in different levels in a computer architecture:
What I want to talk about now is the Instruction-Level Parallelism (ILP), which can be implemented by pipelining with forwarding unit and hazard detection unit in MIPS32 architecture as we have learned in EI209. The issue at that time was to address three types of pipeline hazard: Data Hazard, Structural Hazard and Control Hazard.
However, ILP can be advanced if we allow out-of-order execution of instructions so that data hazard stalls can be further reduced. This is what we call Dynamic Scheduling, which can address Name Dependences in a block of program. There are another two strategies called Dynamic Branch Prediction and Speculation, which can minimize control stalls.
Now I will show you my demo programs of two ILP instances that make good use of Dynamic Scheduling: one is Scoreboard Algorithm in CDC6600, another is Tomasulo Algorithm in IBM360.
Sample Input:
6 LD F6 %34 R2 LD F2 %45 R3 MULTD F0 F2 F4 SUBD F8 F6 F2 DIVD F10 F0 F6 ADDD F6 F8 F2
2. Scoreboard Algorithm
See wikipedia for more information about this algorithm.
1 import java.util.*; 2 import java.io.*; 3 Algorithm 4 public class Scoreboard { 5 private static class Inst { 6 private String op; 7 private int dest,src1,src2; 8 private int stage; 9 private int pos; 10 11 public Inst() { 12 // Interpret and Store Instructions 13 op = in.next(); 14 String buf; 15 buf = in.next(); 16 dest = Integer.parseInt(buf.substring(1))/2; 17 buf = in.next(); 18 if (buf.charAt(0)!='%') 19 src1 = Integer.parseInt(buf.substring(1))/2; 20 else 21 src1 = -1; 22 buf = in.next(); 23 src2 = Integer.parseInt(buf.substring(1))/2; 24 stage = 0; 25 pos = -1; 26 } 27 public boolean ready() { 28 switch (stage) { 29 case 0: 30 return issueReady(); 31 case 1: 32 return readOpReady(); 33 case 2: 34 return execCompReady(); 35 case 3: 36 return wrtResReady(); 37 default: 38 return false; 39 } 40 } 41 private boolean issueReady() { 42 if (iss) { 43 // iss guarantees "in-order" 44 iss = false; 45 pos = -1; 46 srchFreeUnit(); 47 // no structural hazard or WAW 48 return pos>=0 && res[dest]<0; 49 } else 50 return false; 51 } 52 private void srchFreeUnit() { 53 // Search for a Function Unit unoccupied 54 if (op.equals("LD")||op.equals("SD")) { 55 if (!unit[0].busy) 56 pos = 0; 57 } else if (op.equals("MULTD")) { 58 if (!unit[1].busy) 59 pos = 1; 60 else if (!unit[2].busy) 61 pos = 2; 62 } else if (op.equals("ADDD")||op.equals("SUBD")) { 63 if (!unit[3].busy) 64 pos = 3; 65 } else if (op.equals("DIVD")) { 66 if (!unit[4].busy) 67 pos = 4; 68 } 69 } 70 private boolean readOpReady() { 71 // no RAW data hazard 72 return unit[pos].Rj && unit[pos].Rk; 73 } 74 private boolean execCompReady() { 75 return --unit[pos].time==0; 76 } 77 private boolean wrtResReady() { 78 for (int i=0;i<5;i++) { 79 // no WAR hazard 80 if (unit[i].Fj==dest&&unit[i].Rj) 81 return false; 82 if (unit[i].Fk==dest&&unit[i].Rk) 83 return false; 84 } 85 return true; 86 } 87 public boolean next() { 88 // Show the action and do the bookkeeping 89 switch(stage++) { 90 case 0: 91 System.out.println("is issued"); 92 issueBookkeep(); 93 return false; 94 case 1: 95 System.out.println("reads operands"); 96 readOpBookkeep(); 97 return false; 98 case 2: 99 System.out.println("completes execution"); 100 return false; 101 case 3: 102 System.out.println("writes result"); 103 wrtResBookkeep(); 104 return true; 105 default: 106 return false; 107 } 108 } 109 private void issueBookkeep() { 110 unit[pos].busy = true; 111 unit[pos].op = op; 112 if (op.equals("SD")) { 113 unit[pos].Fi = -1; 114 unit[pos].Fj = dest; 115 unit[pos].Fk = src2; 116 } else { 117 unit[pos].Fi = dest; 118 unit[pos].Fj = src1; 119 unit[pos].Fk = src2; 120 } 121 if (src1>=0) 122 unit[pos].Qj = res[src1]; 123 else 124 unit[pos].Qj = -1; 125 unit[pos].Qk = res[src2]; 126 unit[pos].Rj = (unit[pos].Qj<0); 127 unit[pos].Rk = (unit[pos].Qk<0); 128 if (!op.equals("SD")) 129 res[dest] = pos; 130 } 131 private void readOpBookkeep() { 132 // no more WAR hazard 133 unit[pos].Rj = false; 134 unit[pos].Rk = false; 135 if (pos==0) 136 unit[pos].time = 1; 137 else if (pos<=2) 138 unit[pos].time = 10; 139 else if (pos==3) 140 unit[pos].time = 2; 141 else 142 unit[pos].time = 40; 143 } 144 private void wrtResBookkeep() { 145 // no more RAW hazard 146 for (int i=0;i<5;i++) { 147 if (unit[i].Qj==pos) 148 unit[i].Rj = true; 149 if (unit[i].Qk==pos) 150 unit[i].Rk = true; 151 } 152 // no more structural hazard 153 unit[pos].busy = false; 154 // no more WAW hazard 155 if (!op.equals("SD")) 156 res[dest] = -1; 157 } 158 } 159 private static class FU { 160 public int time; 161 public String name; 162 public boolean busy; 163 public String op; 164 public int Fi,Fj,Fk; 165 public int Qj,Qk; 166 public boolean Rj,Rk; 167 168 public FU(String str) { 169 time = 0; 170 name = str; 171 busy = false; 172 op = null; 173 Fi=Fj=Fk = -1; 174 Qj=Qk = -1; 175 Rj=Rk = false; 176 } 177 } 178 179 private static Scanner in; 180 private static boolean iss; 181 private static Inst[] inst; 182 private static FU[] unit; 183 private static int[] res; 184 185 private static void init_all(int n) { 186 inst = new Inst[n]; 187 unit = new FU[5]; 188 unit[0] = new FU("Integer"); 189 unit[1] = new FU("Mult1"); 190 unit[2] = new FU("Mult2"); 191 unit[3] = new FU("Add"); 192 unit[4] = new FU("Divide"); 193 res = new int[8]; 194 for (int i=0;i<8;i++) 195 res[i] = -1; 196 } 197 public static void main(String[] args) throws IOException { 198 // read and buffer all the instructions: 199 in = new Scanner(new FileReader("CDC6600.in")); 200 int n = in.nextInt(); 201 init_all(n); 202 for (int i=0;i<n;i++) 203 inst[i] = new Inst(); 204 in.close(); 205 // in-order issue, out-of-order execution: 206 int clk=0, over=0; 207 boolean flag[] = new boolean[n]; 208 while (over<n) { 209 System.out.print(">> CLOCK CYCLE "); 210 System.out.println(++clk); 211 iss = true; 212 for (int i=0;i<n;i++) 213 flag[i] = inst[i].ready(); 214 for (int i=0;i<n;i++) { 215 if (flag[i]){ 216 System.out.print("\tinst "); 217 System.out.print((i+1)+" "); 218 if (inst[i].next()) 219 over++; 220 } 221 } 222 } 223 } 224 }
3. Tomasulo Algorithm
See wikipedia for more information about this algorithm.
1 import java.util.*; 2 import java.io.*; 3 4 public class Tomasulo { 5 private static class Inst { 6 private String op; 7 private int dest,src1,src2; 8 private int stage; 9 private int pos; 10 11 public Inst() { 12 // Interpret and store instructions 13 op = in.next(); 14 String buf; 15 buf = in.next(); 16 dest = Integer.parseInt(buf.substring(1))/2; 17 buf = in.next(); 18 if (buf.charAt(0)!='%') 19 src1 = Integer.parseInt(buf.substring(1))/2; 20 else 21 src1 = -1; 22 buf = in.next(); 23 src2 = Integer.parseInt(buf.substring(1))/2; 24 stage = 0; 25 pos = -1; 26 } 27 public boolean ready() { 28 switch (stage) { 29 case 0: 30 return issueReady(); 31 case 1: 32 return execReady(); 33 case 2: 34 return execCompReady(); 35 case 3: 36 return wrtResReady(); 37 default: 38 return false; 39 } 40 } 41 private boolean issueReady() { 42 if (iss) { 43 // iss guarantees in-order issue 44 iss = false; 45 pos = -1; 46 srchFreeUnit(); 47 // no structural hazard 48 return pos>=0; 49 } else 50 return false; 51 } 52 private void srchFreeUnit() { 53 // Search for a Reservation Station unoccupied 54 if (op.equals("ADDD")||op.equals("SUBD")) { 55 for (int i=0;i<=2;i++) { 56 if (!unit[i].busy) { 57 pos = i; 58 return; 59 } 60 } 61 } else if (op.equals("MULTD")||op.equals("DIVD")) { 62 for (int i=3;i<=4;i++) { 63 if (!unit[i].busy) { 64 pos = i; 65 return; 66 } 67 } 68 } else if (op.equals("LD")) { 69 for (int i=5;i<=10;i++) { 70 if (!unit[i].busy) { 71 pos = i; 72 return; 73 } 74 } 75 } else if (op.equals("SD")) { 76 for (int i=11;i<=13;i++) { 77 if (!unit[i].busy) { 78 pos = i; 79 return; 80 } 81 } 82 } 83 } 84 private boolean execReady() { 85 // no RAW data hazard 86 if (pos<=4) // FP operations 87 return unit[pos].Qj<0 && unit[pos].Qk<0; 88 else if (mem) { 89 // mem guarantees in-order load/store 90 mem = false; 91 return unit[pos].Qk<0; 92 } else 93 return false; 94 } 95 private boolean execCompReady() { 96 return --unit[pos].time==0; 97 } 98 private boolean wrtResReady() { 99 if (op.equals("SD")) 100 return unit[pos].Qj<0; 101 else if (cbd){ 102 // no CBD conflict 103 cbd = false; 104 return true; 105 } else 106 return false; 107 } 108 public boolean next() { 109 // Show the action and do the bookkeeping 110 switch(stage++) { 111 case 0: 112 System.out.println("is issued"); 113 issueBookkeep(); 114 return false; 115 case 1: 116 System.out.println("starts to execute"); 117 execBookkeep(); 118 return false; 119 case 2: 120 System.out.println("completes execution"); 121 return false; 122 case 3: 123 System.out.println("writes result"); 124 wrtResBookkeep(); 125 return true; 126 default: 127 return false; 128 } 129 } 130 private void issueBookkeep() { 131 unit[pos].busy = true; 132 unit[pos].op = op; 133 if (!op.equals("SD")) { 134 if (src1>=0) 135 unit[pos].Qj = res[src1]; 136 else 137 unit[pos].Qj = -1; 138 unit[pos].Qk = res[src2]; 139 res[dest] = pos; 140 } else { 141 unit[pos].Qj = res[dest]; 142 unit[pos].Qk = res[src2]; 143 } 144 } 145 private void execBookkeep() { 146 if (pos<=2) 147 unit[pos].time = 2; 148 else if (op.equals("MULTD")) 149 unit[pos].time = 10; 150 else if (op.equals("DIVD")) 151 unit[pos].time = 40; 152 else 153 unit[pos].time = 1; 154 } 155 private void wrtResBookkeep() { 156 if (!op.equals("SD")) { 157 for (int i=0;i<8;i++) { 158 if (res[i]==pos) 159 res[i] = -1; 160 } 161 for (int i=0;i<14;i++) { 162 if (unit[i].Qj==pos) 163 unit[i].Qj = -1; 164 if (unit[i].Qk==pos) 165 unit[i].Qk = -1; 166 } 167 } 168 unit[pos].busy = false; 169 } 170 } 171 private static class RS { 172 public int time; 173 public String name; 174 public boolean busy; 175 public String op; 176 public int Qj,Qk; 177 178 public RS(String str) { 179 time = 0; 180 name = str; 181 busy = false; 182 op = null; 183 Qj=Qk = -1; 184 } 185 } 186 187 private static Scanner in; 188 private static boolean iss,cbd,mem; 189 private static Inst[] inst; 190 private static RS[] unit; 191 private static int[] res; 192 193 private static void init_all(int n) { 194 inst = new Inst[n]; 195 unit = new RS[14]; 196 for (int i=0;i<3;i++) 197 unit[i] = new RS("Add"+Integer.toString(i+1)); 198 for (int i=0;i<2;i++) 199 unit[3+i] = new RS("Mult"+Integer.toString(i+1)); 200 for (int i=0;i<6;i++) 201 unit[5+i] = new RS("Load"+Integer.toString(i+1)); 202 for (int i=0;i<3;i++) 203 unit[11+i] = new RS("Store"+Integer.toString(i+1)); 204 res = new int[8]; 205 for (int i=0;i<8;i++) 206 res[i] = -1; 207 } 208 public static void main(String[] args) throws IOException { 209 // read and buffer all the instructions: 210 in = new Scanner(new FileReader("IBM360.in")); 211 int n = in.nextInt(); 212 init_all(n); 213 for (int i=0;i<n;i++) 214 inst[i] = new Inst(); 215 in.close(); 216 // in-order issue, out-of-order execution: 217 int clk=0, over=0; 218 while (over<n) { 219 System.out.print(">> CLOCK CYCLE "); 220 System.out.println(++clk); 221 iss = cbd = mem = true; 222 for (int i=0;i<n;i++) { 223 if (inst[i].ready()){ 224 System.out.print("\tinst "); 225 System.out.print((i+1)+" "); 226 if (inst[i].next()) 227 over++; 228 } 229 } 230 } 231 } 232 }
References:
1. Hennessy, John L., and David A. Patterson. Computer Architecture: A Quantitative Approach[M]. 北京:人民邮电出版社, 2013-01