1 /******************************************************************************
  2 * Copyright 2013, Hectic Tech (Jeff Heckey). All rights reserved
  3 ******************************************************************************/
  4 
  5 module dispatch #(
  6     parameter OP = 3,
  7     parameter TAG = 4,
  8     parameter ADDR = 32
  9 ) (
 10     input  wire                     clk,
 11     input  wire                     rstn,
 12 
 13     input  wire [OP+3*TAG+ADDR-1:0] inst0,
 14     input  wire [OP+3*TAG+ADDR-1:0] inst1,
 15     output reg  [1:0]               inst_pop,
 16 
 17     input  wire [TAG-1:0]           cdb_a_id,
 18     input  wire                     cdb_a_except,
 19     input  wire [TAG-1:0]           cdb_m_id,
 20     input  wire                     cdb_m_except,
 21     input  wire [TAG-1:0]           cdb_l_id,
 22     input  wire                     cdb_l_except,
 23     input  wire [TAG-1:0]           cdb_s_id,
 24     input  wire                     cdb_s_except,
 25 
 26     input  wire [7:0]               regstat_busy,
 27     input  wire [4*TAG-1:0]         regstat_remap,
 28 
 29     output reg  [OP+4*TAG+ADDR-1:0] disp_bus0,
 30     output reg  [OP+4*TAG+ADDR-1:0] disp_bus1
 31 );
 32 
 33 localparam STALL_STALL  = 2'b00,
 34            STALL_POP    = 2'b01,
 35            POP_STALL    = 2'b10,
 36            POP_POP      = 2'b11;
 37 
 38 // OPCODES
 39 localparam STOR = 3'b111,
 40            LOAD = 3'b110,
 41            FDIV = 3'b101,
 42            FMUL = 3'b100,
 43            FSUB = 3'b011,
 44            FADD = 3'b010;
 45 
 46 // Register and reservation station tags
 47 localparam R0 = 4'd4,
 48            R1 = 4'd5,
 49            R2 = 4'd6,
 50            R3 = 4'd7,
 51            A0 = 4'd8,
 52            A1 = 4'd9,
 53            M0 = 4'd10,
 54            M1 = 4'd11,
 55            L0 = 4'd12,
 56            L1 = 4'd13,
 57            S0 = 4'd14,
 58            S1 = 4'd15;
 59 
 60 reg  [TAG-1:0]      cdb_a_idN;
 61 reg  [TAG-1:0]      cdb_m_idN;
 62 reg  [TAG-1:0]      cdb_l_idN;
 63 reg  [TAG-1:0]      cdb_s_idN;
 64 reg                 cdb_a_exceptN;
 65 reg                 cdb_m_exceptN;
 66 reg                 cdb_l_exceptN;
 67 reg                 cdb_s_exceptN;
 68 reg                 exception, exceptionN;
 69 
 70 reg                 dependN;
 71 reg                 depend_nextN;
 72 reg  [4*TAG-1:0]    regstat_remapN;
 73 reg  [3:0]          cdb_free;
 74 reg  [4*TAG-1:0]    cdb_tags;
 75 reg  [TAG-1:0]      map01, map02, map11, map12;
 76 
 77 reg  [OP+3*TAG+ADDR-1:0] inst0_pop;
 78 reg  [OP+3*TAG+ADDR-1:0] inst1_pop;
 79 
 80 reg  [OP-1:0]       op0_next, op1_next;
 81 reg  [TAG-1:0]      rsv0_next, rsv1_next;
 82 reg  [TAG-1:0]      dst0_next, dst1_next;
 83 reg  [TAG-1:0]      src01_next, src02_next;
 84 reg  [TAG-1:0]      src11_next, src12_next;
 85 reg  [7:0]          disp_busyN;
 86 reg  [OP-1:0]       op0N, op1N;
 87 reg  [TAG-1:0]      rsv0N, rsv1N;
 88 reg  [TAG-1:0]      dst0N, dst1N;
 89 reg  [TAG-1:0]      src01N, src02N;
 90 reg  [TAG-1:0]      src11N, src12N;
 91 reg  [ADDR-1:0]     addr0N, addr1N;
 92 reg  [OP-1:0]       op0_nextN, op1_nextN;
 93 reg  [TAG-1:0]      rsv0_nextN, rsv1_nextN;
 94 reg  [TAG-1:0]      dst0_nextN, dst1_nextN;
 95 reg  [TAG-1:0]      src01_nextN, src02_nextN;
 96 reg  [TAG-1:0]      src11_nextN, src12_nextN;
 97 reg  [ADDR-1:0]     addr0_nextN, addr1_nextN;
 98 
 99 
100 always @* begin : DISP_POS_LOGIC
101     // select instructions from queue/stalled
102     case (inst_pop)
103     POP_POP:
104     begin
105         inst0_pop = inst0;
106         inst1_pop = inst1;
107     end
108 
109     POP_STALL:
110     begin
111         inst0_pop = disp_bus0[OP+3*TAG+ADDR-1:0];
112         inst1_pop = inst0;
113     end
114 
115     STALL_POP:
116     begin
117         inst0_pop = disp_bus1[OP+3*TAG+ADDR-1:0];
118         inst1_pop = inst0;
119     end
120 
121     STALL_STALL:
122     begin
123         inst0_pop = disp_bus0[OP+3*TAG+ADDR-1:0];
124         inst1_pop = disp_bus1[OP+3*TAG+ADDR-1:0];
125     end
126     endcase
127 
128     // decode instructions
129     {op0_nextN,
130      dst0_nextN,
131      src01_nextN,
132      src02_nextN,
133      addr0_nextN} = inst0_pop;
134     {op1_nextN,
135      dst1_nextN,
136      src11_nextN,
137      src12_nextN,
138      addr1_nextN} = inst1_pop;
139 
140     // Default busy checking for INST 1
141     disp_busyN = regstat_busy;
142 
143     rsv0_nextN = {TAG{1'b0}};
144     case ( op0_nextN )
145     FADD, FSUB:
146     begin
147         if ( !regstat_busy[A0-8] ) begin
148             rsv0_nextN = A0;
149             disp_busyN[A0-8] = 1'b1;
150         end
151         else if ( !regstat_busy[A1-8] ) begin
152             rsv0_nextN = A1;
153             disp_busyN[A1-8] = 1'b1;
154         end
155     end
156 
157     FMUL, FDIV:
158     begin
159         if ( !regstat_busy[M0-8] ) begin
160             rsv0_nextN = M0;
161             disp_busyN[M0-8] = 1'b1;
162         end
163         else if ( !regstat_busy[M1-8] ) begin
164             rsv0_nextN = M1;
165             disp_busyN[M1-8] = 1'b1;
166         end
167     end
168 
169     LOAD:
170     begin
171         if ( !regstat_busy[L0-8] ) begin
172             rsv0_nextN = L0;
173             disp_busyN[L0-8] = 1'b1;
174         end
175         else if ( !regstat_busy[L1-8] ) begin
176             rsv0_nextN = L1;
177             disp_busyN[L1-8] = 1'b1;
178         end
179     end
180 
181     STOR:
182     begin
183         if ( !regstat_busy[S0-8] ) begin
184             rsv0_nextN = S0;
185             disp_busyN[S0-8] = 1'b1;
186         end
187         else if ( !regstat_busy[S1-8] ) begin
188             rsv0_nextN = S1;
189             disp_busyN[S1-8] = 1'b1;
190         end
191     end
192 
193     default:
194     begin
195         $display( "NOP OPCODE - %b", op0_nextN );
196         rsv0_nextN = {TAG{1'b0}};
197     end
198     endcase
199 
200 
201     depend_nextN = ( src11_nextN == dst0_nextN ) || ( src12_nextN == dst0_nextN );
202 
203     // Stall by default; update if not dependent on stalled inst0
204     rsv1_nextN = {TAG{1'b0}};
205     if ( !( ~|rsv0_nextN && depend_nextN ) ) begin
206         case ( op1_nextN )
207         FADD, FSUB:
208         begin
209             if ( !disp_busyN[A0-8] ) begin
210                 rsv1_nextN = A0;
211             end
212             else if ( !disp_busyN[A1-8] ) begin
213                 rsv1_nextN = A1;
214             end
215         end
216 
217         FMUL, FDIV:
218         begin
219             if ( !disp_busyN[M0-8] ) begin
220                 rsv1_nextN = M0;
221             end
222             else if ( !disp_busyN[M1-8] ) begin
223                 rsv1_nextN = M1;
224             end
225         end
226 
227         LOAD:
228         begin
229             if ( !disp_busyN[L0-8] ) begin
230                 rsv1_nextN = L0;
231             end
232             else if ( !disp_busyN[L1-8] ) begin
233                 rsv1_nextN = L1;
234             end
235         end
236 
237         STOR:
238         begin
239             if ( !disp_busyN[S0-8] ) begin
240                 rsv1_nextN = S0;
241             end
242             else if ( !disp_busyN[S1-8] ) begin
243                 rsv1_nextN = S1;
244             end
245         end
246 
247         default:
248         begin
249             $display( "NOP OPCODE - %b", op1_nextN );
250             rsv1_nextN = {TAG{1'b0}};
251         end
252         endcase
253     end
254 end
255 
256 // CDB is assumed to take 
257 always @* begin : DISP_NEG_LATCH
258     if ( !rstn ) begin
259         exceptionN  <= 1'b0;
260         dependN     <= 1'b0;
261 
262         rsv0N       <= {TAG{1'b0}};
263         op0N        <= {OP{1'b0}};
264         dst0N       <= {TAG{1'b0}};
265         src01N      <= {TAG{1'b0}};
266         src02N      <= {TAG{1'b0}};
267         addr0N      <= {ADDR{1'b0}};
268 
269         rsv1N       <= {TAG{1'b0}};
270         op1N        <= {OP{1'b0}};
271         dst1N       <= {TAG{1'b0}};
272         src11N      <= {TAG{1'b0}};
273         src12N      <= {TAG{1'b0}};
274         addr1N      <= {ADDR{1'b0}};
275 
276         regstat_remapN  <= {4*TAG{1'b0}};
277 
278         cdb_a_idN       <= {TAG{1'b0}};
279         cdb_a_exceptN   <= 1'b0;
280         cdb_m_idN       <= {TAG{1'b0}};
281         cdb_m_exceptN   <= 1'b0;
282         cdb_l_idN       <= {TAG{1'b0}};
283         cdb_l_exceptN   <= 1'b0;
284         cdb_s_idN       <= {TAG{1'b0}};
285     end
286     else begin
287         if ( !clk ) begin
288             exceptionN  <= exception;
289             dependN     <= depend_nextN;
290 
291             rsv0N       <= rsv0_nextN;
292             op0N        <= op0_nextN;
293             dst0N       <= dst0_nextN;
294             src01N      <= src01_nextN;
295             src02N      <= src02_nextN;
296             addr0N      <= addr0_nextN;
297 
298             rsv1N       <= rsv1_nextN;
299             op1N        <= op1_nextN;
300             dst1N       <= dst1_nextN;
301             src11N      <= src11_nextN;
302             src12N      <= src12_nextN;
303             addr1N      <= addr1_nextN;
304 
305             regstat_remapN  <= regstat_remap;
306 
307             cdb_a_idN       <= cdb_a_id;
308             cdb_a_exceptN   <= cdb_a_except;
309             cdb_m_idN       <= cdb_m_id;
310             cdb_m_exceptN   <= cdb_m_except;
311             cdb_l_idN       <= cdb_l_id;
312             cdb_l_exceptN   <= cdb_l_except;
313             cdb_s_idN       <= cdb_s_id;
314             cdb_s_exceptN   <= cdb_s_except;
315         end
316     end
317 end
318 
319 
320 always @* begin : DISP_NEG_LOGIC
321     op0_next    = op0N;
322     op1_next    = op1N;
323     dst0_next   = dst0N;
324     dst1_next   = dst1N;
325 
326     // Map cdb info into arrays for easier usage
327     cdb_free   = { |cdb_s_idN, |cdb_l_idN, |cdb_m_idN, |cdb_a_idN };
328     cdb_tags   = { cdb_s_idN, cdb_l_idN, cdb_m_idN, cdb_a_idN };
329 
330     // Get mappings
331     map01 = regstat_remapN[src01N[1:0]*TAG +: TAG];
332     map02 = regstat_remapN[src02N[1:0]*TAG +: TAG];
333     map11 = regstat_remapN[src11N[1:0]*TAG +: TAG];
334     map12 = regstat_remapN[src12N[1:0]*TAG +: TAG];
335 
336     // Update reservation information based on CDB
337     if ( ~|rsv0N ) begin
338         case ( op0N )
339         FADD, FSUB:
340         begin
341             rsv0_next   = ( cdb_free[0] ) ? cdb_a_idN : {TAG{1'b0}}; // Station freed this cycle, use it next
342             cdb_free    = cdb_free & 4'b1110; // clear bit because only 1 station is freed
343         end
344 
345         FMUL, FDIV:
346         begin
347             rsv0_next   = ( cdb_free[1] ) ? cdb_m_idN : {TAG{1'b0}};
348             cdb_free    = cdb_free & 4'b1101;
349         end
350 
351         LOAD:
352         begin
353             rsv0_next   = ( cdb_free[2] ) ? cdb_l_idN : {TAG{1'b0}};
354             cdb_free    = cdb_free & 4'b1011;
355         end
356 
357         STOR:
358         begin
359             rsv0_next   = ( cdb_free[3] ) ? cdb_s_idN : {TAG{1'b0}};
360             cdb_free    = cdb_free & 4'b0111;
361         end
362 
363         default:
364         begin
365             rsv0_next   = {TAG{1'b0}};
366         end
367         endcase
368     end
369     else begin
370         rsv0_next  = rsv0N;
371     end
372 
373     // Reservation updated, if issuing update tags, otherwise hold register
374     // values
375     src01_next  = ( |rsv0_next && |map01 && map01 != cdb_tags[map01[2:1]] ) ? map01 : src01N;
376     src02_next  = ( |rsv0_next && |map02 && map02 != cdb_tags[map02[2:1]] ) ? map02 : src02N;
377 
378     // If inst1 was stalled && there is no dependence or inst0 is executing,
379     // update reservation
380     if ( ~|rsv1N && ( !dependN || |rsv0N ) ) begin
381         case ( op0N )
382         FADD, FSUB:
383             rsv1_next   = ( cdb_free[0] ) ? cdb_a_idN : {TAG{1'b0}};
384 
385         FMUL, FDIV:
386             rsv1_next   = ( cdb_free[1] ) ? cdb_m_idN : {TAG{1'b0}};
387 
388         LOAD:
389             rsv1_next   = ( cdb_free[2] ) ? cdb_l_idN : {TAG{1'b0}};
390 
391         STOR:
392             rsv1_next   = ( cdb_free[3] ) ? cdb_s_idN : {TAG{1'b0}};
393 
394         default:
395             rsv1_next   = {TAG{1'b0}};
396         endcase
397     end
398     else begin
399         rsv1_next  = rsv1N;
400     end
401 
402     // Use inst0 if the inst1 source matches, or take the remap, or use the
403     // reg specified
404     src11_next  = ( |rsv1_next && src11N == dst0N && op0N != STOR ) ? rsv0_next
405                 : ( |rsv1_next && |map11 && map11 != cdb_tags[map11[2:1]] ) ? map11
406                 : src11N;
407     src12_next  = ( |rsv1_next && src12N == dst0N && op0N != STOR ) ? rsv0_next
408                 : ( |rsv1_next && |map12 && map12 != cdb_tags[map12[2:1]] ) ? map12
409                 : src12N;
410 end
411 
412 
413 always @* begin : DISP_POS_LATCH
414     if ( !rstn ) begin
415         exception   <= 1'b0;
416         inst_pop    <= 2'b11;
417         disp_bus0   <= {OP+4*TAG+ADDR{1'b0}};
418         disp_bus1   <= {OP+4*TAG+ADDR{1'b0}};
419     end
420     else begin
421         if ( clk ) begin
422             if ( exceptionN || cdb_a_exceptN || cdb_m_exceptN || cdb_l_exceptN ) begin
423                 exception   <= 1'b1;
424                 inst_pop    <= 2'b00;
425                 disp_bus0   <= {{TAG{1'b0}},
426                                 op0_next,
427                                 dst0_next,
428                                 src01_next,
429                                 src02_next,
430                                 addr0N};
431                 disp_bus1   <= {{TAG{1'b0}},
432                                 op1_next,
433                                 dst1_next,
434                                 src11_next,
435                                 src12_next,
436                                 addr1N};
437             end
438             else begin
439                 exception   <= 1'b0;
440                 inst_pop    <= { (|rsv1_next || ~|op1_next), (|rsv0_next || ~|op0_next) };
441                 disp_bus0   <= {rsv0_next,
442                                 op0_next,
443                                 dst0_next,
444                                 src01_next,
445                                 src02_next,
446                                 addr0N};
447                 disp_bus1   <= {rsv1_next,
448                                 op1_next,
449                                 dst1_next,
450                                 src11_next,
451                                 src12_next,
452                                 addr1N};
453             end
454         end
455     end
456 end
457 
458 endmodule
459