OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [rtl/] [verilog/] [or1200/] [or1200_mult_mac.v] - Blame information for rev 584

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 350 julius
//////////////////////////////////////////////////////////////////////
2
////                                                              ////
3
////  OR1200's Top level multiplier, divider and MAC              ////
4
////                                                              ////
5
////  This file is part of the OpenRISC 1200 project              ////
6
////  http://opencores.org/project,or1k                           ////
7
////                                                              ////
8
////  Description                                                 ////
9
////  Multiplier is 32x32 however multiply instructions only      ////
10
////  use lower 32 bits of the result. MAC is 32x32=64+64.        ////
11
////                                                              ////
12
////  To Do:                                                      ////
13
////   - make signed division better, w/o negating the operands   ////
14 435 julius
////   - implement non-serial divider that is synthesizable       ////
15 350 julius
////                                                              ////
16
////  Author(s):                                                  ////
17
////      - Damjan Lampret, lampret@opencores.org                 ////
18 435 julius
////      - Julius Baxter, julius@opencores.org                   ////
19 350 julius
////                                                              ////
20
//////////////////////////////////////////////////////////////////////
21
////                                                              ////
22 435 julius
//// Copyright (C) 2000, 2010 Authors and OPENCORES.ORG           ////
23 350 julius
////                                                              ////
24
//// This source file may be used and distributed without         ////
25
//// restriction provided that this copyright statement is not    ////
26
//// removed from the file and that any derivative work contains  ////
27
//// the original copyright notice and the associated disclaimer. ////
28
////                                                              ////
29
//// This source file is free software; you can redistribute it   ////
30
//// and/or modify it under the terms of the GNU Lesser General   ////
31
//// Public License as published by the Free Software Foundation; ////
32
//// either version 2.1 of the License, or (at your option) any   ////
33
//// later version.                                               ////
34
////                                                              ////
35
//// This source is distributed in the hope that it will be       ////
36
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
37
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
38
//// PURPOSE.  See the GNU Lesser General Public License for more ////
39
//// details.                                                     ////
40
////                                                              ////
41
//// You should have received a copy of the GNU Lesser General    ////
42
//// Public License along with this source; if not, download it   ////
43
//// from http://www.opencores.org/lgpl.shtml                     ////
44
////                                                              ////
45
//////////////////////////////////////////////////////////////////////
46
//
47
// CVS Revision History
48
//
49
// $Log: or1200_mult_mac.v,v $
50
// Revision 2.0  2010/06/30 11:00:00  ORSoC
51
// Minor update: 
52
// Bugs fixed. 
53
//
54
 
55
// synopsys translate_off
56
`include "timescale.v"
57
// synopsys translate_on
58
`include "or1200_defines.v"
59
 
60
module or1200_mult_mac(
61 435 julius
                       // Clock and reset
62
                       clk, rst,
63 350 julius
 
64 435 julius
                       // Multiplier/MAC interface
65
                       ex_freeze, id_macrc_op, macrc_op, a, b, mac_op, alu_op,
66
                       result, mult_mac_stall,
67 350 julius
 
68 502 julius
                       // Overflow
69
                       ovforw, ov_we,
70
 
71 435 julius
                       // SPR interface
72
                       spr_cs, spr_write, spr_addr, spr_dat_i, spr_dat_o
73
                       );
74 350 julius
 
75 435 julius
   parameter width = `OR1200_OPERAND_WIDTH;
76 350 julius
 
77 435 julius
   //
78
   // I/O
79
   //
80 350 julius
 
81 435 julius
   //
82
   // Clock and reset
83
   //
84
   input                                clk;
85
   input                                rst;
86 350 julius
 
87 435 julius
   //
88
   // Multiplier/MAC interface
89
   //
90
   input                                ex_freeze;
91
   input                                id_macrc_op;
92
   input                                macrc_op;
93
   input [width-1:0]                     a;
94
   input [width-1:0]                     b;
95
   input [`OR1200_MACOP_WIDTH-1:0]       mac_op;
96
   input [`OR1200_ALUOP_WIDTH-1:0]       alu_op;
97
   output [width-1:0]                    result;
98
   output                               mult_mac_stall;
99 502 julius
   output                               ovforw, ov_we;
100
 
101 435 julius
   //
102
   // SPR interface
103
   //
104
   input                                spr_cs;
105
   input                                spr_write;
106
   input [31:0]                  spr_addr;
107
   input [31:0]                  spr_dat_i;
108
   output [31:0]                         spr_dat_o;
109 350 julius
 
110 435 julius
   //
111
   // Internal wires and regs
112
   //
113
   reg [width-1:0]                       result;
114 499 julius
   reg                                  ex_freeze_r;
115 537 julius
   wire                                 alu_op_mul;
116
   wire                                 alu_op_smul;
117 350 julius
`ifdef OR1200_MULT_IMPLEMENTED
118 435 julius
   reg [2*width-1:0]                     mul_prod_r;
119
   wire                                 alu_op_umul;
120
 `ifdef OR1200_MULT_SERIAL
121
   reg [5:0]                             serial_mul_cnt;
122
   reg                                  mul_free;
123
 `endif
124 350 julius
`else
125 435 julius
   wire [2*width-1:0]                    mul_prod_r;
126 350 julius
`endif
127 435 julius
   wire [2*width-1:0]                    mul_prod;
128
   wire                                 mul_stall;
129 499 julius
   reg [1:0]                             mul_stall_count;
130 435 julius
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op;
131 350 julius
`ifdef OR1200_MAC_IMPLEMENTED
132 435 julius
   reg [`OR1200_MACOP_WIDTH-1:0]         mac_op_r1;
133
   reg [`OR1200_MACOP_WIDTH-1:0]         mac_op_r2;
134
   reg [`OR1200_MACOP_WIDTH-1:0]         mac_op_r3;
135
   reg                                  mac_stall_r;
136
   reg [63:0]                            mac_r;
137 350 julius
`else
138 435 julius
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op_r1;
139
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op_r2;
140
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op_r3;
141
   wire                                 mac_stall_r;
142
   wire [63:0]                           mac_r;
143 350 julius
`endif
144 435 julius
   wire [width-1:0]                      x;
145
   wire [width-1:0]                      y;
146
   wire                                 spr_maclo_we;
147
   wire                                 spr_machi_we;
148
   wire                                 alu_op_div;
149
   wire                                 alu_op_udiv;
150
   wire                                 alu_op_sdiv;
151
   reg                                  div_free;
152
   wire                                 div_stall;
153 350 julius
`ifdef OR1200_DIV_IMPLEMENTED
154 435 julius
 `ifdef OR1200_DIV_SERIAL
155
   reg [2*width-1:0]                     div_quot_r;
156
   wire [width-1:0]                      div_tmp;
157
   reg [5:0]                             div_cntr;
158
 `else
159
   reg [width-1:0]                       div_quot_r;
160
   reg [width-1:0]                       div_quot_generic;
161 502 julius
 `endif
162
   wire                                 div_by_zero;
163 350 julius
`endif
164 502 julius
   reg                                  ovforw, ov_we;
165
 
166 435 julius
   //
167
   // Combinatorial logic
168
   //
169
`ifdef OR1200_MULT_IMPLEMENTED
170
   assign alu_op_smul = (alu_op == `OR1200_ALUOP_MUL);
171
   assign alu_op_umul = (alu_op == `OR1200_ALUOP_MULU);
172
   assign alu_op_mul = alu_op_smul | alu_op_umul;
173 537 julius
`else
174
   assign alu_op_smul = 0;
175
   assign alu_op_mul = 0;
176
`endif
177 350 julius
`ifdef OR1200_MAC_IMPLEMENTED
178 435 julius
   assign spr_maclo_we = spr_cs & spr_write & spr_addr[`OR1200_MAC_ADDR];
179
   assign spr_machi_we = spr_cs & spr_write & !spr_addr[`OR1200_MAC_ADDR];
180
   assign spr_dat_o = spr_addr[`OR1200_MAC_ADDR] ? mac_r[31:0] : mac_r[63:32];
181 350 julius
`else
182 435 julius
   assign spr_maclo_we = 1'b0;
183
   assign spr_machi_we = 1'b0;
184
   assign spr_dat_o = 32'h0000_0000;
185 350 julius
`endif
186
`ifdef OR1200_DIV_IMPLEMENTED
187 435 julius
   assign alu_op_sdiv = (alu_op == `OR1200_ALUOP_DIV);
188
   assign alu_op_udiv = (alu_op == `OR1200_ALUOP_DIVU);
189
   assign alu_op_div = alu_op_sdiv | alu_op_udiv;
190 350 julius
`else
191 435 julius
   assign alu_op_udiv = 1'b0;
192
   assign alu_op_sdiv = 1'b0;
193
   assign alu_op_div = 1'b0;
194 350 julius
`endif
195
 
196 435 julius
   assign x = (alu_op_sdiv | alu_op_smul) & a[31] ? ~a + 32'b1 :
197
              alu_op_div | alu_op_mul | (|mac_op) ? a : 32'd0;
198
   assign y = (alu_op_sdiv | alu_op_smul) & b[31] ? ~b + 32'b1 :
199
              alu_op_div | alu_op_mul | (|mac_op) ? b : 32'd0;
200 350 julius
 
201 502 julius
   assign div_by_zero = !(|b) & alu_op_div;
202
 
203
 
204 499 julius
   // Used to indicate when we should check for new multiply or MAC ops
205
   always @(posedge clk or `OR1200_RST_EVENT rst)
206
     if (rst == `OR1200_RST_VALUE)
207
       ex_freeze_r <= 1'b1;
208
     else
209
       ex_freeze_r <= ex_freeze;
210
 
211 435 julius
   //
212
   // Select result of current ALU operation to be forwarded
213
   // to next instruction and to WB stage
214
   //
215
   always @*
216
     casez(alu_op)      // synopsys parallel_case
217
`ifdef OR1200_DIV_IMPLEMENTED
218
       `OR1200_ALUOP_DIV: begin
219
          result = a[31] ^ b[31] ? ~div_quot_r[31:0] + 32'd1 : div_quot_r[31:0];
220
       end
221
       `OR1200_ALUOP_DIVU: begin
222
          result = div_quot_r[31:0];
223
       end
224
`endif
225
`ifdef OR1200_MULT_IMPLEMENTED
226
       `OR1200_ALUOP_MUL: begin
227
          result = a[31] ^ b[31] ? ~mul_prod_r[31:0] + 32'd1 : mul_prod_r[31:0];
228
       end
229
         `OR1200_ALUOP_MULU: begin
230
          result = mul_prod_r[31:0];
231
       end
232
`endif
233
       default:
234
`ifdef OR1200_MAC_IMPLEMENTED
235 350 julius
 `ifdef OR1200_MAC_SHIFTBY
236 435 julius
         result = mac_r[`OR1200_MAC_SHIFTBY+31:`OR1200_MAC_SHIFTBY];
237 350 julius
 `else
238 435 julius
       result = mac_r[31:0];
239 350 julius
 `endif
240 435 julius
`else
241
       result = {width{1'b0}};
242
`endif
243 502 julius
     endcase // casez (alu_op)
244 435 julius
 
245 502 julius
 
246
   //
247
   // Overflow generation
248
   //
249
   always @*
250
     casez(alu_op)      // synopsys parallel_case
251
`ifdef OR1200_IMPL_OV
252
 `ifdef OR1200_MULT_IMPLEMENTED
253
       `OR1200_ALUOP_MUL: begin
254
          // Actually doing unsigned multiply internally, and then negate on
255
          // output as appropriate, so if sign bit is set, then is overflow
256 505 julius
          // unless incoming signs differ and result is 2^(width-1)
257
          ovforw = (mul_prod_r[width-1] &&
258
                    !((a[width-1]^b[width-1]) && ~|mul_prod_r[width-2:0])) ||
259
                   |mul_prod_r[2*width-1:32];
260
 
261 502 julius
          ov_we = 1;
262
       end
263
       `OR1200_ALUOP_MULU : begin
264
          // Overflow on unsigned multiply is simpler.
265 505 julius
          ovforw = |mul_prod_r[2*width-1:32];
266 502 julius
          ov_we = 1;
267
       end
268
 `endif //  `ifdef OR1200_MULT_IMPLEMENTED
269
 `ifdef OR1200_DIV_IMPLEMENTED
270
       `OR1200_ALUOP_DIVU,
271
       `OR1200_ALUOP_DIV: begin
272 505 julius
          // Overflow on divide by zero or -2^(width-1)/-1
273
          ovforw = div_by_zero || (a==32'h8000_0000 && b==32'hffff_ffff);
274 502 julius
          ov_we = 1;
275
       end
276
 `endif
277
`endif //  `ifdef OR1200_IMPL_OV
278
       default: begin
279
          ovforw = 0;
280
          ov_we = 0;
281
       end
282
     endcase // casez (alu_op)
283
 
284
 
285 435 julius
`ifdef OR1200_MULT_IMPLEMENTED
286
 `ifdef OR1200_MULT_SERIAL
287
 
288
   always @(`OR1200_RST_EVENT rst or posedge clk)
289
     if (rst == `OR1200_RST_VALUE) begin
290
        mul_prod_r <=  64'h0000_0000_0000_0000;
291
        serial_mul_cnt <= 6'd0;
292
        mul_free <= 1'b1;
293
 
294
     end
295
     else if (|serial_mul_cnt) begin
296
        serial_mul_cnt <= serial_mul_cnt - 6'd1;
297
        if (mul_prod_r[0])
298
          mul_prod_r[(width*2)-1:width-1] <= mul_prod_r[(width*2)-1:width] + x;
299
        else
300
          mul_prod_r[(width*2)-1:width-1] <= {1'b0,mul_prod_r[(width*2)-1:
301
                                                              width]};
302
        mul_prod_r[width-2:0] <= mul_prod_r[width-1:1];
303
 
304
     end
305
     else if (alu_op_mul && mul_free) begin
306
        mul_prod_r <= {32'd0, y};
307
        mul_free <= 0;
308
        serial_mul_cnt <= 6'b10_0000;
309
     end
310
     else if (!ex_freeze | mul_free) begin
311
        mul_free <= 1'b1;
312
     end
313
 
314 501 julius
   assign mul_stall = (|serial_mul_cnt) | (alu_op_mul & !ex_freeze_r);
315 350 julius
 
316 435 julius
 `else
317
 
318 350 julius
   //
319
   // Instantiation of the multiplier
320
   //
321 435 julius
  `ifdef OR1200_ASIC_MULTP2_32X32
322
   or1200_amultp2_32x32 or1200_amultp2_32x32(
323
                                             .X(x),
324
                                             .Y(y),
325
                                             .RST(rst),
326
                                             .CLK(clk),
327
                                             .P(mul_prod)
328
                                             );
329
  `else // OR1200_ASIC_MULTP2_32X32
330
   or1200_gmultp2_32x32 or1200_gmultp2_32x32(
331
                                             .X(x),
332
                                             .Y(y),
333
                                             .RST(rst),
334
                                             .CLK(clk),
335
                                             .P(mul_prod)
336
                                             );
337
  `endif // OR1200_ASIC_MULTP2_32X32   
338
 
339
   //
340
   // Registered output from the multiplier
341
   //
342
   always @(`OR1200_RST_EVENT rst or posedge clk)
343
     if (rst == `OR1200_RST_VALUE) begin
344
        mul_prod_r <=  64'h0000_0000_0000_0000;
345
     end
346
     else begin
347
        mul_prod_r <=  mul_prod[63:0];
348
     end
349 350 julius
 
350 499 julius
   //
351
   // Generate stall signal during multiplication
352
   //
353
   always @(`OR1200_RST_EVENT rst or posedge clk)
354
     if (rst == `OR1200_RST_VALUE)
355
       mul_stall_count <= 0;
356
     else if (!(|mul_stall_count))
357
       mul_stall_count <= {mul_stall_count[0], alu_op_mul & !ex_freeze_r};
358
     else
359
       mul_stall_count <= {mul_stall_count[0],1'b0};
360
 
361
   assign mul_stall = (|mul_stall_count) |
362
                      (!(|mul_stall_count) & alu_op_mul & !ex_freeze_r);
363
 
364 435 julius
 `endif // !`ifdef OR1200_MULT_SERIAL   
365
 
366 350 julius
`else // OR1200_MULT_IMPLEMENTED
367 435 julius
   assign mul_prod = {2*width{1'b0}};
368
   assign mul_prod_r = {2*width{1'b0}};
369
   assign mul_stall = 0;
370 350 julius
`endif // OR1200_MULT_IMPLEMENTED
371
 
372
`ifdef OR1200_MAC_IMPLEMENTED
373 356 julius
 
374 435 julius
   //
375
   // Propagation of l.mac opcode, only register it for one cycle
376
   //
377
   always @(posedge clk or `OR1200_RST_EVENT rst)
378
     if (rst == `OR1200_RST_VALUE)
379
       mac_op_r1 <=  `OR1200_MACOP_WIDTH'b0;
380
     else
381
       mac_op_r1 <=  !ex_freeze_r ? mac_op : `OR1200_MACOP_WIDTH'b0;
382 350 julius
 
383 435 julius
   //
384
   // Propagation of l.mac opcode
385
   //
386
   always @(posedge clk or `OR1200_RST_EVENT rst)
387
     if (rst == `OR1200_RST_VALUE)
388
       mac_op_r2 <=  `OR1200_MACOP_WIDTH'b0;
389
     else
390
       mac_op_r2 <=  mac_op_r1;
391 350 julius
 
392 435 julius
   //
393
   // Propagation of l.mac opcode
394
   //
395
   always @(posedge clk or `OR1200_RST_EVENT rst)
396
     if (rst == `OR1200_RST_VALUE)
397
       mac_op_r3 <=  `OR1200_MACOP_WIDTH'b0;
398
     else
399
       mac_op_r3 <=  mac_op_r2;
400 350 julius
 
401 435 julius
   //
402
   // Implementation of MAC
403
   //
404
   always @(`OR1200_RST_EVENT rst or posedge clk)
405
     if (rst == `OR1200_RST_VALUE)
406
       mac_r <=  64'h0000_0000_0000_0000;
407
 `ifdef OR1200_MAC_SPR_WE
408
     else if (spr_maclo_we)
409
       mac_r[31:0] <=  spr_dat_i;
410
     else if (spr_machi_we)
411
       mac_r[63:32] <=  spr_dat_i;
412
 `endif
413
     else if (mac_op_r3 == `OR1200_MACOP_MAC)
414
       mac_r <=  mac_r + mul_prod_r;
415
     else if (mac_op_r3 == `OR1200_MACOP_MSB)
416
       mac_r <=  mac_r - mul_prod_r;
417
     else if (macrc_op && !ex_freeze)
418
       mac_r <=  64'h0000_0000_0000_0000;
419 350 julius
 
420 435 julius
   //
421
   // Stall CPU if l.macrc is in ID and MAC still has to process l.mac 
422
   // instructions in EX stage (e.g. inside multiplier)
423
   // This stall signal is also used by the divider.
424
   //
425
   always @(`OR1200_RST_EVENT rst or posedge clk)
426
     if (rst == `OR1200_RST_VALUE)
427
       mac_stall_r <=  1'b0;
428
     else
429
       mac_stall_r <=  (|mac_op | (|mac_op_r1) | (|mac_op_r2)) &
430
                       (id_macrc_op | mac_stall_r);
431 499 julius
 
432 350 julius
`else // OR1200_MAC_IMPLEMENTED
433 435 julius
   assign mac_stall_r = 1'b0;
434
   assign mac_r = {2*width{1'b0}};
435
   assign mac_op_r1 = `OR1200_MACOP_WIDTH'b0;
436
   assign mac_op_r2 = `OR1200_MACOP_WIDTH'b0;
437
   assign mac_op_r3 = `OR1200_MACOP_WIDTH'b0;
438 350 julius
`endif // OR1200_MAC_IMPLEMENTED
439
 
440 435 julius
`ifdef OR1200_DIV_IMPLEMENTED
441
 
442
   //
443
   // Serial division
444
   //
445
 `ifdef OR1200_DIV_SERIAL
446
   assign div_tmp = div_quot_r[63:32] - y;
447
   always @(`OR1200_RST_EVENT rst or posedge clk)
448
     if (rst == `OR1200_RST_VALUE) begin
449
        div_quot_r <=  64'h0000_0000_0000_0000;
450
        div_free <=  1'b1;
451
        div_cntr <=  6'b00_0000;
452
     end
453 502 julius
     else if (div_by_zero) begin
454
        div_quot_r <=  64'h0000_0000_0000_0000;
455
        div_free <=  1'b1;
456
        div_cntr <=  6'b00_0000;
457
     end
458 435 julius
     else if (|div_cntr) begin
459
        if (div_tmp[31])
460
          div_quot_r <=  {div_quot_r[62:0], 1'b0};
461
        else
462
          div_quot_r <=  {div_tmp[30:0], div_quot_r[31:0], 1'b1};
463
        div_cntr <=  div_cntr - 6'd1;
464
     end
465
     else if (alu_op_div && div_free) begin
466
        div_quot_r <=  {31'b0, x[31:0], 1'b0};
467
        div_cntr <=  6'b10_0000;
468
        div_free <=  1'b0;
469
     end
470
     else if (div_free | !ex_freeze) begin
471
        div_free <=  1'b1;
472
     end
473
 
474 501 julius
   assign div_stall = (|div_cntr) | (!ex_freeze_r & alu_op_div);
475 435 julius
 
476
 
477
 `else // !`ifdef OR1200_DIV_SERIAL
478
 
479
   // Full divider
480
   // TODO: Perhaps provide module that can be technology dependent.
481
   always @(`OR1200_RST_EVENT rst or posedge clk) begin
482
      if (rst == `OR1200_RST_VALUE) begin
483
         div_quot_r <=  32'd0;
484
         div_quot_generic <= 32'd0;
485
      end
486
      else begin
487
         if (alu_op_udiv & !(|y)) // unsigned divide by 0 - force to MAX
488
           div_quot_generic[31:0] <= 32'hffff_ffff;
489
         else if (alu_op_div)
490
           div_quot_generic[31:0] <= x / y;
491
      end
492
 
493
      // Add any additional statges of pipelining as required here. Ensure
494
      // ends with div_quot_r.
495
      // Then add logic to ensure div_stall stays high for as long as the
496
      // division should take.      
497
 
498
      div_quot_r[31:0] <= div_quot_generic;
499
 
500
   end
501
 
502
   assign div_stall = 0;
503
 
504
 `endif
505
 
506
`else // !`ifdef OR1200_DIV_IMPLEMENTED
507
 
508
   assign div_stall = 0;
509
 
510
`endif // !`ifdef OR1200_DIV_IMPLEMENTED
511
 
512
 
513
   //   
514
   // Stall output
515
   //
516
   assign mult_mac_stall = mac_stall_r | div_stall | mul_stall;
517
 
518 350 julius
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.