OpenCores
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

powered by: WebSVN 2.1.0

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