Added everything from the other system

This commit is contained in:
2026-02-28 21:46:59 +01:00
parent 907f244b24
commit 1c37d384c2
34 changed files with 1601 additions and 57 deletions

View File

@@ -52,6 +52,7 @@ module formal_wb_master_checker (
// R3: Once a request starts, hold it stable until the slave responds
if(
f_past_valid &&
!$past(i_rst || i_wb_rst) &&
$past(i_wb_cyc && i_wb_stb && !o_wb_ack) &&
!o_wb_ack &&
!(i_rst || i_wb_rst)

View File

@@ -3,7 +3,7 @@ mode prove
depth 8
[engines]
smtbmc z3
abc pdr
[script]
{{"-formal"|gen_reads}}

View File

@@ -505,8 +505,8 @@ module jtag_wb_bridge #(
// Mark active command complete
act_valid <= 1'b0;
// If there is a queued command, promote and start it
if (q_valid) begin
// If there is a queued command and the WB port is idle, promote it now.
if (q_valid && !wb_busy) begin
act_valid <= 1'b1;
act_opcode <= q_opcode;
act_addr <= q_addr;

View File

@@ -32,7 +32,7 @@ $(SHARED_LIB): $(LIB_OBJS)
$(CXX) -shared $(LDFLAGS) -o $@ $(LIB_OBJS) $(LIBS)
$(TARGET): $(APP_OBJS) $(STATIC_LIB)
$(CXX) $(LDFLAGS) -o $@ $(APP_OBJS) -L. -ljtag_wb_bridge $(LIBS)
$(CXX) $(LDFLAGS) -o $@ $(APP_OBJS) -L. $(STATIC_LIB) $(LIBS)
%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<

View File

@@ -107,7 +107,7 @@ bool JtagWishboneBridge::ping() {
ping_value = static_cast<uint8_t>(response & 0xffu);
if (ping_value != 0xa5) {
char msg[96];
std::snprintf(msg, sizeof(msg), "ping mismatch: expected 0xa4, got 0x%02x", ping_value);
std::snprintf(msg, sizeof(msg), "ping mismatch: expected 0xa5, got 0x%02x", ping_value);
return setError(msg);
}
last_error_.clear();

View File

@@ -31,15 +31,10 @@ int main(int argc, char** argv) {
return -1;
}
uint8_t ping_value = 0;
if (!bridge.ping()) {
std::printf("PING command failed: %s\n", bridge.lastError().c_str());
return -1;
}
if (ping_value != 0xa5u) {
std::printf("PING response was not right: %02x\n", ping_value);
return -1;
}
const std::string file = parser.getString("file");
FILE* f = std::fopen(file.c_str(), "rb");

View File

@@ -5,4 +5,4 @@ with JtagBridge() as bridge:
bridge.clear_flags()
bridge.ping()
bridge.write32(0x0, 0xAA)
bridge.write8(0x0, 0xAA)

View File

@@ -0,0 +1,138 @@
/**
* Module: arbiter
*
* Description:
* A look ahead, round-robing parameterized arbiter.
*
* <> request
* each bit is controlled by an actor and each actor can 'request' ownership
* of the shared resource by bring high its request bit.
*
* <> grant
* when an actor has been given ownership of shared resource its 'grant' bit
* is driven high
*
* <> select
* binary representation of the grant signal (optional use)
*
* <> active
* is brought high by the arbiter when (any) actor has been given ownership
* of shared resource.
*
*
* Created: Sat Jun 1 20:26:44 EDT 2013
*
* Author: Berin Martini // berin.martini@gmail.com
*/
`ifndef _arbiter_ `define _arbiter_
`include "clog2.vh"
module arbiter
#(parameter
NUM_PORTS = 6,
SEL_WIDTH = ((NUM_PORTS > 1) ? `CLOG2(NUM_PORTS) : 1))
(input wire clk,
input wire rst,
input wire [NUM_PORTS-1:0] request,
output reg [NUM_PORTS-1:0] grant,
output reg [SEL_WIDTH-1:0] select,
output reg active
);
/**
* Local parameters
*/
localparam WRAP_LENGTH = 2*NUM_PORTS;
// Find First 1 - Start from MSB and count downwards, returns 0 when no
// bit set
function [SEL_WIDTH-1:0] ff1 (
input [NUM_PORTS-1:0] in
);
reg set;
integer i;
begin
set = 1'b0;
ff1 = 'b0;
for (i = 0; i < NUM_PORTS; i = i + 1) begin
if (in[i] & ~set) begin
set = 1'b1;
ff1 = i[0 +: SEL_WIDTH];
end
end
end
endfunction
`ifdef VERBOSE
initial $display("Bus arbiter with %d units", NUM_PORTS);
`endif
/**
* Internal signals
*/
integer yy;
wire next;
wire [NUM_PORTS-1:0] order;
reg [NUM_PORTS-1:0] token;
wire [NUM_PORTS-1:0] token_lookahead [NUM_PORTS-1:0];
wire [WRAP_LENGTH-1:0] token_wrap;
/**
* Implementation
*/
assign token_wrap = {token, token};
assign next = ~|(token & request);
always @(posedge clk)
grant <= token & request;
always @(posedge clk)
select <= ff1(token & request);
always @(posedge clk)
active <= |(token & request);
always @(posedge clk)
if (rst) token <= 'b1;
else if (next) begin
for (yy = 0; yy < NUM_PORTS; yy = yy + 1) begin : TOKEN_
if (order[yy]) begin
token <= token_lookahead[yy];
end
end
end
genvar xx;
generate
for (xx = 0; xx < NUM_PORTS; xx = xx + 1) begin : ORDER_
assign token_lookahead[xx] = token_wrap[xx +: NUM_PORTS];
assign order[xx] = |(token_lookahead[xx] & request);
end
endgenerate
endmodule
`endif // `ifndef _arbiter_

View File

@@ -0,0 +1,101 @@
/* wb_arbiter. Part of wb_intercon
*
* ISC License
*
* Copyright (C) 2013-2019 Olof Kindgren <olof.kindgren@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
Wishbone arbiter, burst-compatible
Simple round-robin arbiter for multiple Wishbone masters
*/
`include "clog2.vh"
module wb_arbiter
#(parameter dw = 32,
parameter aw = 32,
parameter num_hosts = 0,
parameter num_masters = num_hosts)
(
input wire wb_clk_i,
input wire wb_rst_i,
// Wishbone Master Interface
input wire [num_masters*aw-1:0] wbm_adr_i,
input wire [num_masters*dw-1:0] wbm_dat_i,
input wire [num_masters*4-1:0] wbm_sel_i,
input wire [num_masters-1:0] wbm_we_i,
input wire [num_masters-1:0] wbm_cyc_i,
input wire [num_masters-1:0] wbm_stb_i,
input wire [num_masters*3-1:0] wbm_cti_i,
input wire [num_masters*2-1:0] wbm_bte_i,
output wire [num_masters*dw-1:0] wbm_dat_o,
output wire [num_masters-1:0] wbm_ack_o,
output wire [num_masters-1:0] wbm_err_o,
output wire [num_masters-1:0] wbm_rty_o,
// Wishbone Slave interface
output wire [aw-1:0] wbs_adr_o,
output wire [dw-1:0] wbs_dat_o,
output wire [3:0] wbs_sel_o,
output wire wbs_we_o,
output wire wbs_cyc_o,
output wire wbs_stb_o,
output wire [2:0] wbs_cti_o,
output wire [1:0] wbs_bte_o,
input wire [dw-1:0] wbs_dat_i,
input wire wbs_ack_i,
input wire wbs_err_i,
input wire wbs_rty_i);
///////////////////////////////////////////////////////////////////////////////
// Parameters
///////////////////////////////////////////////////////////////////////////////
//Use parameter instead of localparam to work around a bug in Xilinx ISE
parameter master_sel_bits = num_masters > 1 ? `CLOG2(num_masters) : 1;
wire [num_masters-1:0] grant;
wire [master_sel_bits-1:0] master_sel;
wire active;
arbiter
#(.NUM_PORTS (num_masters))
arbiter0
(.clk (wb_clk_i),
.rst (wb_rst_i),
.request (wbm_cyc_i),
.grant (grant),
.select (master_sel),
.active (active));
/* verilator lint_off WIDTH */
//Mux active master
assign wbs_adr_o = wbm_adr_i[master_sel*aw+:aw];
assign wbs_dat_o = wbm_dat_i[master_sel*dw+:dw];
assign wbs_sel_o = wbm_sel_i[master_sel*4+:4];
assign wbs_we_o = wbm_we_i [master_sel];
assign wbs_cyc_o = wbm_cyc_i[master_sel] & active;
assign wbs_stb_o = wbm_stb_i[master_sel];
assign wbs_cti_o = wbm_cti_i[master_sel*3+:3];
assign wbs_bte_o = wbm_bte_i[master_sel*2+:2];
assign wbm_dat_o = {num_masters{wbs_dat_i}};
assign wbm_ack_o = ((wbs_ack_i & active) << master_sel);
assign wbm_err_o = ((wbs_err_i & active) << master_sel);
assign wbm_rty_o = ((wbs_rty_i & active) << master_sel);
/* verilator lint_on WIDTH */
endmodule // wb_arbiter

View File

@@ -0,0 +1,42 @@
CAPI=2:
name: joppeb:wb:wb_arbiter:1.0
description: Wishbone round-robin arbiter
filesets:
rtl:
depend:
- joppeb:util:clog2
files:
- rtl/arbiter.v
- rtl/wb_arbiter.v
file_type: verilogSource
targets:
default:
filesets:
- rtl
toplevel: wb_arbiter
parameters:
- dw
- aw
- num_hosts
- num_masters
parameters:
dw:
datatype: int
description: Wishbone data width
paramtype: vlogparam
aw:
datatype: int
description: Wishbone address width
paramtype: vlogparam
num_hosts:
datatype: int
description: Deprecated alias for num_masters
paramtype: vlogparam
num_masters:
datatype: int
description: Number of wishbone masters
paramtype: vlogparam

View File

@@ -8,6 +8,7 @@ filesets:
files:
- rtl/wb_gpio.v
file_type: verilogSource
formal_rtl:
depend:
- joppeb:wb:formal_checker
@@ -26,6 +27,7 @@ targets:
toplevel: wb_gpio
parameters:
- address
formal:
default_tool: symbiyosys
filesets:

View File

@@ -0,0 +1,63 @@
`default_nettype none
module wb_gpio_banks #(
parameter integer NUM_BANKS = 4,
parameter [31:0] BASE_ADDR = 32'h8000_0000
) (
input wire i_wb_clk,
input wire i_wb_rst,
input wire [31:0] i_wb_adr,
input wire [31:0] i_wb_dat,
input wire [3:0] i_wb_sel,
input wire i_wb_we,
input wire i_wb_stb,
input wire [NUM_BANKS*32-1:0] i_gpio,
output reg [31:0] o_wb_rdt,
output reg o_wb_ack,
output wire [NUM_BANKS*32-1:0] o_gpio
);
wire [NUM_BANKS-1:0] bank_sel;
wire [NUM_BANKS-1:0] bank_stb;
wire [NUM_BANKS*32-1:0] bank_rdt;
wire [NUM_BANKS-1:0] bank_ack;
genvar gi;
generate
for (gi = 0; gi < NUM_BANKS; gi = gi + 1) begin : gen_gpio
localparam [31:0] BANK_ADDR = BASE_ADDR + (gi * 4);
assign bank_sel[gi] = (i_wb_adr == BANK_ADDR);
assign bank_stb[gi] = i_wb_stb & bank_sel[gi];
wb_gpio #(
.address(BANK_ADDR)
) u_gpio (
.i_wb_clk(i_wb_clk),
.i_wb_rst(i_wb_rst),
.i_wb_adr(i_wb_adr),
.i_wb_dat(i_wb_dat),
.i_wb_sel(i_wb_sel),
.i_wb_we(i_wb_we),
.i_wb_stb(bank_stb[gi]),
.i_gpio(i_gpio[gi*32 +: 32]),
.o_wb_rdt(bank_rdt[gi*32 +: 32]),
.o_wb_ack(bank_ack[gi]),
.o_gpio(o_gpio[gi*32 +: 32])
);
end
endgenerate
integer bi;
always @* begin
o_wb_rdt = 32'h0000_0000;
o_wb_ack = 1'b0;
for (bi = 0; bi < NUM_BANKS; bi = bi + 1) begin
if (bank_sel[bi]) begin
o_wb_rdt = bank_rdt[bi*32 +: 32];
o_wb_ack = bank_ack[bi];
end
end
end
endmodule

View File

@@ -0,0 +1,31 @@
CAPI=2:
name: joppeb:wb:wb_gpio_banks:1.0
description: Wishbone GPIO bank wrapper
filesets:
rtl:
depend:
- joppeb:wb:wb_gpio
files:
- rtl/wb_gpio_banks.v
file_type: verilogSource
targets:
default:
filesets:
- rtl
toplevel: wb_gpio_banks
parameters:
- NUM_BANKS
- BASE_ADDR
parameters:
NUM_BANKS:
datatype: int
description: Number of GPIO banks to instantiate
paramtype: vlogparam
BASE_ADDR:
datatype: int
description: Base wishbone address for bank 0
paramtype: vlogparam

View File

@@ -0,0 +1,145 @@
/* wb_mux. Part of wb_intercon
*
* ISC License
*
* Copyright (C) 2013-2019 Olof Kindgren <olof.kindgren@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
Wishbone multiplexer, burst-compatible
Simple mux with an arbitrary number of slaves.
The parameters MATCH_ADDR and MATCH_MASK are flattened arrays
aw*NUM_SLAVES sized arrays that are used to calculate the
active slave. slave i is selected when
(wb_adr_i & MATCH_MASK[(i+1)*aw-1:i*aw] is equal to
MATCH_ADDR[(i+1)*aw-1:i*aw]
If several regions are overlapping, the slave with the lowest
index is selected. This can be used to have fallback
functionality in the last slave, in case no other slave was
selected.
If no match is found, the wishbone transaction will stall and
an external watchdog is required to abort the transaction
Todo:
Registered master/slave connections
Rewrite with System Verilog 2D arrays when tools support them
*/
`include "clog2.vh"
module wb_mux
#(parameter dw = 32, // Data width
parameter aw = 32, // Address width
parameter num_devices = 2, // Number of devices
parameter num_slaves = num_devices, // Number of devices (deprecated)
parameter [num_slaves*aw-1:0] MATCH_ADDR = 0,
parameter [num_slaves*aw-1:0] MATCH_MASK = 0)
(
input wire wb_clk_i,
input wire wb_rst_i,
// Master Interface
input wire [aw-1:0] wbm_adr_i,
input wire [dw-1:0] wbm_dat_i,
input wire [3:0] wbm_sel_i,
input wire wbm_we_i,
input wire wbm_cyc_i,
input wire wbm_stb_i,
input wire [2:0] wbm_cti_i,
input wire [1:0] wbm_bte_i,
output wire [dw-1:0] wbm_dat_o,
output wire wbm_ack_o,
output wire wbm_err_o,
output wire wbm_rty_o,
// Wishbone Slave interface
output wire [num_slaves*aw-1:0] wbs_adr_o,
output wire [num_slaves*dw-1:0] wbs_dat_o,
output wire [num_slaves*4-1:0] wbs_sel_o,
output wire [num_slaves-1:0] wbs_we_o,
output wire [num_slaves-1:0] wbs_cyc_o,
output wire [num_slaves-1:0] wbs_stb_o,
output wire [num_slaves*3-1:0] wbs_cti_o,
output wire [num_slaves*2-1:0] wbs_bte_o,
input wire [num_slaves*dw-1:0] wbs_dat_i,
input wire [num_slaves-1:0] wbs_ack_i,
input wire [num_slaves-1:0] wbs_err_i,
input wire [num_slaves-1:0] wbs_rty_i);
///////////////////////////////////////////////////////////////////////////////
// Master/slave connection
///////////////////////////////////////////////////////////////////////////////
//Use parameter instead of localparam to work around a bug in Xilinx ISE
parameter slave_sel_bits = num_slaves > 1 ? `CLOG2(num_slaves) : 1;
reg wbm_err;
wire [slave_sel_bits-1:0] slave_sel;
wire [num_slaves-1:0] match;
genvar idx;
generate
for(idx=0; idx<num_slaves ; idx=idx+1) begin : addr_match
assign match[idx] = (wbm_adr_i & MATCH_MASK[idx*aw+:aw]) == MATCH_ADDR[idx*aw+:aw];
end
endgenerate
//
// Find First 1 - Start from MSB and count downwards, returns 0 when no bit set
//
function [slave_sel_bits-1:0] ff1;
input [num_slaves-1:0] in;
integer i;
begin
ff1 = 0;
for (i = num_slaves-1; i >= 0; i=i-1) begin
if (in[i])
/* verilator lint_off WIDTH */
ff1 = i;
/* verilator lint_on WIDTH */
end
end
endfunction
assign slave_sel = ff1(match);
always @(posedge wb_clk_i)
wbm_err <= wbm_cyc_i & !(|match);
assign wbs_adr_o = {num_slaves{wbm_adr_i}};
assign wbs_dat_o = {num_slaves{wbm_dat_i}};
assign wbs_sel_o = {num_slaves{wbm_sel_i}};
assign wbs_we_o = {num_slaves{wbm_we_i}};
/* verilator lint_off WIDTH */
// Expand master CYC to slave bus width before shifting to one-hot select.
// Shifting a 1-bit signal would otherwise zero out all but slave 0.
assign wbs_cyc_o = match & ({num_slaves{wbm_cyc_i}} << slave_sel);
/* verilator lint_on WIDTH */
assign wbs_stb_o = {num_slaves{wbm_stb_i}};
assign wbs_cti_o = {num_slaves{wbm_cti_i}};
assign wbs_bte_o = {num_slaves{wbm_bte_i}};
assign wbm_dat_o = wbs_dat_i[slave_sel*dw+:dw];
assign wbm_ack_o = wbs_ack_i[slave_sel];
assign wbm_err_o = wbs_err_i[slave_sel] | wbm_err;
assign wbm_rty_o = wbs_rty_i[slave_sel];
endmodule

View File

@@ -0,0 +1,51 @@
CAPI=2:
name: joppeb:wb:wb_mux:1.0
description: Wishbone address decoder and multiplexer
filesets:
rtl:
depend:
- joppeb:util:clog2
files:
- rtl/wb_mux.v
file_type: verilogSource
targets:
default:
filesets:
- rtl
toplevel: wb_mux
parameters:
- dw
- aw
- num_devices
- num_slaves
- MATCH_ADDR
- MATCH_MASK
parameters:
dw:
datatype: int
description: Wishbone data width
paramtype: vlogparam
aw:
datatype: int
description: Wishbone address width
paramtype: vlogparam
num_devices:
datatype: int
description: Deprecated alias for num_slaves
paramtype: vlogparam
num_slaves:
datatype: int
description: Number of wishbone slaves
paramtype: vlogparam
MATCH_ADDR:
datatype: int
description: Flattened slave address match table
paramtype: vlogparam
MATCH_MASK:
datatype: int
description: Flattened slave address mask table
paramtype: vlogparam

View File

@@ -0,0 +1,74 @@
`timescale 1ns/1ps
module wb_countdown_timer #(
parameter WIDTH = 32, // counter width (<=32 makes bus mapping easy)
parameter DIVIDER = 0 // optional prescaler: tick every 2^DIVIDER cycles
)(
input wire i_clk,
input wire i_rst,
output reg o_irq,
input wire [31:0] i_wb_dat,
output reg [31:0] o_wb_dat,
input wire i_wb_we,
input wire i_wb_cyc,
input wire i_wb_stb,
output wire o_wb_ack
);
// One-cycle acknowledge on any valid WB access
// (classic, zero-wait-state peripheral)
assign o_wb_ack = i_wb_cyc & i_wb_stb;
// Internal countdown and prescaler
reg [WIDTH-1:0] counter;
reg [DIVIDER:0] presc; // enough bits to count up to 2^DIVIDER-1
wire tick = (DIVIDER == 0) ? 1'b1 : (presc[DIVIDER] == 1'b1);
// Readback: expose the current counter value
always @(*) begin
o_wb_dat = 32'd0;
o_wb_dat[WIDTH-1:0] = counter;
end
// Main logic
always @(posedge i_clk) begin
if (i_rst) begin
counter <= {WIDTH{1'b0}};
presc <= { (DIVIDER+1){1'b0} };
o_irq <= 1'b0;
end else begin
// Default prescaler behavior
if (DIVIDER != 0) begin
if (counter != 0 && !o_irq)
presc <= presc + 1'b1;
else
presc <= { (DIVIDER+1){1'b0} };
end
// Wishbone write: load counter and clear IRQ
if (o_wb_ack && i_wb_we) begin
counter <= i_wb_dat[WIDTH-1:0];
o_irq <= 1'b0;
// reset prescaler on (re)start or stop
presc <= { (DIVIDER+1){1'b0} };
end else begin
// Countdown when running (counter>0), not already IRQ'd
if (!o_irq && counter != 0) begin
if (tick) begin
if (counter == 1) begin
counter <= {WIDTH{1'b0}};
o_irq <= 1'b1; // sticky until next write
presc <= { (DIVIDER+1){1'b0} };
end else begin
counter <= counter - 1'b1;
end
end
end
end
end
end
endmodule

View File

@@ -0,0 +1,29 @@
CAPI=2:
name: joppeb:wb:wb_timer:1.0
description: Wishbone countdown timer peripheral
filesets:
rtl:
files:
- rtl/wb_timer.v
file_type: verilogSource
targets:
default:
filesets:
- rtl
toplevel: wb_countdown_timer
parameters:
- WIDTH
- DIVIDER
parameters:
WIDTH:
datatype: int
description: Counter width in bits
paramtype: vlogparam
DIVIDER:
datatype: int
description: Prescaler divider as a power of two exponent
paramtype: vlogparam