Line 1... |
Line 1... |
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
//// ////
|
//// ////
|
//// OR1200's Top level multiplier and MAC ////
|
//// OR1200's Top level multiplier, divider and MAC ////
|
//// ////
|
//// ////
|
//// This file is part of the OpenRISC 1200 project ////
|
//// This file is part of the OpenRISC 1200 project ////
|
//// http://www.opencores.org/cores/or1k/ ////
|
//// http://opencores.org/project,or1k ////
|
//// ////
|
//// ////
|
//// Description ////
|
//// Description ////
|
//// Multiplier is 32x32 however multiply instructions only ////
|
//// Multiplier is 32x32 however multiply instructions only ////
|
//// use lower 32 bits of the result. MAC is 32x32=64+64. ////
|
//// use lower 32 bits of the result. MAC is 32x32=64+64. ////
|
//// ////
|
//// ////
|
Line 47... |
Line 47... |
// $Log: or1200_mult_mac.v,v $
|
// $Log: or1200_mult_mac.v,v $
|
// Revision 2.0 2010/06/30 11:00:00 ORSoC
|
// Revision 2.0 2010/06/30 11:00:00 ORSoC
|
// Minor update:
|
// Minor update:
|
// Bugs fixed.
|
// Bugs fixed.
|
//
|
//
|
// Revision 1.5 2006/04/09 01:32:29 lampret
|
|
// See OR1200_MAC_SHIFTBY in or1200_defines.v for explanation of the change. Since now no more 28 bits shift for l.macrc insns however for backward compatbility it is possible to set arbitry number of shifts.
|
|
//
|
|
// Revision 1.4 2004/06/08 18:17:36 lampret
|
|
// Non-functional changes. Coding style fixes.
|
|
//
|
|
// Revision 1.3 2003/04/24 00:16:07 lampret
|
|
// No functional changes. Added defines to disable implementation of multiplier/MAC
|
|
//
|
|
// Revision 1.2 2002/09/08 05:52:16 lampret
|
|
// Added optional l.div/l.divu insns. By default they are disabled.
|
|
//
|
|
// Revision 1.1 2002/01/03 08:16:15 lampret
|
|
// New prefixes for RTL files, prefixed module names. Updated cache controllers and MMUs.
|
|
//
|
|
// Revision 1.3 2001/10/21 17:57:16 lampret
|
|
// Removed params from generic_XX.v. Added translate_off/on in sprs.v and id.v. Removed spr_addr from dc.v and ic.v. Fixed CR+LF.
|
|
//
|
|
// Revision 1.2 2001/10/14 13:12:09 lampret
|
|
// MP3 version.
|
|
//
|
|
// Revision 1.1.1.1 2001/10/06 10:18:38 igorm
|
|
// no message
|
|
//
|
|
//
|
|
|
|
// synopsys translate_off
|
// synopsys translate_off
|
`include "timescale.v"
|
`include "timescale.v"
|
// synopsys translate_on
|
// synopsys translate_on
|
`include "or1200_defines.v"
|
`include "or1200_defines.v"
|
Line 155... |
Line 130... |
wire spr_maclo_we;
|
wire spr_maclo_we;
|
wire spr_machi_we;
|
wire spr_machi_we;
|
wire alu_op_div_divu;
|
wire alu_op_div_divu;
|
wire alu_op_div;
|
wire alu_op_div;
|
reg div_free;
|
reg div_free;
|
`ifdef OR1200_IMPL_DIV
|
`ifdef OR1200_DIV_IMPLEMENTED
|
wire [width-1:0] div_tmp;
|
wire [width-1:0] div_tmp;
|
reg [5:0] div_cntr;
|
reg [5:0] div_cntr;
|
`endif
|
`endif
|
|
|
//
|
//
|
Line 173... |
Line 148... |
assign spr_maclo_we = 1'b0;
|
assign spr_maclo_we = 1'b0;
|
assign spr_machi_we = 1'b0;
|
assign spr_machi_we = 1'b0;
|
assign spr_dat_o = 32'h0000_0000;
|
assign spr_dat_o = 32'h0000_0000;
|
`endif
|
`endif
|
`ifdef OR1200_LOWPWR_MULT
|
`ifdef OR1200_LOWPWR_MULT
|
assign x = (alu_op_div & a[31]) ? ~a + 1'b1 : alu_op_div_divu | (alu_op == `OR1200_ALUOP_MUL) | (|mac_op) ? a : 32'h0000_0000;
|
assign x = (alu_op_div & a[31]) ? ~a + 1'b1 :
|
assign y = (alu_op_div & b[31]) ? ~b + 1'b1 : alu_op_div_divu | (alu_op == `OR1200_ALUOP_MUL) | (|mac_op) ? b : 32'h0000_0000;
|
alu_op_div_divu | (alu_op == `OR1200_ALUOP_MUL) | (|mac_op) ?
|
|
a : 32'h0000_0000;
|
|
assign y = (alu_op_div & b[31]) ? ~b + 1'b1 :
|
|
alu_op_div_divu | (alu_op == `OR1200_ALUOP_MUL) | (|mac_op) ?
|
|
b : 32'h0000_0000;
|
`else
|
`else
|
assign x = alu_op_div & a[31] ? ~a + 32'b1 : a;
|
assign x = alu_op_div & a[31] ? ~a + 32'b1 : a;
|
assign y = alu_op_div & b[31] ? ~b + 32'b1 : b;
|
assign y = alu_op_div & b[31] ? ~b + 32'b1 : b;
|
`endif
|
`endif
|
`ifdef OR1200_IMPL_DIV
|
`ifdef OR1200_DIV_IMPLEMENTED
|
assign alu_op_div = (alu_op == `OR1200_ALUOP_DIV);
|
assign alu_op_div = (alu_op == `OR1200_ALUOP_DIV);
|
assign alu_op_div_divu = alu_op_div | (alu_op == `OR1200_ALUOP_DIVU);
|
assign alu_op_div_divu = alu_op_div | (alu_op == `OR1200_ALUOP_DIVU);
|
assign div_tmp = mul_prod_r[63:32] - y;
|
assign div_tmp = mul_prod_r[63:32] - y;
|
`else
|
`else
|
assign alu_op_div = 1'b0;
|
assign alu_op_div = 1'b0;
|
Line 196... |
Line 175... |
// Select result of current ALU operation to be forwarded
|
// Select result of current ALU operation to be forwarded
|
// to next instruction and to WB stage
|
// to next instruction and to WB stage
|
//
|
//
|
always @(alu_op or mul_prod_r or mac_r or a or b)
|
always @(alu_op or mul_prod_r or mac_r or a or b)
|
casex(alu_op) // synopsys parallel_case
|
casex(alu_op) // synopsys parallel_case
|
`ifdef OR1200_IMPL_DIV
|
`ifdef OR1200_DIV_IMPLEMENTED
|
`OR1200_ALUOP_DIV:
|
`OR1200_ALUOP_DIV: begin
|
result = a[31] ^ b[31] ? ~mul_prod_r[31:0] + 1'b1 : mul_prod_r[31:0];
|
result = a[31] ^ b[31] ? ~mul_prod_r[31:0] + 1'b1 : mul_prod_r[31:0];
|
|
end
|
`OR1200_ALUOP_DIVU,
|
`OR1200_ALUOP_DIVU,
|
`endif
|
`endif
|
`OR1200_ALUOP_MUL: begin
|
`OR1200_ALUOP_MUL: begin
|
result = mul_prod_r[31:0];
|
result = mul_prod_r[31:0];
|
end
|
end
|
Line 239... |
Line 219... |
// Registered output from the multiplier and
|
// Registered output from the multiplier and
|
// an optional divider
|
// an optional divider
|
//
|
//
|
always @(posedge rst or posedge clk)
|
always @(posedge rst or posedge clk)
|
if (rst) begin
|
if (rst) begin
|
mul_prod_r <= #1 64'h0000_0000_0000_0000;
|
mul_prod_r <= 64'h0000_0000_0000_0000;
|
div_free <= #1 1'b1;
|
div_free <= 1'b1;
|
`ifdef OR1200_IMPL_DIV
|
`ifdef OR1200_DIV_IMPLEMENTED
|
div_cntr <= #1 6'b00_0000;
|
div_cntr <= 6'b00_0000;
|
`endif
|
`endif
|
end
|
end
|
`ifdef OR1200_IMPL_DIV
|
`ifdef OR1200_DIV_IMPLEMENTED
|
else if (|div_cntr) begin
|
else if (|div_cntr) begin
|
if (div_tmp[31])
|
if (div_tmp[31])
|
mul_prod_r <= #1 {mul_prod_r[62:0], 1'b0};
|
mul_prod_r <= {mul_prod_r[62:0], 1'b0};
|
else
|
else
|
mul_prod_r <= #1 {div_tmp[30:0], mul_prod_r[31:0], 1'b1};
|
mul_prod_r <= {div_tmp[30:0], mul_prod_r[31:0], 1'b1};
|
div_cntr <= #1 div_cntr - 1'b1;
|
div_cntr <= div_cntr - 1'b1;
|
end
|
end
|
else if (alu_op_div_divu && div_free) begin
|
else if (alu_op_div_divu && div_free) begin
|
mul_prod_r <= #1 {31'b0, x[31:0], 1'b0};
|
mul_prod_r <= {31'b0, x[31:0], 1'b0};
|
div_cntr <= #1 6'b10_0000;
|
div_cntr <= 6'b10_0000;
|
div_free <= #1 1'b0;
|
div_free <= 1'b0;
|
end
|
end
|
`endif // OR1200_IMPL_DIV
|
`endif // OR1200_DIV_IMPLEMENTED
|
else if (div_free | !ex_freeze) begin
|
else if (div_free | !ex_freeze) begin
|
mul_prod_r <= #1 mul_prod[63:0];
|
mul_prod_r <= mul_prod[63:0];
|
div_free <= #1 1'b1;
|
div_free <= 1'b1;
|
end
|
end
|
|
|
`else // OR1200_MULT_IMPLEMENTED
|
`else // OR1200_MULT_IMPLEMENTED
|
assign result = {width{1'b0}};
|
assign result = {width{1'b0}};
|
assign mul_prod = {2*width{1'b0}};
|
assign mul_prod = {2*width{1'b0}};
|
Line 277... |
Line 257... |
//
|
//
|
// Propagation of l.mac opcode
|
// Propagation of l.mac opcode
|
//
|
//
|
always @(posedge clk or posedge rst)
|
always @(posedge clk or posedge rst)
|
if (rst)
|
if (rst)
|
mac_op_r1 <= #1 `OR1200_MACOP_WIDTH'b0;
|
mac_op_r1 <= `OR1200_MACOP_WIDTH'b0;
|
else
|
else
|
mac_op_r1 <= #1 mac_op;
|
mac_op_r1 <= mac_op;
|
|
|
//
|
//
|
// Propagation of l.mac opcode
|
// Propagation of l.mac opcode
|
//
|
//
|
always @(posedge clk or posedge rst)
|
always @(posedge clk or posedge rst)
|
if (rst)
|
if (rst)
|
mac_op_r2 <= #1 `OR1200_MACOP_WIDTH'b0;
|
mac_op_r2 <= `OR1200_MACOP_WIDTH'b0;
|
else
|
else
|
mac_op_r2 <= #1 mac_op_r1;
|
mac_op_r2 <= mac_op_r1;
|
|
|
//
|
//
|
// Propagation of l.mac opcode
|
// Propagation of l.mac opcode
|
//
|
//
|
always @(posedge clk or posedge rst)
|
always @(posedge clk or posedge rst)
|
if (rst)
|
if (rst)
|
mac_op_r3 <= #1 `OR1200_MACOP_WIDTH'b0;
|
mac_op_r3 <= `OR1200_MACOP_WIDTH'b0;
|
else
|
else
|
mac_op_r3 <= #1 mac_op_r2;
|
mac_op_r3 <= mac_op_r2;
|
|
|
//
|
//
|
// Implementation of MAC
|
// Implementation of MAC
|
//
|
//
|
always @(posedge rst or posedge clk)
|
always @(posedge rst or posedge clk)
|
if (rst)
|
if (rst)
|
mac_r <= #1 64'h0000_0000_0000_0000;
|
mac_r <= 64'h0000_0000_0000_0000;
|
`ifdef OR1200_MAC_SPR_WE
|
`ifdef OR1200_MAC_SPR_WE
|
else if (spr_maclo_we)
|
else if (spr_maclo_we)
|
mac_r[31:0] <= #1 spr_dat_i;
|
mac_r[31:0] <= spr_dat_i;
|
else if (spr_machi_we)
|
else if (spr_machi_we)
|
mac_r[63:32] <= #1 spr_dat_i;
|
mac_r[63:32] <= spr_dat_i;
|
`endif
|
`endif
|
else if (mac_op_r3 == `OR1200_MACOP_MAC)
|
else if (mac_op_r3 == `OR1200_MACOP_MAC)
|
mac_r <= #1 mac_r + mul_prod_r;
|
mac_r <= mac_r + mul_prod_r;
|
else if (mac_op_r3 == `OR1200_MACOP_MSB)
|
else if (mac_op_r3 == `OR1200_MACOP_MSB)
|
mac_r <= #1 mac_r - mul_prod_r;
|
mac_r <= mac_r - mul_prod_r;
|
else if (macrc_op && !ex_freeze)
|
else if (macrc_op && !ex_freeze)
|
mac_r <= #1 64'h0000_0000_0000_0000;
|
mac_r <= 64'h0000_0000_0000_0000;
|
|
|
//
|
//
|
// Stall CPU if l.macrc is in ID and MAC still has to process l.mac instructions
|
// Stall CPU if l.macrc is in ID and MAC still has to process l.mac instructions
|
// in EX stage (e.g. inside multiplier)
|
// in EX stage (e.g. inside multiplier)
|
// This stall signal is also used by the divider.
|
// This stall signal is also used by the divider.
|
//
|
//
|
always @(posedge rst or posedge clk)
|
always @(posedge rst or posedge clk)
|
if (rst)
|
if (rst)
|
mac_stall_r <= #1 1'b0;
|
mac_stall_r <= 1'b0;
|
else
|
else
|
mac_stall_r <= #1 (|mac_op | (|mac_op_r1) | (|mac_op_r2)) & (id_macrc_op | mac_stall_r)
|
mac_stall_r <= (|mac_op | (|mac_op_r1) | (|mac_op_r2)) & (id_macrc_op | mac_stall_r)
|
`ifdef OR1200_IMPL_DIV
|
`ifdef OR1200_DIV_IMPLEMENTED
|
| (|div_cntr)
|
| (|div_cntr)
|
`endif
|
`endif
|
;
|
;
|
`else // OR1200_MAC_IMPLEMENTED
|
`else // OR1200_MAC_IMPLEMENTED
|
assign mac_stall_r = 1'b0;
|
assign mac_stall_r = 1'b0;
|