Line 130... |
Line 130... |
// Compile time defines
|
// Compile time defines
|
// (Currently unused)
|
// (Currently unused)
|
// `define OPT_SINGLE_FETCH
|
// `define OPT_SINGLE_FETCH
|
// (Best path--define these!)
|
// (Best path--define these!)
|
`define OPT_CONDITIONAL_FLAGS
|
`define OPT_CONDITIONAL_FLAGS
|
`define OPT_PRECLEAR_BUS
|
|
`define OPT_ILLEGAL_INSTRUCTION
|
`define OPT_ILLEGAL_INSTRUCTION
|
|
`ifndef OPT_SINGLE_FETCH
|
|
// The following are pipeline optimization options.
|
|
// They make no sense in a single instruction fetch mode.
|
|
`define OPT_PRECLEAR_BUS
|
`define OPT_EARLY_BRANCHING
|
`define OPT_EARLY_BRANCHING
|
`define OPT_PIPELINED_BUS_ACCESS
|
`define OPT_PIPELINED_BUS_ACCESS
|
|
`endif
|
module zipcpu(i_clk, i_rst, i_interrupt,
|
module zipcpu(i_clk, i_rst, i_interrupt,
|
// Debug interface
|
// Debug interface
|
i_halt, i_clear_pf_cache, i_dbg_reg, i_dbg_we, i_dbg_data,
|
i_halt, i_clear_pf_cache, i_dbg_reg, i_dbg_we, i_dbg_data,
|
o_dbg_stall, o_dbg_reg, o_dbg_cc,
|
o_dbg_stall, o_dbg_reg, o_dbg_cc,
|
o_break,
|
o_break,
|
Line 147... |
Line 151... |
o_wb_we, o_wb_addr, o_wb_data,
|
o_wb_we, o_wb_addr, o_wb_data,
|
i_wb_ack, i_wb_stall, i_wb_data,
|
i_wb_ack, i_wb_stall, i_wb_data,
|
i_wb_err,
|
i_wb_err,
|
// Accounting/CPU usage interface
|
// Accounting/CPU usage interface
|
o_op_stall, o_pf_stall, o_i_count);
|
o_op_stall, o_pf_stall, o_i_count);
|
parameter RESET_ADDRESS=32'h0100000, LGICACHE=9;
|
parameter RESET_ADDRESS=32'h0100000, ADDRESS_WIDTH=24,
|
|
LGICACHE=6, AW=ADDRESS_WIDTH;
|
input i_clk, i_rst, i_interrupt;
|
input i_clk, i_rst, i_interrupt;
|
// Debug interface -- inputs
|
// Debug interface -- inputs
|
input i_halt, i_clear_pf_cache;
|
input i_halt, i_clear_pf_cache;
|
input [4:0] i_dbg_reg;
|
input [4:0] i_dbg_reg;
|
input i_dbg_we;
|
input i_dbg_we;
|
Line 162... |
Line 167... |
output reg [1:0] o_dbg_cc;
|
output reg [1:0] o_dbg_cc;
|
output wire o_break;
|
output wire o_break;
|
// Wishbone interface -- outputs
|
// Wishbone interface -- outputs
|
output wire o_wb_gbl_cyc, o_wb_gbl_stb;
|
output wire o_wb_gbl_cyc, o_wb_gbl_stb;
|
output wire o_wb_lcl_cyc, o_wb_lcl_stb, o_wb_we;
|
output wire o_wb_lcl_cyc, o_wb_lcl_stb, o_wb_we;
|
output wire [31:0] o_wb_addr, o_wb_data;
|
output wire [(AW-1):0] o_wb_addr;
|
|
output wire [31:0] o_wb_data;
|
// Wishbone interface -- inputs
|
// Wishbone interface -- inputs
|
input i_wb_ack, i_wb_stall;
|
input i_wb_ack, i_wb_stall;
|
input [31:0] i_wb_data;
|
input [31:0] i_wb_data;
|
input i_wb_err;
|
input i_wb_err;
|
// Accounting outputs ... to help us count stalls and usage
|
// Accounting outputs ... to help us count stalls and usage
|
Line 195... |
Line 201... |
//
|
//
|
//
|
//
|
// PIPELINE STAGE #1 :: Prefetch
|
// PIPELINE STAGE #1 :: Prefetch
|
// Variable declarations
|
// Variable declarations
|
//
|
//
|
reg [31:0] pf_pc;
|
reg [(AW-1):0] pf_pc;
|
reg new_pc, op_break;
|
reg new_pc, op_break;
|
wire clear_pipeline;
|
wire clear_pipeline;
|
assign clear_pipeline = new_pc || i_clear_pf_cache; // || op_break;
|
assign clear_pipeline = new_pc || i_clear_pf_cache; // || op_break;
|
|
|
wire dcd_stalled;
|
wire dcd_stalled;
|
wire pf_cyc, pf_stb, pf_we, pf_busy, pf_ack, pf_stall, pf_err;
|
wire pf_cyc, pf_stb, pf_we, pf_busy, pf_ack, pf_stall, pf_err;
|
wire [31:0] pf_addr, pf_data;
|
wire [(AW-1):0] pf_addr;
|
wire [31:0] instruction, instruction_pc;
|
wire [31:0] pf_data;
|
|
wire [31:0] instruction;
|
|
wire [(AW-1):0] instruction_pc;
|
wire pf_valid, instruction_gie, pf_illegal;
|
wire pf_valid, instruction_gie, pf_illegal;
|
|
|
//
|
//
|
//
|
//
|
// PIPELINE STAGE #2 :: Instruction Decode
|
// PIPELINE STAGE #2 :: Instruction Decode
|
Line 220... |
Line 228... |
reg [4:0] dcdA, dcdB;
|
reg [4:0] dcdA, dcdB;
|
reg dcdA_cc, dcdB_cc, dcdA_pc, dcdB_pc;
|
reg dcdA_cc, dcdB_cc, dcdA_pc, dcdB_pc;
|
reg [3:0] dcdF;
|
reg [3:0] dcdF;
|
reg dcdA_rd, dcdA_wr, dcdB_rd, dcdvalid,
|
reg dcdA_rd, dcdA_wr, dcdB_rd, dcdvalid,
|
dcdM, dcdF_wr, dcd_gie, dcd_break;
|
dcdM, dcdF_wr, dcd_gie, dcd_break;
|
reg [31:0] dcd_pc;
|
reg [(AW-1):0] dcd_pc;
|
reg [23:0] r_dcdI;
|
reg [23:0] r_dcdI;
|
|
reg dcd_zI; // true if dcdI == 0
|
wire dcdA_stall, dcdB_stall, dcdF_stall;
|
wire dcdA_stall, dcdB_stall, dcdF_stall;
|
|
|
`ifdef OPT_PRECLEAR_BUS
|
`ifdef OPT_PRECLEAR_BUS
|
reg dcd_clear_bus;
|
reg dcd_clear_bus;
|
`endif
|
`endif
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
`ifdef OPT_ILLEGAL_INSTRUCTION
|
reg dcd_illegal;
|
reg dcd_illegal;
|
`endif
|
`endif
|
`ifdef OPT_EARLY_BRANCHING
|
`ifdef OPT_EARLY_BRANCHING
|
reg dcd_early_branch_stb, dcd_early_branch;
|
reg dcd_early_branch_stb, dcd_early_branch;
|
reg [31:0] dcd_branch_pc;
|
reg [(AW-1):0] dcd_branch_pc;
|
`else
|
`else
|
wire dcd_early_branch_stb, dcd_early_branch;
|
wire dcd_early_branch_stb, dcd_early_branch;
|
wire [31:0] dcd_branch_pc;
|
wire [(AW-1):0] dcd_branch_pc;
|
`endif
|
`endif
|
|
|
|
|
//
|
//
|
//
|
//
|
Line 250... |
Line 259... |
//
|
//
|
// Now, let's read our operands
|
// Now, let's read our operands
|
reg [4:0] alu_reg;
|
reg [4:0] alu_reg;
|
reg [3:0] opn;
|
reg [3:0] opn;
|
reg [4:0] opR;
|
reg [4:0] opR;
|
reg [31:0] r_opA, r_opB, op_pc;
|
reg [31:0] r_opA, r_opB;
|
|
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,
|
opA_rd, opB_rd;
|
opA_rd, opB_rd;
|
wire [10:0] opFl;
|
wire [10:0] opFl;
|
Line 273... |
Line 283... |
//
|
//
|
// PIPELINE STAGE #4 :: ALU / Memory
|
// PIPELINE STAGE #4 :: ALU / Memory
|
// Variable declarations
|
// Variable declarations
|
//
|
//
|
//
|
//
|
reg [31:0] alu_pc;
|
reg [(AW-1):0] alu_pc;
|
reg alu_pc_valid;;
|
reg alu_pc_valid;;
|
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;
|
Line 298... |
Line 308... |
wire mem_valid, mem_ack, mem_stall, mem_err, bus_err,
|
wire mem_valid, mem_ack, mem_stall, mem_err, bus_err,
|
mem_cyc_gbl, mem_cyc_lcl, mem_stb_gbl, mem_stb_lcl, mem_we;
|
mem_cyc_gbl, mem_cyc_lcl, mem_stb_gbl, mem_stb_lcl, mem_we;
|
wire [4:0] mem_wreg;
|
wire [4:0] mem_wreg;
|
|
|
wire mem_busy, mem_rdbusy;
|
wire mem_busy, mem_rdbusy;
|
wire [31:0] mem_addr, mem_data, mem_result;
|
wire [(AW-1):0] mem_addr;
|
|
wire [31:0] mem_data, mem_result;
|
|
reg [4:0] mem_last_reg; // Last register result to go in
|
|
|
|
|
|
|
//
|
//
|
//
|
//
|
Line 311... |
Line 323... |
//
|
//
|
wire wr_reg_ce, wr_flags_ce, wr_write_pc, wr_write_cc;
|
wire wr_reg_ce, wr_flags_ce, wr_write_pc, wr_write_cc;
|
wire [4:0] wr_reg_id;
|
wire [4:0] wr_reg_id;
|
wire [31:0] wr_reg_vl;
|
wire [31:0] wr_reg_vl;
|
wire w_switch_to_interrupt, w_release_from_interrupt;
|
wire w_switch_to_interrupt, w_release_from_interrupt;
|
reg [31:0] upc, ipc;
|
reg [(AW-1):0] upc, ipc;
|
|
|
|
|
|
|
//
|
//
|
// MASTER: clock enable.
|
// MASTER: clock enable.
|
Line 394... |
Line 406... |
//
|
//
|
`ifdef OPT_SINGLE_FETCH
|
`ifdef OPT_SINGLE_FETCH
|
wire pf_ce;
|
wire pf_ce;
|
|
|
assign pf_ce = (~dcd_stalled);
|
assign pf_ce = (~dcd_stalled);
|
prefetch pf(i_clk, i_rst, (pf_ce), pf_pc, gie,
|
prefetch #(ADDRESS_WIDTH)
|
|
pf(i_clk, i_rst, (pf_ce), pf_pc, gie,
|
instruction, instruction_pc, instruction_gie,
|
instruction, instruction_pc, instruction_gie,
|
pf_valid, pf_illegal,
|
pf_valid, pf_illegal,
|
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
|
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
|
pf_ack, pf_stall, pf_err, i_wb_data);
|
pf_ack, pf_stall, pf_err, i_wb_data);
|
`else // Pipe fetch
|
`else // Pipe fetch
|
pipefetch #(RESET_ADDRESS, LGICACHE)
|
pipefetch #(RESET_ADDRESS, LGICACHE, ADDRESS_WIDTH)
|
pf(i_clk, i_rst, (new_pc)|(dcd_early_branch_stb),
|
pf(i_clk, i_rst, (new_pc)|(dcd_early_branch_stb),
|
i_clear_pf_cache, ~dcd_stalled,
|
i_clear_pf_cache, ~dcd_stalled,
|
(new_pc)?pf_pc:dcd_branch_pc,
|
(new_pc)?pf_pc:dcd_branch_pc,
|
instruction, instruction_pc, pf_valid,
|
instruction, instruction_pc, pf_valid,
|
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
|
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
|
Line 465... |
Line 478... |
end
|
end
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (dcd_ce)
|
if (dcd_ce)
|
begin
|
begin
|
if (instruction[31]) // Add
|
if (instruction[31]) // Add
|
dcd_branch_pc <= instruction_pc+32'h01+{ {(12){instruction[19]}}, instruction[19:0] };
|
dcd_branch_pc <= instruction_pc+{ {(AW-20){instruction[19]}}, instruction[19:0] } + {{(AW-1){1'b0}},1'b1};
|
else if (~instruction[28]) // 4'h2 = MOV
|
else if (~instruction[28]) // 4'h2 = MOV
|
dcd_branch_pc <= instruction_pc+32'h01+{ {(17){instruction[14]}}, instruction[14:0] };
|
dcd_branch_pc <= instruction_pc+{ {(AW-15){instruction[14]}}, instruction[14:0] } + {{(AW-1){1'b0}},1'b1};
|
else // if (instruction[28]) // 4'h3 = LDI
|
else // if (instruction[28]) // 4'h3 = LDI
|
dcd_branch_pc <= instruction_pc+32'h01+{ {(8){instruction[23]}}, instruction[23:0] };
|
dcd_branch_pc <= instruction_pc+{ {(AW-24){instruction[23]}}, instruction[23:0] } + {{(AW-1){1'b0}},1'b1};
|
end
|
end
|
`else // OPT_EARLY_BRANCHING
|
`else // OPT_EARLY_BRANCHING
|
assign dcd_early_branch_stb = 1'b0;
|
assign dcd_early_branch_stb = 1'b0;
|
assign dcd_early_branch = 1'b0;
|
assign dcd_early_branch = 1'b0;
|
assign dcd_branch_pc = 32'h00;
|
assign dcd_branch_pc = {(AW){1'b0}};
|
`endif // OPT_EARLY_BRANCHING
|
`endif // OPT_EARLY_BRANCHING
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (dcd_ce)
|
if (dcd_ce)
|
begin
|
begin
|
Line 520... |
Line 533... |
end
|
end
|
dcdA_wr <= 1'b1;
|
dcdA_wr <= 1'b1;
|
dcdA_rd <= 1'b0;
|
dcdA_rd <= 1'b0;
|
dcdB_rd <= 1'b1;
|
dcdB_rd <= 1'b1;
|
r_dcdI <= { {(9){instruction[14]}}, instruction[14:0] };
|
r_dcdI <= { {(9){instruction[14]}}, instruction[14:0] };
|
|
dcd_zI <= (instruction[14:0] == 0);
|
dcdF_wr <= 1'b0; // Don't write flags
|
dcdF_wr <= 1'b0; // Don't write flags
|
end
|
end
|
4'h3: begin // Load immediate
|
4'h3: begin // Load immediate
|
dcdA_wr <= 1'b1;
|
dcdA_wr <= 1'b1;
|
dcdA_rd <= 1'b0;
|
dcdA_rd <= 1'b0;
|
dcdB_rd <= 1'b0;
|
dcdB_rd <= 1'b0;
|
r_dcdI <= { instruction[23:0] };
|
r_dcdI <= { instruction[23:0] };
|
|
dcd_zI <= (instruction[23:0] == 0);
|
dcdF_wr <= 1'b0; // Don't write flags
|
dcdF_wr <= 1'b0; // Don't write flags
|
dcdF <= 4'h8; // This is unconditional
|
dcdF <= 4'h8; // This is unconditional
|
dcdOp <= 4'h2;
|
dcdOp <= 4'h2;
|
end
|
end
|
4'h4: begin // Multiply, LDI[HI|LO], or NOOP/BREAK
|
4'h4: begin // Multiply, LDI[HI|LO], or NOOP/BREAK
|
Line 542... |
Line 557... |
`else
|
`else
|
// Don't write flags except for multiplies
|
// Don't write flags except for multiplies
|
dcdF_wr <= (instruction[27:25] != 3'h7);
|
dcdF_wr <= (instruction[27:25] != 3'h7);
|
`endif
|
`endif
|
r_dcdI <= { 8'h00, instruction[15:0] };
|
r_dcdI <= { 8'h00, instruction[15:0] };
|
|
dcd_zI <= (instruction[15:0] == 0);
|
if (instruction[27:24] == 4'he)
|
if (instruction[27:24] == 4'he)
|
begin
|
begin
|
// NOOP instruction
|
// NOOP instruction
|
dcdA_wr <= 1'b0;
|
dcdA_wr <= 1'b0;
|
dcdA_rd <= 1'b0;
|
dcdA_rd <= 1'b0;
|
Line 566... |
Line 582... |
dcdA_pc <= (instruction[19:16] == `CPU_PC_REG);
|
dcdA_pc <= (instruction[19:16] == `CPU_PC_REG);
|
dcdOp <= { 3'h3, instruction[20] };
|
dcdOp <= { 3'h3, instruction[20] };
|
end else begin
|
end else begin
|
// Actual multiply instruction
|
// Actual multiply instruction
|
r_dcdI <= { 8'h00, instruction[15:0] };
|
r_dcdI <= { 8'h00, instruction[15:0] };
|
|
dcd_zI <= (instruction[15:0] == 0);
|
dcdA_rd <= 1'b1;
|
dcdA_rd <= 1'b1;
|
dcdB_rd <= (instruction[19:16] != 4'hf);
|
dcdB_rd <= (instruction[19:16] != 4'hf);
|
dcdOp[3:0] <= (instruction[20])? 4'h4:4'h3;
|
dcdOp[3:0] <= (instruction[20])? 4'h4:4'h3;
|
end end
|
end end
|
4'b011?: begin // Load/Store
|
4'b011?: begin // Load/Store
|
dcdF_wr <= 1'b0; // Don't write flags
|
dcdF_wr <= 1'b0; // Don't write flags
|
dcdA_wr <= (~instruction[28]); // Write on loads
|
dcdA_wr <= (~instruction[28]); // Write on loads
|
dcdA_rd <= (instruction[28]); // Read on stores
|
dcdA_rd <= (instruction[28]); // Read on stores
|
dcdB_rd <= instruction[20];
|
dcdB_rd <= instruction[20];
|
if (instruction[20])
|
if (instruction[20])
|
|
begin
|
r_dcdI <= { {(8){instruction[15]}}, instruction[15:0] };
|
r_dcdI <= { {(8){instruction[15]}}, instruction[15:0] };
|
else
|
dcd_zI <= (instruction[15:0] == 0);
|
|
end else begin
|
r_dcdI <= { {(4){instruction[19]}}, instruction[19:0] };
|
r_dcdI <= { {(4){instruction[19]}}, instruction[19:0] };
|
|
dcd_zI <= (instruction[19:0] == 0);
|
|
end
|
dcdM <= 1'b1; // Memory operation
|
dcdM <= 1'b1; // Memory operation
|
`ifdef OPT_PRECLEAR_BUS
|
`ifdef OPT_PRECLEAR_BUS
|
dcd_clear_bus <= (instruction[23:21]==3'h0);
|
dcd_clear_bus <= (instruction[23:21]==3'h0);
|
`endif
|
`endif
|
end
|
end
|
default: begin
|
default: begin
|
dcdA_wr <= (instruction[31])||(instruction[31:28]==4'h5);
|
dcdA_wr <= (instruction[31])||(instruction[31:28]==4'h5);
|
dcdA_rd <= 1'b1;
|
dcdA_rd <= 1'b1;
|
dcdB_rd <= instruction[20];
|
dcdB_rd <= instruction[20];
|
if (instruction[20])
|
if (instruction[20])
|
|
begin
|
r_dcdI <= { {(8){instruction[15]}}, instruction[15:0] };
|
r_dcdI <= { {(8){instruction[15]}}, instruction[15:0] };
|
else
|
dcd_zI <= (instruction[15:0] == 0);
|
|
end else begin
|
r_dcdI <= { {(4){instruction[19]}}, instruction[19:0] };
|
r_dcdI <= { {(4){instruction[19]}}, instruction[19:0] };
|
end
|
dcd_zI <= (instruction[19:0] == 0);
|
|
end end
|
endcase
|
endcase
|
|
|
|
|
dcd_gie <= instruction_gie;
|
dcd_gie <= instruction_gie;
|
end
|
end
|
Line 643... |
Line 667... |
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;
|
else if ((dcdA_pc)&&(dcdA[4] == dcd_gie))
|
else if ((dcdA_pc)&&(dcdA[4] == dcd_gie))
|
r_opA <= dcd_pc;
|
r_opA <= { {(32-AW){1'b0}}, dcd_pc };
|
else if (dcdA_pc)
|
else if (dcdA_pc)
|
r_opA <= upc;
|
r_opA <= { {(32-AW){1'b0}}, upc };
|
else if (dcdA_cc)
|
else if (dcdA_cc)
|
r_opA <= { w_opA[31:11], (dcd_gie)?w_uflags:w_iflags };
|
r_opA <= { w_opA[31:11], (dcd_gie)?w_uflags:w_iflags };
|
else
|
else
|
r_opA <= w_opA;
|
r_opA <= w_opA;
|
|
end else if (opvalid)
|
|
begin // We were going to pick these up when they became valid,
|
|
// but for some reason we're stuck here as they became
|
|
// valid. Pick them up now anyway
|
|
if ((opA_alu)||((opA_mem)&&(mem_valid)))
|
|
r_opA <= wr_reg_vl;
|
end
|
end
|
wire [31:0] dcdI, w_opBnI;
|
wire [31:0] dcdI, w_opBnI;
|
assign dcdI = { {(8){r_dcdI[23]}}, r_dcdI };
|
assign dcdI = { {(8){r_dcdI[23]}}, r_dcdI };
|
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)&&(dcdB[4] == dcd_gie)) ? dcd_pc
|
: (((dcdB_pc)&&(dcdB[4] == dcd_gie)) ? {{(32-AW){1'b0}},dcd_pc }
|
: ((dcdB_pc) ? upc
|
: ((dcdB_pc) ? {{(32-AW){1'b0}},upc}
|
: ((dcdB_cc) ? { w_opB[31:11], (dcd_gie)?w_uflags:w_iflags}
|
: ((dcdB_cc) ? { w_opB[31:11], (dcd_gie)?w_uflags:w_iflags}
|
: regset[dcdB]))));
|
: regset[dcdB]))));
|
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;
|
|
else if ((opvalid)&&((opB_alu)||((opB_mem)&&(mem_valid))))
|
|
r_opB <= wr_reg_vl;
|
|
|
// 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
|
// be two sets of four bits: the top bits specify what bits matter, the
|
// be two sets of four bits: the top bits specify what bits matter, the
|
// bottom specify what those top bits must equal. However, two of
|
// bottom specify what those top bits must equal. However, two of
|
Line 771... |
Line 803... |
// assign so that there's no wait state between an
|
// assign so that there's no wait state between an
|
// ALU or memory result and the next register that may
|
// ALU or memory result and the next register that may
|
// use that value.
|
// use that value.
|
opA_rd <= dcdA_rd;
|
opA_rd <= dcdA_rd;
|
opB_rd <= dcdB_rd;
|
opB_rd <= dcdB_rd;
|
op_pc <= dcd_pc;
|
|
//
|
//
|
`ifdef OPT_EARLY_BRANCHING
|
`ifdef OPT_EARLY_BRANCHING
|
op_wr_pc <= ((dcdA_wr)&&(dcdA_pc)&&(dcdA[4] == dcd_gie))&&(~dcd_early_branch);
|
op_wr_pc <= ((dcdA_wr)&&(dcdA_pc)&&(dcdA[4] == dcd_gie))&&(~dcd_early_branch);
|
`else
|
`else
|
op_wr_pc <= ((dcdA_wr)&&(dcdA_pc)&&(dcdA[4] == dcd_gie));
|
op_wr_pc <= ((dcdA_wr)&&(dcdA_pc)&&(dcdA[4] == dcd_gie));
|
`endif
|
`endif
|
|
op_pc <= (dcd_early_branch)?dcd_branch_pc:dcd_pc;
|
|
// op_pc <= dcd_pc;
|
|
|
`ifdef OPT_PRECLEAR_BUS
|
`ifdef OPT_PRECLEAR_BUS
|
op_clear_bus <= dcd_clear_bus;
|
op_clear_bus <= dcd_clear_bus;
|
`endif
|
`endif
|
end
|
end
|
Line 797... |
Line 830... |
// The alternative approach would be to define some sort of
|
// The alternative approach would be to define some sort of
|
// 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.
|
reg opA_alu;
|
reg opA_alu, opA_mem;
|
|
always @(posedge i_clk)
|
|
if (op_ce)
|
|
opA_alu <= (opvalid_alu)&&(opR == dcdA)&&(opR_wr)&&(dcdA_rd);
|
|
else if ((opvalid)&&(opA_alu)&&(alu_valid))
|
|
opA_alu <= 1'b0;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (op_ce)
|
if (op_ce)
|
opA_alu <= (opvalid_alu)&&(opR == dcdA)&&(dcdA_rd);
|
opA_mem <= ((opvalid_mem)&&(opR == dcdA)&&(dcdA_rd))
|
assign opA = (opA_alu) ? alu_result : r_opA;
|
||((~opvalid)&&(mem_busy)&&(~mem_we)
|
|
&&(mem_last_reg == dcdA)&&(dcdA_rd));
|
|
else if ((opvalid)&&(opA_mem)&&(mem_valid))
|
|
opA_mem <= 1'b0;
|
|
|
|
always @(posedge i_clk)
|
|
if (mem_ce)
|
|
mem_last_reg <= opR;
|
|
assign opA = (opA_alu) ? alu_result
|
|
: ( ((opA_mem)&&(mem_valid))?mem_result
|
|
: r_opA );
|
|
|
assign dcdA_stall = (dcdvalid)&&(dcdA_rd)&&(
|
assign dcdA_stall = (dcdvalid)&&(dcdA_rd)&&(
|
// Skip the requirement on writing back opA
|
// Skip the requirement on writing back opA
|
// Stall on memory, since we'll always need to stall for a
|
// Stall on memory, since we'll always need to stall for a
|
// memory access anyway
|
// memory access anyway
|
((opvalid_mem)&&(opR_wr)&&(opR == dcdA))||
|
// ((opvalid_mem)&&(opR_wr)&&(opR == dcdA))
|
((opvalid_alu)&&(opF_wr)&&(dcdA_cc))||
|
((opvalid_alu)&&(opF_wr)&&(dcdA_cc)));
|
((mem_busy)&&(~mem_we)&&(mem_wreg == dcdA)));
|
// Place stalls for this latter case into the ops stage
|
|
// ||((mem_busy)&&(~mem_we));
|
|
|
reg opB_alu;
|
reg opB_alu, opB_mem;
|
|
always @(posedge i_clk)
|
|
if (op_ce)
|
|
opB_alu <= (opvalid_alu)&&(opR == dcdB)&&(opR_wr)&&(dcdB_rd)&&(dcd_zI);
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (op_ce)
|
if (op_ce)
|
opB_alu <= (opvalid_alu)&&(opR == dcdB)&&(dcdB_rd)&&(dcdI == 0);
|
opB_mem <= (dcd_zI)&&(dcdB_rd)&&(
|
assign opB = (opB_alu) ? alu_result : r_opB;
|
((opvalid_mem)&&(opR == dcdB))
|
|
||((~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_result
|
|
: ( ((opB_mem)&&(mem_valid))?mem_result
|
|
: r_opB );
|
assign dcdB_stall = (dcdvalid)&&(dcdB_rd)&&(
|
assign dcdB_stall = (dcdvalid)&&(dcdB_rd)&&(
|
// 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:
|
Line 828... |
Line 887... |
// 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)
|
((opvalid)&&(opR_wr)&&(opR == dcdB)
|
&&(opR != { op_gie, `CPU_PC_REG} )
|
&&(opR != { op_gie, `CPU_PC_REG} )
|
&&((opvalid_mem)||(dcdI != 0)))
|
&&(~dcd_zI))
|
// 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
|
||((mem_busy)&&(~mem_we)&&(mem_wreg == dcdB)));
|
||((mem_busy)&&(~mem_we)&&(mem_last_reg==dcdB)));
|
assign dcdF_stall = (dcdvalid)&&((~dcdF[3])||(dcdA_cc)||(dcdB_cc))
|
assign dcdF_stall = (dcdvalid)&&((~dcdF[3])||(dcdA_cc)||(dcdB_cc))
|
&&(opvalid)&&(opR_cc);
|
&&(opvalid)&&(opR_cc);
|
//
|
//
|
//
|
//
|
// PIPELINE STAGE #4 :: Apply Instruction
|
// PIPELINE STAGE #4 :: Apply Instruction
|
Line 884... |
Line 943... |
always @(posedge i_clk)
|
always @(posedge i_clk)
|
alu_pc_valid <= (~i_rst)&&(master_ce)&&(~mem_rdbusy)&&(opvalid)&&(~clear_pipeline)
|
alu_pc_valid <= (~i_rst)&&(master_ce)&&(~mem_rdbusy)&&(opvalid)&&(~clear_pipeline)
|
&&((opvalid_alu)||(~mem_stalled));
|
&&((opvalid_alu)||(~mem_stalled));
|
|
|
`ifdef OPT_PIPELINED_BUS_ACCESS
|
`ifdef OPT_PIPELINED_BUS_ACCESS
|
pipemem domem(i_clk, i_rst, mem_ce,
|
pipemem #(AW) domem(i_clk, i_rst, mem_ce,
|
(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 domem(i_clk, i_rst, mem_ce,
|
memops #(AW) domem(i_clk, i_rst, mem_ce,
|
(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 907... |
Line 966... |
`endif // PIPELINED_BUS_ACCESS
|
`endif // PIPELINED_BUS_ACCESS
|
assign mem_rdbusy = (((mem_cyc_gbl)||(mem_cyc_lcl))&&(~mem_we));
|
assign mem_rdbusy = (((mem_cyc_gbl)||(mem_cyc_lcl))&&(~mem_we));
|
|
|
// Either the prefetch or the instruction gets the memory bus, but
|
// Either the prefetch or the instruction gets the memory bus, but
|
// never both.
|
// never both.
|
wbdblpriarb #(32,32) pformem(i_clk, i_rst,
|
wbdblpriarb #(32,AW) pformem(i_clk, i_rst,
|
// Memory access to the arbiter, priority position
|
// Memory access to the arbiter, priority position
|
mem_cyc_gbl, mem_cyc_lcl, mem_stb_gbl, mem_stb_lcl,
|
mem_cyc_gbl, mem_cyc_lcl, mem_stb_gbl, mem_stb_lcl,
|
mem_we, mem_addr, mem_data, mem_ack, mem_stall, mem_err,
|
mem_we, mem_addr, mem_data, mem_ack, mem_stall, mem_err,
|
// Prefetch access to the arbiter
|
// Prefetch access to the arbiter
|
pf_cyc, 1'b0, pf_stb, 1'b0, pf_we, pf_addr, pf_data,
|
pf_cyc, 1'b0, pf_stb, 1'b0, pf_we, pf_addr, pf_data,
|
Line 1145... |
Line 1204... |
// What happens when the pipeline has gie and ~gie instructions within
|
// What happens when the pipeline has gie and ~gie instructions within
|
// it? Do we clear both? What if a gie instruction tries to clear
|
// it? Do we clear both? What if a gie instruction tries to clear
|
// a non-gie instruction?
|
// a non-gie instruction?
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_pc))
|
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_pc))
|
upc <= wr_reg_vl;
|
upc <= wr_reg_vl[(AW-1):0];
|
else if ((alu_gie)&&(alu_pc_valid)&&(~clear_pipeline))
|
else if ((alu_gie)&&(alu_pc_valid)&&(~clear_pipeline))
|
upc <= alu_pc;
|
upc <= alu_pc;
|
else if ((i_halt)&&(i_dbg_we)
|
else if ((i_halt)&&(i_dbg_we)
|
&&(i_dbg_reg == { 1'b1, `CPU_PC_REG }))
|
&&(i_dbg_reg == { 1'b1, `CPU_PC_REG }))
|
upc <= i_dbg_data;
|
upc <= i_dbg_data[(AW-1):0];
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (i_rst)
|
if (i_rst)
|
ipc <= RESET_ADDRESS;
|
ipc <= RESET_ADDRESS;
|
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_pc))
|
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_pc))
|
ipc <= wr_reg_vl;
|
ipc <= wr_reg_vl[(AW-1):0];
|
else if ((~alu_gie)&&(alu_pc_valid)&&(~clear_pipeline))
|
else if ((~alu_gie)&&(alu_pc_valid)&&(~clear_pipeline))
|
ipc <= alu_pc;
|
ipc <= alu_pc;
|
else if ((i_halt)&&(i_dbg_we)
|
else if ((i_halt)&&(i_dbg_we)
|
&&(i_dbg_reg == { 1'b0, `CPU_PC_REG }))
|
&&(i_dbg_reg == { 1'b0, `CPU_PC_REG }))
|
ipc <= i_dbg_data;
|
ipc <= i_dbg_data[(AW-1):0];
|
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (i_rst)
|
if (i_rst)
|
pf_pc <= RESET_ADDRESS;
|
pf_pc <= RESET_ADDRESS;
|
else if (w_switch_to_interrupt)
|
else if (w_switch_to_interrupt)
|
pf_pc <= ipc;
|
pf_pc <= ipc;
|
else if (w_release_from_interrupt)
|
else if (w_release_from_interrupt)
|
pf_pc <= upc;
|
pf_pc <= upc;
|
else if ((wr_reg_ce)&&(wr_reg_id[4] == gie)&&(wr_write_pc))
|
else if ((wr_reg_ce)&&(wr_reg_id[4] == gie)&&(wr_write_pc))
|
pf_pc <= wr_reg_vl;
|
pf_pc <= wr_reg_vl[(AW-1):0];
|
else if ((i_halt)&&(i_dbg_we)
|
else if ((i_halt)&&(i_dbg_we)
|
&&(i_dbg_reg[4:0] == { gie, `CPU_PC_REG}))
|
&&(i_dbg_reg[4:0] == { gie, `CPU_PC_REG}))
|
pf_pc <= i_dbg_data;
|
pf_pc <= i_dbg_data[(AW-1):0];
|
else if (dcd_ce)
|
else if (dcd_ce)
|
pf_pc <= pf_pc + 1;
|
pf_pc <= pf_pc + 1;
|
|
|
initial new_pc = 1'b1;
|
initial new_pc = 1'b1;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
Line 1200... |
Line 1259... |
// The debug interface
|
// The debug interface
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
begin
|
begin
|
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 <= {{(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)
|
o_dbg_reg[10:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
|
o_dbg_reg[10:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
|
end
|
end
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
o_dbg_cc <= { gie, sleep };
|
o_dbg_cc <= { gie, sleep };
|