| 1 |
195 |
dgisselq |
////////////////////////////////////////////////////////////////////////////////
|
| 2 |
2 |
dgisselq |
//
|
| 3 |
|
|
// Filename: busdelay.v
|
| 4 |
|
|
//
|
| 5 |
|
|
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
|
| 6 |
|
|
//
|
| 7 |
|
|
// Purpose: Delay any access to the wishbone bus by a single clock.
|
| 8 |
|
|
//
|
| 9 |
|
|
// When the first Zip System would not meet the timing requirements of
|
| 10 |
|
|
// the board it was placed upon, this bus delay was added to help out.
|
| 11 |
|
|
// It may no longer be necessary, having cleaned some other problems up
|
| 12 |
|
|
// first, but it will remain here as a means of alleviating timing
|
| 13 |
|
|
// problems.
|
| 14 |
|
|
//
|
| 15 |
|
|
// The specific problem takes place on the stall line: a wishbone master
|
| 16 |
|
|
// *must* know on the first clock whether or not the bus will stall.
|
| 17 |
|
|
//
|
| 18 |
|
|
//
|
| 19 |
195 |
dgisselq |
// After a period of time, I started a new design where the timing
|
| 20 |
|
|
// associated with this original bus clock just wasn't ... fast enough.
|
| 21 |
|
|
// I needed to delay the stall line as well. A new busdelay was then
|
| 22 |
|
|
// written and debugged whcih delays the stall line. (I know, you aren't
|
| 23 |
|
|
// supposed to delay the stall line--but what if you *have* to in order
|
| 24 |
|
|
// to meet timing?) This new logic has been merged in with the old,
|
| 25 |
|
|
// and the DELAY_STALL line can be set to non-zero to use it instead
|
| 26 |
|
|
// of the original logic. Don't use it if you don't need it: it will
|
| 27 |
|
|
// consume resources and slow your bus down more, but if you do need
|
| 28 |
|
|
// it--don't be afraid to use it.
|
| 29 |
2 |
dgisselq |
//
|
| 30 |
195 |
dgisselq |
// Both versions of the bus delay will maintain a single access per
|
| 31 |
|
|
// clock when pipelined, they only delay the time between the strobe
|
| 32 |
|
|
// going high and the actual command being accomplished.
|
| 33 |
2 |
dgisselq |
//
|
| 34 |
195 |
dgisselq |
//
|
| 35 |
2 |
dgisselq |
// Creator: Dan Gisselquist, Ph.D.
|
| 36 |
69 |
dgisselq |
// Gisselquist Technology, LLC
|
| 37 |
2 |
dgisselq |
//
|
| 38 |
195 |
dgisselq |
////////////////////////////////////////////////////////////////////////////////
|
| 39 |
2 |
dgisselq |
//
|
| 40 |
201 |
dgisselq |
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
|
| 41 |
2 |
dgisselq |
//
|
| 42 |
|
|
// This program is free software (firmware): you can redistribute it and/or
|
| 43 |
|
|
// modify it under the terms of the GNU General Public License as published
|
| 44 |
|
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
| 45 |
|
|
// your option) any later version.
|
| 46 |
|
|
//
|
| 47 |
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
| 48 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
| 49 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
| 50 |
|
|
// for more details.
|
| 51 |
|
|
//
|
| 52 |
201 |
dgisselq |
// You should have received a copy of the GNU General Public License along
|
| 53 |
|
|
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
|
| 54 |
|
|
// target there if the PDF file isn't present.) If not, see
|
| 55 |
|
|
// <http://www.gnu.org/licenses/> for a copy.
|
| 56 |
|
|
//
|
| 57 |
2 |
dgisselq |
// License: GPL, v3, as defined and found on www.gnu.org,
|
| 58 |
|
|
// http://www.gnu.org/licenses/gpl.html
|
| 59 |
|
|
//
|
| 60 |
|
|
//
|
| 61 |
195 |
dgisselq |
////////////////////////////////////////////////////////////////////////////////
|
| 62 |
2 |
dgisselq |
//
|
| 63 |
201 |
dgisselq |
//
|
| 64 |
2 |
dgisselq |
module busdelay(i_clk,
|
| 65 |
|
|
// The input bus
|
| 66 |
201 |
dgisselq |
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
|
| 67 |
36 |
dgisselq |
o_wb_ack, o_wb_stall, o_wb_data, o_wb_err,
|
| 68 |
2 |
dgisselq |
// The delayed bus
|
| 69 |
201 |
dgisselq |
o_dly_cyc, o_dly_stb, o_dly_we, o_dly_addr,o_dly_data,o_dly_sel,
|
| 70 |
36 |
dgisselq |
i_dly_ack, i_dly_stall, i_dly_data, i_dly_err);
|
| 71 |
195 |
dgisselq |
parameter AW=32, DW=32, DELAY_STALL = 0;
|
| 72 |
2 |
dgisselq |
input i_clk;
|
| 73 |
|
|
// Input/master bus
|
| 74 |
|
|
input i_wb_cyc, i_wb_stb, i_wb_we;
|
| 75 |
|
|
input [(AW-1):0] i_wb_addr;
|
| 76 |
|
|
input [(DW-1):0] i_wb_data;
|
| 77 |
201 |
dgisselq |
input [(DW/8-1):0] i_wb_sel;
|
| 78 |
2 |
dgisselq |
output reg o_wb_ack;
|
| 79 |
|
|
output wire o_wb_stall;
|
| 80 |
|
|
output reg [(DW-1):0] o_wb_data;
|
| 81 |
36 |
dgisselq |
output wire o_wb_err;
|
| 82 |
2 |
dgisselq |
// Delayed bus
|
| 83 |
|
|
output reg o_dly_cyc, o_dly_stb, o_dly_we;
|
| 84 |
|
|
output reg [(AW-1):0] o_dly_addr;
|
| 85 |
|
|
output reg [(DW-1):0] o_dly_data;
|
| 86 |
201 |
dgisselq |
output reg [(DW/8-1):0] o_dly_sel;
|
| 87 |
2 |
dgisselq |
input i_dly_ack;
|
| 88 |
|
|
input i_dly_stall;
|
| 89 |
|
|
input [(DW-1):0] i_dly_data;
|
| 90 |
36 |
dgisselq |
input i_dly_err;
|
| 91 |
2 |
dgisselq |
|
| 92 |
195 |
dgisselq |
generate
|
| 93 |
|
|
if (DELAY_STALL != 0)
|
| 94 |
|
|
begin
|
| 95 |
|
|
reg r_stb, r_we, r_rtn_stall, r_rtn_err;
|
| 96 |
201 |
dgisselq |
reg [(AW-1):0] r_addr;
|
| 97 |
195 |
dgisselq |
reg [(DW-1):0] r_data;
|
| 98 |
201 |
dgisselq |
reg [(DW/8-1):0] r_sel;
|
| 99 |
2 |
dgisselq |
|
| 100 |
195 |
dgisselq |
initial o_dly_cyc = 1'b0;
|
| 101 |
|
|
initial r_rtn_stall= 1'b0;
|
| 102 |
|
|
initial r_stb = 1'b0;
|
| 103 |
|
|
always @(posedge i_clk)
|
| 104 |
|
|
begin
|
| 105 |
|
|
o_dly_cyc <= (i_wb_cyc);
|
| 106 |
|
|
|
| 107 |
|
|
if (!i_dly_stall)
|
| 108 |
|
|
begin
|
| 109 |
|
|
r_we <= i_wb_we;
|
| 110 |
|
|
r_addr <= i_wb_addr;
|
| 111 |
|
|
r_data <= i_wb_data;
|
| 112 |
201 |
dgisselq |
r_sel <= i_wb_sel;
|
| 113 |
2 |
dgisselq |
|
| 114 |
195 |
dgisselq |
if (r_stb)
|
| 115 |
|
|
begin
|
| 116 |
|
|
o_dly_we <= r_we;
|
| 117 |
|
|
o_dly_addr <= r_addr;
|
| 118 |
|
|
o_dly_data <= r_data;
|
| 119 |
201 |
dgisselq |
o_dly_sel <= r_sel;
|
| 120 |
195 |
dgisselq |
o_dly_stb <= 1'b1;
|
| 121 |
|
|
r_rtn_stall <= 1'b0;
|
| 122 |
|
|
r_stb <= 1'b0;
|
| 123 |
|
|
end else begin
|
| 124 |
|
|
o_dly_we <= i_wb_we;
|
| 125 |
|
|
o_dly_addr <= i_wb_addr;
|
| 126 |
|
|
o_dly_data <= i_wb_data;
|
| 127 |
201 |
dgisselq |
o_dly_sel <= i_wb_sel;
|
| 128 |
195 |
dgisselq |
o_dly_stb <= i_wb_stb;
|
| 129 |
|
|
r_stb <= 1'b0;
|
| 130 |
|
|
r_rtn_stall <= 1'b0;
|
| 131 |
|
|
end
|
| 132 |
|
|
end else if ((!r_stb)&&(!o_wb_stall))
|
| 133 |
|
|
begin
|
| 134 |
|
|
r_we <= i_wb_we;
|
| 135 |
|
|
r_addr <= i_wb_addr;
|
| 136 |
|
|
r_data <= i_wb_data;
|
| 137 |
201 |
dgisselq |
r_sel <= i_wb_sel;
|
| 138 |
195 |
dgisselq |
r_stb <= i_wb_stb;
|
| 139 |
2 |
dgisselq |
|
| 140 |
195 |
dgisselq |
r_rtn_stall <= i_wb_stb;
|
| 141 |
|
|
end
|
| 142 |
|
|
|
| 143 |
|
|
if (!i_wb_cyc)
|
| 144 |
|
|
begin
|
| 145 |
|
|
o_dly_stb <= 1'b0;
|
| 146 |
|
|
r_stb <= 1'b0;
|
| 147 |
|
|
r_rtn_stall <= 1'b0;
|
| 148 |
|
|
end
|
| 149 |
|
|
|
| 150 |
|
|
o_wb_ack <= (i_dly_ack)&&(i_wb_cyc)&&(o_dly_cyc);
|
| 151 |
|
|
o_wb_data <= i_dly_data;
|
| 152 |
|
|
r_rtn_err <= (i_dly_err)&&(i_wb_cyc)&&(o_dly_cyc);
|
| 153 |
|
|
end
|
| 154 |
|
|
|
| 155 |
|
|
assign o_wb_stall = r_rtn_stall;
|
| 156 |
|
|
assign o_wb_err = r_rtn_err;
|
| 157 |
|
|
|
| 158 |
|
|
end else begin
|
| 159 |
|
|
|
| 160 |
|
|
initial o_dly_cyc = 1'b0;
|
| 161 |
|
|
initial o_dly_stb = 1'b0;
|
| 162 |
|
|
|
| 163 |
|
|
always @(posedge i_clk)
|
| 164 |
|
|
o_dly_cyc <= i_wb_cyc;
|
| 165 |
|
|
// Add the i_wb_cyc criteria here, so we can simplify the
|
| 166 |
|
|
// o_wb_stall criteria below, which would otherwise *and*
|
| 167 |
|
|
// these two.
|
| 168 |
|
|
always @(posedge i_clk)
|
| 169 |
|
|
if (~o_wb_stall)
|
| 170 |
|
|
o_dly_stb <= ((i_wb_cyc)&&(i_wb_stb));
|
| 171 |
|
|
always @(posedge i_clk)
|
| 172 |
|
|
if (~o_wb_stall)
|
| 173 |
|
|
o_dly_we <= i_wb_we;
|
| 174 |
|
|
always @(posedge i_clk)
|
| 175 |
|
|
if (~o_wb_stall)
|
| 176 |
|
|
o_dly_addr<= i_wb_addr;
|
| 177 |
|
|
always @(posedge i_clk)
|
| 178 |
|
|
if (~o_wb_stall)
|
| 179 |
|
|
o_dly_data <= i_wb_data;
|
| 180 |
|
|
always @(posedge i_clk)
|
| 181 |
201 |
dgisselq |
if (~o_wb_stall)
|
| 182 |
|
|
o_dly_sel <= i_wb_sel;
|
| 183 |
|
|
always @(posedge i_clk)
|
| 184 |
195 |
dgisselq |
o_wb_ack <= (i_dly_ack)&&(o_dly_cyc)&&(i_wb_cyc);
|
| 185 |
|
|
always @(posedge i_clk)
|
| 186 |
|
|
o_wb_data <= i_dly_data;
|
| 187 |
|
|
|
| 188 |
|
|
// Our only non-delayed line, yet still really delayed. Perhaps
|
| 189 |
|
|
// there's a way to register this?
|
| 190 |
|
|
// o_wb_stall <= (i_wb_cyc)&&(i_wb_stb) ... or some such?
|
| 191 |
|
|
// assign o_wb_stall=((i_wb_cyc)&&(i_dly_stall)&&(o_dly_stb));//&&o_cyc
|
| 192 |
|
|
assign o_wb_stall = ((i_dly_stall)&&(o_dly_stb));//&&o_cyc
|
| 193 |
|
|
assign o_wb_err = i_dly_err;
|
| 194 |
|
|
end endgenerate
|
| 195 |
|
|
|
| 196 |
2 |
dgisselq |
endmodule
|