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
    from Rev 36 to Rev 38
    Reverse comparison

Rev 36 → Rev 38

/core/pipemem.v
0,0 → 1,146
///////////////////////////////////////////////////////////////////////////
//
// Filename: pipemem.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: A memory unit to support a CPU, this time one supporting
// pipelined wishbone memory accesses. The goal is to be able
// to issue one pipelined wishbone access per clock, and (given the memory
// is fast enough) to be able to read the results back at one access per
// clock. This renders on-chip memory fast enough to handle single cycle
// (pipelined) access.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
module pipemem(i_clk, i_rst, i_pipe_stb,
i_op, i_addr, i_data, i_oreg,
o_busy, o_pipe_stalled, 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_pipe_stb;
// CPU interface
input i_op;
input [31:0] i_addr;
input [31:0] i_data;
input [4:0] i_oreg;
// CPU outputs
output wire o_busy;
output wire o_pipe_stalled;
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_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, i_wb_err;
input [31:0] i_wb_data;
 
reg [3:0] rdaddr, wraddr;
wire [3:0] nxt_rdaddr;
reg [(5-1):0] fifo_oreg [0:15];
initial rdaddr = 0;
initial wraddr = 0;
always @(posedge i_clk)
fifo_oreg[wraddr] <= i_oreg;
always @(posedge i_clk)
if ((i_rst)||(i_wb_err))
wraddr <= 0;
else if (i_pipe_stb)
wraddr <= wraddr + 1;
always @(posedge i_clk)
if ((i_rst)||(i_wb_err))
rdaddr <= 0;
else if ((i_wb_ack)&&((o_wb_cyc_gbl)||(o_wb_cyc_lcl)))
rdaddr <= rdaddr + 1;
assign nxt_rdaddr = rdaddr + 1;
 
wire gbl_stb, lcl_stb;
assign lcl_stb = (i_addr[31:8]==24'hc00000)&&(i_addr[7:5]==3'h0);
assign gbl_stb = ((i_addr[31:8]!=24'hc00000)||(i_addr[7:5]!=3'h0));
 
always @(posedge i_clk)
if (i_rst)
begin
o_wb_cyc_gbl <= 1'b0;
o_wb_cyc_lcl <= 1'b0;
o_wb_stb_gbl <= 1'b0;
o_wb_stb_lcl <= 1'b0;
end else if ((o_wb_cyc_gbl)||(o_wb_cyc_lcl))
begin
if ((~i_wb_stall)&&(~i_pipe_stb))
begin
o_wb_stb_gbl <= 1'b0;
o_wb_stb_lcl <= 1'b0;
end else if ((i_pipe_stb)&&(~i_wb_stall))
begin
o_wb_addr <= i_addr;
o_wb_data <= i_data;
end
 
if (((i_wb_ack)&&(nxt_rdaddr == wraddr))||(i_wb_err))
begin
o_wb_cyc_gbl <= 1'b0;
o_wb_cyc_lcl <= 1'b0;
end
end else if (i_pipe_stb) // New memory operation
begin // Grab the wishbone
o_wb_cyc_lcl <= lcl_stb;
o_wb_cyc_gbl <= gbl_stb;
o_wb_stb_lcl <= lcl_stb;
o_wb_stb_gbl <= gbl_stb;
o_wb_addr <= i_addr;
o_wb_data <= i_data;
// o_wb_we <= i_op
end
always @(posedge i_clk)
if ((i_pipe_stb)
&&((~i_wb_stall)
||((~o_wb_cyc_gbl)&&(~o_wb_cyc_lcl))))
o_wb_we <= i_op;
 
initial o_valid = 1'b0;
always @(posedge i_clk)
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)
o_wreg <= fifo_oreg[rdaddr];
always @(posedge i_clk)
if (i_wb_ack)
o_result <= i_wb_data;
 
assign o_pipe_stalled = ((o_wb_cyc_gbl)||(o_wb_cyc_lcl))
&&((i_wb_stall)||((~o_wb_stb_lcl)&&(~o_wb_stb_gbl)));
endmodule
/core/pipefetch.v
215,7 → 215,13
always @(posedge i_clk)
if (i_clear_cache)
o_wb_addr <= i_pc;
else if ((~o_wb_cyc)&&((w_pc_out_of_bounds)
else if ((o_wb_cyc)&&(w_pc_out_of_bounds))
begin
if (i_wb_ack)
o_wb_addr <= r_cache_base + bus_nvalid+1;
else
o_wb_addr <= r_cache_base + bus_nvalid;
end else if ((~o_wb_cyc)&&((w_pc_out_of_bounds)
||(w_ran_off_end_of_cache)))
o_wb_addr <= (i_new_pc) ? i_pc : r_addr;
else if ((o_wb_cyc)&&(o_wb_stb)&&(~i_wb_stall))
225,9 → 231,9
always @(posedge i_clk)
if (~o_wb_cyc)
r_acks_waiting <= 0;
else if ((o_wb_stb)&&(~i_wb_stall)&&(~i_wb_ack))
else if ((o_wb_cyc)&&(o_wb_stb)&&(~i_wb_stall)&&(~i_wb_ack))
r_acks_waiting <= r_acks_waiting + 1;
else if ((i_wb_ack)&&((~o_wb_stb)||(i_wb_stall)))
else if ((o_wb_cyc)&&(i_wb_ack)&&((~o_wb_stb)||(i_wb_stall)))
r_acks_waiting <= r_acks_waiting - 1;
 
always @(posedge i_clk)
/core/zipcpu.v
116,7 → 116,7
// Single Fetching 2521 1734
// Pipelined fetching 2796 2046
//
// `define SINGLE_FETCH
// `define OPT_SINGLE_FETCH
//
//
//
128,12 → 128,14
`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 ????
// (Currently unused)
// `define OPT_SINGLE_FETCH
// (Best path--define these!)
`define OPT_CONDITIONAL_FLAGS
`define OPT_PRECLEAR_BUS
`define OPT_ILLEGAL_INSTRUCTION
`define OPT_EARLY_BRANCHING
`define OPT_PIPELINED_BUS_ACCESS
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,
147,7 → 149,7
i_wb_err,
// Accounting/CPU usage interface
o_op_stall, o_pf_stall, o_i_count);
parameter RESET_ADDRESS=32'h0100000;
parameter RESET_ADDRESS=32'h0100000, LGICACHE=9;
input i_clk, i_rst, i_interrupt;
// Debug interface -- inputs
input i_halt, i_clear_pf_cache;
180,8 → 182,10
reg [3:0] flags, iflags; // (TRAP,FPEN,BREAKEN,STEP,GIE,SLEEP ), V, N, C, Z
wire [10:0] w_uflags, w_iflags;
reg trap, break_en, step, gie, sleep;
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_ILLEGAL_INSTRUCTION
reg ill_err;
`else
wire ill_err;
`endif
reg bus_err_flag;
 
222,13 → 226,13
reg [23:0] r_dcdI;
wire dcdA_stall, dcdB_stall, dcdF_stall;
 
`ifdef NG_PRECLEAR_BUS
`ifdef OPT_PRECLEAR_BUS
reg dcd_clear_bus;
`endif
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_ILLEGAL_INSTRUCTION
reg dcd_illegal;
`endif
`ifdef NG_EARLY_BRANCHING
`ifdef OPT_EARLY_BRANCHING
reg dcd_early_branch_stb, dcd_early_branch;
reg [31:0] dcd_branch_pc;
`else
257,10 → 261,10
reg [6:0] r_opF;
wire [8:0] opF;
wire op_ce;
`ifdef NG_PRECLEAR_BUS
`ifdef OPT_PRECLEAR_BUS
reg op_clear_bus;
`endif
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_ILLEGAL_INSTRUCTION
reg op_illegal;
`endif
 
279,13 → 283,18
wire alu_valid;
wire set_cond;
reg alu_wr, alF_wr, alu_gie;
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_ILLEGAL_INSTRUCTION
reg alu_illegal;
`else
wire alu_illegal;
`endif
 
 
 
wire mem_ce, mem_stalled;
`ifdef OPT_PIPELINED_BUS_ACCESS
wire mem_pipe_stalled;
`endif
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;
311,7 → 320,7
//
// MASTER: clock enable.
//
assign master_ce = (~i_halt)&&(~o_break)&&(~sleep)&&(~mem_rdbusy);
assign master_ce = (~i_halt)&&(~o_break)&&(~sleep);
 
 
//
325,9 → 334,7
assign dcd_stalled = (dcdvalid)&&(
(op_stall)
||((dcdA_stall)||(dcdB_stall)||(dcdF_stall))
`ifndef NG_BRANCH_DELAY_SLOT
||((opvalid_mem)&&(op_wr_pc))
`endif
||((opvalid_mem)&&(opR_cc)));
//
// PIPELINE STAGE #3 :: Read Operands
350,17 → 357,26
// 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)) // 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 alu_ce = (master_ce)&&(~mem_rdbusy)&&(opvalid_alu)&&(~alu_stall)&&(~clear_pipeline);
//
`ifdef OPT_PIPELINED_BUS_ACCESS
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~clear_pipeline)
&&(set_cond)&&(~mem_stalled);
assign mem_stalled = (~master_ce)||((opvalid_mem)&&(
(mem_pipe_stalled)
||((~op_pipe)&&(mem_busy))
// Stall waiting for flags to be valid
// Or waiting for a write to the PC register
// Or CC register, since that can change the
// PC as well
||((wr_reg_ce)&&(wr_reg_id[4] == op_gie)
&&((wr_write_pc)||(wr_write_cc)))));
`else
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~mem_stalled)&&(~clear_pipeline)&&(set_cond);
 
assign mem_stalled = (mem_busy)||((opvalid_mem)&&(
(~master_ce)
// Stall waiting for flags to be valid
368,6 → 384,7
// Or CC register, since that can change the
// PC as well
||((wr_reg_ce)&&(wr_reg_id[4] == op_gie)&&((wr_write_pc)||(wr_write_cc)))));
`endif
 
 
//
375,7 → 392,7
// PIPELINE STAGE #1 :: Prefetch
//
//
`ifdef SINGLE_FETCH
`ifdef OPT_SINGLE_FETCH
wire pf_ce;
 
assign pf_ce = (~dcd_stalled);
385,7 → 402,7
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)
pipefetch #(RESET_ADDRESS, LGICACHE)
pf(i_clk, i_rst, (new_pc)|(dcd_early_branch_stb),
i_clear_pf_cache, ~dcd_stalled,
(new_pc)?pf_pc:dcd_branch_pc,
392,7 → 409,7
instruction, instruction_pc, pf_valid,
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, pf_err, i_wb_data,
`ifdef NG_PRECLEAR_BUS
`ifdef OPT_PRECLEAR_BUS
((dcd_clear_bus)&&(dcdvalid))
||((op_clear_bus)&&(opvalid))
||
411,9 → 428,9
else if ((~dcd_stalled)||(clear_pipeline)||(dcd_early_branch))
dcdvalid <= 1'b0;
 
`ifdef NG_EARLY_BRANCHING
`ifdef OPT_EARLY_BRANCHING
always @(posedge i_clk)
if ((dcd_ce)&&(instruction[27:24]==`CPU_PC_REG))
if ((dcd_ce)&&(instruction[27:24]==`CPU_PC_REG)&&(~sleep))
begin
dcd_early_branch <= 1'b0;
// First case, a move to PC instruction
456,11 → 473,11
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
`else // OPT_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
`endif // OPT_EARLY_BRANCHING
 
always @(posedge i_clk)
if (dcd_ce)
478,15 → 495,15
dcdA_pc <= (instruction[27:24] == `CPU_PC_REG);
dcdB_pc <= (instruction[19:16] == `CPU_PC_REG);
dcdM <= 1'b0;
`ifdef NG_CONDITIONAL_FLAGS
`ifdef OPT_CONDITIONAL_FLAGS
dcdF_wr <= (instruction[23:21]==3'h0);
`else
dcdF_wr <= 1'b1;
`endif
`ifdef NG_PRECLEAR_BUS
`ifdef OPT_PRECLEAR_BUS
dcd_clear_bus <= 1'b0;
`endif
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_ILLEGAL_INSTRUCTION
dcd_illegal <= pf_illegal;
`endif
 
517,7 → 534,7
dcdOp <= 4'h2;
end
4'h4: begin // Multiply, LDI[HI|LO], or NOOP/BREAK
`ifdef NG_CONDITIONAL_FLAGS
`ifdef OPT_CONDITIONAL_FLAGS
// Don't write flags except for multiplies
// and then only if they are unconditional
dcdF_wr <= ((instruction[27:25] != 3'h7)
536,7 → 553,7
dcdOp <= 4'h2;
// Might also be a break. Big
// instruction set hole here.
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_ILLEGAL_INSTRUCTION
dcd_illegal <= (pf_illegal)||(instruction[23:1] != 0);
`endif
end else if (instruction[27:24] == 4'hf)
565,7 → 582,7
else
r_dcdI <= { {(4){instruction[19]}}, instruction[19:0] };
dcdM <= 1'b1; // Memory operation
`ifdef NG_PRECLEAR_BUS
`ifdef OPT_PRECLEAR_BUS
dcd_clear_bus <= (instruction[23:21]==3'h0);
`endif
end
586,10 → 603,35
always @(posedge i_clk)
if (dcd_ce)
dcd_break <= (instruction[31:0] == 32'h4e000001);
else if ((clear_pipeline)||(~dcdvalid))
else if ((clear_pipeline)||(~dcdvalid)) // SHOULDNT THIS BE ||op_ce?
dcd_break <= 1'b0;
 
`ifdef OPT_PIPELINED_BUS_ACCESS
reg [23:0] r_opI;
reg [4:0] op_B;
reg op_pipe;
 
initial op_pipe = 1'b0;
// To be a pipeable operation, there must be
// two valid adjacent instructions
// Both must be memory instructions
// Both must be writes, or both must be reads
// Both operations must be to the same identical address,
// or at least a single (one) increment above that address
always @(posedge i_clk)
if (op_ce)
op_pipe <= (dcdvalid)&&(opvalid_mem)&&(dcdM) // Both mem
&&(dcdOp[0]==opn[0]) // Both Rd, or both Wr
&&(dcdB == op_B) // Same address register
&&((r_dcdI == r_opI)||(r_dcdI==r_opI+24'h1));
always @(posedge i_clk)
if (op_ce) // &&(dcdvalid))
r_opI <= r_dcdI;
always @(posedge i_clk)
if (op_ce) // &&(dcdvalid))
op_B <= dcdB;
`endif
 
//
//
// PIPELINE STAGE #3 :: Read Operands (Registers)
668,7 → 710,7
// wait until our operands are valid, then we aren't
// valid yet until then.
opvalid<= (~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled);
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_ILLEGAL_INSTRUCTION
opvalid_mem <= (dcdM)&&(~dcd_illegal)&&(~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled);
opvalid_alu <= ((~dcdM)||(dcd_illegal))&&(~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled);
`else
698,7 → 740,7
else if ((clear_pipeline)||(~opvalid))
op_break <= 1'b0;
 
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_ILLEGAL_INSTRUCTION
always @(posedge i_clk)
if(op_ce)
op_illegal <= dcd_illegal;
709,7 → 751,7
begin
opn <= dcdOp; // Which ALU operation?
// opM <= dcdM; // Is this a memory operation?
`ifdef NG_EARLY_BRANCH
`ifdef OPT_EARLY_BRANCHING
opF_wr <= (dcdF_wr)&&((~dcdA_cc)||(~dcdA_wr))&&(~dcd_early_branch);
opR_wr <= (dcdA_wr)&&(~dcd_early_branch);
`else
720,7 → 762,7
`endif
// What register will these results be written into?
opR <= dcdA;
opR_cc <= (dcdA_wr)&&(dcdA_cc);
opR_cc <= (dcdA_wr)&&(dcdA_cc)&&(dcdA[4]==dcd_gie);
// User level (1), vs supervisor (0)/interrupts disabled
op_gie <= dcd_gie;
 
733,13 → 775,13
opB_rd <= dcdB_rd;
op_pc <= dcd_pc;
//
`ifdef NG_EARLY_BRANCHING
`ifdef OPT_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
`ifdef OPT_PRECLEAR_BUS
op_clear_bus <= dcd_clear_bus;
`endif
end
777,9 → 819,24
opB_alu <= (opvalid_alu)&&(opR == dcdB)&&(dcdB_rd)&&(dcdI == 0);
assign opB = (opB_alu) ? alu_result : r_opB;
assign dcdB_stall = (dcdvalid)&&(dcdB_rd)&&(
// Stall on memory ops writing to my register
// (i.e. loads), or on any write to my
// register if I have an immediate offset
// Note the exception for writing to the PC:
// if I write to the PC, the whole next
// instruction is invalid, not just the
// operand. That'll get wiped in the
// next operation anyway, so don't stall
// here.
((opvalid)&&(opR_wr)&&(opR == dcdB)
&&(opR != { op_gie, `CPU_PC_REG} )
&&((opvalid_mem)||(dcdI != 0)))
// Stall on any write to the flags register,
// if we're going to need the flags value for
// opB.
||((opvalid_alu)&&(opF_wr)&&(dcdB_cc))
// Stall on any ongoing memory operation that
// will write to opB
||((mem_busy)&&(~mem_we)&&(mem_wreg == dcdB)));
assign dcdF_stall = (dcdvalid)&&((~dcdF[3])||(dcdA_cc)||(dcdB_cc))
&&(opvalid)&&(opR_cc);
817,18 → 874,37
always @(posedge i_clk)
if ((alu_ce)||(mem_ce))
alu_pc <= op_pc;
`ifdef OPT_ILLEGAL_INSTRUCTION
always @(posedge i_clk)
if ((alu_ce)||(mem_ce))
alu_illegal <= op_illegal;
`endif
 
initial alu_pc_valid = 1'b0;
always @(posedge i_clk)
alu_pc_valid <= (~i_rst)&&(master_ce)&&(opvalid)&&(~clear_pipeline)
alu_pc_valid <= (~i_rst)&&(master_ce)&&(~mem_rdbusy)&&(opvalid)&&(~clear_pipeline)
&&((opvalid_alu)||(~mem_stalled));
 
`ifdef OPT_PIPELINED_BUS_ACCESS
pipemem domem(i_clk, i_rst, mem_ce,
(opn[0]), opB, opA, opR,
mem_busy, mem_pipe_stalled,
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);
`else // PIPELINED_BUS_ACCESS
memops domem(i_clk, i_rst, mem_ce,
(opn[0]), opB, opA, opR,
mem_busy, mem_valid, bus_err, mem_wreg, mem_result,
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);
`endif // PIPELINED_BUS_ACCESS
assign mem_rdbusy = (((mem_cyc_gbl)||(mem_cyc_lcl))&&(~mem_we));
 
// Either the prefetch or the instruction gets the memory bus, but
863,12 → 939,14
// 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.
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_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?
// COULD SIMPLIFY THIS: by adding three bits to these registers,
// One or PC, one for CC, and one for GIE match
assign wr_reg_id = (alu_wr)?alu_reg:mem_wreg;
// Are we writing to the CC register?
assign wr_write_cc = (wr_reg_id[3:0] == `CPU_CC_REG);
887,7 → 965,7
// When shall we write to our flags register? alF_wr already
// includes the set condition ...
assign wr_flags_ce = (alF_wr)&&(alu_valid)&&(~clear_pipeline)&&(~alu_illegal);
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_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
939,7 → 1017,7
else if ((i_halt)&&(i_dbg_we)
&&(i_dbg_reg == { 1'b0, `CPU_CC_REG }))
break_en <= i_dbg_data[`CPU_BREAK_BIT];
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_ILLEGAL_INSTRUCTION
assign o_break = ((break_en)||(~op_gie))&&(op_break)
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy)
&&(~clear_pipeline)
949,7 → 1027,7
assign o_break = (((break_en)||(~op_gie))&&(op_break)
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy)
&&(~clear_pipeline))
||((~alu_gie)&&(bus_err))
||((~alu_gie)&&(bus_err));
`endif
 
 
984,7 → 1062,7
else if ((i_halt)&&(i_dbg_we)
&&(i_dbg_reg == { 1'b1, `CPU_CC_REG }))
step <= i_dbg_data[`CPU_STEP_BIT];
else if ((master_ce)&&(alu_pc_valid)&&(step)&&(gie))
else if ((alu_pc_valid)&&(step)&&(gie))
step <= 1'b0;
 
// The GIE register. Only interrupts can disable the interrupt register
992,11 → 1070,11
// On interrupt (obviously)
(i_interrupt)
// If we are stepping the CPU
||((master_ce)&&(alu_pc_valid)&&(step))
||((alu_pc_valid)&&(step))
// If we encounter a break instruction, if the break
// enable isn't set.
||((master_ce)&&(op_break)&&(~break_en))
`ifdef NG_ILLEGAL_INSTRUCTION
||((master_ce)&&(~mem_rdbusy)&&(op_break)&&(~break_en))
`ifdef OPT_ILLEGAL_INSTRUCTION
// On an illegal instruction
||((alu_valid)&&(alu_illegal))
`endif
1036,7 → 1114,7
else if (w_release_from_interrupt)
trap <= 1'b0;
 
`ifdef NG_ILLEGAL_INSTRUCTION
`ifdef OPT_ILLEGAL_INSTRUCTION
initial ill_err = 1'b0;
always @(posedge i_clk)
if (i_rst)
1045,6 → 1123,8
ill_err <= 1'b0;
else if ((alu_valid)&&(alu_illegal)&&(gie))
ill_err <= 1'b1;
`else
assign ill_err = 1'b0;
`endif
initial bus_err_flag = 1'b0;
always @(posedge i_clk)
1143,5 → 1223,5
//
assign o_op_stall = (master_ce)&&((~opvalid)||(op_stall));
assign o_pf_stall = (master_ce)&&(~pf_valid);
assign o_i_count = alu_pc_valid;
assign o_i_count = (alu_pc_valid)&&(~clear_pipeline);
endmodule
/zipsystem.v
287,6 → 287,8
2'b00, cpu_dbg_cc,
1'b0, cmd_halt, (~cpu_dbg_stall), 1'b0,
pic_data[15], cpu_reset, cmd_addr };
wire cpu_gie;
assign cpu_gie = cpu_dbg_cc[1];
 
`ifdef USE_TRAP
//
368,7 → 370,7
// User task counter
wire utc_ack, utc_stall, utc_int;
wire [31:0] utc_data;
zipcounter utask_ctr(i_clk,(~cpu_halt), sys_cyc,
zipcounter utask_ctr(i_clk,(~cpu_halt)&&(cpu_gie), sys_cyc,
(sys_stb)&&(sys_addr == `USER_TASK_CTR),
sys_we, sys_data,
utc_ack, utc_stall, utc_data, utc_int);
376,7 → 378,7
// User Op-Stall counter
wire uoc_ack, uoc_stall, uoc_int;
wire [31:0] uoc_data;
zipcounter umstall_ctr(i_clk,(cpu_op_stall), sys_cyc,
zipcounter umstall_ctr(i_clk,(cpu_op_stall)&&(cpu_gie), sys_cyc,
(sys_stb)&&(sys_addr == `USER_MSTL_CTR),
sys_we, sys_data,
uoc_ack, uoc_stall, uoc_data, uoc_int);
384,7 → 386,7
// User PreFetch-Stall counter
wire upc_ack, upc_stall, upc_int;
wire [31:0] upc_data;
zipcounter upstall_ctr(i_clk,(cpu_pf_stall), sys_cyc,
zipcounter upstall_ctr(i_clk,(cpu_pf_stall)&&(cpu_gie), sys_cyc,
(sys_stb)&&(sys_addr == `USER_PSTL_CTR),
sys_we, sys_data,
upc_ack, upc_stall, upc_data, upc_int);
392,7 → 394,7
// User instruction counter
wire uic_ack, uic_stall, uic_int;
wire [31:0] uic_data;
zipcounter uins_ctr(i_clk,(cpu_i_count), sys_cyc,
zipcounter uins_ctr(i_clk,(cpu_i_count)&&(cpu_gie), sys_cyc,
(sys_stb)&&(sys_addr == `USER_INST_CTR),
sys_we, sys_data,
uic_ack, uic_stall, uic_data, uic_int);
/Makefile
32,7 → 32,7
################################################################################
#
.PHONY: all
all: zipsystem
all: zipsystem zipbones cpudefs.h
 
CORED:= core
PRPHD:= peripherals
43,9 → 43,14
$(PRPHD)/ziptimer.v $(PRPHD)/ziptrap.v \
$(CORED)/zipcpu.v $(CORED)/cpuops.v \
$(CORED)/pipefetch.v $(CORED)/prefetch.v \
$(CORED)/memops.v \
$(AUXD)/busdelay.v $(AUXD)/wbarbiter.v \
$(CORED)/memops.v $(CORED)/pipemem.v \
$(AUXD)/busdelay.v \
$(AUXD)/wbdblpriarb.v $(AUXD)/wbpriarbiter.v
VZIP := zipbones.v \
$(CORED)/zipcpu.v $(CORED)/cpuops.v \
$(CORED)/pipefetch.v $(CORED)/prefetch.v \
$(CORED)/memops.v $(CORED)/pipemem.v \
$(AUXD)/busdelay.v $(AUXD)/wbdblpriarb.v
 
VOBJ := obj_dir
 
52,12 → 57,25
$(VOBJ)/Vzipsystem.cpp: $(VSRC)
verilator -cc -y $(CORED) -y $(PRPHD) -y $(AUXD) zipsystem.v
 
$(VOBJ)/Vzipbones.cpp: $(VZIP)
verilator -cc -y $(CORED) -y $(PRPHD) -y $(AUXD) zipbones.v
 
$(VOBJ)/Vzipsystem__ALL.a: $(VOBJ)/Vzipsystem.cpp $(VOBJ)/Vzipsystem.h
cd $(VOBJ); make -f Vzipsystem.mk
 
$(VOBJ)/Vzipbones__ALL.a: $(VOBJ)/Vzipbones.cpp $(VOBJ)/Vzipbones.h
cd $(VOBJ); make -f Vzipbones.mk
 
cpudefs.h: $(CORED)/zipcpu.v
@echo "// Do not edit this file, it is automatically generated!" > $@
@grep ^.define $^ | grep OPT_ | sed -e '{ s/^.d/#d/ }' >> $@
 
.PHONY: zipsystem
zipsystem: $(VOBJ)/Vzipsystem__ALL.a
 
.PHONY: zipbones
zipbones: $(VOBJ)/Vzipbones__ALL.a
 
.PHONY: clean
clean:
rm -rf $(VOBJ)
rm -rf $(VOBJ) cpudefs.h
/zipbones.v
0,0 → 1,179
///////////////////////////////////////////////////////////////////////////
//
// Filename: zipbones.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: In the spirit of keeping the Zip CPU small, this implements a
// Zip System with no peripherals: Any peripherals you wish will
// need to be implemented off-module.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
module zipbones(i_clk, i_rst,
// Wishbone master interface from the CPU
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_err,
// Incoming interrupts
i_ext_int,
// Our one outgoing interrupt
o_ext_int,
// Wishbone slave interface for debugging purposes
i_dbg_cyc, i_dbg_stb, i_dbg_we, i_dbg_addr, i_dbg_data,
o_dbg_ack, o_dbg_stall, o_dbg_data);
parameter RESET_ADDRESS=32'h0100000, START_HALTED=1,
EXTERNAL_INTERRUPTS=1;
input i_clk, i_rst;
// Wishbone master
output wire o_wb_cyc, o_wb_stb, o_wb_we;
output wire [31:0] o_wb_addr;
output wire [31:0] o_wb_data;
input i_wb_ack, i_wb_stall;
input [31:0] i_wb_data;
input i_wb_err;
// Incoming interrupts
input [(EXTERNAL_INTERRUPTS-1):0] i_ext_int;
// Outgoing interrupt
output wire o_ext_int;
// Wishbone slave
input i_dbg_cyc, i_dbg_stb, i_dbg_we, i_dbg_addr;
input [31:0] i_dbg_data;
output reg o_dbg_ack;
output wire o_dbg_stall;
output wire [31:0] o_dbg_data;
 
//
//
//
wire sys_cyc, sys_stb, sys_we;
wire [4:0] sys_addr;
wire [31:0] cpu_addr;
wire [31:0] sys_data;
wire sys_ack, sys_stall;
 
//
// The external debug interface
//
// We offer only a limited interface here, requiring a pre-register
// write to set the local address. This interface allows access to
// the Zip System on a debug basis only, and not to the rest of the
// wishbone bus. Further, to access these registers, the control
// register must first be accessed to both stop the CPU and to
// set the following address in question. Hence all accesses require
// two accesses: write the address to the control register (and halt
// the CPU if not halted), then read/write the data from the data
// register.
//
wire cpu_break, dbg_cmd_write;
reg cmd_reset, cmd_halt, cmd_step, cmd_clear_pf_cache;
reg [4:0] cmd_addr;
wire [1:0] cpu_dbg_cc;
assign dbg_cmd_write = (i_dbg_cyc)&&(i_dbg_stb)&&(i_dbg_we)&&(~i_dbg_addr);
//
initial cmd_reset = 1'b1;
always @(posedge i_clk)
cmd_reset <= ((dbg_cmd_write)&&(i_dbg_data[6]));
//
initial cmd_halt = 1'b1;
always @(posedge i_clk)
if (i_rst)
cmd_halt <= (START_HALTED == 1)? 1'b1 : 1'b0;
else if (dbg_cmd_write)
cmd_halt <= ((i_dbg_data[10])||(i_dbg_data[8]));
else if ((cmd_step)||(cpu_break))
cmd_halt <= 1'b1;
 
always @(posedge i_clk)
if (i_rst)
cmd_clear_pf_cache <= 1'b0;
else if (dbg_cmd_write)
cmd_clear_pf_cache <= i_dbg_data[11];
else
cmd_clear_pf_cache <= 1'b0;
//
initial cmd_step = 1'b0;
always @(posedge i_clk)
cmd_step <= (dbg_cmd_write)&&(i_dbg_data[8]);
//
always @(posedge i_clk)
if (dbg_cmd_write)
cmd_addr <= i_dbg_data[4:0];
 
wire cpu_reset;
assign cpu_reset = (cmd_reset)||(i_rst);
 
wire cpu_halt, cpu_dbg_stall;
assign cpu_halt = (i_rst)||((cmd_halt)&&(~cmd_step));
wire [31:0] pic_data;
wire [31:0] cmd_data;
// Values:
// 0x0003f -> cmd_addr mask
// 0x00040 -> reset
// 0x00080 -> PIC interrrupts enabled
// 0x00100 -> cmd_step
// 0x00200 -> cmd_stall
// 0x00400 -> cmd_halt
// 0x00800 -> cmd_clear_pf_cache
// 0x01000 -> cc.sleep
// 0x02000 -> cc.gie
// 0x10000 -> External interrupt line is high
assign cmd_data = { 7'h00, {(9-EXTERNAL_INTERRUPTS){1'b0}}, i_ext_int,
2'b00, cpu_dbg_cc,
1'b0, cmd_halt, (~cpu_dbg_stall), 1'b0,
pic_data[15], cpu_reset, 1'b0, cmd_addr };
wire cpu_gie;
assign cpu_gie = cpu_dbg_cc[1];
 
//
// The CPU itself
//
wire cpu_gbl_stb, cpu_lcl_cyc, cpu_lcl_stb,
cpu_we, cpu_dbg_we,
cpu_op_stall, cpu_pf_stall, cpu_i_count;
wire [31:0] cpu_data, wb_data;
wire cpu_ack, cpu_stall, cpu_err;
wire [31:0] cpu_dbg_data;
assign cpu_dbg_we = ((i_dbg_cyc)&&(i_dbg_stb)
&&(i_dbg_we)&&(i_dbg_addr));
zipcpu #(RESET_ADDRESS) thecpu(i_clk, cpu_reset, i_ext_int,
cpu_halt, cmd_clear_pf_cache, cmd_addr[4:0], cpu_dbg_we,
i_dbg_data, cpu_dbg_stall, cpu_dbg_data,
cpu_dbg_cc, cpu_break,
o_wb_cyc, o_wb_stb,
cpu_lcl_cyc, cpu_lcl_stb,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, wb_data,
i_wb_err,
cpu_op_stall, cpu_pf_stall, cpu_i_count);
 
// Return debug response values
assign o_dbg_data = (~i_dbg_addr)?cmd_data :cpu_dbg_data;
initial o_dbg_ack = 1'b0;
always @(posedge i_clk)
o_dbg_ack <= (i_dbg_cyc)&&((~i_dbg_addr)||(~o_dbg_stall));
assign o_dbg_stall=(i_dbg_cyc)&&(cpu_dbg_stall)&&(i_dbg_addr);
 
assign o_ext_int = (cmd_halt) && (~cpu_stall);
 
endmodule

powered by: WebSVN 2.1.0

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