Line 139... |
Line 139... |
`ifdef OPT_MULTIPLY
|
`ifdef OPT_MULTIPLY
|
parameter IMPLEMENT_MPY = 1;
|
parameter IMPLEMENT_MPY = 1;
|
`else
|
`else
|
parameter IMPLEMENT_MPY = 0;
|
parameter IMPLEMENT_MPY = 0;
|
`endif
|
`endif
|
parameter IMPLEMENT_DIVIDE = 1, IMPLEMENT_FPU = 0,
|
`ifdef OPT_DIVIDE
|
|
parameter IMPLEMENT_DIVIDE = 1;
|
|
`else
|
|
parameter IMPLEMENT_DIVIDE = 0;
|
|
`endif
|
|
`ifdef OPT_IMPLEMENT_FPU
|
|
parameter IMPLEMENT_FPU = 1,
|
|
`else
|
|
parameter IMPLEMENT_FPU = 0,
|
|
`endif
|
IMPLEMENT_LOCK=1;
|
IMPLEMENT_LOCK=1;
|
`ifdef OPT_EARLY_BRANCHING
|
`ifdef OPT_EARLY_BRANCHING
|
parameter EARLY_BRANCHING = 1;
|
parameter EARLY_BRANCHING = 1;
|
`else
|
`else
|
parameter EARLY_BRANCHING = 0;
|
parameter EARLY_BRANCHING = 0;
|
Line 240... |
Line 249... |
wire [4:0] dcdA, dcdB, dcdR;
|
wire [4:0] dcdA, dcdB, dcdR;
|
wire dcdA_cc, dcdB_cc, dcdA_pc, dcdB_pc, dcdR_cc, dcdR_pc;
|
wire dcdA_cc, dcdB_cc, dcdA_pc, dcdB_pc, dcdR_cc, dcdR_pc;
|
wire [3:0] dcdF;
|
wire [3:0] dcdF;
|
wire dcdR_wr, dcdA_rd, dcdB_rd,
|
wire dcdR_wr, dcdA_rd, dcdB_rd,
|
dcdALU, dcdM, dcdDV, dcdFP,
|
dcdALU, dcdM, dcdDV, dcdFP,
|
dcdF_wr, dcd_gie, dcd_break, dcd_lock;
|
dcdF_wr, dcd_gie, dcd_break, dcd_lock,
|
|
dcd_pipe;
|
reg r_dcdvalid;
|
reg r_dcdvalid;
|
wire dcdvalid;
|
wire dcdvalid;
|
wire [(AW-1):0] dcd_pc;
|
wire [(AW-1):0] dcd_pc;
|
wire [31:0] dcdI;
|
wire [31:0] dcdI;
|
wire dcd_zI; // true if dcdI == 0
|
wire dcd_zI; // true if dcdI == 0
|
Line 298... |
Line 308... |
reg alu_pc_valid;
|
reg alu_pc_valid;
|
wire alu_phase;
|
wire alu_phase;
|
wire alu_ce, alu_stall;
|
wire alu_ce, alu_stall;
|
wire [31:0] alu_result;
|
wire [31:0] alu_result;
|
wire [3:0] alu_flags;
|
wire [3:0] alu_flags;
|
wire alu_valid;
|
wire alu_valid, alu_busy;
|
wire set_cond;
|
wire set_cond;
|
reg alu_wr, alF_wr, alu_gie;
|
reg alu_wr, alF_wr, alu_gie;
|
wire alu_illegal_op;
|
wire alu_illegal_op;
|
wire alu_illegal;
|
wire alu_illegal;
|
|
|
Line 317... |
Line 327... |
wire [4:0] mem_wreg;
|
wire [4:0] mem_wreg;
|
|
|
wire mem_busy, mem_rdbusy;
|
wire mem_busy, mem_rdbusy;
|
wire [(AW-1):0] mem_addr;
|
wire [(AW-1):0] mem_addr;
|
wire [31:0] mem_data, mem_result;
|
wire [31:0] mem_data, mem_result;
|
reg [4:0] mem_last_reg; // Last register result to go in
|
|
|
|
wire div_ce, div_error, div_busy, div_valid;
|
wire div_ce, div_error, div_busy, div_valid;
|
wire [31:0] div_result;
|
wire [31:0] div_result;
|
wire [3:0] div_flags;
|
wire [3:0] div_flags;
|
|
|
Line 405... |
Line 414... |
// ||((opvalid_alu)&&(mem_rdbusy)) // part of alu_stall
|
// ||((opvalid_alu)&&(mem_rdbusy)) // part of alu_stall
|
// Stall if we are going into memory with an operation
|
// Stall if we are going into memory with an operation
|
// that cannot be pipelined, and the memory is
|
// that cannot be pipelined, and the memory is
|
// already busy
|
// already busy
|
||((opvalid_mem)&&(mem_stalled))
|
||((opvalid_mem)&&(mem_stalled))
|
|
// ||((opvalid_mem)&&(dcdvalid)&&(dcdM)&&(~dcd_pipe))
|
)
|
)
|
||(dcdvalid)&&(
|
||(dcdvalid)&&(
|
// Stall if we've got a read going with an
|
// Stall if we need to wait for an operand A
|
// unknown output (known w/in the memory module)
|
|
(mem_rdbusy)
|
|
// Or if we need to wait for an operand A
|
|
// to be ready to read
|
// to be ready to read
|
||(dcdA_stall)
|
(dcdA_stall)
|
// Likewise for B, also includes logic
|
// Likewise for B, also includes logic
|
// regarding immediate offset (register must
|
// regarding immediate offset (register must
|
// be in register file if we need to add to
|
// be in register file if we need to add to
|
// an immediate)
|
// an immediate)
|
||(dcdB_stall)
|
||(dcdB_stall)
|
// Or if we need to wait on flags to work on the
|
// Or if we need to wait on flags to work on the
|
// CC register
|
// CC register
|
||(dcdF_stall)
|
||(dcdF_stall)
|
);
|
);
|
assign op_ce = (dcdvalid)&&((~opvalid)||(~op_stall))&&(~clear_pipeline);
|
assign op_ce = ((dcdvalid)||(dcd_illegal))&&(~op_stall)&&(~clear_pipeline);
|
`else
|
`else
|
assign op_stall = (opvalid)&&(~master_ce);
|
assign op_stall = (opvalid)&&(~master_ce);
|
assign op_ce = (dcdvalid);
|
assign op_ce = ((dcdvalid)||(dcd_illegal));
|
`endif
|
`endif
|
|
|
//
|
//
|
// PIPELINE STAGE #4 :: ALU / Memory
|
// PIPELINE STAGE #4 :: ALU / Memory
|
// Calculate stall conditions
|
// Calculate stall conditions
|
Line 442... |
Line 449... |
// since we don't know if it'll put us to sleep or not.
|
// since we don't know if it'll put us to sleep or not.
|
// 4. Last case: Stall if we would otherwise move a break instruction
|
// 4. Last case: Stall if we would otherwise move a break instruction
|
// through the ALU. Break instructions are not allowed through
|
// through the ALU. Break instructions are not allowed through
|
// the ALU.
|
// the ALU.
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
assign alu_stall = (((~master_ce)||(mem_rdbusy))&&(opvalid_alu)) //Case 1&2
|
assign alu_stall = (((~master_ce)||(mem_rdbusy)||(alu_busy))&&(opvalid_alu)) //Case 1&2
|
// Old case #3--this isn't an ALU stall though ...
|
// Old case #3--this isn't an ALU stall though ...
|
||((opvalid_alu)&&(wr_reg_ce)&&(wr_reg_id[4] == op_gie)
|
||((opvalid_alu)&&(wr_reg_ce)&&(wr_reg_id[4] == op_gie)
|
&&(wr_write_cc)) // Case 3
|
&&(wr_write_cc)) // Case 3
|
||((opvalid)&&(op_lock)&&(op_lock_stall))
|
||((opvalid)&&(op_lock)&&(op_lock_stall))
|
||((opvalid)&&(op_break))
|
||((opvalid)&&(op_break))
|
||(div_busy)||(fpu_busy);
|
||(div_busy)||(fpu_busy);
|
assign alu_ce = (master_ce)&&(opvalid_alu)
|
assign alu_ce = (master_ce)&&((opvalid_alu)||(op_illegal))
|
&&(~alu_stall)
|
&&(~alu_stall)
|
&&(~clear_pipeline);
|
&&(~clear_pipeline);
|
`else
|
`else
|
assign alu_stall = ((~master_ce)&&(opvalid_alu))
|
assign alu_stall = ((~master_ce)&&(opvalid_alu))
|
||((opvalid_alu)&&(op_break));
|
||((opvalid_alu)&&(op_break));
|
assign alu_ce = (master_ce)&&(opvalid_alu)&&(~alu_stall);
|
assign alu_ce = (master_ce)&&((opvalid_alu)||(op_illegal))&&(~alu_stall);
|
`endif
|
`endif
|
//
|
//
|
|
|
//
|
//
|
// Note: if you change the conditions for mem_ce, you must also change
|
// Note: if you change the conditions for mem_ce, you must also change
|
// alu_pc_valid.
|
// alu_pc_valid.
|
//
|
//
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~mem_stalled)
|
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~mem_stalled)
|
&&(~clear_pipeline)&&(set_cond);
|
&&(~clear_pipeline);
|
`else
|
`else
|
// If we aren't pipelined, then no one will be changing what's in the
|
// If we aren't pipelined, then no one will be changing what's in the
|
// pipeline (i.e. clear_pipeline), while our only instruction goes
|
// pipeline (i.e. clear_pipeline), while our only instruction goes
|
// through the ... pipeline.
|
// through the ... pipeline.
|
assign mem_ce = (master_ce)&&(opvalid_mem)
|
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~mem_stalled);
|
&&(set_cond)&&(~mem_stalled);
|
|
`endif
|
`endif
|
`ifdef OPT_PIPELINED_BUS_ACCESS
|
`ifdef OPT_PIPELINED_BUS_ACCESS
|
assign mem_stalled = (~master_ce)||((opvalid_mem)&&(
|
assign mem_stalled = (~master_ce)||(alu_busy)||((opvalid_mem)&&(
|
(mem_pipe_stalled)
|
(mem_pipe_stalled)
|
||((~op_pipe)&&(mem_busy))
|
||((~op_pipe)&&(mem_busy))
|
||(div_busy)
|
||(div_busy)
|
||(fpu_busy)
|
||(fpu_busy)
|
// Stall waiting for flags to be valid
|
// Stall waiting for flags to be valid
|
Line 583... |
Line 589... |
{ dcdB_cc, dcdB_pc, dcdB },
|
{ dcdB_cc, dcdB_pc, dcdB },
|
dcdI, dcd_zI, dcdF, dcdF_wr, dcdOp,
|
dcdI, dcd_zI, dcdF, dcdF_wr, dcdOp,
|
dcdALU, dcdM, dcdDV, dcdFP, dcd_break, dcd_lock,
|
dcdALU, dcdM, dcdDV, dcdFP, dcd_break, dcd_lock,
|
dcdR_wr,dcdA_rd, dcdB_rd,
|
dcdR_wr,dcdA_rd, dcdB_rd,
|
dcd_early_branch,
|
dcd_early_branch,
|
dcd_branch_pc);
|
dcd_branch_pc,
|
|
dcd_pipe);
|
`else
|
`else
|
idecode_deprecated
|
idecode_deprecated
|
#(AW, IMPLEMENT_MPY, EARLY_BRANCHING, IMPLEMENT_DIVIDE,
|
#(AW, IMPLEMENT_MPY, EARLY_BRANCHING, IMPLEMENT_DIVIDE,
|
IMPLEMENT_FPU)
|
IMPLEMENT_FPU)
|
instruction_decoder(i_clk, (i_rst)||(clear_pipeline),
|
instruction_decoder(i_clk, (i_rst)||(clear_pipeline),
|
Line 599... |
Line 606... |
{ dcdB_cc, dcdB_pc, dcdB },
|
{ dcdB_cc, dcdB_pc, dcdB },
|
dcdI, dcd_zI, dcdF, dcdF_wr, dcdOp,
|
dcdI, dcd_zI, dcdF, dcdF_wr, dcdOp,
|
dcdALU, dcdM, dcdDV, dcdFP, dcd_break, dcd_lock,
|
dcdALU, dcdM, dcdDV, dcdFP, dcd_break, dcd_lock,
|
dcdR_wr,dcdA_rd, dcdB_rd,
|
dcdR_wr,dcdA_rd, dcdB_rd,
|
dcd_early_branch,
|
dcd_early_branch,
|
dcd_branch_pc);
|
dcd_branch_pc,
|
|
dcd_pipe);
|
`endif
|
`endif
|
|
|
`ifdef OPT_PIPELINED_BUS_ACCESS
|
`ifdef OPT_PIPELINED_BUS_ACCESS
|
reg [23:0] r_opI;
|
|
reg [4:0] op_B;
|
|
reg op_pipe;
|
reg op_pipe;
|
|
|
initial op_pipe = 1'b0;
|
initial op_pipe = 1'b0;
|
// To be a pipeable operation, there must be
|
// To be a pipeable operation, there must be
|
// two valid adjacent instructions
|
// two valid adjacent instructions
|
// Both must be memory instructions
|
// Both must be memory instructions
|
// Both must be writes, or both must be reads
|
// Both must be writes, or both must be reads
|
// Both operations must be to the same identical address,
|
// Both operations must be to the same identical address,
|
// or at least a single (one) increment above that address
|
// or at least a single (one) increment above that address
|
|
//
|
|
// However ... we need to know this before this clock, hence this is
|
|
// calculated in the instruction decoder.
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (op_ce)
|
if (op_ce)
|
op_pipe <= (dcdvalid)&&(opvalid_mem)&&(dcdM) // Both mem
|
op_pipe <= dcd_pipe;
|
&&(dcdOp[0]==opn[0]) // Both Rd, or both Wr
|
|
&&(dcdB == op_B) // Same address register
|
|
&&((dcdF[2:0] == opF_cp) // Same condition
|
|
||(opF_cp == 3'h0)) // or no prev condition
|
|
&&((dcdI[23:0] == r_opI)||(dcdI[23:0]==r_opI+24'h1));
|
|
always @(posedge i_clk)
|
|
if (op_ce) // &&(dcdvalid))
|
|
r_opI <= dcdI[23:0];
|
|
always @(posedge i_clk)
|
|
if (op_ce) // &&(dcdvalid))
|
|
op_B <= dcdB;
|
|
`endif
|
`endif
|
|
|
//
|
//
|
//
|
//
|
// PIPELINE STAGE #3 :: Read Operands (Registers)
|
// PIPELINE STAGE #3 :: Read Operands (Registers)
|
Line 645... |
Line 643... |
if (AW < 32)
|
if (AW < 32)
|
assign w_pcA_v = {{(32-AW){1'b0}}, (dcdA[4] == dcd_gie)?dcd_pc:upc };
|
assign w_pcA_v = {{(32-AW){1'b0}}, (dcdA[4] == dcd_gie)?dcd_pc:upc };
|
else
|
else
|
assign w_pcA_v = (dcdA[4] == dcd_gie)?dcd_pc:upc;
|
assign w_pcA_v = (dcdA[4] == dcd_gie)?dcd_pc:upc;
|
endgenerate
|
endgenerate
|
|
|
|
`ifdef OPT_PIPELINED
|
|
reg [4:0] opA_id, opB_id;
|
|
reg opA_rd, opB_rd;
|
|
always @(posedge i_clk)
|
|
if (op_ce)
|
|
begin
|
|
opA_id <= dcdA;
|
|
opB_id <= dcdB;
|
|
opA_rd <= dcdA_rd;
|
|
opB_rd <= dcdB_rd;
|
|
end
|
|
`endif
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (op_ce) // &&(dcdvalid))
|
if (op_ce) // &&(dcdvalid))
|
begin
|
begin
|
if ((wr_reg_ce)&&(wr_reg_id == dcdA))
|
if ((wr_reg_ce)&&(wr_reg_id == dcdA))
|
r_opA <= wr_reg_vl;
|
r_opA <= wr_reg_vl;
|
Line 657... |
Line 669... |
else if (dcdA_cc)
|
else if (dcdA_cc)
|
r_opA <= { w_opA[31:13], (dcdA[4])?w_uflags:w_iflags };
|
r_opA <= { w_opA[31:13], (dcdA[4])?w_uflags:w_iflags };
|
else
|
else
|
r_opA <= w_opA;
|
r_opA <= w_opA;
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
end else if (opvalid)
|
end else
|
begin // We were going to pick these up when they became valid,
|
begin // We were going to pick these up when they became valid,
|
// but for some reason we're stuck here as they became
|
// but for some reason we're stuck here as they became
|
// valid. Pick them up now anyway
|
// valid. Pick them up now anyway
|
if (((opA_alu)&&(alu_wr))||((opA_mem)&&(mem_valid)))
|
// if (((opA_alu)&&(alu_wr))||((opA_mem)&&(mem_valid)))
|
|
// r_opA <= wr_reg_vl;
|
|
if ((wr_reg_ce)&&(wr_reg_id == opA_id)&&(opA_rd))
|
r_opA <= wr_reg_vl;
|
r_opA <= wr_reg_vl;
|
`endif
|
`endif
|
end
|
end
|
|
|
wire [31:0] w_opBnI, w_pcB_v;
|
wire [31:0] w_opBnI, w_pcB_v;
|
Line 684... |
Line 698... |
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (op_ce) // &&(dcdvalid))
|
if (op_ce) // &&(dcdvalid))
|
r_opB <= w_opBnI + dcdI;
|
r_opB <= w_opBnI + dcdI;
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
else if ((opvalid)&&(
|
else if ((wr_reg_ce)&&(opB_id == wr_reg_id)&&(opB_rd))
|
((opB_alu)&&(alu_wr))
|
|
||((opB_mem)&&(mem_valid))))
|
|
r_opB <= wr_reg_vl;
|
r_opB <= wr_reg_vl;
|
`endif
|
`endif
|
|
|
// The logic here has become more complex than it should be, no thanks
|
// The logic here has become more complex than it should be, no thanks
|
// to Xilinx's Vivado trying to help. The conditions are supposed to
|
// to Xilinx's Vivado trying to help. The conditions are supposed to
|
Line 825... |
Line 837... |
assign op_lock_stall = 1'b0;
|
assign op_lock_stall = 1'b0;
|
assign op_lock = 1'b0;
|
assign op_lock = 1'b0;
|
`endif
|
`endif
|
|
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
|
initial op_illegal = 1'b0;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if(op_ce)
|
if ((i_rst)||(clear_pipeline))
|
|
op_illegal <= 1'b0;
|
|
else if(op_ce)
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
op_illegal <=(dcd_illegal)||((dcd_lock)&&(IMPLEMENT_LOCK == 0));
|
op_illegal <=(dcd_illegal)||((dcd_lock)&&(IMPLEMENT_LOCK == 0));
|
`else
|
`else
|
op_illegal <= (dcd_illegal)||(dcd_lock);
|
op_illegal <= (dcd_illegal)||(dcd_lock);
|
`endif
|
`endif
|
`endif
|
`endif
|
|
|
generate
|
// No generate on EARLY_BRANCHING here, since if EARLY_BRANCHING is not
|
if (EARLY_BRANCHING > 0)
|
// set, dcd_early_branch will simply be a wire connected to zero and
|
begin
|
// this logic should just optimize.
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (op_ce)
|
if (op_ce)
|
begin
|
begin
|
opF_wr <= (dcdF_wr)&&((~dcdR_cc)||(~dcdR_wr))&&(~dcd_early_branch);
|
opF_wr <= (dcdF_wr)&&((~dcdR_cc)||(~dcdR_wr))&&(~dcd_early_branch);
|
opR_wr <= (dcdR_wr)&&(~dcd_early_branch);
|
opR_wr <= (dcdR_wr)&&(~dcd_early_branch);
|
op_wr_pc <= ((dcdR_wr)&&(dcdR_pc)
|
op_wr_pc <= ((dcdR_wr)&&(dcdR_pc)
|
&&(dcdR[4] == dcd_gie))
|
&&(dcdR[4] == dcd_gie))
|
&&(~dcd_early_branch);
|
&&(~dcd_early_branch);
|
end
|
end
|
end else begin
|
|
always @(posedge i_clk)
|
|
if (op_ce)
|
|
begin
|
|
// Will we write the flags/CC Register with
|
|
// our result?
|
|
opF_wr <= (dcdF_wr)&&((~dcdR_cc)||(~dcdR_wr));
|
|
// Will we be writing our results into a
|
|
// register?
|
|
opR_wr <= dcdR_wr;
|
|
op_wr_pc <= ((dcdR_wr)&&(dcdR_pc)
|
|
&&(dcdR[4] == dcd_gie));
|
|
end
|
|
end endgenerate
|
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (op_ce)
|
if (op_ce)
|
begin
|
begin
|
opn <= dcdOp; // Which ALU operation?
|
opn <= dcdOp; // Which ALU operation?
|
Line 904... |
Line 905... |
// op_stall wire, which would stall any upstream stage.
|
// op_stall wire, which would stall any upstream stage.
|
// We'll create a flag here to start our coordination. Once we
|
// We'll create a flag here to start our coordination. Once we
|
// define this flag to something other than just plain zero, then
|
// define this flag to something other than just plain zero, then
|
// the stalls will already be in place.
|
// the stalls will already be in place.
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
initial opA_alu = 1'b0;
|
assign opA = ((wr_reg_ce)&&(wr_reg_id == opA_id)&&(opA_rd))
|
always @(posedge i_clk)
|
? wr_reg_vl : r_opA;
|
if (op_ce)
|
|
opA_alu <= (opvalid_alu)&&(opR == dcdA)&&(opR_wr)&&(dcdA_rd);
|
|
else if ((opvalid)&&(opA_alu)&&(alu_valid))
|
|
opA_alu <= 1'b0;
|
|
initial opA_mem = 1'b0;
|
|
always @(posedge i_clk)
|
|
if (op_ce)
|
|
opA_mem <= ((opvalid_mem)&&(opR == dcdA)&&(dcdA_rd)&&(~opn[0]))
|
|
||((~opvalid)&&(mem_busy)&&(~mem_we)
|
|
&&(mem_last_reg == dcdA)&&(dcdA_rd));
|
|
else if ((opvalid)&&(opA_mem)&&(mem_valid))
|
|
opA_mem <= 1'b0;
|
|
`endif
|
|
|
|
always @(posedge i_clk)
|
|
if (mem_ce)
|
|
mem_last_reg <= opR;
|
|
`ifdef OPT_PIPELINED
|
|
assign opA = ((opA_alu)&&(alu_wr)) ? alu_result
|
|
: ( ((opA_mem)&&(mem_valid))?mem_result
|
|
: r_opA );
|
|
`else
|
`else
|
assign opA = r_opA;
|
assign opA = r_opA;
|
`endif
|
`endif
|
|
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
assign dcdA_stall = (dcdvalid)&&(dcdA_rd)&&(
|
assign dcdA_stall = (dcdvalid)&&(dcdA_rd)&&(
|
((opvalid_alu)&&(opF_wr)&&(dcdA_cc)));
|
((opvalid_alu)&&(opF_wr)&&(dcdA_cc))
|
|
);
|
`else
|
`else
|
// There are no pipeline hazards, if we aren't pipelined
|
// There are no pipeline hazards, if we aren't pipelined
|
assign dcdA_stall = 1'b0;
|
assign dcdA_stall = 1'b0;
|
`endif
|
`endif
|
|
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
always @(posedge i_clk)
|
assign opB = ((wr_reg_ce)&&(wr_reg_id == opB_id)&&(opB_rd))
|
if (op_ce)
|
? wr_reg_vl: r_opB;
|
opB_alu <= (opvalid_alu)&&(opR == dcdB)&&(opR_wr)&&(dcdB_rd)&&(dcd_zI);
|
|
always @(posedge i_clk)
|
|
if (op_ce)
|
|
opB_mem <= (dcd_zI)&&(dcdB_rd)&&(
|
|
((opvalid_mem)&&(opR == dcdB)&&(~opn[0]))
|
|
||((~opvalid)&&(mem_busy)&&(~mem_we)
|
|
&&(mem_last_reg == dcdB)));
|
|
else if ((opvalid)&&(opB_mem)&&(mem_valid))
|
|
opB_mem <= 1'b0;
|
|
assign opB = ((opB_alu)&&(alu_wr)) ? alu_result
|
|
: ( ((opB_mem)&&(mem_valid))?mem_result
|
|
: r_opB );
|
|
`else
|
`else
|
assign opB = r_opB;
|
assign opB = r_opB;
|
`endif
|
`endif
|
|
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
Line 969... |
Line 938... |
// if I write to the PC, the whole next
|
// if I write to the PC, the whole next
|
// instruction is invalid, not just the
|
// instruction is invalid, not just the
|
// operand. That'll get wiped in the
|
// operand. That'll get wiped in the
|
// next operation anyway, so don't stall
|
// next operation anyway, so don't stall
|
// here.
|
// here.
|
((opvalid)&&(opR_wr)&&(opR == dcdB)
|
((~dcd_zI)&&(dcdB_rd)&&(opR == dcdB)&&(opR_wr)
|
&&(opR != { op_gie, `CPU_PC_REG} )
|
&&(opR != { op_gie, `CPU_PC_REG} )
|
&&(~dcd_zI))
|
&&((opvalid)||(mem_rdbusy)
|
|
||(div_busy)||(fpu_busy)))
|
// Stall on any write to the flags register,
|
// Stall on any write to the flags register,
|
// if we're going to need the flags value for
|
// if we're going to need the flags value for
|
// opB.
|
// opB.
|
||((opvalid_alu)&&(opF_wr)&&(dcdB_cc))
|
||((opvalid_alu)&&(opF_wr)&&(dcdB_cc))
|
// Stall on any ongoing memory operation that
|
// Stall on any ongoing memory operation that
|
// will write to opB
|
// will write to opB -- captured above
|
||((mem_busy)&&(~mem_we)&&(mem_last_reg==dcdB)));
|
// ||((mem_busy)&&(~mem_we)&&(mem_last_reg==dcdB)&&(~dcd_zI))
|
|
);
|
`else
|
`else
|
// No stalls without pipelining, 'cause how can you have a pipeline
|
// No stalls without pipelining, 'cause how can you have a pipeline
|
// hazard without the pipeline?
|
// hazard without the pipeline?
|
assign dcdB_stall = 1'b0;
|
assign dcdB_stall = 1'b0;
|
`endif
|
`endif
|
Line 996... |
Line 967... |
//
|
//
|
//
|
//
|
`ifdef OPT_NEW_INSTRUCTION_SET
|
`ifdef OPT_NEW_INSTRUCTION_SET
|
cpuops #(IMPLEMENT_MPY) doalu(i_clk, i_rst, alu_ce,
|
cpuops #(IMPLEMENT_MPY) doalu(i_clk, i_rst, alu_ce,
|
(opvalid_alu), opn, opA, opB,
|
(opvalid_alu), opn, opA, opB,
|
alu_result, alu_flags, alu_valid, alu_illegal_op);
|
alu_result, alu_flags, alu_valid, alu_illegal_op,
|
|
alu_busy);
|
`else
|
`else
|
cpuops_deprecated #(IMPLEMENT_MPY) doalu(i_clk, i_rst, alu_ce,
|
cpuops_deprecated #(IMPLEMENT_MPY) doalu(i_clk, i_rst, alu_ce,
|
(opvalid_alu), opn, opA, opB,
|
(opvalid_alu), opn, opA, opB,
|
alu_result, alu_flags, alu_valid, alu_illegal_op);
|
alu_result, alu_flags, alu_valid, alu_illegal_op);
|
|
assign alu_busy = 1'b0;
|
`endif
|
`endif
|
|
|
generate
|
generate
|
if (IMPLEMENT_DIVIDE != 0)
|
if (IMPLEMENT_DIVIDE != 0)
|
begin
|
begin
|
Line 1052... |
Line 1025... |
end else if (alu_ce)
|
end else if (alu_ce)
|
begin
|
begin
|
// alu_reg <= opR;
|
// alu_reg <= opR;
|
alu_wr <= (opR_wr)&&(set_cond);
|
alu_wr <= (opR_wr)&&(set_cond);
|
alF_wr <= (opF_wr)&&(set_cond);
|
alF_wr <= (opF_wr)&&(set_cond);
|
end else begin
|
end else if (~alu_busy) begin
|
// These are strobe signals, so clear them if not
|
// These are strobe signals, so clear them if not
|
// set for any particular clock
|
// set for any particular clock
|
alu_wr <= (i_halt)&&(i_dbg_we);
|
alu_wr <= (i_halt)&&(i_dbg_we);
|
alF_wr <= 1'b0;
|
alF_wr <= 1'b0;
|
end
|
end
|
Line 1097... |
Line 1070... |
|
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
reg r_alu_illegal;
|
reg r_alu_illegal;
|
initial r_alu_illegal = 0;
|
initial r_alu_illegal = 0;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if ((alu_ce)||(mem_ce))
|
if (clear_pipeline)
|
|
r_alu_illegal <= 1'b0;
|
|
else if ((alu_ce)||(mem_ce))
|
r_alu_illegal <= op_illegal;
|
r_alu_illegal <= op_illegal;
|
assign alu_illegal = (alu_illegal_op)||(r_alu_illegal);
|
assign alu_illegal = (alu_illegal_op)||(r_alu_illegal);
|
`endif
|
`endif
|
|
|
// This _almost_ is equal to (alu_ce)||(mem_ce). The only
|
// This _almost_ is equal to (alu_ce)||(mem_ce). The only
|
Line 1134... |
Line 1109... |
`else
|
`else
|
assign bus_lock = 1'b0;
|
assign bus_lock = 1'b0;
|
`endif
|
`endif
|
|
|
`ifdef OPT_PIPELINED_BUS_ACCESS
|
`ifdef OPT_PIPELINED_BUS_ACCESS
|
pipemem #(AW,IMPLEMENT_LOCK) domem(i_clk, i_rst, mem_ce, bus_lock,
|
pipemem #(AW,IMPLEMENT_LOCK) domem(i_clk, i_rst,(mem_ce)&&(set_cond), bus_lock,
|
(opn[0]), opB, opA, opR,
|
(opn[0]), opB, opA, opR,
|
mem_busy, mem_pipe_stalled,
|
mem_busy, mem_pipe_stalled,
|
mem_valid, bus_err, mem_wreg, mem_result,
|
mem_valid, bus_err, mem_wreg, mem_result,
|
mem_cyc_gbl, mem_cyc_lcl,
|
mem_cyc_gbl, mem_cyc_lcl,
|
mem_stb_gbl, mem_stb_lcl,
|
mem_stb_gbl, mem_stb_lcl,
|
mem_we, mem_addr, mem_data,
|
mem_we, mem_addr, mem_data,
|
mem_ack, mem_stall, mem_err, i_wb_data);
|
mem_ack, mem_stall, mem_err, i_wb_data);
|
|
|
`else // PIPELINED_BUS_ACCESS
|
`else // PIPELINED_BUS_ACCESS
|
memops #(AW,IMPLEMENT_LOCK) domem(i_clk, i_rst, mem_ce, bus_lock,
|
memops #(AW,IMPLEMENT_LOCK) domem(i_clk, i_rst,(mem_ce)&&(set_cond), bus_lock,
|
(opn[0]), opB, opA, opR,
|
(opn[0]), opB, opA, opR,
|
mem_busy,
|
mem_busy,
|
mem_valid, bus_err, mem_wreg, mem_result,
|
mem_valid, bus_err, mem_wreg, mem_result,
|
mem_cyc_gbl, mem_cyc_lcl,
|
mem_cyc_gbl, mem_cyc_lcl,
|
mem_stb_gbl, mem_stb_lcl,
|
mem_stb_gbl, mem_stb_lcl,
|
Line 1188... |
Line 1163... |
// Note that the flags needed to be checked before issuing the
|
// Note that the flags needed to be checked before issuing the
|
// bus instruction, so they don't need to be checked here.
|
// bus instruction, so they don't need to be checked here.
|
// Further, alu_wr includes (set_cond), so we don't need to
|
// Further, alu_wr includes (set_cond), so we don't need to
|
// check for that here either.
|
// check for that here either.
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
assign wr_reg_ce = (~alu_illegal)&&((alu_wr)&&(~clear_pipeline))||(mem_valid)||(div_valid)||(fpu_valid);
|
assign wr_reg_ce = (~alu_illegal)&&((alu_wr)&&(alu_valid)&&(~clear_pipeline))||(mem_valid)||(div_valid)||(fpu_valid);
|
`else
|
`else
|
assign wr_reg_ce = ((alu_wr)&&(~clear_pipeline))||(mem_valid)||(div_valid)||(fpu_valid);
|
assign wr_reg_ce = ((alu_wr)&&(~clear_pipeline))||(mem_valid)||(div_valid)||(fpu_valid);
|
`endif
|
`endif
|
// Which register shall be written?
|
// Which register shall be written?
|
// COULD SIMPLIFY THIS: by adding three bits to these registers,
|
// COULD SIMPLIFY THIS: by adding three bits to these registers,
|
Line 1203... |
Line 1178... |
// Are we writing to the CC register?
|
// Are we writing to the CC register?
|
assign wr_write_cc = (wr_reg_id[3:0] == `CPU_CC_REG);
|
assign wr_write_cc = (wr_reg_id[3:0] == `CPU_CC_REG);
|
// Are we writing to the PC?
|
// Are we writing to the PC?
|
assign wr_write_pc = (wr_reg_id[3:0] == `CPU_PC_REG);
|
assign wr_write_pc = (wr_reg_id[3:0] == `CPU_PC_REG);
|
// What value to write?
|
// What value to write?
|
assign wr_reg_vl = (alu_wr)?((dbgv)?dbg_val: alu_result)
|
assign wr_reg_vl = ((mem_valid) ? mem_result
|
:((mem_valid) ? mem_result
|
:((div_valid|fpu_valid))
|
:((div_valid) ? div_result
|
? ((div_valid) ? div_result:fpu_result)
|
:fpu_result));
|
:((dbgv) ? dbg_val : alu_result));
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (wr_reg_ce)
|
if (wr_reg_ce)
|
regset[wr_reg_id] <= wr_reg_vl;
|
regset[wr_reg_id] <= wr_reg_vl;
|
|
|
//
|
//
|
// Write back to the condition codes/flags register ...
|
// Write back to the condition codes/flags register ...
|
// When shall we write to our flags register? alF_wr already
|
// When shall we write to our flags register? alF_wr already
|
// includes the set condition ...
|
// includes the set condition ...
|
assign wr_flags_ce = ((alF_wr)||(div_valid)||(fpu_valid))&&(~clear_pipeline)&&(~alu_illegal);
|
assign wr_flags_ce = ((alF_wr)||(div_valid)||(fpu_valid))&&(~clear_pipeline)&&(~alu_illegal);
|
assign w_uflags = { ufpu_err_flag, udiv_err_flag, ubus_err_flag, trap, ill_err_u, 1'b0, step, 1'b1, sleep, ((wr_flags_ce)&&(alu_gie))?alu_flags:flags };
|
assign w_uflags = { ufpu_err_flag,
|
assign w_iflags = { ifpu_err_flag, idiv_err_flag, ibus_err_flag, trap, ill_err_i,break_en, 1'b0, 1'b0, sleep, ((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags };
|
udiv_err_flag, ubus_err_flag, trap, ill_err_u,
|
|
1'b0, step, 1'b1, sleep,
|
|
((wr_flags_ce)&&(alu_gie))?alu_flags:flags };
|
|
assign w_iflags = { ifpu_err_flag,
|
|
idiv_err_flag, ibus_err_flag, trap, ill_err_i,
|
|
break_en, 1'b0, 1'b0, sleep,
|
|
((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags };
|
|
|
|
|
// What value to write?
|
// What value to write?
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
// If explicitly writing the register itself
|
// If explicitly writing the register itself
|
Line 1266... |
Line 1247... |
&&(~div_busy)&&(~fpu_busy)
|
&&(~div_busy)&&(~fpu_busy)
|
&&(~clear_pipeline)
|
&&(~clear_pipeline)
|
||((~alu_gie)&&(bus_err))
|
||((~alu_gie)&&(bus_err))
|
||((~alu_gie)&&(div_valid)&&(div_error))
|
||((~alu_gie)&&(div_valid)&&(div_error))
|
||((~alu_gie)&&(fpu_valid)&&(fpu_error))
|
||((~alu_gie)&&(fpu_valid)&&(fpu_error))
|
||((~alu_gie)&&(alu_valid)&&(alu_illegal));
|
||((~alu_gie)&&(alu_pc_valid)&&(alu_illegal));
|
`else
|
`else
|
assign o_break = (((break_en)||(~op_gie))&&(op_break)
|
assign o_break = (((break_en)||(~op_gie))&&(op_break)
|
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy)
|
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy)
|
&&(~clear_pipeline))
|
&&(~clear_pipeline))
|
||((~alu_gie)&&(bus_err));
|
||((~alu_gie)&&(bus_err));
|
Line 1322... |
Line 1303... |
// enable isn't set.
|
// enable isn't set.
|
||((master_ce)&&(~mem_rdbusy)&&(~div_busy)&&(~fpu_busy)
|
||((master_ce)&&(~mem_rdbusy)&&(~div_busy)&&(~fpu_busy)
|
&&(op_break)&&(~break_en))
|
&&(op_break)&&(~break_en))
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
// On an illegal instruction
|
// On an illegal instruction
|
||((alu_valid)&&(alu_illegal))
|
||((alu_pc_valid)&&(alu_illegal))
|
`endif
|
`endif
|
|
// On division by zero. If the divide isn't
|
|
// implemented, div_valid and div_error will be short
|
|
// circuited and that logic will be bypassed
|
||((div_valid)&&(div_error))
|
||((div_valid)&&(div_error))
|
|
// Same thing on a floating point error.
|
||((fpu_valid)&&(fpu_error))
|
||((fpu_valid)&&(fpu_error))
|
|
//
|
||(bus_err)
|
||(bus_err)
|
// If we write to the CC register
|
// If we write to the CC register
|
||((wr_reg_ce)&&(~wr_reg_vl[`CPU_GIE_BIT])
|
||((wr_reg_ce)&&(~wr_reg_vl[`CPU_GIE_BIT])
|
&&(wr_reg_id[4])&&(wr_write_cc))
|
&&(wr_reg_id[4])&&(wr_write_cc))
|
);
|
);
|
Line 1363... |
Line 1349... |
ill_err_i <= 1'b0;
|
ill_err_i <= 1'b0;
|
// The debug interface can clear this bit
|
// The debug interface can clear this bit
|
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG})
|
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG})
|
&&(~wr_reg_vl[`CPU_ILL_BIT]))
|
&&(~wr_reg_vl[`CPU_ILL_BIT]))
|
ill_err_i <= 1'b0;
|
ill_err_i <= 1'b0;
|
else if ((alu_valid)&&(alu_illegal)&&(~alu_gie))
|
else if ((alu_pc_valid)&&(alu_illegal)&&(~alu_gie))
|
ill_err_i <= 1'b1;
|
ill_err_i <= 1'b1;
|
initial ill_err_u = 1'b0;
|
initial ill_err_u = 1'b0;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (i_rst)
|
if (i_rst)
|
ill_err_u <= 1'b0;
|
ill_err_u <= 1'b0;
|
Line 1378... |
Line 1364... |
// bit, then clear it
|
// bit, then clear it
|
else if (((~alu_gie)||(dbgv))
|
else if (((~alu_gie)||(dbgv))
|
&&(wr_reg_ce)&&(~wr_reg_vl[`CPU_ILL_BIT])
|
&&(wr_reg_ce)&&(~wr_reg_vl[`CPU_ILL_BIT])
|
&&(wr_reg_id[4])&&(wr_write_cc))
|
&&(wr_reg_id[4])&&(wr_write_cc))
|
ill_err_u <= 1'b0;
|
ill_err_u <= 1'b0;
|
else if ((alu_valid)&&(alu_illegal)&&(gie))
|
else if ((alu_pc_valid)&&(alu_illegal)&&(alu_gie))
|
ill_err_u <= 1'b1;
|
ill_err_u <= 1'b1;
|
`else
|
`else
|
assign ill_err_u = 1'b0;
|
assign ill_err_u = 1'b0;
|
assign ill_err_i = 1'b0;
|
assign ill_err_i = 1'b0;
|
`endif
|
`endif
|
Line 1612... |
Line 1598... |
//
|
//
|
// Produce accounting outputs: Account for any CPU stalls, so we can
|
// Produce accounting outputs: Account for any CPU stalls, so we can
|
// later evaluate how well we are doing.
|
// later evaluate how well we are doing.
|
//
|
//
|
//
|
//
|
assign o_op_stall = (master_ce)&&((~opvalid)||(op_stall));
|
assign o_op_stall = (master_ce)&&(op_stall);
|
assign o_pf_stall = (master_ce)&&(~pf_valid);
|
assign o_pf_stall = (master_ce)&&(~pf_valid);
|
assign o_i_count = (alu_pc_valid)&&(~clear_pipeline);
|
assign o_i_count = (alu_pc_valid)&&(~clear_pipeline);
|
|
|
`ifdef DEBUG_SCOPE
|
`ifdef DEBUG_SCOPE
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
o_debug <= {
|
o_debug <= {
|
|
pf_pc[3:0], flags,
|
|
pf_valid, dcdvalid, opvalid, alu_valid, mem_valid,
|
|
op_ce, alu_ce, mem_ce,
|
|
//
|
|
master_ce, opvalid_alu, opvalid_mem,
|
|
//
|
|
alu_stall, mem_busy, op_pipe, mem_pipe_stalled,
|
|
mem_we,
|
|
// ((opvalid_alu)&&(alu_stall))
|
|
// ||((opvalid_mem)&&(~op_pipe)&&(mem_busy))
|
|
// ||((opvalid_mem)&&( op_pipe)&&(mem_pipe_stalled)));
|
|
// opA[23:20], opA[3:0],
|
|
gie, sleep,
|
|
wr_reg_ce, wr_reg_vl[4:0]
|
/*
|
/*
|
pf_pc[3:0], flags,
|
i_rst, master_ce, (new_pc),
|
pf_valid, dcdvalid, opvalid, alu_valid, mem_valid,
|
((dcd_early_branch)&&(dcdvalid)),
|
op_ce, alu_ce, mem_ce,
|
pf_valid, pf_illegal,
|
//
|
op_ce, dcd_ce, dcdvalid, dcd_stalled,
|
master_ce, opvalid_alu, opvalid_mem,
|
pf_cyc, pf_stb, pf_we, pf_ack, pf_stall, pf_err,
|
//
|
pf_pc[7:0], pf_addr[7:0]
|
alu_stall, mem_busy, op_pipe, mem_pipe_stalled,
|
|
mem_we,
|
|
// ((opvalid_alu)&&(alu_stall))
|
|
// ||((opvalid_mem)&&(~op_pipe)&&(mem_busy))
|
|
// ||((opvalid_mem)&&( op_pipe)&&(mem_pipe_stalled)));
|
|
// opA[23:20], opA[3:0],
|
|
gie, sleep,
|
|
wr_reg_vl[5:0]
|
|
*/
|
*/
|
i_rst, master_ce, (new_pc),
|
|
((dcd_early_branch)&&(dcdvalid)),
|
|
pf_valid, pf_illegal,
|
|
op_ce, dcd_ce, dcdvalid, dcd_stalled,
|
|
pf_cyc, pf_stb, pf_we, pf_ack, pf_stall, pf_err,
|
|
pf_pc[7:0], pf_addr[7:0]
|
|
};
|
};
|
`endif
|
`endif
|
|
|
endmodule
|
endmodule
|
|
|
No newline at end of file
|
No newline at end of file
|