OpenCores
URL https://opencores.org/ocsvn/zipcpu/zipcpu/trunk

Subversion Repositories zipcpu

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /zipcpu/trunk/rtl/core
    from Rev 34 to Rev 36
    Reverse comparison

Rev 34 → Rev 36

/memops.v
11,6 → 11,9
// before it completes the last one. Unpredictable results might then
// occurr.
//
// 20150919 -- Added support for handling BUS ERR's (i.e., the WB
// error signal).
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
36,9 → 39,11
//
module memops(i_clk, i_rst, i_stb,
i_op, i_addr, i_data, i_oreg,
o_busy, o_valid, o_wreg, o_result,
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_data);
o_busy, o_valid, o_err, o_wreg, o_result,
o_wb_cyc_gbl, o_wb_cyc_lcl,
o_wb_stb_gbl, o_wb_stb_lcl,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_err, i_wb_data);
input i_clk, i_rst;
input i_stb;
// CPU interface
49,29 → 54,49
// CPU outputs
output wire o_busy;
output reg o_valid;
output reg o_err;
output reg [4:0] o_wreg;
output reg [31:0] o_result;
// Wishbone outputs
output reg o_wb_cyc, o_wb_stb, o_wb_we;
output reg o_wb_cyc_gbl, o_wb_stb_gbl;
output reg o_wb_cyc_lcl, o_wb_stb_lcl, o_wb_we;
output reg [31:0] o_wb_addr, o_wb_data;
// Wishbone inputs
input i_wb_ack, i_wb_stall;
input i_wb_ack, i_wb_stall, i_wb_err;
input [31:0] i_wb_data;
 
wire gbl_stb, lcl_stb;
assign lcl_stb = (i_stb)&&(i_addr[31:8]==24'hc00000)&&(i_addr[7:5]==3'h0);
assign gbl_stb = (i_stb)&&((i_addr[31:8]!=24'hc00000)||(i_addr[7:5]!=3'h0));
 
always @(posedge i_clk)
if (i_rst)
o_wb_cyc <= 1'b0;
else if (o_wb_cyc)
o_wb_cyc <= (~i_wb_ack);
else if (i_stb) // New memory operation
// Grab the wishbone
o_wb_cyc <= 1'b1;
begin
o_wb_cyc_gbl <= 1'b0;
o_wb_cyc_lcl <= 1'b0;
end else if ((o_wb_cyc_gbl)||(o_wb_cyc_lcl))
begin
if ((i_wb_ack)||(i_wb_err))
begin
o_wb_cyc_gbl <= 1'b0;
o_wb_cyc_lcl <= 1'b0;
end
end else if (i_stb) // New memory operation
begin // Grab the wishbone
o_wb_cyc_lcl <= lcl_stb;
o_wb_cyc_gbl <= gbl_stb;
end
always @(posedge i_clk)
if (o_wb_cyc)
o_wb_stb <= (o_wb_stb)&&(i_wb_stall);
if (o_wb_cyc_gbl)
o_wb_stb_gbl <= (o_wb_stb_gbl)&&(i_wb_stall);
else
o_wb_stb <= i_stb; // Grab wishbone on new operation
o_wb_stb_gbl <= gbl_stb; // Grab wishbone on new operation
always @(posedge i_clk)
if (o_wb_cyc_lcl)
o_wb_stb_lcl <= (o_wb_stb_lcl)&&(i_wb_stall);
else
o_wb_stb_lcl <= lcl_stb; // Grab wishbone on new operation
always @(posedge i_clk)
if (i_stb)
begin
o_wb_we <= i_op;
81,8 → 106,11
 
initial o_valid = 1'b0;
always @(posedge i_clk)
o_valid <= (o_wb_cyc)&&(i_wb_ack)&&(~o_wb_we);
assign o_busy = o_wb_cyc;
o_valid <= ((o_wb_cyc_gbl)||(o_wb_cyc_lcl))&&(i_wb_ack)&&(~o_wb_we);
initial o_err = 1'b0;
always @(posedge i_clk)
o_err <= ((o_wb_cyc_gbl)||(o_wb_cyc_lcl))&&(i_wb_err);
assign o_busy = (o_wb_cyc_gbl)||(o_wb_cyc_lcl);
 
always @(posedge i_clk)
if (i_stb)
/prefetch.v
13,6 → 13,12
// a suggestion of what to load. Other wires may be loaded
// instead. i_pc is what must be output, not necessarily input.
//
// 20150919 -- Added support for the WB error signal. When reading an
// instruction results in this signal being raised, the pipefetch
// module will set an illegal instruction flag to be returned to
// the CPU together with the instruction. Hence, the ZipCPU
// can trap on it if necessary.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
42,9 → 48,9
// flash will require (16+6+6)*2 = 56 clocks plus 16 clocks per word read,
// or 72 clocks to fetch one instruction.
module prefetch(i_clk, i_rst, i_ce, i_pc, i_aux,
o_i, o_pc, o_aux, o_valid,
o_i, o_pc, o_aux, o_valid, o_illegal,
o_wb_cyc, o_wb_stb, 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_err, i_wb_data);
parameter AW = 1;
input i_clk, i_rst, i_ce;
input [31:0] i_pc;
52,7 → 58,7
output reg [31:0] o_i;
output reg [31:0] o_pc;
output reg [(AW-1):0] o_aux;
output wire o_valid;
output wire o_valid, o_illegal;
// Wishbone outputs
output reg o_wb_cyc, o_wb_stb;
output wire o_wb_we;
59,7 → 65,7
output reg [31:0] o_wb_addr;
output wire [31:0] o_wb_data;
// And return inputs
input i_wb_ack, i_wb_stall;
input i_wb_ack, i_wb_stall, i_wb_err;
input [31:0] i_wb_data;
 
assign o_wb_we = 1'b0;
103,5 → 109,6
o_pc <= o_wb_addr;
 
assign o_valid = (i_pc == o_pc)&&(i_aux == o_aux)&&(~o_wb_cyc);
assign o_illegal = (o_wb_cyc)&&(i_wb_err);
 
endmodule
/pipefetch.v
14,6 → 14,17
// the purposes of this instruction fetch module: 1) Pipeline
// wishbone accesses, and 2) an instruction cache.
//
// 20150919 -- Fixed a nasty race condition whereby the pipefetch routine
// would produce either the same instruction twice, or skip
// an instruction. This condition was dependent on the CPU stall
// condition, and would only take place if the pipeline wasn't
// completely full throughout the stall.
//
// Interface support was also added for trapping on illegal
// instructions (i.e., instruction fetches that cause bus errors),
// however the internal interface has not caught up to supporting
// these exceptions yet.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
40,7 → 51,8
module pipefetch(i_clk, i_rst, i_new_pc, i_clear_cache, i_stall_n, i_pc,
o_i, o_pc, o_v,
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_data, i_wb_request);
i_wb_ack, i_wb_stall, i_wb_err, i_wb_data, i_wb_request,
o_illegal);
parameter RESET_ADDRESS=32'h0010_0000,
LGCACHELEN = 6, CACHELEN=(1<<LGCACHELEN),
BUSW=32;
56,12 → 68,15
output reg [(BUSW-1):0] o_wb_addr;
output wire [(BUSW-1):0] o_wb_data;
//
input i_wb_ack, i_wb_stall;
input i_wb_ack, i_wb_stall, i_wb_err;
input [(BUSW-1):0] i_wb_data;
//
// Is the (data) memory unit also requesting access to the bus?
input i_wb_request;
output wire o_illegal;
 
assign o_illegal = 1'b0;
 
// Fixed bus outputs: we read from the bus only, never write.
// Thus the output data is ... irrelevant and don't care. We set it
// to zero just to set it to something.
93,7 → 108,6
assign w_running_out_of_cache = (r_addr_set)
&&(r_addr >= r_cache_base + (1<<(LGCACHELEN-2))
+ (1<<(LGCACHELEN-1)));
initial r_nvalid = 0;
initial r_cache_base = RESET_ADDRESS;
always @(posedge i_clk)
begin
161,10 → 175,12
// r_nvalid <= r_nvalid + 1;
if ((r_acks_waiting == 1)&&(~o_wb_stb))
o_wb_cyc <= 1'b0;
end
end else if ((r_acks_waiting == 0)&&(~o_wb_stb))
o_wb_cyc <= 1'b0;
end
end
 
initial r_nvalid = 0;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache)) // Required, so we can reload memoy and then reset
r_nvalid <= 0;
210,9 → 226,9
if (~o_wb_cyc)
r_acks_waiting <= 0;
else if ((o_wb_stb)&&(~i_wb_stall)&&(~i_wb_ack))
r_acks_waiting <= r_acks_waiting + ((i_wb_ack)? 0:1);
r_acks_waiting <= r_acks_waiting + 1;
else if ((i_wb_ack)&&((~o_wb_stb)||(i_wb_stall)))
r_acks_waiting <= r_acks_waiting - 1;
r_acks_waiting <= r_acks_waiting - 1;
 
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
232,13 → 248,13
assign w_cv = ((r_nvalid != 0)&&(r_addr>=r_cache_base)
&&(r_addr-r_cache_base < bus_nvalid));
always @(posedge i_clk)
r_cv <= (~i_new_pc)&&(w_cv);
r_cv <= (~i_new_pc)&&((w_cv)||((~i_stall_n)&&(r_cv)));
assign o_v = (r_cv)&&(~i_new_pc);
 
always @(posedge i_clk)
if (i_new_pc)
r_addr <= i_pc;
else if ((i_stall_n)&&(w_cv))
else if ( ((i_stall_n)&&(w_cv)) || ((~i_stall_n)&&(w_cv)&&(r_addr == o_pc)) )
r_addr <= r_addr + 1;
 
wire [(LGCACHELEN-1):0] c_rdaddr, c_cache_base;
245,10 → 261,10
assign c_cache_base = r_cache_base[(LGCACHELEN-1):0];
assign c_rdaddr = r_addr[(LGCACHELEN-1):0]-c_cache_base+r_cache_offset;
always @(posedge i_clk)
if (i_stall_n)
if ((~o_v)||((i_stall_n)&&(o_v)))
o_i <= cache[c_rdaddr];
always @(posedge i_clk)
if (i_stall_n)
if ((~o_v)||((i_stall_n)&&(o_v)))
o_pc <= r_addr;
 
endmodule
/zipcpu.v
106,6 → 106,20
//
///////////////////////////////////////////////////////////////////////////////
//
// We can either pipeline our fetches, or issue one fetch at a time. Pipelined
// fetches are more complicated and therefore use more FPGA resources, while
// single fetches will cause the CPU to stall for about 5 stalls each
// instruction cycle, effectively reducing the instruction count per clock to
// about 0.2. However, the area cost may be worth it. Consider:
//
// Slice LUTs ZipSystem ZipCPU
// Single Fetching 2521 1734
// Pipelined fetching 2796 2046
//
// `define SINGLE_FETCH
//
//
//
`define CPU_CC_REG 4'he
`define CPU_PC_REG 4'hf
`define CPU_TRAP_BIT 9
113,6 → 127,13
`define CPU_STEP_BIT 6
`define CPU_GIE_BIT 5
`define CPU_SLEEP_BIT 4
// Compile time defines
// `define SINGLE_FETCH
`define NG_CONDITIONAL_FLAGS
`define NG_PRECLEAR_BUS // 0.61 w/ or w/o
// `define NG_BRANCH_DELAY_SLOT
`define NG_ILLEGAL_INSTRUCTION
`define NG_EARLY_BRANCHING // 0.60 w/, 0.61 w/o ????
module zipcpu(i_clk, i_rst, i_interrupt,
// Debug interface
i_halt, i_clear_pf_cache, i_dbg_reg, i_dbg_we, i_dbg_data,
119,8 → 140,11
o_dbg_stall, o_dbg_reg, o_dbg_cc,
o_break,
// CPU interface to the wishbone bus
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
o_wb_gbl_cyc, o_wb_gbl_stb,
o_wb_lcl_cyc, o_wb_lcl_stb,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_data,
i_wb_err,
// Accounting/CPU usage interface
o_op_stall, o_pf_stall, o_i_count);
parameter RESET_ADDRESS=32'h0100000;
136,11 → 160,13
output reg [1:0] o_dbg_cc;
output wire o_break;
// Wishbone interface -- outputs
output wire o_wb_cyc, o_wb_stb, o_wb_we;
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 [31:0] o_wb_addr, o_wb_data;
// Wishbone interface -- inputs
input i_wb_ack, i_wb_stall;
input [31:0] i_wb_data;
input i_wb_err;
// Accounting outputs ... to help us count stalls and usage
output wire o_op_stall;
output wire o_pf_stall;
152,8 → 178,12
 
// Condition codes
reg [3:0] flags, iflags; // (TRAP,FPEN,BREAKEN,STEP,GIE,SLEEP ), V, N, C, Z
wire [9:0] w_uflags, w_iflags;
wire [10:0] w_uflags, w_iflags;
reg trap, break_en, step, gie, sleep;
`ifdef NG_ILLEGAL_INSTRUCTION
reg ill_err;
`endif
reg bus_err_flag;
 
// The master chip enable
wire master_ce;
166,13 → 196,13
reg [31:0] pf_pc;
reg new_pc, op_break;
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 pf_cyc, pf_stb, pf_we, pf_busy, pf_ack, pf_stall;
wire pf_cyc, pf_stb, pf_we, pf_busy, pf_ack, pf_stall, pf_err;
wire [31:0] pf_addr, pf_data;
wire [31:0] instruction, instruction_pc;
wire pf_valid, instruction_gie;
wire pf_valid, instruction_gie, pf_illegal;
 
//
//
192,6 → 222,19
reg [23:0] r_dcdI;
wire dcdA_stall, dcdB_stall, dcdF_stall;
 
`ifdef NG_PRECLEAR_BUS
reg dcd_clear_bus;
`endif
`ifdef NG_ILLEGAL_INSTRUCTION
reg dcd_illegal;
`endif
`ifdef NG_EARLY_BRANCHING
reg dcd_early_branch_stb, dcd_early_branch;
reg [31:0] dcd_branch_pc;
`else
wire dcd_early_branch_stb, dcd_early_branch;
wire [31:0] dcd_branch_pc;
`endif
 
 
//
210,13 → 253,18
wire [31:0] opA_nowait, opB_nowait, opA, opB;
reg opR_wr, opR_cc, opF_wr, op_gie,
opA_rd, opB_rd;
wire [9:0] opFl;
wire [10:0] opFl;
reg [6:0] r_opF;
wire [8:0] opF;
wire op_ce;
`ifdef NG_PRECLEAR_BUS
reg op_clear_bus;
`endif
`ifdef NG_ILLEGAL_INSTRUCTION
reg op_illegal;
`endif
 
 
 
//
//
// PIPELINE STAGE #4 :: ALU / Memory
231,12 → 279,15
wire alu_valid;
wire set_cond;
reg alu_wr, alF_wr, alu_gie;
`ifdef NG_ILLEGAL_INSTRUCTION
reg alu_illegal;
`endif
 
 
 
wire mem_ce, mem_stalled;
wire mem_valid, mem_ack, mem_stall,
mem_cyc, mem_stb, mem_we;
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;
wire [4:0] mem_wreg;
 
wire mem_busy, mem_rdbusy;
274,7 → 325,10
assign dcd_stalled = (dcdvalid)&&(
(op_stall)
||((dcdA_stall)||(dcdB_stall)||(dcdF_stall))
||((opvalid)&&((op_wr_pc)||(opR_cc))));
`ifndef NG_BRANCH_DELAY_SLOT
||((opvalid_mem)&&(op_wr_pc))
`endif
||((opvalid_mem)&&(opR_cc)));
//
// PIPELINE STAGE #3 :: Read Operands
// Calculate stall conditions
285,9 → 339,25
//
// PIPELINE STAGE #4 :: ALU / Memory
// Calculate stall conditions
assign alu_stall = (((~master_ce)||(mem_rdbusy))&&(opvalid_alu))
//
// 1. Basic stall is if the previous stage is valid and the next is
// busy.
// 2. Also stall if the prior stage is valid and the master clock enable
// is de-selected
// 3. Next case: Stall if we want to start a memory operation and the
// prior operation will write either the PC or CC registers.
// 4. Last case: Stall if we would otherwise move a break instruction
// through the ALU. Break instructions are not allowed through
// the ALU.
assign alu_stall = (((~master_ce)||(mem_rdbusy))&&(opvalid_alu)) //Case 1&2
`ifdef BEFORE
||((opvalid)&&(wr_reg_ce)&&(wr_reg_id[4] == op_gie)
&&(wr_write_pc)||(wr_write_cc));
&&((wr_write_pc)||(wr_write_cc)) // Case 3
`else
||((opvalid_mem)&&(wr_reg_ce)&&(wr_reg_id[4] == op_gie)
&&((wr_write_pc)||(wr_write_cc))) // Case 3
`endif
||((opvalid)&&(op_break)); // Case 4
assign alu_ce = (master_ce)&&(opvalid_alu)&&(~alu_stall)&&(~clear_pipeline);
//
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~mem_stalled)&&(~clear_pipeline)&&(set_cond);
311,31 → 381,90
assign pf_ce = (~dcd_stalled);
prefetch pf(i_clk, i_rst, (pf_ce), pf_pc, gie,
instruction, instruction_pc, instruction_gie,
pf_valid,
pf_cyc, pf_stb, pf_we, pf_addr,
pf_data,
pf_ack, pf_stall, i_wb_data);
pf_valid, pf_illegal,
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, pf_err, i_wb_data);
`else // Pipe fetch
pipefetch #(RESET_ADDRESS)
pf(i_clk, i_rst, new_pc, i_clear_pf_cache, ~dcd_stalled, pf_pc,
pf(i_clk, i_rst, (new_pc)|(dcd_early_branch_stb),
i_clear_pf_cache, ~dcd_stalled,
(new_pc)?pf_pc:dcd_branch_pc,
instruction, instruction_pc, pf_valid,
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, i_wb_data,
mem_cyc);
pf_ack, pf_stall, pf_err, i_wb_data,
`ifdef NG_PRECLEAR_BUS
((dcd_clear_bus)&&(dcdvalid))
||((op_clear_bus)&&(opvalid))
||
`endif
(mem_cyc_lcl)||(mem_cyc_gbl),
pf_illegal);
assign instruction_gie = gie;
`endif
 
initial dcdvalid = 1'b0;
always @(posedge i_clk)
if (i_rst)
dcdvalid <= 1'b0;
else if (dcd_ce)
dcdvalid <= (~clear_pipeline);
else if ((~dcd_stalled)||(clear_pipeline))
dcdvalid <= (~clear_pipeline)&&(~dcd_early_branch_stb);
else if ((~dcd_stalled)||(clear_pipeline)||(dcd_early_branch))
dcdvalid <= 1'b0;
 
`ifdef NG_EARLY_BRANCHING
always @(posedge i_clk)
if ((dcd_ce)&&(instruction[27:24]==`CPU_PC_REG))
begin
dcd_early_branch <= 1'b0;
// First case, a move to PC instruction
if ((instruction[31:28] == 4'h2)
&&((instruction_gie)
||((~instruction[20])&&(~instruction[15])))
&&(instruction[23:21]==3'h0))
begin
dcd_early_branch_stb <= 1'b1;
dcd_early_branch <= 1'b1;
// r_dcdI <= { {(17){instruction[14]}}, instruction[14:0] };
end else // Next case, an Add Imm -> PC instruction
if ((instruction[31:28] == 4'ha) // Add
&&(~instruction[20]) // Immediate
&&(instruction[23:21]==3'h0)) // Always
begin
dcd_early_branch_stb <= 1'b1;
dcd_early_branch <= 1'b1;
// r_dcdI <= { {(4){instruction[19]}}, instruction[19:0] };
end else // Next case: load Immediate to PC
if (instruction[31:28] == 4'h3)
begin
dcd_early_branch_stb <= 1'b1;
dcd_early_branch <= 1'b1;
// r_dcdI <= { instruction[23:0] };
end
end else
begin
if (dcd_ce) dcd_early_branch <= 1'b0;
dcd_early_branch_stb <= 1'b0;
end
always @(posedge i_clk)
if (dcd_ce)
begin
if (instruction[31]) // Add
dcd_branch_pc <= instruction_pc+32'h01+{ {(12){instruction[19]}}, instruction[19:0] };
else if (~instruction[28]) // 4'h2 = MOV
dcd_branch_pc <= instruction_pc+32'h01+{ {(17){instruction[14]}}, instruction[14:0] };
else // if (instruction[28]) // 4'h3 = LDI
dcd_branch_pc <= instruction_pc+32'h01+{ {(8){instruction[23]}}, instruction[23:0] };
end
`else // NG_EARLY_BRANCHING
assign dcd_early_branch_stb = 1'b0;
assign dcd_early_branch = 1'b0;
assign dcd_branch_pc = 32'h00;
`endif // NG_EARLY_BRANCHING
 
always @(posedge i_clk)
if (dcd_ce)
begin
dcd_pc <= instruction_pc+1;
 
// Record what operation we are doing
349,7 → 478,17
dcdA_pc <= (instruction[27:24] == `CPU_PC_REG);
dcdB_pc <= (instruction[19:16] == `CPU_PC_REG);
dcdM <= 1'b0;
`ifdef NG_CONDITIONAL_FLAGS
dcdF_wr <= (instruction[23:21]==3'h0);
`else
dcdF_wr <= 1'b1;
`endif
`ifdef NG_PRECLEAR_BUS
dcd_clear_bus <= 1'b0;
`endif
`ifdef NG_ILLEGAL_INSTRUCTION
dcd_illegal <= pf_illegal;
`endif
 
// Set the condition under which we do this operation
// The top four bits are a mask, the bottom four the
378,8 → 517,15
dcdOp <= 4'h2;
end
4'h4: begin // Multiply, LDI[HI|LO], or NOOP/BREAK
`ifdef NG_CONDITIONAL_FLAGS
// Don't write flags except for multiplies
// and then only if they are unconditional
dcdF_wr <= ((instruction[27:25] != 3'h7)
&&(instruction[23:21]==3'h0));
`else
// Don't write flags except for multiplies
dcdF_wr <= (instruction[27:25] != 3'h7);
`endif
r_dcdI <= { 8'h00, instruction[15:0] };
if (instruction[27:24] == 4'he)
begin
388,6 → 534,11
dcdA_rd <= 1'b0;
dcdB_rd <= 1'b0;
dcdOp <= 4'h2;
// Might also be a break. Big
// instruction set hole here.
`ifdef NG_ILLEGAL_INSTRUCTION
dcd_illegal <= (pf_illegal)||(instruction[23:1] != 0);
`endif
end else if (instruction[27:24] == 4'hf)
begin // Load partial immediate(s)
dcdA_wr <= 1'b1;
414,6 → 565,9
else
r_dcdI <= { {(4){instruction[19]}}, instruction[19:0] };
dcdM <= 1'b1; // Memory operation
`ifdef NG_PRECLEAR_BUS
dcd_clear_bus <= (instruction[23:21]==3'h0);
`endif
end
default: begin
dcdA_wr <= (instruction[31])||(instruction[31:28]==4'h5);
432,7 → 586,7
always @(posedge i_clk)
if (dcd_ce)
dcd_break <= (instruction[31:0] == 32'h4e000001);
else
else if ((clear_pipeline)||(~dcdvalid))
dcd_break <= 1'b0;
 
 
453,28 → 607,21
else if (dcdA_pc)
r_opA <= upc;
else if (dcdA_cc)
r_opA <= { w_opA[31:10], (dcd_gie)?w_uflags:w_iflags };
r_opA <= { w_opA[31:11], (dcd_gie)?w_uflags:w_iflags };
else
r_opA <= w_opA;
end
wire [31:0] dcdI;
wire [31:0] dcdI, w_opBnI;
assign dcdI = { {(8){r_dcdI[23]}}, r_dcdI };
assign w_opBnI = (~dcdB_rd) ? 32'h00
: (((wr_reg_ce)&&(wr_reg_id == dcdB)) ? wr_reg_vl
: (((dcdB_pc)&&(dcdB[4] == dcd_gie)) ? dcd_pc
: ((dcdB_pc) ? upc
: ((dcdB_cc) ? { w_opB[31:11], (dcd_gie)?w_uflags:w_iflags}
: regset[dcdB]))));
always @(posedge i_clk)
if (op_ce) // &&(dcdvalid))
begin
if (~dcdB_rd)
r_opB <= dcdI;
else if ((wr_reg_ce)&&(wr_reg_id == dcdB))
r_opB <= wr_reg_vl + dcdI;
else if ((dcdB_pc)&&(dcdB[4] == dcd_gie))
r_opB <= dcd_pc + dcdI;
else if (dcdB_pc) // & dcdB[4] != dcd_gie thus is user
r_opB <= upc + dcdI;
else if (dcdB_cc)
r_opB <= { w_opB[31:10], (dcd_gie)?w_uflags:w_iflags} + dcdI;
else
r_opB <= regset[dcdB] + dcdI;
end
r_opB <= w_opBnI + dcdI;
 
// 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
487,7 → 634,7
// opF.
always @(posedge i_clk)
if (op_ce)
begin // Set the flag condition codes
begin // Set the flag condition codes, bit order is [3:0]=VNCZ
case(dcdF[2:0])
3'h0: r_opF <= 7'h80; // Always
3'h1: r_opF <= 7'h11; // Z
498,9 → 645,12
3'h6: r_opF <= 7'h02; // C
3'h7: r_opF <= 7'h08; // V
endcase
end
end // Bit order is { (flags_not_used), VNCZ mask, VNCZ value }
assign opF = { r_opF[6], r_opF[3], r_opF[5], r_opF[1], r_opF[4:0] };
 
initial opvalid = 1'b0;
initial opvalid_alu = 1'b0;
initial opvalid_mem = 1'b0;
always @(posedge i_clk)
if (i_rst)
begin
518,8 → 668,13
// wait until our operands are valid, then we aren't
// valid yet until then.
opvalid<= (~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled);
`ifdef NG_ILLEGAL_INSTRUCTION
opvalid_mem <= (dcdM)&&(~dcd_illegal)&&(~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled);
opvalid_alu <= ((~dcdM)||(dcd_illegal))&&(~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled);
`else
opvalid_alu <= (~dcdM)&&(~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled);
opvalid_mem <= (dcdM)&&(~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled);
`endif
end else if ((~op_stall)||(clear_pipeline))
begin
opvalid <= 1'b0;
543,15 → 698,26
else if ((clear_pipeline)||(~opvalid))
op_break <= 1'b0;
 
`ifdef NG_ILLEGAL_INSTRUCTION
always @(posedge i_clk)
if(op_ce)
op_illegal <= dcd_illegal;
`endif
 
always @(posedge i_clk)
if (op_ce)
begin
opn <= dcdOp; // Which ALU operation?
// opM <= dcdM; // Is this a memory operation?
`ifdef NG_EARLY_BRANCH
opF_wr <= (dcdF_wr)&&((~dcdA_cc)||(~dcdA_wr))&&(~dcd_early_branch);
opR_wr <= (dcdA_wr)&&(~dcd_early_branch);
`else
// Will we write the flags/CC Register with our result?
opF_wr <= (dcdF_wr)&&((~dcdA_cc)||(~dcdA_wr));
// Will we be writing our results into a register?
opR_wr <= dcdA_wr;
`endif
// What register will these results be written into?
opR <= dcdA;
opR_cc <= (dcdA_wr)&&(dcdA_cc);
567,7 → 733,15
opB_rd <= dcdB_rd;
op_pc <= dcd_pc;
//
`ifdef NG_EARLY_BRANCHING
op_wr_pc <= ((dcdA_wr)&&(dcdA_pc)&&(dcdA[4] == dcd_gie))&&(~dcd_early_branch);
`else
op_wr_pc <= ((dcdA_wr)&&(dcdA_pc)&&(dcdA[4] == dcd_gie));
`endif
 
`ifdef NG_PRECLEAR_BUS
op_clear_bus <= dcd_clear_bus;
`endif
end
assign opFl = (op_gie)?(w_uflags):(w_iflags);
 
583,45 → 757,29
// We'll create a flag here to start our coordination. Once we
// define this flag to something other than just plain zero, then
// the stalls will already be in place.
`define DONT_STALL_ON_OPA
`ifdef DONT_STALL_ON_OPA
reg opA_alu;
always @(posedge i_clk)
if (op_ce)
opA_alu <= (opvalid_alu)&&(opR == dcdA)&&(dcdA_rd);
assign opA = (opA_alu) ? alu_result : r_opA;
`else
assign opA = r_opA;
`endif
 
assign dcdA_stall = (dcdvalid)&&(dcdA_rd)&&(
`define DONT_STALL_ON_OPA
`ifdef DONT_STALL_ON_OPA
// Skip the requirement on writing back opA
// Stall on memory, since we'll always need to stall for a
// memory access anyway
((opvalid_mem)&&(opR_wr)&&(opR == dcdA))||
((opvalid_alu)&&(opF_wr)&&(dcdA_cc))||
`else
((opvalid)&&(opR_wr)&&(opR == dcdA))||
`endif
((mem_busy)&&(~mem_we)&&(mem_wreg == dcdA)));
`define DONT_STALL_ON_OPB
`ifdef DONT_STALL_ON_OPB
 
reg opB_alu;
always @(posedge i_clk)
if (op_ce)
opB_alu <= (opvalid_alu)&&(opR == dcdB)&&(dcdB_rd)&&(dcdI == 0);
assign opB = (opB_alu) ? alu_result : r_opB;
`else
assign opB = r_opB;
`endif
assign dcdB_stall = (dcdvalid)&&(dcdB_rd)&&(
((opvalid)&&(opR_wr)&&(opR == dcdB)
&&((opvalid_mem)||(dcdI != 0)))
||((opvalid_alu)&&(opF_wr)&&(dcdB_cc))
`ifdef DONT_STALL_ON_OPB
`endif
||((mem_busy)&&(~mem_we)&&(mem_wreg == dcdB)));
assign dcdF_stall = (dcdvalid)&&((~dcdF[3])||(dcdA_cc)||(dcdB_cc))
&&(opvalid)&&(opR_cc);
666,21 → 824,26
 
memops domem(i_clk, i_rst, mem_ce,
(opn[0]), opB, opA, opR,
mem_busy, mem_valid, mem_wreg, mem_result,
mem_cyc, mem_stb, mem_we, mem_addr, mem_data,
mem_ack, mem_stall, i_wb_data);
assign mem_rdbusy = ((mem_cyc)&&(~mem_we));
mem_busy, mem_valid, bus_err, mem_wreg, mem_result,
mem_cyc_gbl, mem_cyc_lcl,
mem_stb_gbl, mem_stb_lcl,
mem_we, mem_addr, mem_data,
mem_ack, mem_stall, mem_err, i_wb_data);
assign mem_rdbusy = (((mem_cyc_gbl)||(mem_cyc_lcl))&&(~mem_we));
 
// Either the prefetch or the instruction gets the memory bus, but
// never both.
wbarbiter #(32,32) pformem(i_clk, i_rst,
wbdblpriarb #(32,32) pformem(i_clk, i_rst,
// Memory access to the arbiter, priority position
mem_cyc_gbl, mem_cyc_lcl, mem_stb_gbl, mem_stb_lcl,
mem_we, mem_addr, mem_data, mem_ack, mem_stall, mem_err,
// Prefetch access to the arbiter
pf_addr, pf_data, pf_we, pf_stb, pf_cyc, pf_ack, pf_stall,
// Memory access to the arbiter
mem_addr, mem_data, mem_we, mem_stb, mem_cyc, mem_ack, mem_stall,
pf_cyc, 1'b0, pf_stb, 1'b0, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, pf_err,
// Common wires, in and out, of the arbiter
o_wb_addr, o_wb_data, o_wb_we, o_wb_stb, o_wb_cyc, i_wb_ack,
i_wb_stall);
o_wb_gbl_cyc, o_wb_lcl_cyc, o_wb_gbl_stb, o_wb_lcl_stb,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_err);
 
//
//
700,7 → 863,11
// bus instruction, so they don't need to be checked here.
// Further, alu_wr includes (set_cond), so we don't need to
// check for that here either.
assign wr_reg_ce = ((alu_wr)&&(alu_valid))||(mem_valid);
`ifdef NG_ILLEGAL_INSTRUCTION
assign wr_reg_ce = (~alu_illegal)&&((alu_wr)&&(alu_valid)&&(~clear_pipeline))||(mem_valid);
`else
assign wr_reg_ce = ((alu_wr)&&(alu_valid)&&(~clear_pipeline))||(mem_valid);
`endif
// Which register shall be written?
assign wr_reg_id = (alu_wr)?alu_reg:mem_wreg;
// Are we writing to the CC register?
719,9 → 886,14
// Write back to the condition codes/flags register ...
// When shall we write to our flags register? alF_wr already
// includes the set condition ...
assign wr_flags_ce = (alF_wr)&&(alu_valid);
assign w_uflags = { trap, 1'b0, 1'b0, step, 1'b1, sleep, ((wr_flags_ce)&&(alu_gie))?alu_flags:flags };
assign w_iflags = { trap, 1'b0, break_en, 1'b0, 1'b0, sleep, ((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags };
assign wr_flags_ce = (alF_wr)&&(alu_valid)&&(~clear_pipeline)&&(~alu_illegal);
`ifdef NG_ILLEGAL_INSTRUCTION
assign w_uflags = { bus_err_flag, trap, ill_err, 1'b0, step, 1'b1, sleep, ((wr_flags_ce)&&(alu_gie))?alu_flags:flags };
assign w_iflags = { bus_err_flag, trap, ill_err, break_en, 1'b0, 1'b0, sleep, ((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags };
`else
assign w_uflags = { bus_err_flag, trap, ill_err, 1'b0, step, 1'b1, sleep, ((wr_flags_ce)&&(alu_gie))?alu_flags:flags };
assign w_iflags = { bus_err_flag, trap, ill_err, break_en, 1'b0, 1'b0, sleep, ((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags };
`endif
// What value to write?
always @(posedge i_clk)
// If explicitly writing the register itself
767,7 → 939,18
else if ((i_halt)&&(i_dbg_we)
&&(i_dbg_reg == { 1'b0, `CPU_CC_REG }))
break_en <= i_dbg_data[`CPU_BREAK_BIT];
assign o_break = ((break_en)||(~op_gie))&&(op_break)&&(~alu_valid)&&(~mem_valid)&&(~mem_busy);
`ifdef NG_ILLEGAL_INSTRUCTION
assign o_break = ((break_en)||(~op_gie))&&(op_break)
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy)
&&(~clear_pipeline)
||((~alu_gie)&&(bus_err))
||((~alu_gie)&&(alu_valid)&&(alu_illegal));
`else
assign o_break = (((break_en)||(~op_gie))&&(op_break)
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy)
&&(~clear_pipeline))
||((~alu_gie)&&(bus_err))
`endif
 
 
// The sleep register. Setting the sleep register causes the CPU to
811,8 → 994,12
// If we are stepping the CPU
||((master_ce)&&(alu_pc_valid)&&(step))
// If we encounter a break instruction, if the break
// enable isn't not set.
// enable isn't set.
||((master_ce)&&(op_break)&&(~break_en))
`ifdef NG_ILLEGAL_INSTRUCTION
// On an illegal instruction
||((alu_valid)&&(alu_illegal))
`endif
// If we write to the CC register
||((wr_reg_ce)&&(~wr_reg_vl[`CPU_GIE_BIT])
&&(wr_reg_id[4])&&(wr_write_cc))
849,6 → 1036,25
else if (w_release_from_interrupt)
trap <= 1'b0;
 
`ifdef NG_ILLEGAL_INSTRUCTION
initial ill_err = 1'b0;
always @(posedge i_clk)
if (i_rst)
ill_err <= 1'b0;
else if (w_release_from_interrupt)
ill_err <= 1'b0;
else if ((alu_valid)&&(alu_illegal)&&(gie))
ill_err <= 1'b1;
`endif
initial bus_err_flag = 1'b0;
always @(posedge i_clk)
if (i_rst)
bus_err_flag <= 1'b0;
else if (w_release_from_interrupt)
bus_err_flag <= 1'b0;
else if ((bus_err)&&(alu_gie))
bus_err_flag <= 1'b1;
 
//
// Write backs to the PC register, and general increments of it
// We support two: upc and ipc. If the instruction is normal,
862,7 → 1068,7
always @(posedge i_clk)
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_pc))
upc <= wr_reg_vl;
else if ((alu_gie)&&(alu_pc_valid))
else if ((alu_gie)&&(alu_pc_valid)&&(~clear_pipeline))
upc <= alu_pc;
else if ((i_halt)&&(i_dbg_we)
&&(i_dbg_reg == { 1'b1, `CPU_PC_REG }))
873,7 → 1079,7
ipc <= RESET_ADDRESS;
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_pc))
ipc <= wr_reg_vl;
else if ((~alu_gie)&&(alu_pc_valid))
else if ((~alu_gie)&&(alu_pc_valid)&&(~clear_pipeline))
ipc <= alu_pc;
else if ((i_halt)&&(i_dbg_we)
&&(i_dbg_reg == { 1'b0, `CPU_PC_REG }))
918,7 → 1124,7
if (i_dbg_reg[3:0] == `CPU_PC_REG)
o_dbg_reg <= (i_dbg_reg[4])?upc:ipc;
else if (i_dbg_reg[3:0] == `CPU_CC_REG)
o_dbg_reg[9:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
o_dbg_reg[10:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
end
always @(posedge i_clk)
o_dbg_cc <= { gie, sleep };
925,7 → 1131,7
 
always @(posedge i_clk)
o_dbg_stall <= (i_halt)&&(
(pf_cyc)||(mem_cyc)||(mem_busy)
(pf_cyc)||(mem_cyc_gbl)||(mem_cyc_lcl)||(mem_busy)
||((~opvalid)&&(~i_rst))
||((~dcdvalid)&&(~i_rst)));
 

powered by: WebSVN 2.1.0

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