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 502

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 350 julius
`ifdef OR1200_MULT_IMPLEMENTED
116 435 julius
   reg [2*width-1:0]                     mul_prod_r;
117
   wire                                 alu_op_smul;
118
   wire                                 alu_op_umul;
119
   wire                                 alu_op_mul;
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
`endif
174 350 julius
`ifdef OR1200_MAC_IMPLEMENTED
175 435 julius
   assign spr_maclo_we = spr_cs & spr_write & spr_addr[`OR1200_MAC_ADDR];
176
   assign spr_machi_we = spr_cs & spr_write & !spr_addr[`OR1200_MAC_ADDR];
177
   assign spr_dat_o = spr_addr[`OR1200_MAC_ADDR] ? mac_r[31:0] : mac_r[63:32];
178 350 julius
`else
179 435 julius
   assign spr_maclo_we = 1'b0;
180
   assign spr_machi_we = 1'b0;
181
   assign spr_dat_o = 32'h0000_0000;
182 350 julius
`endif
183
`ifdef OR1200_DIV_IMPLEMENTED
184 435 julius
   assign alu_op_sdiv = (alu_op == `OR1200_ALUOP_DIV);
185
   assign alu_op_udiv = (alu_op == `OR1200_ALUOP_DIVU);
186
   assign alu_op_div = alu_op_sdiv | alu_op_udiv;
187 350 julius
`else
188 435 julius
   assign alu_op_udiv = 1'b0;
189
   assign alu_op_sdiv = 1'b0;
190
   assign alu_op_div = 1'b0;
191 350 julius
`endif
192
 
193 435 julius
   assign x = (alu_op_sdiv | alu_op_smul) & a[31] ? ~a + 32'b1 :
194
              alu_op_div | alu_op_mul | (|mac_op) ? a : 32'd0;
195
   assign y = (alu_op_sdiv | alu_op_smul) & b[31] ? ~b + 32'b1 :
196
              alu_op_div | alu_op_mul | (|mac_op) ? b : 32'd0;
197 350 julius
 
198 502 julius
   assign div_by_zero = !(|b) & alu_op_div;
199
 
200
 
201 499 julius
   // Used to indicate when we should check for new multiply or MAC ops
202
   always @(posedge clk or `OR1200_RST_EVENT rst)
203
     if (rst == `OR1200_RST_VALUE)
204
       ex_freeze_r <= 1'b1;
205
     else
206
       ex_freeze_r <= ex_freeze;
207
 
208 435 julius
   //
209
   // Select result of current ALU operation to be forwarded
210
   // to next instruction and to WB stage
211
   //
212
   always @*
213
     casez(alu_op)      // synopsys parallel_case
214
`ifdef OR1200_DIV_IMPLEMENTED
215
       `OR1200_ALUOP_DIV: begin
216
          result = a[31] ^ b[31] ? ~div_quot_r[31:0] + 32'd1 : div_quot_r[31:0];
217
       end
218
       `OR1200_ALUOP_DIVU: begin
219
          result = div_quot_r[31:0];
220
       end
221
`endif
222
`ifdef OR1200_MULT_IMPLEMENTED
223
       `OR1200_ALUOP_MUL: begin
224
          result = a[31] ^ b[31] ? ~mul_prod_r[31:0] + 32'd1 : mul_prod_r[31:0];
225
       end
226
         `OR1200_ALUOP_MULU: begin
227
          result = mul_prod_r[31:0];
228
       end
229
`endif
230
       default:
231
`ifdef OR1200_MAC_IMPLEMENTED
232 350 julius
 `ifdef OR1200_MAC_SHIFTBY
233 435 julius
         result = mac_r[`OR1200_MAC_SHIFTBY+31:`OR1200_MAC_SHIFTBY];
234 350 julius
 `else
235 435 julius
       result = mac_r[31:0];
236 350 julius
 `endif
237 435 julius
`else
238
       result = {width{1'b0}};
239
`endif
240 502 julius
     endcase // casez (alu_op)
241 435 julius
 
242 502 julius
 
243
   //
244
   // Overflow generation
245
   //
246
   always @*
247
     casez(alu_op)      // synopsys parallel_case
248
`ifdef OR1200_IMPL_OV
249
 `ifdef OR1200_MULT_IMPLEMENTED
250
       `OR1200_ALUOP_MUL: begin
251
          // Actually doing unsigned multiply internally, and then negate on
252
          // output as appropriate, so if sign bit is set, then is overflow
253
          ovforw = mul_prod_r[31];
254
          ov_we = 1;
255
       end
256
       `OR1200_ALUOP_MULU : begin
257
          // Overflow on unsigned multiply is simpler.
258
          ovforw = mul_prod_r[32];
259
          ov_we = 1;
260
       end
261
 `endif //  `ifdef OR1200_MULT_IMPLEMENTED
262
 `ifdef OR1200_DIV_IMPLEMENTED
263
       `OR1200_ALUOP_DIVU,
264
       `OR1200_ALUOP_DIV: begin
265
          // Overflow on divide by zero
266
          ovforw = div_by_zero;
267
          ov_we = 1;
268
       end
269
 `endif
270
`endif //  `ifdef OR1200_IMPL_OV
271
       default: begin
272
          ovforw = 0;
273
          ov_we = 0;
274
       end
275
     endcase // casez (alu_op)
276
 
277
 
278 435 julius
`ifdef OR1200_MULT_IMPLEMENTED
279
 `ifdef OR1200_MULT_SERIAL
280
 
281
   always @(`OR1200_RST_EVENT rst or posedge clk)
282
     if (rst == `OR1200_RST_VALUE) begin
283
        mul_prod_r <=  64'h0000_0000_0000_0000;
284
        serial_mul_cnt <= 6'd0;
285
        mul_free <= 1'b1;
286
 
287
     end
288
     else if (|serial_mul_cnt) begin
289
        serial_mul_cnt <= serial_mul_cnt - 6'd1;
290
        if (mul_prod_r[0])
291
          mul_prod_r[(width*2)-1:width-1] <= mul_prod_r[(width*2)-1:width] + x;
292
        else
293
          mul_prod_r[(width*2)-1:width-1] <= {1'b0,mul_prod_r[(width*2)-1:
294
                                                              width]};
295
        mul_prod_r[width-2:0] <= mul_prod_r[width-1:1];
296
 
297
     end
298
     else if (alu_op_mul && mul_free) begin
299
        mul_prod_r <= {32'd0, y};
300
        mul_free <= 0;
301
        serial_mul_cnt <= 6'b10_0000;
302
     end
303
     else if (!ex_freeze | mul_free) begin
304
        mul_free <= 1'b1;
305
     end
306
 
307 501 julius
   assign mul_stall = (|serial_mul_cnt) | (alu_op_mul & !ex_freeze_r);
308 350 julius
 
309 435 julius
 `else
310
 
311 350 julius
   //
312
   // Instantiation of the multiplier
313
   //
314 435 julius
  `ifdef OR1200_ASIC_MULTP2_32X32
315
   or1200_amultp2_32x32 or1200_amultp2_32x32(
316
                                             .X(x),
317
                                             .Y(y),
318
                                             .RST(rst),
319
                                             .CLK(clk),
320
                                             .P(mul_prod)
321
                                             );
322
  `else // OR1200_ASIC_MULTP2_32X32
323
   or1200_gmultp2_32x32 or1200_gmultp2_32x32(
324
                                             .X(x),
325
                                             .Y(y),
326
                                             .RST(rst),
327
                                             .CLK(clk),
328
                                             .P(mul_prod)
329
                                             );
330
  `endif // OR1200_ASIC_MULTP2_32X32   
331
 
332
   //
333
   // Registered output from the multiplier
334
   //
335
   always @(`OR1200_RST_EVENT rst or posedge clk)
336
     if (rst == `OR1200_RST_VALUE) begin
337
        mul_prod_r <=  64'h0000_0000_0000_0000;
338
     end
339
     else begin
340
        mul_prod_r <=  mul_prod[63:0];
341
     end
342 350 julius
 
343 499 julius
   //
344
   // Generate stall signal during multiplication
345
   //
346
   always @(`OR1200_RST_EVENT rst or posedge clk)
347
     if (rst == `OR1200_RST_VALUE)
348
       mul_stall_count <= 0;
349
     else if (!(|mul_stall_count))
350
       mul_stall_count <= {mul_stall_count[0], alu_op_mul & !ex_freeze_r};
351
     else
352
       mul_stall_count <= {mul_stall_count[0],1'b0};
353
 
354
   assign mul_stall = (|mul_stall_count) |
355
                      (!(|mul_stall_count) & alu_op_mul & !ex_freeze_r);
356
 
357 435 julius
 `endif // !`ifdef OR1200_MULT_SERIAL   
358
 
359 350 julius
`else // OR1200_MULT_IMPLEMENTED
360 435 julius
   assign mul_prod = {2*width{1'b0}};
361
   assign mul_prod_r = {2*width{1'b0}};
362
   assign mul_stall = 0;
363 350 julius
`endif // OR1200_MULT_IMPLEMENTED
364
 
365
`ifdef OR1200_MAC_IMPLEMENTED
366 356 julius
 
367 435 julius
   //
368
   // Propagation of l.mac opcode, only register it for one cycle
369
   //
370
   always @(posedge clk or `OR1200_RST_EVENT rst)
371
     if (rst == `OR1200_RST_VALUE)
372
       mac_op_r1 <=  `OR1200_MACOP_WIDTH'b0;
373
     else
374
       mac_op_r1 <=  !ex_freeze_r ? mac_op : `OR1200_MACOP_WIDTH'b0;
375 350 julius
 
376 435 julius
   //
377
   // Propagation of l.mac opcode
378
   //
379
   always @(posedge clk or `OR1200_RST_EVENT rst)
380
     if (rst == `OR1200_RST_VALUE)
381
       mac_op_r2 <=  `OR1200_MACOP_WIDTH'b0;
382
     else
383
       mac_op_r2 <=  mac_op_r1;
384 350 julius
 
385 435 julius
   //
386
   // Propagation of l.mac opcode
387
   //
388
   always @(posedge clk or `OR1200_RST_EVENT rst)
389
     if (rst == `OR1200_RST_VALUE)
390
       mac_op_r3 <=  `OR1200_MACOP_WIDTH'b0;
391
     else
392
       mac_op_r3 <=  mac_op_r2;
393 350 julius
 
394 435 julius
   //
395
   // Implementation of MAC
396
   //
397
   always @(`OR1200_RST_EVENT rst or posedge clk)
398
     if (rst == `OR1200_RST_VALUE)
399
       mac_r <=  64'h0000_0000_0000_0000;
400
 `ifdef OR1200_MAC_SPR_WE
401
     else if (spr_maclo_we)
402
       mac_r[31:0] <=  spr_dat_i;
403
     else if (spr_machi_we)
404
       mac_r[63:32] <=  spr_dat_i;
405
 `endif
406
     else if (mac_op_r3 == `OR1200_MACOP_MAC)
407
       mac_r <=  mac_r + mul_prod_r;
408
     else if (mac_op_r3 == `OR1200_MACOP_MSB)
409
       mac_r <=  mac_r - mul_prod_r;
410
     else if (macrc_op && !ex_freeze)
411
       mac_r <=  64'h0000_0000_0000_0000;
412 350 julius
 
413 435 julius
   //
414
   // Stall CPU if l.macrc is in ID and MAC still has to process l.mac 
415
   // instructions in EX stage (e.g. inside multiplier)
416
   // This stall signal is also used by the divider.
417
   //
418
   always @(`OR1200_RST_EVENT rst or posedge clk)
419
     if (rst == `OR1200_RST_VALUE)
420
       mac_stall_r <=  1'b0;
421
     else
422
       mac_stall_r <=  (|mac_op | (|mac_op_r1) | (|mac_op_r2)) &
423
                       (id_macrc_op | mac_stall_r);
424 499 julius
 
425 350 julius
`else // OR1200_MAC_IMPLEMENTED
426 435 julius
   assign mac_stall_r = 1'b0;
427
   assign mac_r = {2*width{1'b0}};
428
   assign mac_op_r1 = `OR1200_MACOP_WIDTH'b0;
429
   assign mac_op_r2 = `OR1200_MACOP_WIDTH'b0;
430
   assign mac_op_r3 = `OR1200_MACOP_WIDTH'b0;
431 350 julius
`endif // OR1200_MAC_IMPLEMENTED
432
 
433 435 julius
`ifdef OR1200_DIV_IMPLEMENTED
434
 
435
   //
436
   // Serial division
437
   //
438
 `ifdef OR1200_DIV_SERIAL
439
   assign div_tmp = div_quot_r[63:32] - y;
440
   always @(`OR1200_RST_EVENT rst or posedge clk)
441
     if (rst == `OR1200_RST_VALUE) begin
442
        div_quot_r <=  64'h0000_0000_0000_0000;
443
        div_free <=  1'b1;
444
        div_cntr <=  6'b00_0000;
445
     end
446 502 julius
     else if (div_by_zero) begin
447
        div_quot_r <=  64'h0000_0000_0000_0000;
448
        div_free <=  1'b1;
449
        div_cntr <=  6'b00_0000;
450
     end
451 435 julius
     else if (|div_cntr) begin
452
        if (div_tmp[31])
453
          div_quot_r <=  {div_quot_r[62:0], 1'b0};
454
        else
455
          div_quot_r <=  {div_tmp[30:0], div_quot_r[31:0], 1'b1};
456
        div_cntr <=  div_cntr - 6'd1;
457
     end
458
     else if (alu_op_div && div_free) begin
459
        div_quot_r <=  {31'b0, x[31:0], 1'b0};
460
        div_cntr <=  6'b10_0000;
461
        div_free <=  1'b0;
462
     end
463
     else if (div_free | !ex_freeze) begin
464
        div_free <=  1'b1;
465
     end
466
 
467 501 julius
   assign div_stall = (|div_cntr) | (!ex_freeze_r & alu_op_div);
468 435 julius
 
469
 
470
 `else // !`ifdef OR1200_DIV_SERIAL
471
 
472
   // Full divider
473
   // TODO: Perhaps provide module that can be technology dependent.
474
   always @(`OR1200_RST_EVENT rst or posedge clk) begin
475
      if (rst == `OR1200_RST_VALUE) begin
476
         div_quot_r <=  32'd0;
477
         div_quot_generic <= 32'd0;
478
      end
479
      else begin
480
         if (alu_op_udiv & !(|y)) // unsigned divide by 0 - force to MAX
481
           div_quot_generic[31:0] <= 32'hffff_ffff;
482
         else if (alu_op_div)
483
           div_quot_generic[31:0] <= x / y;
484
      end
485
 
486
      // Add any additional statges of pipelining as required here. Ensure
487
      // ends with div_quot_r.
488
      // Then add logic to ensure div_stall stays high for as long as the
489
      // division should take.      
490
 
491
      div_quot_r[31:0] <= div_quot_generic;
492
 
493
   end
494
 
495
   assign div_stall = 0;
496
 
497
 `endif
498
 
499
`else // !`ifdef OR1200_DIV_IMPLEMENTED
500
 
501
   assign div_stall = 0;
502
 
503
`endif // !`ifdef OR1200_DIV_IMPLEMENTED
504
 
505
 
506
   //   
507
   // Stall output
508
   //
509
   assign mult_mac_stall = mac_stall_r | div_stall | mul_stall;
510
 
511 350 julius
endmodule

powered by: WebSVN 2.1.0

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