URL
https://opencores.org/ocsvn/zipcpu/zipcpu/trunk
Subversion Repositories zipcpu
Compare Revisions
- This comparison shows the changes necessary to convert path
/zipcpu
- from Rev 48 to Rev 47
- ↔ Reverse comparison
Rev 48 → Rev 47
/trunk/rtl/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 |
/trunk/rtl/core/pipefetch.v
54,18 → 54,18
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, ADDRESS_WIDTH=24, |
CACHELEN=(1<<LGCACHELEN), BUSW=32, AW=ADDRESS_WIDTH; |
LGCACHELEN = 6, CACHELEN=(1<<LGCACHELEN), |
BUSW=32; |
input i_clk, i_rst, i_new_pc, |
i_clear_cache, i_stall_n; |
input [(AW-1):0] i_pc; |
input [(BUSW-1):0] i_pc; |
output reg [(BUSW-1):0] o_i; |
output reg [(AW-1):0] o_pc; |
output reg [(BUSW-1):0] o_pc; |
output wire o_v; |
// |
output reg o_wb_cyc, o_wb_stb; |
output wire o_wb_we; |
output reg [(AW-1):0] o_wb_addr; |
output reg [(BUSW-1):0] o_wb_addr; |
output wire [(BUSW-1):0] o_wb_data; |
// |
input i_wb_ack, i_wb_stall, i_wb_err; |
83,7 → 83,7
assign o_wb_we = 1'b0; |
assign o_wb_data = 0; |
|
reg [(AW-1):0] r_cache_base; |
reg [(BUSW-1):0] r_cache_base; |
reg [(LGCACHELEN):0] r_nvalid, r_acks_waiting; |
reg [(BUSW-1):0] cache[0:(CACHELEN-1)]; |
|
90,10 → 90,10
reg [(LGCACHELEN-1):0] r_cache_offset; |
|
reg r_addr_set; |
reg [(AW-1):0] r_addr; |
reg [(BUSW-1):0] r_addr; |
|
wire [(AW-1):0] bus_nvalid; |
assign bus_nvalid = { {(AW-LGCACHELEN-1){1'b0}}, r_nvalid }; |
wire [(BUSW-1):0] bus_nvalid; |
assign bus_nvalid = { {(BUSW-LGCACHELEN-1){1'b0}}, r_nvalid }; |
|
// What are some of the conditions for which we need to restart the |
// cache? |
100,18 → 100,14
wire w_pc_out_of_bounds; |
assign w_pc_out_of_bounds = ((i_new_pc)&&((r_nvalid == 0) |
||(i_pc < r_cache_base) |
||(i_pc >= r_cache_base + CACHELEN) |
||(i_pc >= r_cache_base + bus_nvalid+5))); |
||(i_pc >= r_cache_base + CACHELEN))); |
wire w_ran_off_end_of_cache; |
assign w_ran_off_end_of_cache =((r_addr_set)&&((r_addr < r_cache_base) |
||(r_addr >= r_cache_base + CACHELEN) |
||(r_addr >= r_cache_base + bus_nvalid+5))); |
||(r_addr >= r_cache_base + CACHELEN))); |
wire w_running_out_of_cache; |
assign w_running_out_of_cache = (r_addr_set) |
&&(r_addr >= r_cache_base + (1<<(LGCACHELEN-2)) |
+ (1<<(LGCACHELEN-1))) |
&&(|r_nvalid[(LGCACHELEN):(LGCACHELEN-1)]); |
|
+ (1<<(LGCACHELEN-1))); |
initial r_cache_base = RESET_ADDRESS; |
always @(posedge i_clk) |
begin |
/trunk/rtl/core/zipcpu.v
132,14 → 132,10
// `define OPT_SINGLE_FETCH |
// (Best path--define these!) |
`define OPT_CONDITIONAL_FLAGS |
`define OPT_PRECLEAR_BUS |
`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_PIPELINED_BUS_ACCESS |
`endif |
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, |
153,8 → 149,7
i_wb_err, |
// Accounting/CPU usage interface |
o_op_stall, o_pf_stall, o_i_count); |
parameter RESET_ADDRESS=32'h0100000, ADDRESS_WIDTH=24, |
LGICACHE=6, AW=ADDRESS_WIDTH; |
parameter RESET_ADDRESS=32'h0100000, LGICACHE=9; |
input i_clk, i_rst, i_interrupt; |
// Debug interface -- inputs |
input i_halt, i_clear_pf_cache; |
169,8 → 164,7
// Wishbone interface -- outputs |
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 [(AW-1):0] o_wb_addr; |
output wire [31:0] o_wb_data; |
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; |
203,7 → 197,7
// PIPELINE STAGE #1 :: Prefetch |
// Variable declarations |
// |
reg [(AW-1):0] pf_pc; |
reg [31:0] pf_pc; |
reg new_pc, op_break; |
wire clear_pipeline; |
assign clear_pipeline = new_pc || i_clear_pf_cache; // || op_break; |
210,10 → 204,8
|
wire dcd_stalled; |
wire pf_cyc, pf_stb, pf_we, pf_busy, pf_ack, pf_stall, pf_err; |
wire [(AW-1):0] pf_addr; |
wire [31:0] pf_data; |
wire [31:0] instruction; |
wire [(AW-1):0] instruction_pc; |
wire [31:0] pf_addr, pf_data; |
wire [31:0] instruction, instruction_pc; |
wire pf_valid, instruction_gie, pf_illegal; |
|
// |
230,9 → 222,8
reg [3:0] dcdF; |
reg dcdA_rd, dcdA_wr, dcdB_rd, dcdvalid, |
dcdM, dcdF_wr, dcd_gie, dcd_break; |
reg [(AW-1):0] dcd_pc; |
reg [31:0] dcd_pc; |
reg [23:0] r_dcdI; |
reg dcd_zI; // true if dcdI == 0 |
wire dcdA_stall, dcdB_stall, dcdF_stall; |
|
`ifdef OPT_PRECLEAR_BUS |
242,11 → 233,11
reg dcd_illegal; |
`endif |
`ifdef OPT_EARLY_BRANCHING |
reg dcd_early_branch_stb, dcd_early_branch; |
reg [(AW-1):0] dcd_branch_pc; |
reg dcd_early_branch_stb, dcd_early_branch; |
reg [31:0] dcd_branch_pc; |
`else |
wire dcd_early_branch_stb, dcd_early_branch; |
wire [(AW-1):0] dcd_branch_pc; |
wire dcd_early_branch_stb, dcd_early_branch; |
wire [31:0] dcd_branch_pc; |
`endif |
|
|
261,8 → 252,7
reg [4:0] alu_reg; |
reg [3:0] opn; |
reg [4:0] opR; |
reg [31:0] r_opA, r_opB; |
reg [(AW-1):0] op_pc; |
reg [31:0] r_opA, r_opB, op_pc; |
wire [31:0] w_opA, w_opB; |
wire [31:0] opA_nowait, opB_nowait, opA, opB; |
reg opR_wr, opR_cc, opF_wr, op_gie, |
285,7 → 275,7
// Variable declarations |
// |
// |
reg [(AW-1):0] alu_pc; |
reg [31:0] alu_pc; |
reg alu_pc_valid;; |
wire alu_ce, alu_stall; |
wire [31:0] alu_result; |
307,12 → 297,10
`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; |
wire [4:0] mem_wreg; |
|
wire mem_busy, mem_rdbusy; |
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 |
wire mem_busy, mem_rdbusy; |
wire [31:0] mem_addr, mem_data, mem_result; |
|
|
|
325,7 → 313,7
wire [4:0] wr_reg_id; |
wire [31:0] wr_reg_vl; |
wire w_switch_to_interrupt, w_release_from_interrupt; |
reg [(AW-1):0] upc, ipc; |
reg [31:0] upc, ipc; |
|
|
|
408,14 → 396,13
wire pf_ce; |
|
assign pf_ce = (~dcd_stalled); |
prefetch #(ADDRESS_WIDTH) |
pf(i_clk, i_rst, (pf_ce), pf_pc, gie, |
prefetch pf(i_clk, i_rst, (pf_ce), pf_pc, gie, |
instruction, instruction_pc, instruction_gie, |
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, LGICACHE, ADDRESS_WIDTH) |
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, |
480,16 → 467,16
if (dcd_ce) |
begin |
if (instruction[31]) // Add |
dcd_branch_pc <= instruction_pc+{ {(AW-20){instruction[19]}}, instruction[19:0] } + {{(AW-1){1'b0}},1'b1}; |
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+{ {(AW-15){instruction[14]}}, instruction[14:0] } + {{(AW-1){1'b0}},1'b1}; |
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+{ {(AW-24){instruction[23]}}, instruction[23:0] } + {{(AW-1){1'b0}},1'b1}; |
dcd_branch_pc <= instruction_pc+32'h01+{ {(8){instruction[23]}}, instruction[23:0] }; |
end |
`else // OPT_EARLY_BRANCHING |
assign dcd_early_branch_stb = 1'b0; |
assign dcd_early_branch = 1'b0; |
assign dcd_branch_pc = {(AW){1'b0}}; |
assign dcd_branch_pc = 32'h00; |
`endif // OPT_EARLY_BRANCHING |
|
always @(posedge i_clk) |
535,7 → 522,6
dcdA_rd <= 1'b0; |
dcdB_rd <= 1'b1; |
r_dcdI <= { {(9){instruction[14]}}, instruction[14:0] }; |
dcd_zI <= (instruction[14:0] == 0); |
dcdF_wr <= 1'b0; // Don't write flags |
end |
4'h3: begin // Load immediate |
543,7 → 529,6
dcdA_rd <= 1'b0; |
dcdB_rd <= 1'b0; |
r_dcdI <= { instruction[23:0] }; |
dcd_zI <= (instruction[23:0] == 0); |
dcdF_wr <= 1'b0; // Don't write flags |
dcdF <= 4'h8; // This is unconditional |
dcdOp <= 4'h2; |
559,7 → 544,6
dcdF_wr <= (instruction[27:25] != 3'h7); |
`endif |
r_dcdI <= { 8'h00, instruction[15:0] }; |
dcd_zI <= (instruction[15:0] == 0); |
if (instruction[27:24] == 4'he) |
begin |
// NOOP instruction |
584,7 → 568,6
end else begin |
// Actual multiply instruction |
r_dcdI <= { 8'h00, instruction[15:0] }; |
dcd_zI <= (instruction[15:0] == 0); |
dcdA_rd <= 1'b1; |
dcdB_rd <= (instruction[19:16] != 4'hf); |
dcdOp[3:0] <= (instruction[20])? 4'h4:4'h3; |
595,13 → 578,9
dcdA_rd <= (instruction[28]); // Read on stores |
dcdB_rd <= instruction[20]; |
if (instruction[20]) |
begin |
r_dcdI <= { {(8){instruction[15]}}, instruction[15:0] }; |
dcd_zI <= (instruction[15:0] == 0); |
end else begin |
else |
r_dcdI <= { {(4){instruction[19]}}, instruction[19:0] }; |
dcd_zI <= (instruction[19:0] == 0); |
end |
dcdM <= 1'b1; // Memory operation |
`ifdef OPT_PRECLEAR_BUS |
dcd_clear_bus <= (instruction[23:21]==3'h0); |
612,13 → 591,10
dcdA_rd <= 1'b1; |
dcdB_rd <= instruction[20]; |
if (instruction[20]) |
begin |
r_dcdI <= { {(8){instruction[15]}}, instruction[15:0] }; |
dcd_zI <= (instruction[15:0] == 0); |
end else begin |
else |
r_dcdI <= { {(4){instruction[19]}}, instruction[19:0] }; |
dcd_zI <= (instruction[19:0] == 0); |
end end |
end |
endcase |
|
|
669,33 → 645,25
if ((wr_reg_ce)&&(wr_reg_id == dcdA)) |
r_opA <= wr_reg_vl; |
else if ((dcdA_pc)&&(dcdA[4] == dcd_gie)) |
r_opA <= { {(32-AW){1'b0}}, dcd_pc }; |
r_opA <= dcd_pc; |
else if (dcdA_pc) |
r_opA <= { {(32-AW){1'b0}}, upc }; |
r_opA <= upc; |
else if (dcdA_cc) |
r_opA <= { w_opA[31:11], (dcd_gie)?w_uflags:w_iflags }; |
else |
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 |
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)) ? {{(32-AW){1'b0}},dcd_pc } |
: ((dcdB_pc) ? {{(32-AW){1'b0}},upc} |
: (((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)) |
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 |
// to Xilinx's Vivado trying to help. The conditions are supposed to |
805,6 → 773,7
// use that value. |
opA_rd <= dcdA_rd; |
opB_rd <= dcdB_rd; |
op_pc <= dcd_pc; |
// |
`ifdef OPT_EARLY_BRANCHING |
op_wr_pc <= ((dcdA_wr)&&(dcdA_pc)&&(dcdA[4] == dcd_gie))&&(~dcd_early_branch); |
811,8 → 780,6
`else |
op_wr_pc <= ((dcdA_wr)&&(dcdA_pc)&&(dcdA[4] == dcd_gie)); |
`endif |
op_pc <= (dcd_early_branch)?dcd_branch_pc:dcd_pc; |
// op_pc <= dcd_pc; |
|
`ifdef OPT_PRECLEAR_BUS |
op_clear_bus <= dcd_clear_bus; |
832,51 → 799,25
// 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. |
reg opA_alu, opA_mem; |
reg opA_alu; |
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) |
if (op_ce) |
opA_mem <= ((opvalid_mem)&&(opR == dcdA)&&(dcdA_rd)) |
||((~opvalid)&&(mem_busy)&&(~mem_we) |
&&(mem_last_reg == dcdA)&&(dcdA_rd)); |
else if ((opvalid)&&(opA_mem)&&(mem_valid)) |
opA_mem <= 1'b0; |
opA_alu <= (opvalid_alu)&&(opR == dcdA)&&(dcdA_rd); |
assign opA = (opA_alu) ? alu_result : r_opA; |
|
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)&&( |
// 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))); |
// Place stalls for this latter case into the ops stage |
// ||((mem_busy)&&(~mem_we)); |
((opvalid_mem)&&(opR_wr)&&(opR == dcdA))|| |
((opvalid_alu)&&(opF_wr)&&(dcdA_cc))|| |
((mem_busy)&&(~mem_we)&&(mem_wreg == dcdA))); |
|
reg opB_alu, opB_mem; |
reg opB_alu; |
always @(posedge i_clk) |
if (op_ce) |
opB_alu <= (opvalid_alu)&&(opR == dcdB)&&(opR_wr)&&(dcdB_rd)&&(dcd_zI); |
always @(posedge i_clk) |
if (op_ce) |
opB_mem <= (dcd_zI)&&(dcdB_rd)&&( |
((opvalid_mem)&&(opR == dcdB)) |
||((~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 ); |
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 |
889,7 → 830,7
// here. |
((opvalid)&&(opR_wr)&&(opR == dcdB) |
&&(opR != { op_gie, `CPU_PC_REG} ) |
&&(~dcd_zI)) |
&&((opvalid_mem)||(dcdI != 0))) |
// Stall on any write to the flags register, |
// if we're going to need the flags value for |
// opB. |
896,7 → 837,7
||((opvalid_alu)&&(opF_wr)&&(dcdB_cc)) |
// Stall on any ongoing memory operation that |
// will write to opB |
||((mem_busy)&&(~mem_we)&&(mem_last_reg==dcdB))); |
||((mem_busy)&&(~mem_we)&&(mem_wreg == dcdB))); |
assign dcdF_stall = (dcdvalid)&&((~dcdF[3])||(dcdA_cc)||(dcdB_cc)) |
&&(opvalid)&&(opR_cc); |
// |
945,7 → 886,7
&&((opvalid_alu)||(~mem_stalled)); |
|
`ifdef OPT_PIPELINED_BUS_ACCESS |
pipemem #(AW) domem(i_clk, i_rst, mem_ce, |
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, |
955,7 → 896,7
mem_ack, mem_stall, mem_err, i_wb_data); |
|
`else // PIPELINED_BUS_ACCESS |
memops #(AW) domem(i_clk, i_rst, mem_ce, |
memops domem(i_clk, i_rst, mem_ce, |
(opn[0]), opB, opA, opR, |
mem_busy, |
mem_valid, bus_err, mem_wreg, mem_result, |
968,7 → 909,7
|
// Either the prefetch or the instruction gets the memory bus, but |
// never both. |
wbdblpriarb #(32,AW) 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, |
1206,23 → 1147,23
// a non-gie instruction? |
always @(posedge i_clk) |
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_pc)) |
upc <= wr_reg_vl[(AW-1):0]; |
upc <= wr_reg_vl; |
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 })) |
upc <= i_dbg_data[(AW-1):0]; |
upc <= i_dbg_data; |
|
always @(posedge i_clk) |
if (i_rst) |
ipc <= RESET_ADDRESS; |
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_pc)) |
ipc <= wr_reg_vl[(AW-1):0]; |
ipc <= wr_reg_vl; |
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 })) |
ipc <= i_dbg_data[(AW-1):0]; |
ipc <= i_dbg_data; |
|
always @(posedge i_clk) |
if (i_rst) |
1232,10 → 1173,10
else if (w_release_from_interrupt) |
pf_pc <= upc; |
else if ((wr_reg_ce)&&(wr_reg_id[4] == gie)&&(wr_write_pc)) |
pf_pc <= wr_reg_vl[(AW-1):0]; |
pf_pc <= wr_reg_vl; |
else if ((i_halt)&&(i_dbg_we) |
&&(i_dbg_reg[4:0] == { gie, `CPU_PC_REG})) |
pf_pc <= i_dbg_data[(AW-1):0]; |
pf_pc <= i_dbg_data; |
else if (dcd_ce) |
pf_pc <= pf_pc + 1; |
|
1261,7 → 1202,7
begin |
o_dbg_reg <= regset[i_dbg_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 <= (i_dbg_reg[4])?upc:ipc; |
else if (i_dbg_reg[3:0] == `CPU_CC_REG) |
o_dbg_reg[10:0] <= (i_dbg_reg[4])?w_uflags:w_iflags; |
end |
/trunk/rtl/core/memops.v
44,7 → 44,6
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); |
parameter ADDRESS_WIDTH=24, AW=ADDRESS_WIDTH; |
input i_clk, i_rst; |
input i_stb; |
// CPU interface |
61,8 → 60,7
// 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 [(AW-1):0] o_wb_addr; |
output reg [31:0] o_wb_data; |
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; |
103,7 → 101,7
begin |
o_wb_we <= i_op; |
o_wb_data <= i_data; |
o_wb_addr <= i_addr[(AW-1):0]; |
o_wb_addr <= i_addr; |
end |
|
initial o_valid = 1'b0; |
/trunk/rtl/core/prefetch.v
51,19 → 51,19
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_err, i_wb_data); |
parameter ADDRESS_WIDTH=32, AUX_WIDTH = 1, AW=ADDRESS_WIDTH; |
input i_clk, i_rst, i_ce; |
input [(AW-1):0] i_pc; |
input [(AUX_WIDTH-1):0] i_aux; |
output reg [31:0] o_i; |
output reg [(AW-1):0] o_pc; |
output reg [(AUX_WIDTH-1):0] o_aux; |
output wire o_valid, o_illegal; |
parameter AW = 1; |
input i_clk, i_rst, i_ce; |
input [31:0] i_pc; |
input [(AW-1):0] i_aux; |
output reg [31:0] o_i; |
output reg [31:0] o_pc; |
output reg [(AW-1):0] o_aux; |
output wire o_valid, o_illegal; |
// Wishbone outputs |
output reg o_wb_cyc, o_wb_stb; |
output wire o_wb_we; |
output reg [(AW-1):0] o_wb_addr; |
output wire [31:0] o_wb_data; |
output reg o_wb_cyc, o_wb_stb; |
output wire o_wb_we; |
output reg [31:0] o_wb_addr; |
output wire [31:0] o_wb_data; |
// And return inputs |
input i_wb_ack, i_wb_stall, i_wb_err; |
input [31:0] i_wb_data; |
/trunk/rtl/zipsystem.v
162,14 → 162,12
// 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=24'h0100000, ADDRESS_WIDTH=24, |
LGICACHE=6, START_HALTED=1, EXTERNAL_INTERRUPTS=1, |
// Derived parameters |
AW=ADDRESS_WIDTH; |
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 [(AW-1):0] o_wb_addr; |
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; |
215,7 → 213,7
// |
wire sys_cyc, sys_stb, sys_we; |
wire [4:0] sys_addr; |
wire [(AW-1):0] cpu_addr; |
wire [31:0] cpu_addr; |
wire [31:0] sys_data; |
wire sys_ack, sys_stall; |
|
445,11 → 443,10
wire [31:0] dmac_data; |
wire dmac_ack, dmac_stall; |
wire dc_cyc, dc_stb, dc_we, dc_ack, dc_stall; |
wire [31:0] dc_data; |
wire [(AW-1):0] dc_addr; |
wire [31:0] dc_data, dc_addr; |
wire cpu_gbl_cyc; |
assign dmac_stb = (sys_stb)&&(sys_addr[4]); |
wbdmac #(AW) dma_controller(i_clk, |
wbdmac dma_controller(i_clk, |
sys_cyc, dmac_stb, sys_we, |
sys_addr[1:0], sys_data, |
dmac_ack, dmac_stall, dmac_data, |
561,8 → 558,7
wire [31:0] cpu_dbg_data; |
assign cpu_dbg_we = ((dbg_cyc)&&(dbg_stb)&&(~cmd_addr[5]) |
&&(dbg_we)&&(dbg_addr)); |
zipcpu #(RESET_ADDRESS,ADDRESS_WIDTH,LGICACHE) |
thecpu(i_clk, cpu_reset, pic_interrupt, |
zipcpu #(RESET_ADDRESS) thecpu(i_clk, cpu_reset, pic_interrupt, |
cpu_halt, cmd_clear_pf_cache, cmd_addr[4:0], cpu_dbg_we, |
dbg_idata, cpu_dbg_stall, cpu_dbg_data, |
cpu_dbg_cc, cpu_break, |
616,9 → 612,8
wire ext_cyc, ext_stb, ext_we, ext_err; |
wire cpu_ext_ack, cpu_ext_stall, ext_ack, ext_stall, |
cpu_ext_err; |
wire [(AW-1):0] ext_addr; |
wire [31:0] ext_odata; |
wbpriarbiter #(32,AW) dmacvcpu(i_clk, i_rst, |
wire [31:0] ext_addr, ext_odata; |
wbpriarbiter #(32,32) dmacvcpu(i_clk, i_rst, |
cpu_gbl_cyc, cpu_gbl_stb, cpu_we, cpu_addr, cpu_data, |
cpu_ext_ack, cpu_ext_stall, cpu_ext_err, |
dc_cyc, dc_stb, dc_we, dc_addr, dc_data, |
627,7 → 622,7
ext_ack, ext_stall, ext_err); |
|
`ifdef DELAY_EXT_BUS |
busdelay #(AW,32) extbus(i_clk, |
busdelay #(32,32) extbus(i_clk, |
ext_cyc, ext_stb, ext_we, ext_addr, ext_odata, |
ext_ack, ext_stall, ext_idata, ext_err, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
/trunk/rtl/zipbones.v
42,19 → 42,18
// 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, ADDRESS_WIDTH=32, |
LGICACHE=6, START_HALTED=1, |
AW=ADDRESS_WIDTH; |
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 [(AW-1):0] o_wb_addr; |
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 i_ext_int; |
input [(EXTERNAL_INTERRUPTS-1):0] i_ext_int; |
// Outgoing interrupt |
output wire o_ext_int; |
// Wishbone slave |
69,7 → 68,7
// |
wire sys_cyc, sys_stb, sys_we; |
wire [4:0] sys_addr; |
wire [(AW-1):0] cpu_addr; |
wire [31:0] cpu_addr; |
wire [31:0] sys_data; |
wire sys_ack, sys_stall; |
|
139,7 → 138,7
// 0x01000 -> cc.sleep |
// 0x02000 -> cc.gie |
// 0x10000 -> External interrupt line is high |
assign cmd_data = { 7'h00, 8'h00, i_ext_int, |
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 }; |
157,8 → 156,7
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,ADDRESS_WIDTH,LGICACHE) |
thecpu(i_clk, cpu_reset, i_ext_int, |
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, |
/trunk/rtl/peripherals/wbdmac.v
113,8 → 113,7
i_dev_ints, |
o_interrupt, |
i_other_busmaster_requests_bus); |
parameter ADDRESS_WIDTH=32, LGMEMLEN = 10, |
DW=32, LGDV=5,AW=ADDRESS_WIDTH; |
parameter LGMEMLEN = 10, DW=32, LGDV=5; |
input i_clk; |
// Slave/control wishbone inputs |
input i_swb_cyc, i_swb_stb, i_swb_we; |
126,8 → 125,7
output reg [(DW-1):0] o_swb_data; |
// Master/DMA wishbone control |
output reg o_mwb_cyc, o_mwb_stb, o_mwb_we; |
output reg [(AW-1):0] o_mwb_addr; |
output reg [(DW-1):0] o_mwb_data; |
output reg [(DW-1):0] o_mwb_addr, o_mwb_data; |
// Master/DMA wishbone responses from the bus |
input i_mwb_ack, i_mwb_stall; |
input [(DW-1):0] i_mwb_data; |
142,7 → 140,7
|
reg cfg_wp; // Write protect |
reg cfg_err; |
reg [(AW-1):0] cfg_waddr, cfg_raddr, cfg_len; |
reg [(DW-1):0] cfg_waddr, cfg_raddr, cfg_len; |
reg [(LGMEMLEN-1):0] cfg_blocklen_sub_one; |
reg cfg_incs, cfg_incd; |
reg [(LGDV-1):0] cfg_dev_trigger; |
153,14 → 151,14
|
reg [(DW-1):0] dma_mem [0:(((1<<LGMEMLEN))-1)]; |
reg [(LGMEMLEN):0] nread, nwritten, nacks; |
wire [(AW-1):0] bus_nacks; |
assign bus_nacks = { {(AW-LGMEMLEN-1){1'b0}}, nacks }; |
wire [(DW-1):0] bus_nacks; |
assign bus_nacks = { {(DW-LGMEMLEN-1){1'b0}}, nacks }; |
|
initial o_interrupt = 1'b0; |
initial o_mwb_cyc = 1'b0; |
initial cfg_err = 1'b0; |
initial cfg_wp = 1'b0; |
initial cfg_len = {(AW){1'b0}}; |
initial cfg_len = 32'h00; |
initial cfg_blocklen_sub_one = {(LGMEMLEN){1'b1}}; |
initial cfg_on_dev_trigger = 1'b0; |
always @(posedge i_clk) |
273,9 → 271,9
cfg_incd <= ~i_swb_data[28]; |
cfg_err <= 1'b0; |
end |
2'b01: cfg_len <= i_swb_data[(AW-1):0]; |
2'b10: cfg_raddr <= i_swb_data[(AW-1):0]; |
2'b11: cfg_waddr <= i_swb_data[(AW-1):0]; |
2'b01: cfg_len <= i_swb_data; |
2'b10: cfg_raddr <= i_swb_data; |
2'b11: cfg_waddr <= i_swb_data; |
endcase |
end |
end |
313,9 → 311,9
cfg_on_dev_trigger, cfg_dev_trigger, |
cfg_blocklen_sub_one |
}; |
2'b01: o_swb_data <= { {(DW-AW){1'b0}}, cfg_len }; |
2'b10: o_swb_data <= { {(DW-AW){1'b0}}, cfg_raddr}; |
2'b11: o_swb_data <= { {(DW-AW){1'b0}}, cfg_waddr}; |
2'b01: o_swb_data <= cfg_len; |
2'b10: o_swb_data <= cfg_raddr; |
2'b11: o_swb_data <= cfg_waddr; |
endcase |
|
always @(posedge i_clk) |
/trunk/rtl/peripherals/zipport.v
0,0 → 1,129
/////////////////////////////////////////////////////////////////////////// |
// |
// Filename: zipport.v |
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core |
// |
// Purpose: A communications port for passing data between CPU's in a |
// multi-cpu system. |
// |
// Example: Imagine a signal processing system with many 'CPUs' working |
// together. Each communicates its outputs to the next CPU. |
// Writes to this port will send values to the next port over, |
// and reads from this port will read such values. |
// |
// These ports are ripe for adding FIFO's too, but the port |
// itself doesn't offer a FIFO. Worse, as written, the port |
// offers no flags to a FIFO to know when to read the next |
// value. |
// |
// Note: There are other means of message passing, this is just |
// one--perhaps not even the best one. |
// |
// Interface: |
// 2-bits of control: |
// top bit means valid data that hasn't been read. |
// next bit means data has not been read, but instead has been |
// lost |
// These statuses are cleared upon any read. |
// 30-bits of data. |
// |
// External CPU: |
// Can read/write to the port. |
// Writes to the port take place by setting i_port_v and strobing i_port_w. |
// Writes from this port to other ports take place the same way. |
// Reads/writes to/from this port by the CPU take place via the single |
// wishbone address. |
// |
// |
// 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 zipport(i_clk, |
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data, |
o_wb_ack, o_wb_stall, o_wb_data, |
i_port_w, i_port_v, |
o_port_w, o_port_v, |
o_int_full, o_int_ovflw); |
parameter BW = 32, DW = (BW-2); |
input i_clk; |
// Wishbone inputs |
input i_wb_cyc, i_wb_stb, i_wb_we; |
input [(BW-1):0] i_wb_data; |
// Wishbone outputs |
output reg o_wb_ack; |
output wire o_wb_stall; |
output wire [(BW-1):0] o_wb_data; |
// Port connections |
input i_port_w; // Write strobe |
input [(DW-1):0] i_port_v; // Value received |
output reg o_port_w; // Writing strobe |
output reg [(BW-1):0] o_port_v; // Value being sent |
// Interrupt line |
output wire o_int_full, o_int_ovflw; |
|
wire wb_write, wb_read, wb_cycle; |
assign wb_write = (i_wb_cyc)&&(i_wb_stb)&&(i_wb_we); |
assign wb_read = (i_wb_cyc)&&(i_wb_stb)&&(~i_wb_we); |
assign wb_cycle = (i_wb_cyc)&&(i_wb_stb); |
|
reg r_valid, r_ovflw; |
reg [(DW-1):0] r_data; |
|
initial r_valid = 1'b0; |
initial r_ovflw = 1'b0; |
always @(posedge i_clk) |
if (wb_write) |
begin |
o_port_w <= 1'b1; |
o_port_v <= i_wb_data; |
end else |
o_port_w <= 1'b0; |
|
always @(posedge i_clk) |
if (i_port_w) |
r_valid <= 1'b1; |
else if (wb_read) |
r_valid <= 1'b0; |
|
always @(posedge i_clk) |
if (i_port_w) |
r_ovflw <= (r_valid); |
else if (wb_read) |
r_ovflw <= 1'b0; |
|
always @(posedge i_clk) |
if (i_port_w) |
r_data <= i_port_v; |
|
assign o_int_full = r_valid; |
assign o_int_ovflw= r_ovflw; |
|
initial o_wb_ack = 1'b0; |
always @(posedge i_clk) |
o_wb_ack <= wb_cycle; |
assign o_wb_stall = 1'b0; |
|
assign o_wb_data = { r_valid, r_ovflw, {(BW-2-DW){1'b0}}, r_data }; |
|
endmodule |