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

Subversion Repositories openrisc

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

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

Line No. Rev Author Line
1 10 unneback
//////////////////////////////////////////////////////////////////////
2
////                                                              ////
3 258 julius
////  OR1200's Top level multiplier, divider and MAC              ////
4 10 unneback
////                                                              ////
5
////  This file is part of the OpenRISC 1200 project              ////
6 258 julius
////  http://opencores.org/project,or1k                           ////
7 10 unneback
////                                                              ////
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 481 julius
////   - implement non-serial divider that is synthesizable       ////
15 10 unneback
////                                                              ////
16
////  Author(s):                                                  ////
17
////      - Damjan Lampret, lampret@opencores.org                 ////
18 481 julius
////      - Julius Baxter, julius@opencores.org                   ////
19 10 unneback
////                                                              ////
20
//////////////////////////////////////////////////////////////////////
21
////                                                              ////
22 481 julius
//// Copyright (C) 2000, 2010 Authors and OPENCORES.ORG           ////
23 10 unneback
////                                                              ////
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 141 marcus.erl
// $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 10 unneback
 
55
// synopsys translate_off
56
`include "timescale.v"
57
// synopsys translate_on
58
`include "or1200_defines.v"
59
 
60
module or1200_mult_mac(
61 481 julius
                       // Clock and reset
62
                       clk, rst,
63 10 unneback
 
64 481 julius
                       // Multiplier/MAC interface
65
                       ex_freeze, id_macrc_op, macrc_op, a, b, mac_op, alu_op,
66
                       result, mult_mac_stall,
67 10 unneback
 
68 481 julius
                       // SPR interface
69
                       spr_cs, spr_write, spr_addr, spr_dat_i, spr_dat_o
70
                       );
71 10 unneback
 
72 481 julius
   parameter width = `OR1200_OPERAND_WIDTH;
73 10 unneback
 
74 481 julius
   //
75
   // I/O
76
   //
77 10 unneback
 
78 481 julius
   //
79
   // Clock and reset
80
   //
81
   input                                clk;
82
   input                                rst;
83 10 unneback
 
84 481 julius
   //
85
   // Multiplier/MAC interface
86
   //
87
   input                                ex_freeze;
88
   input                                id_macrc_op;
89
   input                                macrc_op;
90
   input [width-1:0]                     a;
91
   input [width-1:0]                     b;
92
   input [`OR1200_MACOP_WIDTH-1:0]       mac_op;
93
   input [`OR1200_ALUOP_WIDTH-1:0]       alu_op;
94
   output [width-1:0]                    result;
95
   output                               mult_mac_stall;
96 10 unneback
 
97 481 julius
   //
98
   // SPR interface
99
   //
100
   input                                spr_cs;
101
   input                                spr_write;
102
   input [31:0]                  spr_addr;
103
   input [31:0]                  spr_dat_i;
104
   output [31:0]                         spr_dat_o;
105 10 unneback
 
106 481 julius
   //
107
   // Internal wires and regs
108
   //
109
   reg [width-1:0]                       result;
110 10 unneback
`ifdef OR1200_MULT_IMPLEMENTED
111 481 julius
   reg [2*width-1:0]                     mul_prod_r;
112
   wire                                 alu_op_smul;
113
   wire                                 alu_op_umul;
114
   wire                                 alu_op_mul;
115
 `ifdef OR1200_MULT_SERIAL
116
   reg [5:0]                             serial_mul_cnt;
117
   reg                                  mul_free;
118
 `endif
119 10 unneback
`else
120 481 julius
   wire [2*width-1:0]                    mul_prod_r;
121 10 unneback
`endif
122 481 julius
   wire [2*width-1:0]                    mul_prod;
123
   wire                                 mul_stall;
124
 
125
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op;
126 10 unneback
`ifdef OR1200_MAC_IMPLEMENTED
127 481 julius
   reg [`OR1200_MACOP_WIDTH-1:0]         mac_op_r1;
128
   reg [`OR1200_MACOP_WIDTH-1:0]         mac_op_r2;
129
   reg [`OR1200_MACOP_WIDTH-1:0]         mac_op_r3;
130
   reg                                  mac_stall_r;
131
   reg [63:0]                            mac_r;
132 10 unneback
`else
133 481 julius
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op_r1;
134
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op_r2;
135
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op_r3;
136
   wire                                 mac_stall_r;
137
   wire [63:0]                           mac_r;
138 10 unneback
`endif
139 481 julius
   wire [width-1:0]                      x;
140
   wire [width-1:0]                      y;
141
   wire                                 spr_maclo_we;
142
   wire                                 spr_machi_we;
143
   wire                                 alu_op_div;
144
   wire                                 alu_op_udiv;
145
   wire                                 alu_op_sdiv;
146
   reg                                  div_free;
147
   wire                                 div_stall;
148 258 julius
`ifdef OR1200_DIV_IMPLEMENTED
149 481 julius
 `ifdef OR1200_DIV_SERIAL
150
   reg [2*width-1:0]                     div_quot_r;
151
   wire [width-1:0]                      div_tmp;
152
   reg [5:0]                             div_cntr;
153
 `else
154
   reg [width-1:0]                       div_quot_r;
155
   reg [width-1:0]                       div_quot_generic;
156
 `endif
157 10 unneback
`endif
158
 
159 481 julius
   //
160
   // Combinatorial logic
161
   //
162
`ifdef OR1200_MULT_IMPLEMENTED
163
   assign alu_op_smul = (alu_op == `OR1200_ALUOP_MUL);
164
   assign alu_op_umul = (alu_op == `OR1200_ALUOP_MULU);
165
   assign alu_op_mul = alu_op_smul | alu_op_umul;
166
`endif
167 10 unneback
`ifdef OR1200_MAC_IMPLEMENTED
168 481 julius
   assign spr_maclo_we = spr_cs & spr_write & spr_addr[`OR1200_MAC_ADDR];
169
   assign spr_machi_we = spr_cs & spr_write & !spr_addr[`OR1200_MAC_ADDR];
170
   assign spr_dat_o = spr_addr[`OR1200_MAC_ADDR] ? mac_r[31:0] : mac_r[63:32];
171 10 unneback
`else
172 481 julius
   assign spr_maclo_we = 1'b0;
173
   assign spr_machi_we = 1'b0;
174
   assign spr_dat_o = 32'h0000_0000;
175 10 unneback
`endif
176 258 julius
`ifdef OR1200_DIV_IMPLEMENTED
177 481 julius
   assign alu_op_sdiv = (alu_op == `OR1200_ALUOP_DIV);
178
   assign alu_op_udiv = (alu_op == `OR1200_ALUOP_DIVU);
179
   assign alu_op_div = alu_op_sdiv | alu_op_udiv;
180 10 unneback
`else
181 481 julius
   assign alu_op_udiv = 1'b0;
182
   assign alu_op_sdiv = 1'b0;
183
   assign alu_op_div = 1'b0;
184 10 unneback
`endif
185
 
186 481 julius
   assign x = (alu_op_sdiv | alu_op_smul) & a[31] ? ~a + 32'b1 :
187
              alu_op_div | alu_op_mul | (|mac_op) ? a : 32'd0;
188
   assign y = (alu_op_sdiv | alu_op_smul) & b[31] ? ~b + 32'b1 :
189
              alu_op_div | alu_op_mul | (|mac_op) ? b : 32'd0;
190 10 unneback
 
191 481 julius
   //
192
   // Select result of current ALU operation to be forwarded
193
   // to next instruction and to WB stage
194
   //
195
   always @*
196
     casez(alu_op)      // synopsys parallel_case
197
`ifdef OR1200_DIV_IMPLEMENTED
198
       `OR1200_ALUOP_DIV: begin
199
          result = a[31] ^ b[31] ? ~div_quot_r[31:0] + 32'd1 : div_quot_r[31:0];
200
       end
201
       `OR1200_ALUOP_DIVU: begin
202
          result = div_quot_r[31:0];
203
       end
204
`endif
205
`ifdef OR1200_MULT_IMPLEMENTED
206
       `OR1200_ALUOP_MUL: begin
207
          result = a[31] ^ b[31] ? ~mul_prod_r[31:0] + 32'd1 : mul_prod_r[31:0];
208
       end
209
         `OR1200_ALUOP_MULU: begin
210
          result = mul_prod_r[31:0];
211
       end
212
`endif
213
       default:
214
`ifdef OR1200_MAC_IMPLEMENTED
215 258 julius
 `ifdef OR1200_MAC_SHIFTBY
216 481 julius
         result = mac_r[`OR1200_MAC_SHIFTBY+31:`OR1200_MAC_SHIFTBY];
217 258 julius
 `else
218 481 julius
       result = mac_r[31:0];
219 258 julius
 `endif
220 481 julius
`else
221
       result = {width{1'b0}};
222
`endif
223
     endcase
224
 
225
`ifdef OR1200_MULT_IMPLEMENTED
226
 `ifdef OR1200_MULT_SERIAL
227
 
228
   always @(`OR1200_RST_EVENT rst or posedge clk)
229
     if (rst == `OR1200_RST_VALUE) begin
230
        mul_prod_r <=  64'h0000_0000_0000_0000;
231
        serial_mul_cnt <= 6'd0;
232
        mul_free <= 1'b1;
233
 
234
     end
235
     else if (|serial_mul_cnt) begin
236
        serial_mul_cnt <= serial_mul_cnt - 6'd1;
237
        if (mul_prod_r[0])
238
          mul_prod_r[(width*2)-1:width-1] <= mul_prod_r[(width*2)-1:width] + x;
239
        else
240
          mul_prod_r[(width*2)-1:width-1] <= {1'b0,mul_prod_r[(width*2)-1:
241
                                                              width]};
242
        mul_prod_r[width-2:0] <= mul_prod_r[width-1:1];
243
 
244
     end
245
     else if (alu_op_mul && mul_free) begin
246
        mul_prod_r <= {32'd0, y};
247
        mul_free <= 0;
248
        serial_mul_cnt <= 6'b10_0000;
249
     end
250
     else if (!ex_freeze | mul_free) begin
251
        mul_free <= 1'b1;
252
     end
253
 
254
   assign mul_stall = (|serial_mul_cnt);
255 258 julius
 
256 481 julius
 `else
257
 
258 258 julius
   //
259
   // Instantiation of the multiplier
260
   //
261 481 julius
  `ifdef OR1200_ASIC_MULTP2_32X32
262
   or1200_amultp2_32x32 or1200_amultp2_32x32(
263
                                             .X(x),
264
                                             .Y(y),
265
                                             .RST(rst),
266
                                             .CLK(clk),
267
                                             .P(mul_prod)
268
                                             );
269
  `else // OR1200_ASIC_MULTP2_32X32
270
   or1200_gmultp2_32x32 or1200_gmultp2_32x32(
271
                                             .X(x),
272
                                             .Y(y),
273
                                             .RST(rst),
274
                                             .CLK(clk),
275
                                             .P(mul_prod)
276
                                             );
277
  `endif // OR1200_ASIC_MULTP2_32X32   
278
 
279
   //
280
   // Registered output from the multiplier
281
   //
282
   always @(`OR1200_RST_EVENT rst or posedge clk)
283
     if (rst == `OR1200_RST_VALUE) begin
284
        mul_prod_r <=  64'h0000_0000_0000_0000;
285
     end
286
     else begin
287
        mul_prod_r <=  mul_prod[63:0];
288
     end
289 10 unneback
 
290 481 julius
   assign mul_stall = 0;
291
 `endif // !`ifdef OR1200_MULT_SERIAL   
292
 
293 10 unneback
`else // OR1200_MULT_IMPLEMENTED
294 481 julius
   assign mul_prod = {2*width{1'b0}};
295
   assign mul_prod_r = {2*width{1'b0}};
296
   assign mul_stall = 0;
297 10 unneback
`endif // OR1200_MULT_IMPLEMENTED
298
 
299
`ifdef OR1200_MAC_IMPLEMENTED
300 481 julius
   // Signal to indicate when we should check for new MAC op
301
   reg ex_freeze_r;
302 356 julius
 
303 481 julius
   always @(posedge clk or `OR1200_RST_EVENT rst)
304
     if (rst == `OR1200_RST_VALUE)
305
       ex_freeze_r <= 1'b1;
306
     else
307
       ex_freeze_r <= ex_freeze;
308 356 julius
 
309 481 julius
   //
310
   // Propagation of l.mac opcode, only register it for one cycle
311
   //
312
   always @(posedge clk or `OR1200_RST_EVENT rst)
313
     if (rst == `OR1200_RST_VALUE)
314
       mac_op_r1 <=  `OR1200_MACOP_WIDTH'b0;
315
     else
316
       mac_op_r1 <=  !ex_freeze_r ? mac_op : `OR1200_MACOP_WIDTH'b0;
317 10 unneback
 
318 481 julius
   //
319
   // Propagation of l.mac opcode
320
   //
321
   always @(posedge clk or `OR1200_RST_EVENT rst)
322
     if (rst == `OR1200_RST_VALUE)
323
       mac_op_r2 <=  `OR1200_MACOP_WIDTH'b0;
324
     else
325
       mac_op_r2 <=  mac_op_r1;
326 10 unneback
 
327 481 julius
   //
328
   // Propagation of l.mac opcode
329
   //
330
   always @(posedge clk or `OR1200_RST_EVENT rst)
331
     if (rst == `OR1200_RST_VALUE)
332
       mac_op_r3 <=  `OR1200_MACOP_WIDTH'b0;
333
     else
334
       mac_op_r3 <=  mac_op_r2;
335 10 unneback
 
336 481 julius
   //
337
   // Implementation of MAC
338
   //
339
   always @(`OR1200_RST_EVENT rst or posedge clk)
340
     if (rst == `OR1200_RST_VALUE)
341
       mac_r <=  64'h0000_0000_0000_0000;
342
 `ifdef OR1200_MAC_SPR_WE
343
     else if (spr_maclo_we)
344
       mac_r[31:0] <=  spr_dat_i;
345
     else if (spr_machi_we)
346
       mac_r[63:32] <=  spr_dat_i;
347
 `endif
348
     else if (mac_op_r3 == `OR1200_MACOP_MAC)
349
       mac_r <=  mac_r + mul_prod_r;
350
     else if (mac_op_r3 == `OR1200_MACOP_MSB)
351
       mac_r <=  mac_r - mul_prod_r;
352
     else if (macrc_op && !ex_freeze)
353
       mac_r <=  64'h0000_0000_0000_0000;
354 10 unneback
 
355 481 julius
   //
356
   // Stall CPU if l.macrc is in ID and MAC still has to process l.mac 
357
   // instructions in EX stage (e.g. inside multiplier)
358
   // This stall signal is also used by the divider.
359
   //
360
   always @(`OR1200_RST_EVENT rst or posedge clk)
361
     if (rst == `OR1200_RST_VALUE)
362
       mac_stall_r <=  1'b0;
363
     else
364
       mac_stall_r <=  (|mac_op | (|mac_op_r1) | (|mac_op_r2)) &
365
                       (id_macrc_op | mac_stall_r);
366 10 unneback
`else // OR1200_MAC_IMPLEMENTED
367 481 julius
   assign mac_stall_r = 1'b0;
368
   assign mac_r = {2*width{1'b0}};
369
   assign mac_op_r1 = `OR1200_MACOP_WIDTH'b0;
370
   assign mac_op_r2 = `OR1200_MACOP_WIDTH'b0;
371
   assign mac_op_r3 = `OR1200_MACOP_WIDTH'b0;
372 10 unneback
`endif // OR1200_MAC_IMPLEMENTED
373
 
374 481 julius
`ifdef OR1200_DIV_IMPLEMENTED
375
 
376
   //
377
   // Serial division
378
   //
379
 `ifdef OR1200_DIV_SERIAL
380
   assign div_tmp = div_quot_r[63:32] - y;
381
   always @(`OR1200_RST_EVENT rst or posedge clk)
382
     if (rst == `OR1200_RST_VALUE) begin
383
        div_quot_r <=  64'h0000_0000_0000_0000;
384
        div_free <=  1'b1;
385
        div_cntr <=  6'b00_0000;
386
     end
387
     else if (|div_cntr) begin
388
        if (div_tmp[31])
389
          div_quot_r <=  {div_quot_r[62:0], 1'b0};
390
        else
391
          div_quot_r <=  {div_tmp[30:0], div_quot_r[31:0], 1'b1};
392
        div_cntr <=  div_cntr - 6'd1;
393
     end
394
     else if (alu_op_div && div_free) begin
395
        div_quot_r <=  {31'b0, x[31:0], 1'b0};
396
        div_cntr <=  6'b10_0000;
397
        div_free <=  1'b0;
398
     end
399
     else if (div_free | !ex_freeze) begin
400
        //div_quot_r <=  div_quot[63:0];
401
        div_free <=  1'b1;
402
     end
403
 
404
   assign div_stall = (|div_cntr);
405
 
406
 
407
 `else // !`ifdef OR1200_DIV_SERIAL
408
 
409
   // Full divider
410
   // TODO: Perhaps provide module that can be technology dependent.
411
   always @(`OR1200_RST_EVENT rst or posedge clk) begin
412
      if (rst == `OR1200_RST_VALUE) begin
413
         div_quot_r <=  32'd0;
414
         div_quot_generic <= 32'd0;
415
      end
416
      else begin
417
         if (alu_op_udiv & !(|y)) // unsigned divide by 0 - force to MAX
418
           div_quot_generic[31:0] <= 32'hffff_ffff;
419
         else if (alu_op_div)
420
           div_quot_generic[31:0] <= x / y;
421
      end
422
 
423
      // Add any additional statges of pipelining as required here. Ensure
424
      // ends with div_quot_r.
425
      // Then add logic to ensure div_stall stays high for as long as the
426
      // division should take.      
427
 
428
      div_quot_r[31:0] <= div_quot_generic;
429
 
430
   end
431
 
432
   assign div_stall = 0;
433
 
434
 `endif
435
 
436
`else // !`ifdef OR1200_DIV_IMPLEMENTED
437
 
438
   assign div_stall = 0;
439
 
440
`endif // !`ifdef OR1200_DIV_IMPLEMENTED
441
 
442
 
443
   //   
444
   // Stall output
445
   //
446
   assign mult_mac_stall = mac_stall_r | div_stall | mul_stall;
447
 
448 10 unneback
endmodule

powered by: WebSVN 2.1.0

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