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 640

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 640 julius
   reg                                  ex_freeze_r;
111 10 unneback
`ifdef OR1200_MULT_IMPLEMENTED
112 481 julius
   reg [2*width-1:0]                     mul_prod_r;
113
   wire                                 alu_op_smul;
114
   wire                                 alu_op_umul;
115
   wire                                 alu_op_mul;
116
 `ifdef OR1200_MULT_SERIAL
117
   reg [5:0]                             serial_mul_cnt;
118
   reg                                  mul_free;
119
 `endif
120 10 unneback
`else
121 481 julius
   wire [2*width-1:0]                    mul_prod_r;
122 10 unneback
`endif
123 481 julius
   wire [2*width-1:0]                    mul_prod;
124
   wire                                 mul_stall;
125 640 julius
   reg [1:0]                             mul_stall_count;
126 481 julius
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op;
127 10 unneback
`ifdef OR1200_MAC_IMPLEMENTED
128 481 julius
   reg [`OR1200_MACOP_WIDTH-1:0]         mac_op_r1;
129
   reg [`OR1200_MACOP_WIDTH-1:0]         mac_op_r2;
130
   reg [`OR1200_MACOP_WIDTH-1:0]         mac_op_r3;
131
   reg                                  mac_stall_r;
132
   reg [63:0]                            mac_r;
133 10 unneback
`else
134 481 julius
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op_r1;
135
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op_r2;
136
   wire [`OR1200_MACOP_WIDTH-1:0]        mac_op_r3;
137
   wire                                 mac_stall_r;
138
   wire [63:0]                           mac_r;
139 10 unneback
`endif
140 481 julius
   wire [width-1:0]                      x;
141
   wire [width-1:0]                      y;
142
   wire                                 spr_maclo_we;
143
   wire                                 spr_machi_we;
144
   wire                                 alu_op_div;
145
   wire                                 alu_op_udiv;
146
   wire                                 alu_op_sdiv;
147
   reg                                  div_free;
148
   wire                                 div_stall;
149 258 julius
`ifdef OR1200_DIV_IMPLEMENTED
150 481 julius
 `ifdef OR1200_DIV_SERIAL
151
   reg [2*width-1:0]                     div_quot_r;
152
   wire [width-1:0]                      div_tmp;
153
   reg [5:0]                             div_cntr;
154
 `else
155
   reg [width-1:0]                       div_quot_r;
156
   reg [width-1:0]                       div_quot_generic;
157
 `endif
158 10 unneback
`endif
159
 
160 481 julius
   //
161
   // Combinatorial logic
162
   //
163
`ifdef OR1200_MULT_IMPLEMENTED
164
   assign alu_op_smul = (alu_op == `OR1200_ALUOP_MUL);
165
   assign alu_op_umul = (alu_op == `OR1200_ALUOP_MULU);
166
   assign alu_op_mul = alu_op_smul | alu_op_umul;
167
`endif
168 10 unneback
`ifdef OR1200_MAC_IMPLEMENTED
169 481 julius
   assign spr_maclo_we = spr_cs & spr_write & spr_addr[`OR1200_MAC_ADDR];
170
   assign spr_machi_we = spr_cs & spr_write & !spr_addr[`OR1200_MAC_ADDR];
171
   assign spr_dat_o = spr_addr[`OR1200_MAC_ADDR] ? mac_r[31:0] : mac_r[63:32];
172 10 unneback
`else
173 481 julius
   assign spr_maclo_we = 1'b0;
174
   assign spr_machi_we = 1'b0;
175
   assign spr_dat_o = 32'h0000_0000;
176 10 unneback
`endif
177 258 julius
`ifdef OR1200_DIV_IMPLEMENTED
178 481 julius
   assign alu_op_sdiv = (alu_op == `OR1200_ALUOP_DIV);
179
   assign alu_op_udiv = (alu_op == `OR1200_ALUOP_DIVU);
180
   assign alu_op_div = alu_op_sdiv | alu_op_udiv;
181 10 unneback
`else
182 481 julius
   assign alu_op_udiv = 1'b0;
183
   assign alu_op_sdiv = 1'b0;
184
   assign alu_op_div = 1'b0;
185 10 unneback
`endif
186
 
187 481 julius
   assign x = (alu_op_sdiv | alu_op_smul) & a[31] ? ~a + 32'b1 :
188
              alu_op_div | alu_op_mul | (|mac_op) ? a : 32'd0;
189
   assign y = (alu_op_sdiv | alu_op_smul) & b[31] ? ~b + 32'b1 :
190
              alu_op_div | alu_op_mul | (|mac_op) ? b : 32'd0;
191 10 unneback
 
192 640 julius
   // Used to indicate when we should check for new multiply or MAC ops
193
   always @(posedge clk or `OR1200_RST_EVENT rst)
194
     if (rst == `OR1200_RST_VALUE)
195
       ex_freeze_r <= 1'b1;
196
     else
197
       ex_freeze_r <= ex_freeze;
198
 
199 481 julius
   //
200
   // Select result of current ALU operation to be forwarded
201
   // to next instruction and to WB stage
202
   //
203
   always @*
204
     casez(alu_op)      // synopsys parallel_case
205
`ifdef OR1200_DIV_IMPLEMENTED
206
       `OR1200_ALUOP_DIV: begin
207
          result = a[31] ^ b[31] ? ~div_quot_r[31:0] + 32'd1 : div_quot_r[31:0];
208
       end
209
       `OR1200_ALUOP_DIVU: begin
210
          result = div_quot_r[31:0];
211
       end
212
`endif
213
`ifdef OR1200_MULT_IMPLEMENTED
214
       `OR1200_ALUOP_MUL: begin
215
          result = a[31] ^ b[31] ? ~mul_prod_r[31:0] + 32'd1 : mul_prod_r[31:0];
216
       end
217
         `OR1200_ALUOP_MULU: begin
218
          result = mul_prod_r[31:0];
219
       end
220
`endif
221
       default:
222
`ifdef OR1200_MAC_IMPLEMENTED
223 258 julius
 `ifdef OR1200_MAC_SHIFTBY
224 481 julius
         result = mac_r[`OR1200_MAC_SHIFTBY+31:`OR1200_MAC_SHIFTBY];
225 258 julius
 `else
226 481 julius
       result = mac_r[31:0];
227 258 julius
 `endif
228 481 julius
`else
229
       result = {width{1'b0}};
230
`endif
231
     endcase
232
 
233
`ifdef OR1200_MULT_IMPLEMENTED
234
 `ifdef OR1200_MULT_SERIAL
235
 
236
   always @(`OR1200_RST_EVENT rst or posedge clk)
237
     if (rst == `OR1200_RST_VALUE) begin
238
        mul_prod_r <=  64'h0000_0000_0000_0000;
239
        serial_mul_cnt <= 6'd0;
240
        mul_free <= 1'b1;
241
 
242
     end
243
     else if (|serial_mul_cnt) begin
244
        serial_mul_cnt <= serial_mul_cnt - 6'd1;
245
        if (mul_prod_r[0])
246
          mul_prod_r[(width*2)-1:width-1] <= mul_prod_r[(width*2)-1:width] + x;
247
        else
248
          mul_prod_r[(width*2)-1:width-1] <= {1'b0,mul_prod_r[(width*2)-1:
249
                                                              width]};
250
        mul_prod_r[width-2:0] <= mul_prod_r[width-1:1];
251
 
252
     end
253
     else if (alu_op_mul && mul_free) begin
254
        mul_prod_r <= {32'd0, y};
255
        mul_free <= 0;
256
        serial_mul_cnt <= 6'b10_0000;
257
     end
258
     else if (!ex_freeze | mul_free) begin
259
        mul_free <= 1'b1;
260
     end
261
 
262
   assign mul_stall = (|serial_mul_cnt);
263 258 julius
 
264 481 julius
 `else
265
 
266 258 julius
   //
267
   // Instantiation of the multiplier
268
   //
269 481 julius
  `ifdef OR1200_ASIC_MULTP2_32X32
270
   or1200_amultp2_32x32 or1200_amultp2_32x32(
271
                                             .X(x),
272
                                             .Y(y),
273
                                             .RST(rst),
274
                                             .CLK(clk),
275
                                             .P(mul_prod)
276
                                             );
277
  `else // OR1200_ASIC_MULTP2_32X32
278
   or1200_gmultp2_32x32 or1200_gmultp2_32x32(
279
                                             .X(x),
280
                                             .Y(y),
281
                                             .RST(rst),
282
                                             .CLK(clk),
283
                                             .P(mul_prod)
284
                                             );
285
  `endif // OR1200_ASIC_MULTP2_32X32   
286
 
287
   //
288
   // Registered output from the multiplier
289
   //
290
   always @(`OR1200_RST_EVENT rst or posedge clk)
291
     if (rst == `OR1200_RST_VALUE) begin
292
        mul_prod_r <=  64'h0000_0000_0000_0000;
293
     end
294
     else begin
295
        mul_prod_r <=  mul_prod[63:0];
296
     end
297 10 unneback
 
298 640 julius
   //
299
   // Generate stall signal during multiplication
300
   //
301
   always @(`OR1200_RST_EVENT rst or posedge clk)
302
     if (rst == `OR1200_RST_VALUE)
303
       mul_stall_count <= 0;
304
     else if (!(|mul_stall_count))
305
       mul_stall_count <= {mul_stall_count[0], alu_op_mul & !ex_freeze_r};
306
     else
307
       mul_stall_count <= {mul_stall_count[0],1'b0};
308
 
309
   assign mul_stall = (|mul_stall_count) |
310
                      (!(|mul_stall_count) & alu_op_mul & !ex_freeze_r);
311
 
312 481 julius
 `endif // !`ifdef OR1200_MULT_SERIAL   
313
 
314 10 unneback
`else // OR1200_MULT_IMPLEMENTED
315 481 julius
   assign mul_prod = {2*width{1'b0}};
316
   assign mul_prod_r = {2*width{1'b0}};
317
   assign mul_stall = 0;
318 10 unneback
`endif // OR1200_MULT_IMPLEMENTED
319
 
320
`ifdef OR1200_MAC_IMPLEMENTED
321 356 julius
 
322 481 julius
   //
323
   // Propagation of l.mac opcode, only register it for one cycle
324
   //
325
   always @(posedge clk or `OR1200_RST_EVENT rst)
326
     if (rst == `OR1200_RST_VALUE)
327
       mac_op_r1 <=  `OR1200_MACOP_WIDTH'b0;
328
     else
329
       mac_op_r1 <=  !ex_freeze_r ? mac_op : `OR1200_MACOP_WIDTH'b0;
330 10 unneback
 
331 481 julius
   //
332
   // Propagation of l.mac opcode
333
   //
334
   always @(posedge clk or `OR1200_RST_EVENT rst)
335
     if (rst == `OR1200_RST_VALUE)
336
       mac_op_r2 <=  `OR1200_MACOP_WIDTH'b0;
337
     else
338
       mac_op_r2 <=  mac_op_r1;
339 10 unneback
 
340 481 julius
   //
341
   // Propagation of l.mac opcode
342
   //
343
   always @(posedge clk or `OR1200_RST_EVENT rst)
344
     if (rst == `OR1200_RST_VALUE)
345
       mac_op_r3 <=  `OR1200_MACOP_WIDTH'b0;
346
     else
347
       mac_op_r3 <=  mac_op_r2;
348 10 unneback
 
349 481 julius
   //
350
   // Implementation of MAC
351
   //
352
   always @(`OR1200_RST_EVENT rst or posedge clk)
353
     if (rst == `OR1200_RST_VALUE)
354
       mac_r <=  64'h0000_0000_0000_0000;
355
 `ifdef OR1200_MAC_SPR_WE
356
     else if (spr_maclo_we)
357
       mac_r[31:0] <=  spr_dat_i;
358
     else if (spr_machi_we)
359
       mac_r[63:32] <=  spr_dat_i;
360
 `endif
361
     else if (mac_op_r3 == `OR1200_MACOP_MAC)
362
       mac_r <=  mac_r + mul_prod_r;
363
     else if (mac_op_r3 == `OR1200_MACOP_MSB)
364
       mac_r <=  mac_r - mul_prod_r;
365
     else if (macrc_op && !ex_freeze)
366
       mac_r <=  64'h0000_0000_0000_0000;
367 10 unneback
 
368 481 julius
   //
369
   // Stall CPU if l.macrc is in ID and MAC still has to process l.mac 
370
   // instructions in EX stage (e.g. inside multiplier)
371
   // This stall signal is also used by the divider.
372
   //
373
   always @(`OR1200_RST_EVENT rst or posedge clk)
374
     if (rst == `OR1200_RST_VALUE)
375
       mac_stall_r <=  1'b0;
376
     else
377
       mac_stall_r <=  (|mac_op | (|mac_op_r1) | (|mac_op_r2)) &
378
                       (id_macrc_op | mac_stall_r);
379 640 julius
 
380 10 unneback
`else // OR1200_MAC_IMPLEMENTED
381 481 julius
   assign mac_stall_r = 1'b0;
382
   assign mac_r = {2*width{1'b0}};
383
   assign mac_op_r1 = `OR1200_MACOP_WIDTH'b0;
384
   assign mac_op_r2 = `OR1200_MACOP_WIDTH'b0;
385
   assign mac_op_r3 = `OR1200_MACOP_WIDTH'b0;
386 10 unneback
`endif // OR1200_MAC_IMPLEMENTED
387
 
388 481 julius
`ifdef OR1200_DIV_IMPLEMENTED
389
 
390
   //
391
   // Serial division
392
   //
393
 `ifdef OR1200_DIV_SERIAL
394
   assign div_tmp = div_quot_r[63:32] - y;
395
   always @(`OR1200_RST_EVENT rst or posedge clk)
396
     if (rst == `OR1200_RST_VALUE) begin
397
        div_quot_r <=  64'h0000_0000_0000_0000;
398
        div_free <=  1'b1;
399
        div_cntr <=  6'b00_0000;
400
     end
401
     else if (|div_cntr) begin
402
        if (div_tmp[31])
403
          div_quot_r <=  {div_quot_r[62:0], 1'b0};
404
        else
405
          div_quot_r <=  {div_tmp[30:0], div_quot_r[31:0], 1'b1};
406
        div_cntr <=  div_cntr - 6'd1;
407
     end
408
     else if (alu_op_div && div_free) begin
409
        div_quot_r <=  {31'b0, x[31:0], 1'b0};
410
        div_cntr <=  6'b10_0000;
411
        div_free <=  1'b0;
412
     end
413
     else if (div_free | !ex_freeze) begin
414
        //div_quot_r <=  div_quot[63:0];
415
        div_free <=  1'b1;
416
     end
417
 
418
   assign div_stall = (|div_cntr);
419
 
420
 
421
 `else // !`ifdef OR1200_DIV_SERIAL
422
 
423
   // Full divider
424
   // TODO: Perhaps provide module that can be technology dependent.
425
   always @(`OR1200_RST_EVENT rst or posedge clk) begin
426
      if (rst == `OR1200_RST_VALUE) begin
427
         div_quot_r <=  32'd0;
428
         div_quot_generic <= 32'd0;
429
      end
430
      else begin
431
         if (alu_op_udiv & !(|y)) // unsigned divide by 0 - force to MAX
432
           div_quot_generic[31:0] <= 32'hffff_ffff;
433
         else if (alu_op_div)
434
           div_quot_generic[31:0] <= x / y;
435
      end
436
 
437
      // Add any additional statges of pipelining as required here. Ensure
438
      // ends with div_quot_r.
439
      // Then add logic to ensure div_stall stays high for as long as the
440
      // division should take.      
441
 
442
      div_quot_r[31:0] <= div_quot_generic;
443
 
444
   end
445
 
446
   assign div_stall = 0;
447
 
448
 `endif
449
 
450
`else // !`ifdef OR1200_DIV_IMPLEMENTED
451
 
452
   assign div_stall = 0;
453
 
454
`endif // !`ifdef OR1200_DIV_IMPLEMENTED
455
 
456
 
457
   //   
458
   // Stall output
459
   //
460
   assign mult_mac_stall = mac_stall_r | div_stall | mul_stall;
461
 
462 10 unneback
endmodule

powered by: WebSVN 2.1.0

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