Line 201... |
Line 201... |
reg [31:0] regset [0:31];
|
reg [31:0] regset [0:31];
|
|
|
// Condition codes
|
// Condition codes
|
// (BUS, TRAP,ILL,BREAKEN,STEP,GIE,SLEEP ), V, N, C, Z
|
// (BUS, TRAP,ILL,BREAKEN,STEP,GIE,SLEEP ), V, N, C, Z
|
reg [3:0] flags, iflags;
|
reg [3:0] flags, iflags;
|
wire [12:0] w_uflags, w_iflags;
|
wire [13:0] w_uflags, w_iflags;
|
reg trap, break_en, step, gie, sleep;
|
reg trap, break_en, step, gie, sleep;
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
reg ill_err_u, ill_err_i;
|
reg ill_err_u, ill_err_i;
|
`else
|
`else
|
wire ill_err_u, ill_err_i;
|
wire ill_err_u, ill_err_i;
|
Line 240... |
Line 240... |
//
|
//
|
// PIPELINE STAGE #2 :: Instruction Decode
|
// PIPELINE STAGE #2 :: Instruction Decode
|
// Variable declarations
|
// Variable declarations
|
//
|
//
|
//
|
//
|
reg opvalid, opvalid_mem, opvalid_alu, op_wr_pc;
|
reg opvalid, opvalid_mem, opvalid_alu;
|
reg opvalid_div, opvalid_fpu;
|
reg opvalid_div, opvalid_fpu;
|
wire op_stall, dcd_ce, dcd_phase;
|
wire op_stall, dcd_ce, dcd_phase;
|
wire [3:0] dcdOp;
|
wire [3:0] dcdOp;
|
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;
|
Line 279... |
Line 279... |
reg [31:0] r_opA, r_opB;
|
reg [31:0] r_opA, r_opB;
|
reg [(AW-1):0] op_pc;
|
reg [(AW-1):0] op_pc;
|
wire [31:0] w_opA, w_opB;
|
wire [31:0] w_opA, w_opB;
|
wire [31:0] opA_nowait, opB_nowait, opA, opB;
|
wire [31:0] opA_nowait, opB_nowait, opA, opB;
|
reg opR_wr, opR_cc, opF_wr, op_gie;
|
reg opR_wr, opR_cc, opF_wr, op_gie;
|
wire [12:0] opFl;
|
wire [13:0] opFl;
|
reg [5:0] r_opF;
|
reg [5:0] r_opF;
|
wire [7:0] opF;
|
wire [7:0] opF;
|
reg [2:0] opF_cp;
|
|
wire op_ce, op_phase;
|
wire op_ce, op_phase;
|
// Some pipeline control wires
|
// Some pipeline control wires
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
reg opA_alu, opA_mem;
|
reg opA_alu, opA_mem;
|
reg opB_alu, opB_mem;
|
reg opB_alu, opB_mem;
|
Line 402... |
Line 401... |
// Stall if going into the ALU and the ALU is stalled
|
// Stall if going into the ALU and the ALU is stalled
|
// i.e. if the memory is busy, or we are single
|
// i.e. if the memory is busy, or we are single
|
// stepping. This also includes our stalls for
|
// stepping. This also includes our stalls for
|
// op_break and op_lock, so we don't need to
|
// op_break and op_lock, so we don't need to
|
// include those as well here.
|
// include those as well here.
|
((opvalid)&&(alu_stall))
|
// This also includes whether or not the divide or
|
// Stall if the divide is busy, since we can't have
|
// floating point units are busy.
|
// two parallel stages writing back at the same time
|
(alu_stall)
|
||(div_busy)
|
|
// Same for the floating point unit
|
|
||(fpu_busy)
|
|
//
|
//
|
// ||((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))
|
||(mem_stalled) // &&(opvalid_mem) part of mem_stalled
|
// ||((opvalid_mem)&&(dcdvalid)&&(dcdM)&&(~dcd_pipe))
|
|
)
|
)
|
||(dcdvalid)&&(
|
||(dcdvalid)&&(
|
// Stall if we need to wait for an operand A
|
// Stall if we need to wait for an operand A
|
// to be ready to read
|
// to be ready to read
|
(dcdA_stall)
|
(dcdA_stall)
|
Line 665... |
Line 659... |
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;
|
else if (dcdA_pc)
|
else if (dcdA_pc)
|
r_opA <= w_pcA_v;
|
r_opA <= w_pcA_v;
|
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:14], (dcdA[4])?w_uflags:w_iflags };
|
else
|
else
|
r_opA <= w_opA;
|
r_opA <= w_opA;
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
end else
|
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,
|
Line 691... |
Line 685... |
endgenerate
|
endgenerate
|
|
|
assign w_opBnI = (~dcdB_rd) ? 32'h00
|
assign w_opBnI = (~dcdB_rd) ? 32'h00
|
: (((wr_reg_ce)&&(wr_reg_id == dcdB)) ? wr_reg_vl
|
: (((wr_reg_ce)&&(wr_reg_id == dcdB)) ? wr_reg_vl
|
: ((dcdB_pc) ? w_pcB_v
|
: ((dcdB_pc) ? w_pcB_v
|
: ((dcdB_cc) ? { w_opB[31:13], (dcdB[4])?w_uflags:w_iflags}
|
: ((dcdB_cc) ? { w_opB[31:14], (dcdB[4])?w_uflags:w_iflags}
|
: w_opB)));
|
: w_opB)));
|
|
|
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;
|
Line 738... |
Line 732... |
3'h6: r_opF <= 6'h02; // C
|
3'h6: r_opF <= 6'h02; // C
|
3'h7: r_opF <= 6'h08; // V
|
3'h7: r_opF <= 6'h08; // V
|
endcase
|
endcase
|
end // Bit order is { (flags_not_used), VNCZ mask, VNCZ value }
|
end // Bit order is { (flags_not_used), VNCZ mask, VNCZ value }
|
assign opF = { r_opF[3], r_opF[5], r_opF[1], r_opF[4:0] };
|
assign opF = { r_opF[3], r_opF[5], r_opF[1], r_opF[4:0] };
|
always @(posedge i_clk)
|
|
if (op_ce)
|
|
opF_cp[2:0] <= dcdF[2:0];
|
|
|
|
wire w_opvalid;
|
wire w_opvalid;
|
assign w_opvalid = (~clear_pipeline)&&(dcdvalid);
|
assign w_opvalid = (~clear_pipeline)&&(dcdvalid);
|
initial opvalid = 1'b0;
|
initial opvalid = 1'b0;
|
initial opvalid_alu = 1'b0;
|
initial opvalid_alu = 1'b0;
|
Line 855... |
Line 846... |
// set, dcd_early_branch will simply be a wire connected to zero and
|
// set, dcd_early_branch will simply be a wire connected to zero and
|
// this logic should just optimize.
|
// 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))
|
opR_wr <= (dcdR_wr)&&(~dcd_early_branch);
|
&&(~dcd_early_branch)&&(~dcd_illegal);
|
op_wr_pc <= ((dcdR_wr)&&(dcdR_pc)
|
opR_wr <= (dcdR_wr)&&(~dcd_early_branch)&&(~dcd_illegal);
|
&&(dcdR[4] == dcd_gie))
|
|
&&(~dcd_early_branch);
|
|
end
|
end
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (op_ce)
|
if (op_ce)
|
begin
|
begin
|
Line 905... |
Line 894... |
// 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
|
assign opA = ((wr_reg_ce)&&(wr_reg_id == opA_id)&&(opA_rd))
|
assign opA = ((wr_reg_ce)&&(wr_reg_id == opA_id)) // &&(opA_rd))
|
? wr_reg_vl : r_opA;
|
? wr_reg_vl : 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)&&(
|
// Stall if we have decoded an instruction that will read register A
|
((opvalid_alu)&&(opF_wr)&&(dcdA_cc))
|
// AND ... something that may write a register is running
|
);
|
// AND (series of conditions here ...)
|
|
// The operation might set flags, and we wish to read the
|
|
// CC register
|
|
// OR ... (No other conditions)
|
|
assign dcdA_stall = (dcdA_rd) // &&(dcdvalid) is checked for elsewhere
|
|
&&((opvalid)||(mem_rdbusy)
|
|
||(div_busy)||(fpu_busy))
|
|
&&((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
|
|
|
Line 928... |
Line 924... |
`else
|
`else
|
assign opB = r_opB;
|
assign opB = r_opB;
|
`endif
|
`endif
|
|
|
`ifdef OPT_PIPELINED
|
`ifdef OPT_PIPELINED
|
assign dcdB_stall = (dcdvalid)&&(dcdB_rd)&&(
|
// Stall if we have decoded an instruction that will read register B
|
|
// AND ... something that may write a (unknown) register is running
|
|
// AND (series of conditions here ...)
|
|
// The operation might set flags, and we wish to read the
|
|
// CC register
|
|
// OR the operation might set register B, and we still need
|
|
// a clock to add the offset to it
|
|
assign dcdB_stall = (dcdB_rd) // &&(dcdvalid) is checked for elsewhere
|
|
// If the op stage isn't valid, yet something
|
|
// is running, then it must have been valid.
|
|
// We'll use the last values from that stage
|
|
// (opR_wr, opF_wr, opR) in our logic below.
|
|
&&((opvalid)||(mem_rdbusy)
|
|
||(div_busy)||(fpu_busy))
|
|
&&(
|
// Stall on memory ops writing to my register
|
// Stall on memory ops writing to my register
|
// (i.e. loads), or on any write to my
|
// (i.e. loads), or on any write to my
|
// register if I have an immediate offset
|
// register if I have an immediate offset
|
// Note the exception for writing to the PC:
|
// Note the exception for writing to the PC:
|
// 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. This keeps a BC X, BNZ Y from
|
((~dcd_zI)&&(dcdB_rd)&&(opR == dcdB)&&(opR_wr)
|
// stalling between the two branches.
|
&&(opR != { op_gie, `CPU_PC_REG } )
|
// BC X, BRA Y is still clear, since BRA Y
|
&&((opvalid)||(mem_rdbusy)
|
// is an early branch instruction.
|
||(div_busy)||(fpu_busy)))
|
// (This exception is commented out in
|
// Stall on any write to the flags register,
|
// order to help keep our logic simple, and
|
// if we're going to need the flags value for
|
// because multiple conditional branches
|
// opB.
|
// following each other constitutes a
|
||((opvalid_alu)&&(opF_wr)&&(dcdB_cc))
|
// fairly unusualy code structure.)
|
|
//
|
|
((~dcd_zI)&&(opR == dcdB)&&(opR_wr))
|
|
// &&(opR != { op_gie, `CPU_PC_REG } )
|
|
// Stall following any instruction that will
|
|
// set the flags, if we're going to need the
|
|
// flags (CC) register for opB.
|
|
||((opF_wr)&&(dcdB_cc))
|
// Stall on any ongoing memory operation that
|
// Stall on any ongoing memory operation that
|
// will write to opB -- captured above
|
// will write to opB -- captured above
|
// ||((mem_busy)&&(~mem_we)&&(mem_last_reg==dcdB)&&(~dcd_zI))
|
// ||((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
|
assign dcdF_stall = (dcdvalid)&&((~dcdF[3])
|
assign dcdF_stall = ((~dcdF[3])
|
||((dcdA_rd)&&(dcdA_cc))
|
||((dcdA_rd)&&(dcdA_cc))
|
||((dcdB_rd)&&(dcdB_cc)))
|
||((dcdB_rd)&&(dcdB_cc)))
|
&&(opvalid)&&(opR_cc);
|
&&(opvalid)&&(opR_cc);
|
|
// &&(dcdvalid) is checked for elsewhere
|
//
|
//
|
//
|
//
|
// PIPELINE STAGE #4 :: Apply Instruction
|
// PIPELINE STAGE #4 :: Apply Instruction
|
//
|
//
|
//
|
//
|
Line 979... |
Line 997... |
`endif
|
`endif
|
|
|
generate
|
generate
|
if (IMPLEMENT_DIVIDE != 0)
|
if (IMPLEMENT_DIVIDE != 0)
|
begin
|
begin
|
div thedivide(i_clk, i_rst, div_ce, opn[0],
|
div thedivide(i_clk, (i_rst)||(clear_pipeline), div_ce, opn[0],
|
opA, opB, div_busy, div_valid, div_error, div_result,
|
opA, opB, div_busy, div_valid, div_error, div_result,
|
div_flags);
|
div_flags);
|
end else begin
|
end else begin
|
assign div_error = 1'b1;
|
assign div_error = 1'b1;
|
assign div_busy = 1'b0;
|
assign div_busy = 1'b0;
|
Line 1163... |
Line 1181... |
// 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)&&(alu_valid)&&(~clear_pipeline))||(mem_valid)||(div_valid)||(fpu_valid);
|
assign wr_reg_ce = (~alu_illegal)&&
|
|
(((alu_wr)&&(~clear_pipeline)
|
|
&&((alu_valid)||(div_valid)||(fpu_valid)))
|
|
||(mem_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 1191... |
Line 1212... |
//
|
//
|
// 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,
|
assign w_uflags = { uhalt_phase, ufpu_err_flag,
|
udiv_err_flag, ubus_err_flag, trap, ill_err_u,
|
udiv_err_flag, ubus_err_flag, trap, ill_err_u,
|
1'b0, step, 1'b1, sleep,
|
1'b0, step, 1'b1, sleep,
|
((wr_flags_ce)&&(alu_gie))?alu_flags:flags };
|
((wr_flags_ce)&&(alu_gie))?alu_flags:flags };
|
assign w_iflags = { ifpu_err_flag,
|
assign w_iflags = { ihalt_phase, ifpu_err_flag,
|
idiv_err_flag, ibus_err_flag, trap, ill_err_i,
|
idiv_err_flag, ibus_err_flag, trap, ill_err_i,
|
break_en, 1'b0, 1'b0, sleep,
|
break_en, 1'b0, 1'b0, sleep,
|
((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags };
|
((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags };
|
|
|
|
|
Line 1565... |
Line 1586... |
o_dbg_reg <= regset[i_dbg_reg];
|
o_dbg_reg <= regset[i_dbg_reg];
|
if (i_dbg_reg[3:0] == `CPU_PC_REG)
|
if (i_dbg_reg[3:0] == `CPU_PC_REG)
|
o_dbg_reg <= {{(32-AW){1'b0}},(i_dbg_reg[4])?upc:ipc};
|
o_dbg_reg <= {{(32-AW){1'b0}},(i_dbg_reg[4])?upc:ipc};
|
else if (i_dbg_reg[3:0] == `CPU_CC_REG)
|
else if (i_dbg_reg[3:0] == `CPU_CC_REG)
|
begin
|
begin
|
o_dbg_reg[12:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
|
o_dbg_reg[13:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
|
o_dbg_reg[`CPU_GIE_BIT] <= gie;
|
o_dbg_reg[`CPU_GIE_BIT] <= gie;
|
end
|
end
|
end
|
end
|
end else begin
|
end else begin
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
Line 1577... |
Line 1598... |
o_dbg_reg <= regset[i_dbg_reg];
|
o_dbg_reg <= regset[i_dbg_reg];
|
if (i_dbg_reg[3:0] == `CPU_PC_REG)
|
if (i_dbg_reg[3:0] == `CPU_PC_REG)
|
o_dbg_reg <= (i_dbg_reg[4])?upc:ipc;
|
o_dbg_reg <= (i_dbg_reg[4])?upc:ipc;
|
else if (i_dbg_reg[3:0] == `CPU_CC_REG)
|
else if (i_dbg_reg[3:0] == `CPU_CC_REG)
|
begin
|
begin
|
o_dbg_reg[12:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
|
o_dbg_reg[13:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
|
o_dbg_reg[`CPU_GIE_BIT] <= gie;
|
o_dbg_reg[`CPU_GIE_BIT] <= gie;
|
end
|
end
|
end
|
end
|
end endgenerate
|
end endgenerate
|
|
|