URL
https://opencores.org/ocsvn/wbscope/wbscope/trunk
Subversion Repositories wbscope
Compare Revisions
- This comparison shows the changes necessary to convert path
/wbscope
- from Rev 13 to Rev 14
- ↔ Reverse comparison
Rev 13 → Rev 14
/trunk/README.md
3,7 → 3,8
This is a generic/library routine for providing a bus accessed 'scope' or |
(perhaps more appropriately) a bus accessed logic analyzer for use internal to |
an FPGA. The general operation is such that this 'scope' can record and report |
on any 32 bit value transiting through the FPGA. Once started and reset, the |
on any 32 bit value transiting through the FPGA that you have connected to the |
scope. Once started and reset, the |
scope records a copy of the input data every time the clock ticks with the |
circuit enabled. That is, it records these values up until the trigger. Once |
the trigger goes high, the scope will record for ``bw_holdoff`` more counts |
16,7 → 17,7
2. Recording starts, in a circular buffer, and continues until |
3. The trigger line is asserted. |
The scope registers the asserted trigger by setting the ``o_triggered`` output flag. |
4. A counter then ticks until the last value is written. |
4. A counter then ticks until the last value is written. |
The scope registers that it has stopped recording by setting the ``o_stopped`` output flag. |
5. The scope recording is then paused until the next reset. |
6. While stopped, the CPU can read the data from the scope |
23,10 → 24,31
|
- oldest to most recent |
- one value per bus clock |
|
|
7. Writes to the data register reset the address to the beginning of the buffer |
|
# Tutorials |
|
The Wishbone scope was featured on [zipcpu.com](http://zipcpu.com) as [a |
conclusion](http://zipcpu.com/blog/2017/07/08/getting-started-with-wbscope.html) |
to the discussion of the example [debugging |
bus](https://github.com/ZipCPU/dbgbus/tree/master/hexbus). |
That example discussed how to hook up the scope to your logic, as well as how |
to employ the [scope software](sw/scopecls.cpp) to create a VCD file |
that could then be viewed in GTKWave. |
The scope was also mentioned as a means of capturing [traces of button |
bounces](http://zipcpu.com/blog/2017/08/02/debounce-teaser.html), |
with the short discussion of how to set it up for that task |
[here](http://zipcpu.com/blog/2017/08/07/bounce-dbgbus.html). |
|
# Interfaces supported |
|
1. [Wishbone B4/pipelined](rtl/wbscope.v) |
2. [AXI lite](rtl/axi4lscope.v) |
3. [Avalon](rtl/avscope.v) |
|
# Commercial Applications |
|
Should you find the GPLv3 license insufficient for your needs, other licenses |
can be purchased from Gisselquist Technology, LLC. |
can be purchased from [Gisselquist Technology, |
LLC](http://zipcpu.com/about/gisselquist-technology.html). |
/trunk/bench/rtl/wbscope_tb.v
8,8 → 8,8
// designed to create a "signal" which can then be scoped and |
// proven. In our case here, the "signal" is a counter. When we test |
// the scope within our bench/cpp Verilator testbench, we'll know if our |
// test was "correct" if the counter 1) only ever counts by 1, and 2) if |
// the trigger lands on thte right data sample. |
// test was "correct" if the counter 1) only ever increments by 1, and |
// 2) if the trigger lands on thte right data sample. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
40,6 → 40,8
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
`default_nettype none |
// |
module wbscope_tb(i_clk, |
// i_rst is required by our test infrastructure, yet unused here |
i_rst, |
52,18 → 54,18
o_wb_ack, o_wb_stall, o_wb_data, |
// And our output interrupt |
o_interrupt); |
input i_clk, i_rst, i_trigger; |
input wire i_clk, i_rst, i_trigger; |
output wire [31:0] o_data; |
// |
input i_wb_cyc, i_wb_stb, i_wb_we; |
input i_wb_addr; |
input [31:0] i_wb_data; |
input wire i_wb_cyc, i_wb_stb, i_wb_we; |
input wire i_wb_addr; |
input wire [31:0] i_wb_data; |
// |
output wire o_wb_ack; |
output wire o_wb_stall; |
output wire [31:0] o_wb_data; |
// |
output o_interrupt; |
output wire o_interrupt; |
|
reg [30:0] counter; |
initial counter = 0; |
/trunk/rtl/axi4lscope.v
68,7 → 68,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2017, Gisselquist Technology, LLC |
// Copyright (C) 2015-2018, 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 |
187,13 → 187,11
// AXI4LITE signals |
reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr; |
reg axi_awready; |
reg axi_wready; |
// reg [1 : 0] axi_bresp; |
reg axi_bvalid; |
reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr; |
reg axi_arready; |
// reg [1 : 0] axi_rresp; |
reg axi_rvalid; |
|
|
wire write_stb; |
214,74 → 212,67
// Gisselquist Technology, LLC, claims no copyright |
// or ownership of this section of the code. |
// |
wire i_reset; |
wire i_reset, axi_bstall, axi_rstall; |
assign i_reset = !S_AXI_ARESETN; |
|
always @(posedge S_AXI_ACLK) |
if (i_reset) |
axi_awready <= 1'b0; |
else if ((!axi_awready)&&(S_AXI_AWVALID)&&(S_AXI_WVALID)) |
axi_awready <= 1'b1; |
else |
axi_awready <= 1'b0; |
always @(*) |
if ((!axi_bstall)&&(S_AXI_AWVALID)&&(S_AXI_WVALID)) |
axi_awready <= 1'b1; |
else |
axi_awready <= 1'b0; |
assign S_AXI_AWREADY = axi_awready; |
assign S_AXI_WREADY = axi_awready; |
|
always @(posedge S_AXI_ACLK) |
if ((!axi_awready)&&(S_AXI_AWVALID)&&(S_AXI_WVALID)) |
axi_awaddr <= S_AXI_AWADDR; |
if ((S_AXI_AWVALID)&&(S_AXI_AWREADY)) |
axi_awaddr <= S_AXI_AWADDR; |
|
initial axi_bvalid = 0; |
always @(posedge S_AXI_ACLK) |
if (i_reset) |
axi_wready <= 1'b0; |
else if ((!axi_wready)&&(S_AXI_WVALID)&&(S_AXI_AWVALID)) |
axi_wready <= 1'b1; |
else |
axi_wready <= 1'b0; |
assign S_AXI_WREADY = axi_wready; |
|
always @(posedge S_AXI_ACLK) |
if (i_reset) |
begin |
axi_bvalid <= 0; |
// axi_bresp <= 2'b00; |
end else if ((~axi_bvalid)&&(write_stb)) |
begin |
axi_bvalid <= 1'b1; |
// axi_bresp <= 2'b00; // 'Okay' response |
end else if ((S_AXI_BREADY)&&(axi_bvalid)) |
axi_bvalid <= 1'b0; |
if (i_reset) |
axi_bvalid <= 0; |
else if (write_stb) |
axi_bvalid <= 1'b1; |
else if (S_AXI_BREADY) |
axi_bvalid <= 1'b0; |
assign S_AXI_BRESP = 2'b00; // An 'OKAY' response |
assign S_AXI_BVALID= axi_bvalid; |
|
assign axi_bstall = (S_AXI_BVALID)&&(!S_AXI_BREADY); |
|
|
always @(*) |
if (i_reset) |
axi_arready = 1'b0; |
else if (axi_rstall) |
axi_arready = 1'b0; |
else |
axi_arready = 1'b1; |
|
always @(posedge S_AXI_ACLK) |
if (i_reset) |
begin |
axi_arready <= 1'b0; |
axi_araddr <= 0; |
end else if ((!axi_arready)&&(S_AXI_ARVALID)) |
begin |
axi_arready <= 1'b1; |
axi_araddr <= S_AXI_ARADDR; |
end else |
axi_arready <= 1'b0; |
if (i_reset) |
axi_araddr <= 0; |
else if ((axi_arready)&&(S_AXI_ARVALID)) |
axi_araddr <= S_AXI_ARADDR; |
|
assign S_AXI_ARREADY = axi_arready; |
|
reg [1:0] rvalid; |
initial rvalid = 2'b00; |
always @(posedge S_AXI_ACLK) |
if (i_reset) |
begin |
axi_rvalid <= 0; |
// axi_rresp <= 0; |
end else if ((axi_arready)&&(S_AXI_ARVALID)&&(!axi_rvalid)) |
begin |
axi_rvalid <= 1'b0; |
// axi_rresp <= 2'b00; |
end else if ((axi_rvalid)&&(S_AXI_RREADY)) |
axi_rvalid <= 1'b0; |
assign S_AXI_RVALID = axi_rvalid; |
if (i_reset) |
rvalid <= 2'b00; |
else if ((axi_arready)&&(S_AXI_ARVALID)) |
rvalid <= 2'b01; |
else if (rvalid == 2'b01) |
rvalid <= 2'b10; |
else if (S_AXI_RREADY) |
rvalid <= 2'b00; |
|
assign S_AXI_RVALID = rvalid[1]; |
assign S_AXI_RRESP = 2'b00; |
|
assign axi_rstall = ((rvalid[0])||(S_AXI_RVALID)&&(!S_AXI_RREADY)); |
|
|
|
314,12 → 305,13
&&(axi_araddr[0]); |
|
assign write_stb = ((axi_awready)&&(S_AXI_AWVALID) |
&&(axi_wready)&&(S_AXI_WVALID)); |
&&(S_AXI_WVALID)); |
wire write_to_control; |
assign write_to_control = (write_stb)&&(!axi_awaddr[0]); |
|
reg read_address; |
always @(posedge bus_clock) |
if ((axi_arready)&&(S_AXI_ARVALID)) |
read_address <= axi_araddr[0]; |
|
wire [31:0] i_wb_data; |
352,14 → 344,14
initial br_config = 3'b0; |
initial br_holdoff = DEFAULT_HOLDOFF; |
always @(posedge bus_clock) |
if (write_to_control) |
begin |
br_config <= { i_wb_data[31], |
i_wb_data[27], |
i_wb_data[26] }; |
br_holdoff <= i_wb_data[(HOLDOFFBITS-1):0]; |
end else if (bw_reset_complete) |
br_config[2] <= 1'b1; |
if (write_to_control) |
begin |
br_config <= { i_wb_data[31], |
i_wb_data[27], |
i_wb_data[26] }; |
br_holdoff <= i_wb_data[(HOLDOFFBITS-1):0]; |
end else if (bw_reset_complete) |
br_config[2] <= 1'b1; |
assign bw_reset_request = (!br_config[2]); |
assign bw_manual_trigger = (br_config[1]); |
assign bw_disable_trigger = (br_config[0]); |
379,7 → 371,7
|
// Resets are synchronous to the bus clock, not the data clock |
// so do a clock transfer here |
initial q_iflags = 3'b000; |
initial { q_iflags, r_iflags } = 6'h0; |
initial r_reset_complete = 1'b0; |
always @(posedge i_data_clk) |
begin |
405,6 → 397,15
end |
|
assign bw_reset_complete = qq_reset_complete; |
|
`ifdef FORMAL |
always @($global_clock) |
if (f_past_valid_data) |
begin |
if ($rose(r_reset_complete)) |
assert(bw_reset_request); |
end |
`endif |
end endgenerate |
|
// |
420,10 → 421,10
||(dw_manual_trigger)); |
initial dr_triggered = 1'b0; |
always @(posedge i_data_clk) |
if (dw_reset) |
dr_triggered <= 1'b0; |
else if ((i_ce)&&(dw_trigger)) |
dr_triggered <= 1'b1; |
if (dw_reset) |
dr_triggered <= 1'b0; |
else if ((i_ce)&&(dw_trigger)) |
dr_triggered <= 1'b1; |
|
// |
// Determine when memory is full and capture is complete |
436,19 → 437,18
initial dr_stopped = 1'b0; |
initial counter = 0; |
always @(posedge i_data_clk) |
if (dw_reset) |
counter <= 0; |
else if ((i_ce)&&(dr_triggered)&&(!dr_stopped)) |
begin |
counter <= counter + 1'b1; |
end |
if (dw_reset) |
counter <= 0; |
else if ((i_ce)&&(dr_triggered)&&(!dr_stopped)) |
counter <= counter + 1'b1; |
|
always @(posedge i_data_clk) |
if ((!dr_triggered)||(dw_reset)) |
dr_stopped <= 1'b0; |
else if (HOLDOFFBITS > 1) // if (i_ce) |
dr_stopped <= (counter >= br_holdoff); |
else if (HOLDOFFBITS <= 1) |
dr_stopped <= ((i_ce)&&(dw_trigger)); |
if ((!dr_triggered)||(dw_reset)) |
dr_stopped <= 1'b0; |
else if (HOLDOFFBITS > 1) // if (i_ce) |
dr_stopped <= (counter >= br_holdoff); |
else if (HOLDOFFBITS <= 1) |
dr_stopped <= ((i_ce)&&(dw_trigger)); |
|
// |
// Actually do our writes to memory. Record, via 'primed' when |
464,23 → 464,23
initial waddr = {(LGMEM){1'b0}}; |
initial dr_primed = 1'b0; |
always @(posedge i_data_clk) |
if (dw_reset) // For simulation purposes, supply a valid value |
if (dw_reset) // For simulation purposes, supply a valid value |
begin |
waddr <= 0; // upon reset. |
dr_primed <= 1'b0; |
end else if ((i_ce)&&(!dr_stopped)) |
begin |
// mem[waddr] <= i_data; |
waddr <= waddr + {{(LGMEM-1){1'b0}},1'b1}; |
if (!dr_primed) |
begin |
waddr <= 0; // upon reset. |
dr_primed <= 1'b0; |
end else if ((i_ce)&&(!dr_stopped)) |
begin |
// mem[waddr] <= i_data; |
waddr <= waddr + {{(LGMEM-1){1'b0}},1'b1}; |
if (!dr_primed) |
begin |
//if (br_holdoff[(HOLDOFFBITS-1):LGMEM]==0) |
// dr_primed <= (waddr >= br_holdoff[(LGMEM-1):0]); |
// else |
|
dr_primed <= (&waddr); |
end |
//if (br_holdoff[(HOLDOFFBITS-1):LGMEM]==0) |
// dr_primed <= (waddr >= br_holdoff[(LGMEM-1):0]); |
// else |
|
dr_primed <= (&waddr); |
end |
end |
|
// Delay the incoming data so that we can get our trigger |
// logic to line up with the data. The goal is to have a |
551,6 → 551,7
end endgenerate |
|
// Reads use the bus clock |
initial raddr = 0; |
always @(posedge bus_clock) |
begin |
if ((bw_reset_request)||(write_to_control)) |
561,13 → 562,14
|
reg [(LGMEM-1):0] this_addr; |
always @(posedge bus_clock) |
if (read_from_data) |
this_addr <= raddr + waddr + 1'b1; |
else |
this_addr <= raddr + waddr; |
if ((bw_stopped)&&(read_from_data)) |
this_addr <= raddr + waddr + 1'b1; |
else |
this_addr <= raddr + waddr; |
|
reg [31:0] nxt_mem; |
always @(posedge bus_clock) |
if (read_from_data) |
nxt_mem <= mem[this_addr]; |
|
wire [19:0] full_holdoff; |
580,6 → 582,8
wire [4:0] bw_lgmem; |
assign bw_lgmem = LGMEM; |
always @(posedge bus_clock) |
if (rvalid[0]) |
begin |
if (!read_address) // Control register read |
o_bus_data <= { bw_reset_request, |
bw_stopped, |
594,6 → 598,7
o_bus_data <= i_data; |
else // if (i_wb_addr) // Read from FIFO memory |
o_bus_data <= nxt_mem; // mem[raddr+waddr]; |
end |
|
assign S_AXI_RDATA = o_bus_data; |
|
602,10 → 607,10
assign o_interrupt = (bw_stopped)&&(!bw_disable_trigger) |
&&(!br_level_interrupt); |
always @(posedge bus_clock) |
if ((bw_reset_complete)||(bw_reset_request)) |
br_level_interrupt<= 1'b0; |
else |
br_level_interrupt<= (bw_stopped)&&(!bw_disable_trigger); |
if ((bw_reset_complete)||(bw_reset_request)) |
br_level_interrupt<= 1'b0; |
else |
br_level_interrupt<= (bw_stopped)&&(!bw_disable_trigger); |
|
// verilator lint_off UNUSED |
// Make verilator happy |
614,4 → 619,220
axi_awaddr[3:1], axi_araddr[3:1], |
i_wb_data[30:28], i_wb_data[25:0] }; |
// verilator lint_on UNUSED |
`ifdef FORMAL |
generate if (SYNCHRONOUS) |
begin |
|
always @(*) |
assume(i_data_clk == S_AXI_ACLK); |
|
end else begin |
localparam CKSTEP_BITS = 3; |
localparam [CKSTEP_BITS-1:0] |
MAX_STEP = { 1'b0, {(CKSTEP_BITS-1){1'b1}} }; |
|
// "artificially" generate two clocks |
`ifdef VERIFIC |
(* gclk *) wire gbl_clock; |
global clocking @(posedge gbl_clock); endclocking |
`endif |
|
(* anyconst *) wire [CKSTEP_BITS-1:0] f_data_step, f_bus_step; |
reg [CKSTEP_BITS-1:0] f_data_count, f_bus_count; |
|
always @(*) |
begin |
assume(f_data_step > 0); |
assume(f_bus_step > 0); |
assume(f_data_step <= MAX_STEP); |
assume(f_bus_step <= MAX_STEP); |
|
assume((f_data_step == MAX_STEP) |
||(f_bus_step == MAX_STEP)); |
end |
|
always @($global_clock) |
begin |
f_data_count <= f_data_count + f_data_step; |
f_bus_count <= f_bus_count + f_bus_step; |
|
assume(i_data_clk == f_data_count[CKSTEP_BITS-1]); |
assume(bus_clock == f_bus_count[CKSTEP_BITS-1]); |
end |
|
always @($global_clock) |
if (!$rose(i_data_clk)) |
begin |
assume($stable(i_trigger)); |
assume($stable(i_data)); |
end |
|
always @($global_clock) |
if (!$rose(S_AXI_ACLK)) |
begin |
assume($stable(S_AXI_ARESETN)); |
// |
assume($stable(S_AXI_AWADDR)); |
assume($stable(S_AXI_AWPROT)); |
assume($stable(S_AXI_AWVALID)); |
// |
assume($stable(S_AXI_WDATA)); |
assume($stable(S_AXI_WSTRB)); |
assume($stable(S_AXI_WVALID)); |
// |
assume($stable(S_AXI_BREADY)); |
// |
assume($stable(S_AXI_ARADDR)); |
assume($stable(S_AXI_ARPROT)); |
assume($stable(S_AXI_ARVALID)); |
// |
assume($stable(S_AXI_RREADY)); |
// |
end |
|
end endgenerate |
|
reg f_past_valid_bus, f_past_valid_gbl, f_past_valid_data; |
initial { f_past_valid_bus, f_past_valid_gbl, f_past_valid_data }= 3'b0; |
always @(posedge S_AXI_ACLK) |
f_past_valid_bus = 1'b1; |
|
generate if (!SYNCHRONOUS) |
begin |
always @($global_clock) |
f_past_valid_gbl <= 1'b1; |
|
always @(posedge i_data_clk) |
f_past_valid_data = 1'b1; |
|
always @(posedge i_data_clk) |
if (f_past_valid_data) |
assert($stable(o_interrupt)); |
|
always @($global_clock) |
if ((f_past_valid_gbl)&&(!$rose(S_AXI_ACLK))) |
begin |
assert($stable(S_AXI_AWREADY)); |
assert($stable(S_AXI_ARREADY)); |
assert($stable(S_AXI_RDATA)); |
assert($stable(S_AXI_RRESP)); |
assert($stable(S_AXI_RVALID)); |
assert($stable(S_AXI_WREADY)); |
assert($stable(S_AXI_BRESP)); |
assert($stable(S_AXI_BVALID)); |
end |
|
end else begin |
|
always @(*) |
f_past_valid_data = f_past_valid_bus; |
always @(*) |
f_past_valid_gbl = f_past_valid_bus; |
|
end endgenerate |
|
localparam F_LGDEPTH = 5; |
wire [F_LGDEPTH-1:0] f_axi_rd_outstanding, |
f_axi_wr_outstanding, |
f_axi_awr_outstanding; |
|
faxil_slave #( |
// .C_S_AXI_DATA_WIDth(C_S_AXI_DATA_WIDTH), |
// Width of S_AXI address bus |
.C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH), |
.F_LGDEPTH(F_LGDEPTH), |
.F_OPT_HAS_CACHE(1'b0), |
// .F_OPT_CLK2FFLOGIC(!SYNCHRONOUS), |
.F_AXI_MAXWAIT(5'h6), |
.F_AXI_MAXDELAY(5'h6), |
) faxil_slave( |
.i_clk(S_AXI_ACLK), |
.i_axi_reset_n(S_AXI_ARESETN), |
// |
.i_axi_awaddr(S_AXI_AWADDR), |
.i_axi_awprot(S_AXI_AWPROT), |
.i_axi_awcache(4'h0), |
.i_axi_awvalid(S_AXI_AWVALID), |
.i_axi_awready(S_AXI_AWREADY), |
// |
.i_axi_wdata(S_AXI_WDATA), |
.i_axi_wstrb(S_AXI_WSTRB), |
.i_axi_wvalid(S_AXI_WVALID), |
.i_axi_wready(S_AXI_WREADY), |
// |
.i_axi_bresp(S_AXI_BRESP), |
.i_axi_bvalid(S_AXI_BVALID), |
.i_axi_bready(S_AXI_BREADY), |
// |
.i_axi_araddr(S_AXI_ARADDR), |
.i_axi_arprot(S_AXI_ARPROT), |
.i_axi_arvalid(S_AXI_ARVALID), |
.i_axi_arready(S_AXI_ARREADY), |
.i_axi_arcache(4'h0), |
// |
.i_axi_rdata(S_AXI_RDATA), |
.i_axi_rresp(S_AXI_RRESP), |
.i_axi_rvalid(S_AXI_RVALID), |
.i_axi_rready(S_AXI_RREADY), |
// |
.f_axi_rd_outstanding(f_axi_rd_outstanding), |
.f_axi_wr_outstanding(f_axi_wr_outstanding), |
.f_axi_awr_outstanding(f_axi_awr_outstanding)); |
|
always @(*) |
begin |
assert(f_axi_wr_outstanding == f_axi_awr_outstanding); |
if (axi_bvalid) |
assert(f_axi_wr_outstanding == 1); |
else |
assert(f_axi_wr_outstanding == 0); |
if (|rvalid) |
assert(f_axi_rd_outstanding == 1); |
else |
assert(f_axi_rd_outstanding == 0); |
assert(rvalid != 2'b11); |
end |
|
always @(*) |
if (dr_triggered) |
assert(dr_primed); |
|
always @(*) |
if (dr_stopped) |
assert((dr_primed)&&(dr_triggered)); |
|
reg dr_triggered, dr_primed; |
wire dw_trigger; |
assign dw_trigger = (dr_primed)&&( |
((i_trigger)&&(!dw_disable_trigger)) |
||(dw_manual_trigger)); |
|
(* anyconst *) wire [(LGMEM-1):0] f_addr; |
reg [31:0] f_data; |
reg f_filled; |
|
initial f_filled = 1'b0; |
always @(posedge i_data_clk) |
if (dw_reset) |
f_filled <= 1'b0; |
else if ((i_ce)&&(!dr_stopped)&&(waddr == f_addr)) |
f_filled <= 1'b1; |
|
always @(posedge i_data_clk) |
if (waddr > f_addr) |
assert(f_filled); |
|
always @(posedge i_data_clk) |
if (!f_filled) |
assert(!dr_primed); |
|
always @(posedge i_data_clk) |
if ((i_ce)&&(!dr_stopped)&&(waddr == f_addr)) |
f_data <= wr_piped_data; |
|
always @(posedge i_data_clk) |
if (f_filled) |
assert(mem[f_addr] == f_data); |
|
`endif |
endmodule |
/trunk/rtl/wbscopc.v
488,14 → 488,14
assign o_interrupt = (bw_stopped)&&(!bw_disable_trigger) |
&&(!br_level_interrupt); |
always @(posedge i_wb_clk) |
if ((bw_reset_complete)||(bw_reset_request)) |
br_level_interrupt<= 1'b0; |
else |
br_level_interrupt<= (bw_stopped)&&(!bw_disable_trigger); |
if ((bw_reset_complete)||(bw_reset_request)) |
br_level_interrupt<= 1'b0; |
else |
br_level_interrupt<= (bw_stopped)&&(!bw_disable_trigger); |
|
// Make Verilator happy |
// verilator lint_off UNUSED |
wire [3+5+(20-HOLDOFFBITS)-1:0] unused; |
wire [3+6+(20-HOLDOFFBITS)-1:0] unused; |
assign unused = { i_wb_data[30:28], i_wb_data[25:HOLDOFFBITS] }; |
// verilator lint_on UNUSED |
|
/trunk/rtl/wbscope.v
32,7 → 32,7
// beginning of the buffer |
// |
// Although the data width DW is parameterized, it is not very changable, |
// since the width is tied to the width of the data bus, as is the |
// since the width is tied to the width of the data bus, as is the |
// control word. Therefore changing the data width would require changing |
// the interface. It's doable, but it would be a change to the interface. |
// |
104,7 → 104,7
output wire o_wb_ack, o_wb_stall; |
output wire [(BUSW-1):0] o_wb_data; |
// And, finally, for a final flair --- offer to interrupt the CPU after |
// our trigger has gone off. This line is equivalent to the scope |
// our trigger has gone off. This line is equivalent to the scope |
// being stopped. It is not maskable here. |
output wire o_interrupt; |
|
266,13 → 266,7
// mem[waddr] <= i_data; |
waddr <= waddr + {{(LGMEM-1){1'b0}},1'b1}; |
if (!dr_primed) |
begin |
//if (br_holdoff[(HOLDOFFBITS-1):LGMEM]==0) |
// dr_primed <= (waddr >= br_holdoff[(LGMEM-1):0]); |
// else |
|
dr_primed <= (&waddr); |
end |
dr_primed <= (&waddr); |
end |
|
// Delay the incoming data so that we can get our trigger |
/trunk/sw/devbus.h
5,17 → 5,24
// Project: OpenArty, an entirely open SoC based upon the Arty platform |
// |
// Purpose: The purpose of this file is to document an interface which |
// any devic with a bus, whether it be implemented over a UART, |
// an ethernet, or a PCI express bus, must implement. This describes only |
// an interface, and not how that interface is to be accomplished. |
// any device with a bus, whether it be implemented over a UART, |
// an ethernet, or a PCI express bus, must implement. This describes |
// only an interface, and not how that interface is to be accomplished. |
// |
// The neat part of this interface is that, if programs are designed to |
// work with it, than the implementation details may be changed later |
// and any program that once worked with the interface should be able |
// to continue to do so. (i.e., switch from a UART controlled bus to a |
// PCI express controlled bus, with minimal change to the software of |
// interest.) |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// Copyright (C) 2015-2017, 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 |
28,7 → 35,7
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// with this program. (It's in the $(ROOT)/doc directory. Run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
61,18 → 68,56
virtual void close(void) = 0; |
|
// Write a single value to a single address |
// a is the address of the value to be read as it exists on the |
// wishbone bus within the FPGA. |
// v is the singular value to write to this address |
virtual void writeio(const BUSW a, const BUSW v) = 0; |
|
// Read a single value to a single address |
// a is the address of the value to be read as it exists on the |
// wishbone bus within the FPGA. |
// This function returns the value read from the device wishbone |
// at address a. |
virtual BUSW readio(const BUSW a) = 0; |
|
// Read a series of values from values from a block of memory |
// a is the address of the value to be read as it exists on the |
// wishbone bus within the FPGA. |
// len is the number of words to read |
// buf is a pointer to a place to store the words once read. |
// This is equivalent to: |
// for(int i=0; i<len; i++) |
// buf[i] = readio(a+i); |
// only it's faster in our implementation. |
virtual void readi(const BUSW a, const int len, BUSW *buf) = 0; |
|
// Read a series of values from the same address in memory |
// Read a series of values from the same address in memory. This |
// call is identical to readi, save that the address is not incremented |
// from one read to the next. It is equivalent to: |
// for(int i=0; i<len; i++) |
// buf[i] = readio(a); |
// only it's faster in our implementation. |
// |
virtual void readz(const BUSW a, const int len, BUSW *buf) = 0; |
|
// Write a series of values into a block of memory on the FPGA |
// a is the address of the value to be written as it exists on the |
// wishbone bus within the FPGA. |
// len is the number of words to write |
// buf is a pointer to a place to from whence to grab the data |
// to be written. |
// This is equivalent to: |
// for(int i=0; i<len; i++) |
// writeio(a+i, buf[i]); |
// only it's faster in our implementation. |
virtual void writei(const BUSW a, const int len, const BUSW *buf) = 0; |
// Write a series of values into the same address on the FPGA bus. This |
// call is identical to writei, save that the address is not incremented |
// from one write to the next. It is equivalent to: |
// for(int i=0; i<len; i++) |
// writeio(a, buf[i]); |
// only it's faster in our implementation. |
// |
virtual void writez(const BUSW a, const int len, const BUSW *buf) = 0; |
|
// Query whether or not an interrupt has taken place |