├── .gitignore ├── wb_intercon ├── wave.png ├── README.md ├── testbench.sv └── design.sv ├── wb_master_nop ├── wave.png ├── README.md ├── testbench.sv └── design.sv ├── wb_master_seq_mem_access ├── wave.png ├── README.md ├── testbench.sv └── design.sv ├── wb_slave_register ├── one_single_read.png ├── pipelined_read.png ├── pipelined_write.png ├── one_single_write.png ├── read_modify_write.png ├── README.md ├── testvector.tv ├── design.sv └── testbench.sv ├── wb_slave_nop ├── README.md ├── testbench.sv └── design.sv ├── wb_loopback ├── README.md ├── testbench.sv └── design.sv ├── Makefile ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | *.vcd 3 | *.gtkw 4 | -------------------------------------------------------------------------------- /wb_intercon/wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/semahawk/wishbone/HEAD/wb_intercon/wave.png -------------------------------------------------------------------------------- /wb_master_nop/wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/semahawk/wishbone/HEAD/wb_master_nop/wave.png -------------------------------------------------------------------------------- /wb_master_seq_mem_access/wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/semahawk/wishbone/HEAD/wb_master_seq_mem_access/wave.png -------------------------------------------------------------------------------- /wb_slave_register/one_single_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/semahawk/wishbone/HEAD/wb_slave_register/one_single_read.png -------------------------------------------------------------------------------- /wb_slave_register/pipelined_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/semahawk/wishbone/HEAD/wb_slave_register/pipelined_read.png -------------------------------------------------------------------------------- /wb_slave_register/pipelined_write.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/semahawk/wishbone/HEAD/wb_slave_register/pipelined_write.png -------------------------------------------------------------------------------- /wb_slave_register/one_single_write.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/semahawk/wishbone/HEAD/wb_slave_register/one_single_write.png -------------------------------------------------------------------------------- /wb_slave_register/read_modify_write.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/semahawk/wishbone/HEAD/wb_slave_register/read_modify_write.png -------------------------------------------------------------------------------- /wb_slave_nop/README.md: -------------------------------------------------------------------------------- 1 | # nop, slave device 2 | 3 | this device does an equivalent to a "nop" - it does nothing, and responds with 4 | ACK as soon as possible. 5 | 6 | -------------------------------------------------------------------------------- /wb_loopback/README.md: -------------------------------------------------------------------------------- 1 | # loopback device 2 | 3 | a basic loopback device, which basically means that it implements both a master 4 | and a slave Wishbone interfaces 5 | 6 | it's called loopback because it makes only sense to connect it to itself hehe 7 | 8 | -------------------------------------------------------------------------------- /wb_master_seq_mem_access/README.md: -------------------------------------------------------------------------------- 1 | # seq mem access, master device 2 | 3 | this master device continuously issues SINGLE WRITE and then SINGLE READ bus cycles 4 | over a range of memory address space (configurable via module parameters) 5 | 6 | ![wave](wave.png) 7 | -------------------------------------------------------------------------------- /wb_master_nop/README.md: -------------------------------------------------------------------------------- 1 | # nop, master device 2 | 3 | this is a basic "nop" master device 4 | 5 | it will start the bus cycle by asserting `cyc_o` and `stb_o`, on the first rising 6 | edge of `clk_i` that follows the assertion of `trigger_i` 7 | 8 | after asserting `cyc_o` and `stb_o` it will keep waiting for an ACK indefinitely 9 | 10 | ![wave](wave.png) 11 | -------------------------------------------------------------------------------- /wb_slave_register/README.md: -------------------------------------------------------------------------------- 1 | # registers, slave device 2 | 3 | here's what's actually implemented here: 4 | 5 | #### single read 6 | 7 | ![single read](one_single_read.png) 8 | 9 | #### single write 10 | 11 | ![single write](one_single_write.png) 12 | 13 | #### read modify write 14 | 15 | ![read modify write](read_modify_write.png) 16 | 17 | #### pipelined read 18 | 19 | ![pipelined read](pipelined_read.png) 20 | 21 | #### pipelined write 22 | 23 | ![pipelined write](pipelined_write.png) 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DUT ?= $(shell find -maxdepth 1 -type d -name "wb_*" -printf '%P\n' -quit) 2 | 3 | wave_file = wave.vcd 4 | wave_save_file = wave.gtkw 5 | 6 | compiler ?= iverilog 7 | compiler_opts ?= -g2012 -DWAVE_FILE='"$(wave_file)"' 8 | runtime ?= vvp 9 | viewer ?= gtkwave 10 | 11 | files = $(shell find -name "*.sv") 12 | 13 | $(DUT)/main: $(files) 14 | $(compiler) $(compiler_opts) -s$(DUT)_tb -o $@ $(files) 15 | 16 | .PHONY: run 17 | run: $(DUT)/main 18 | (cd $(DUT); $(runtime) main) 19 | 20 | .PHONY: wave 21 | wave: run 22 | (cd $(DUT); $(viewer) $(wave_file) $(wave_save_file)) 23 | 24 | .PHONY: clean 25 | clean: 26 | rm -rf **/main $(wave_file) 27 | -------------------------------------------------------------------------------- /wb_loopback/testbench.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module wb_loopback_tb (); 4 | reg rst_i; 5 | reg clk_i; 6 | 7 | wire ack; 8 | wire stb; 9 | wire cyc; 10 | 11 | wb_loopback loopback_tb ( 12 | .rst_i(rst_i), 13 | .clk_i(clk_i), 14 | .cyc_o(cyc), 15 | .ack_i(ack), 16 | .stb_o(stb), 17 | .cyc_i(cyc), 18 | .ack_o(ack), 19 | .stb_i(stb) 20 | ); 21 | 22 | initial begin 23 | $dumpfile(`WAVE_FILE); 24 | $dumpvars(0, loopback_tb); 25 | 26 | rst_i = 0; 27 | clk_i = 0; 28 | 29 | #1; 30 | rst_i = 1; 31 | #10; 32 | rst_i = 0; 33 | 34 | #1000; 35 | 36 | $finish; 37 | end 38 | 39 | always begin 40 | #10 clk_i = ~clk_i; 41 | end 42 | endmodule 43 | -------------------------------------------------------------------------------- /wb_master_nop/testbench.sv: -------------------------------------------------------------------------------- 1 | module wb_master_nop_tb (); 2 | reg rst_i; 3 | reg clk_i; 4 | reg ack_o; 5 | reg stb_i; 6 | reg cyc_i; 7 | int i; 8 | 9 | wb_master_nop master_tb ( 10 | .rst_i(rst_i), 11 | .clk_i(clk_i), 12 | .cyc_o(cyc_i), 13 | .ack_i(ack_o), 14 | .stb_o(stb_i) 15 | ); 16 | 17 | initial begin 18 | $dumpfile(`WAVE_FILE); 19 | $dumpvars(0, master_tb); 20 | 21 | rst_i = 0; 22 | clk_i = 0; 23 | ack_o = 0; 24 | 25 | for (i = 0; i < 16; i++) begin 26 | $display("Waiting for phase start"); 27 | @(posedge stb_i); 28 | 29 | $display("Responding with ACK"); 30 | 31 | ack_o = 1; 32 | 33 | $display("Waiting for phase end"); 34 | @(negedge stb_i); 35 | 36 | ack_o = 0; 37 | end 38 | 39 | $finish; 40 | end 41 | 42 | always begin 43 | #1 clk_i = ~clk_i; 44 | end 45 | endmodule 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wishbone 2 | 3 | Trying to learn Wishbone by implementing few master/slave devices 4 | 5 | ## what devices are implemented 6 | 7 | ### nop, slave 8 | 9 | [wb_slave_nop/](wb_slave_nop/) 10 | 11 | a slave device does nothing - it _only_ responds with an ACK as soon as possible 12 | 13 | ### nop, master 14 | 15 | [wb_master_nop/](wb_master_nop/) 16 | 17 | a master device does nothing - it basically only starts a bus cycle, waits for ACK and that's it 18 | 19 | ### register(s), slave 20 | 21 | [wb_slave_register/](wb_slave_register/) 22 | 23 | a slave device which implements a set of basic registers - writing to them will retain the given value, and reading will return it. 24 | 25 | number of registers is configurable and is done via a module parameter 26 | 27 | ### seq mem access, master 28 | 29 | [wb_master_seq_mem_access/](wb_master_seq_mem_access/) 30 | 31 | this master device continuously issues SINGLE WRITE and then SINGLE READ bus cycles 32 | over a range of memory address space (configurable via module parameters) 33 | 34 | ### interconnect 35 | 36 | [wb_intercon/](wb_intercon/) 37 | 38 | a simple round robin interconnect, supporting multiple masters and multiple slave devices 39 | 40 | ### loopback 41 | 42 | [wb_loopback/](wb_loopback/) 43 | 44 | a simple device which has both a master and a slave interface, which means it can be loopbacked 45 | -------------------------------------------------------------------------------- /wb_slave_nop/testbench.sv: -------------------------------------------------------------------------------- 1 | module wb_slave_nop_tb (); 2 | reg rst_o; 3 | reg clk_i; 4 | reg ack_i; 5 | reg stb_o; 6 | reg cyc_o; 7 | 8 | wb_slave_nop slave_tb ( 9 | .rst_i(rst_o), 10 | .clk_i(clk_i), 11 | .cyc_i(cyc_o), 12 | .ack_o(ack_i), 13 | .stb_i(stb_o) 14 | ); 15 | 16 | initial begin 17 | $dumpfile(`WAVE_FILE); 18 | $dumpvars(0, slave_tb); 19 | 20 | clk_i = 0; 21 | cyc_o = 0; 22 | stb_o = 0; 23 | 24 | $display("Resetting the slave"); 25 | 26 | #1; 27 | rst_o = 1; 28 | #1; 29 | rst_o = 0; 30 | 31 | #10; 32 | 33 | $display("Waiting for positive edge of the clock"); 34 | 35 | @(posedge clk_i); 36 | 37 | $display("Starting the cycle"); 38 | 39 | stb_o = 1; 40 | cyc_o = 1; 41 | 42 | $display("Waiting for positive edge of the clock"); 43 | #1; 44 | 45 | while (ack_i != 1) begin 46 | $display("Waiting for an ACK..."); 47 | @(posedge clk_i); 48 | end 49 | 50 | $display("Got an ACK"); 51 | $display("Ending the cycle"); 52 | 53 | stb_o = 0; 54 | cyc_o = 0; 55 | 56 | #4; 57 | 58 | $finish; 59 | end 60 | 61 | always begin 62 | #1 clk_i = ~clk_i; 63 | end 64 | endmodule 65 | -------------------------------------------------------------------------------- /wb_intercon/README.md: -------------------------------------------------------------------------------- 1 | # intercon 2 | 3 | a general Wishbone interconnect, supporting `N` masters and `M` slaves 4 | 5 | ## test scenario 6 | 7 | in the test scenario ([testbench.sv](testbench.sv)), we have three master devices (two [wb_master_nop](wb_master_nop/) and one [wb_master_seq_mem_access](wb_master_seq_mem_access/)) and 3 slave devices (two [wb_slave_nop](wb_slave_nop/) and one [wb_slave_register](wb_slave_register/)) 8 | 9 | master device #0 (nop) always accesses address 0x0000, and master device #1 (nop) always accesses address 0x1000 10 | master device #2 (seq_mem_access) sequentially accesses the memory range 0x2000 - 0x200f, issuing SINGLE WRITE and SINGLE READ commands 11 | 12 | ### memory map 13 | 14 | | Adress space | Device | 15 | | --------------- | ---------- | 16 | | 0x0000 - 0x0fff | NOP0 | 17 | | 0x1000 - 0x1fff | NOP1 | 18 | | 0x2000 - 0x2fff | REG0 | 19 | | 0x3000 - 0x3fff | Reserved | 20 | | 0x4000 - 0x4fff | Reserved | 21 | | 0x5000 - 0x5fff | Reserved | 22 | | 0x6000 - 0x6fff | Reserved | 23 | | 0x7000 - 0x7fff | Reserved | 24 | | 0x8000 - 0x8fff | Reserved | 25 | | 0x9000 - 0x9fff | Reserved | 26 | | 0xa000 - 0xafff | Reserved | 27 | | 0xb000 - 0xbfff | Reserved | 28 | | 0xc000 - 0xcfff | Reserved | 29 | | 0xd000 - 0xdfff | Reserved | 30 | | 0xe000 - 0xefff | Reserved | 31 | | 0xf000 - 0xffff | Reserved | 32 | 33 | ### wave 34 | 35 | ![wave](wave.png) 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Szymon Urbaś 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /wb_slave_nop/design.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * General description: 4 | * 5 | * A NOP device, which does nothing, and only responds with an ACK as soon 6 | * as possible 7 | * 8 | * Wishbone specification used: B4 (https://cdn.opencores.org/downloads/wbspec_b4.pdf) 9 | * 10 | * Copyright (c) Szymon Urbaś All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. Neither the name of the copyright holder nor the names of its 21 | * contributors may be used to endorse or promote products derived from 22 | * this software without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 | * POSSIBILITY OF SUCH DAMAGE. 35 | * 36 | */ 37 | 38 | `default_nettype none 39 | 40 | module wb_slave_nop ( 41 | input wire rst_i, 42 | input wire clk_i, 43 | input wire stb_i, 44 | output wire ack_o, 45 | input wire cyc_i 46 | ); 47 | 48 | // I believe it doesn't get any simpler than this 49 | assign ack_o = stb_i; 50 | 51 | endmodule 52 | 53 | -------------------------------------------------------------------------------- /wb_master_seq_mem_access/testbench.sv: -------------------------------------------------------------------------------- 1 | /* dupa */ 2 | 3 | module wb_master_seq_mem_access_tb (); 4 | localparam ADDR_WIDTH = 16; 5 | localparam DATA_WIDTH = 32; 6 | 7 | reg rst_i; 8 | reg clk_i; 9 | reg stb_i; 10 | reg cyc_i; 11 | reg [ADDR_WIDTH-1:0] adr_i; 12 | reg [DATA_WIDTH-1:0] dat_i; 13 | reg [DATA_WIDTH-1:0] dat_o; 14 | reg we_i; 15 | reg ack_o; 16 | reg err_o; 17 | int i; 18 | 19 | reg [DATA_WIDTH-1:0] input_data; 20 | reg [DATA_WIDTH-1:0] output_data; 21 | 22 | wb_master_seq_mem_access #( 23 | .ADDR_WIDTH(ADDR_WIDTH), 24 | .DATA_WIDTH(DATA_WIDTH), 25 | .START_ADDR(0), 26 | .END_ADDR(7), 27 | .STEP(1) 28 | ) master_tb ( 29 | .rst_i(rst_i), 30 | .clk_i(clk_i), 31 | .stb_o(stb_i), 32 | .cyc_o(cyc_i), 33 | .we_o(we_i), 34 | .adr_o(adr_i), 35 | .dat_o(dat_i), 36 | .dat_i(dat_o), 37 | .ack_i(ack_o), 38 | .err_i(err_o) 39 | ); 40 | 41 | task cycle; 42 | $display("Waiting for STB to be asserted"); 43 | @(posedge stb_i); 44 | 45 | if (we_i != 1) begin 46 | $display("Not a write cycle!"); 47 | $finish; 48 | end 49 | 50 | input_data = dat_i; 51 | 52 | $display("Write cycle started"); 53 | $display("Responding with ACK"); 54 | 55 | ack_o = 1; 56 | 57 | $display("Waiting for phase end"); 58 | @(negedge stb_i); 59 | 60 | ack_o = 0; 61 | 62 | $display("Waiting for the read cycle..."); 63 | 64 | @(posedge stb_i); 65 | 66 | if (we_i != 0) begin 67 | $display("Not a read cycle!"); 68 | $finish; 69 | end 70 | 71 | $display("Responding with ACK"); 72 | dat_o = input_data; 73 | ack_o = 1; 74 | 75 | $display("Waiting for phase end"); 76 | @(negedge stb_i); 77 | 78 | ack_o = 0; 79 | 80 | endtask 81 | 82 | initial begin 83 | $dumpfile(`WAVE_FILE); 84 | $dumpvars(0, master_tb); 85 | 86 | rst_i = 0; 87 | clk_i = 0; 88 | ack_o = 0; 89 | err_o = 0; 90 | dat_o = 0; 91 | 92 | for (i = 0; i < 16; i++) begin 93 | #2 cycle(); 94 | end 95 | 96 | #2; 97 | 98 | $finish; 99 | end 100 | 101 | always begin 102 | #1 clk_i = ~clk_i; 103 | end 104 | endmodule 105 | -------------------------------------------------------------------------------- /wb_slave_register/testvector.tv: -------------------------------------------------------------------------------- 1 | // format: 2 | // 3 | // _____ 4 | // 5 | // where is a 4 bit value, and can be one of the following: 6 | // 7 | // 0 - classic single read ( ignored) 8 | // 1 - classic single write ( ignored) 9 | // 2 - read modfy write 10 | // 3 - pipelined single read ( ignored) 11 | // 4 - pipelined single write ( ignored) 12 | // 13 | // indicates where valid data is placed (each bit specifiec which byte is valid) 14 | // and is DATA_WIDTH / GRANULE bits long 15 | // 16 | // indicates how the device is supposed to have returned, eg via ACK, or ERR 17 | // and is 4 bits long, where: 18 | // 19 | // 0 - the device is expected to return with ACK 20 | // 1 - the device is expected to return with ERR 21 | // 22 | // is ADDR_WIDTH long (parameter to wb_slave_register) 23 | // and are both DATA_WIDTH (parameter to wb_slave_register) 24 | // 25 | 26 | // check that it's all zeroes initially 27 | 0_f_0000_xxxxxxxx_00000000_0 28 | // write with some value 29 | 1_f_0000_11111111_xxxxxxxx_0 30 | // read it back 31 | 0_f_0000_xxxxxxxx_11111111_0 32 | // write two lower bytes 33 | 1_3_0000_22222222_xxxxxxxx_0 34 | // read the whole thing, and only two lower bytes should be modified 35 | 0_f_0000_xxxxxxxx_11112222_0 36 | // write two upper bytes 37 | 1_c_0000_33333333_xxxxxxxx_0 38 | // read the whole thing, and only two upper bytes should be modified 39 | 0_f_0000_xxxxxxxx_33332222_0 40 | // write upper- and lower-most bytes 41 | 1_9_0000_44444444_xxxxxxxx_0 42 | // read the whole thing, and only the upper- and lower-most bytes should be modified 43 | 0_f_0000_xxxxxxxx_44332244_0 44 | // do the RMW cycle 45 | 2_f_0000_55555555_44332244_0 46 | // and a second one 47 | 2_f_0000_66666666_55555555_0 48 | // now a single, normal read, to double check 49 | 0_f_0000_xxxxxxxx_66666666_0 50 | 51 | // get register #0 back to it's original state 52 | 1_f_0000_00000000_xxxxxxxx_0 53 | // make sure it's 0x0 54 | 0_f_0000_xxxxxxxx_00000000_0 55 | // now check that register #1 is also 0x0 56 | 0_f_0001_xxxxxxxx_00000000_0 57 | // overwrite register #1 58 | 1_f_0001_11111111_xxxxxxxx_0 59 | // make sure that it's modified... 60 | 0_f_0001_xxxxxxxx_11111111_0 61 | // ...and that #0 stayed the same 62 | 0_f_0000_xxxxxxxx_00000000_0 63 | 64 | // let's address a nonexistent register 65 | 0_f_ffff_xxxxxxxx_00000000_1 66 | 67 | // pipelined single read 68 | 3_f_0002_xxxxxxxx_00000000_0 69 | // pipelined single write 70 | 4_f_0002_12345678_00000000_0 71 | // pipelined single read 72 | 3_f_0002_xxxxxxxx_12345678_0 73 | -------------------------------------------------------------------------------- /wb_master_nop/design.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * General description: 4 | * 5 | * A NOP master device, which does basically nothing. It only starts a cycle/phase 6 | * waits for ACK and that's about it. 7 | * 8 | * Wishbone specification used: B4 (https://cdn.opencores.org/downloads/wbspec_b4.pdf) 9 | * 10 | * Copyright (c) Szymon Urbaś All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. Neither the name of the copyright holder nor the names of its 21 | * contributors may be used to endorse or promote products derived from 22 | * this software without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 | * POSSIBILITY OF SUCH DAMAGE. 35 | * 36 | */ 37 | 38 | `default_nettype none 39 | 40 | package wb_master_nop_pkg; 41 | 42 | typedef enum int { 43 | STATE_WAIT, 44 | STATE_START, 45 | STATE_WAIT_FOR_ACK 46 | } state_t; 47 | 48 | endpackage 49 | 50 | module wb_master_nop ( 51 | input wire rst_i, 52 | input wire clk_i, 53 | input wire ack_i, 54 | output wire stb_o, 55 | output wire cyc_o 56 | ); 57 | 58 | parameter INITIAL_DELAY = 2; 59 | parameter WAIT_CYCLES = 4; 60 | 61 | import wb_master_nop_pkg::*; 62 | 63 | state_t state = STATE_WAIT; 64 | int wait_cycles = INITIAL_DELAY; 65 | reg stb = 1'h0; 66 | reg cyc = 1'h0; 67 | 68 | assign stb_o = stb; 69 | assign cyc_o = cyc; 70 | 71 | always @(posedge clk_i) begin 72 | if (rst_i) begin 73 | state <= STATE_WAIT; 74 | stb <= 0; 75 | cyc <= 0; 76 | wait_cycles <= WAIT_CYCLES; 77 | end else begin 78 | case (state) 79 | STATE_WAIT: begin 80 | if (wait_cycles == 0) begin 81 | state <= STATE_START; 82 | wait_cycles <= WAIT_CYCLES; 83 | end else begin 84 | wait_cycles <= wait_cycles - 1; 85 | end 86 | end 87 | STATE_START: begin 88 | state <= STATE_WAIT_FOR_ACK; 89 | stb <= 1; 90 | cyc <= 1; 91 | end 92 | STATE_WAIT_FOR_ACK: begin 93 | if (ack_i) begin 94 | state <= STATE_WAIT; 95 | stb <= 0; 96 | cyc <= 0; 97 | end 98 | end 99 | endcase 100 | end 101 | end 102 | 103 | endmodule 104 | -------------------------------------------------------------------------------- /wb_intercon/testbench.sv: -------------------------------------------------------------------------------- 1 | `timescale 1us / 1ns 2 | 3 | module wb_intercon_tb (); 4 | localparam MASTERS_NUM = 3; 5 | localparam SLAVES_NUM = 3; 6 | localparam ADDR_WIDTH = 16; 7 | localparam DATA_WIDTH = 32; 8 | localparam GRANULE = 8; 9 | 10 | reg rst_o; 11 | reg clk_o; 12 | 13 | wire m0_nop_cyc_o; 14 | wire m0_nop_stb_o; 15 | wire m0_nop_ack_i; 16 | 17 | wire m1_nop_cyc_o; 18 | wire m1_nop_stb_o; 19 | wire m1_nop_ack_i; 20 | 21 | wire m2_mem_cyc_o; 22 | wire m2_mem_stb_o; 23 | wire m2_mem_we_o; 24 | wire [ADDR_WIDTH-1:0] m2_mem_adr_o; 25 | wire [DATA_WIDTH-1:0] m2_mem_dat_o; 26 | wire [7:0] m2_mem_sel_o; 27 | wire m2_mem_ack_i; 28 | wire m2_mem_err_i; 29 | 30 | wire s0_nop_stb_i; 31 | wire s0_nop_ack_o; 32 | 33 | wire s1_nop_stb_i; 34 | wire s1_nop_ack_o; 35 | 36 | wire s2_reg_stb_i; 37 | wire s2_reg_ack_o; 38 | wire s2_reg_err_o; 39 | wire [DATA_WIDTH-1:0] s2_reg_dat_o; 40 | 41 | // wires shared across all masters 42 | wire [DATA_WIDTH-1:0] master_dat_i; 43 | 44 | // wires shared across all slaves 45 | wire slave_cyc_i; 46 | wire slave_we_i; 47 | wire [ADDR_WIDTH-1:0] slave_adr_i; 48 | wire [DATA_WIDTH-1:0] slave_dat_i; 49 | wire [7:0] slave_sel_i; 50 | 51 | wire nc; 52 | 53 | wb_intercon #( 54 | .MASTERS_NUM(MASTERS_NUM), 55 | .SLAVES_NUM(SLAVES_NUM) 56 | ) wb_intercon_dut ( 57 | .rst_i(rst_o), 58 | .clk_i(clk_o), 59 | .m2i_cyc_i({ m2_mem_cyc_o, m1_nop_cyc_o, m0_nop_cyc_o }), 60 | .m2i_stb_i({ m2_mem_stb_o, m1_nop_stb_o, m0_nop_stb_o }), 61 | .m2i_we_i({ m2_mem_we_o, 1'b0, 1'b0 }), 62 | .m2i_adr_i({ m2_mem_adr_o, 16'h1000, 16'h0000 }), 63 | .m2i_dat_i({ m2_mem_dat_o, 32'h0000, 32'h0000 }), 64 | .m2i_sel_i({ 8'hff, 8'h00, 8'h00 }), 65 | .i2m_ack_o({ m2_mem_ack_i, m1_nop_ack_i, m0_nop_ack_i }), 66 | .i2m_err_o({ m2_mem_err_i, nc, nc }), 67 | .i2m_dat_o(master_dat_i), 68 | .s2i_ack_i({ s2_reg_ack_o, s1_nop_ack_o, s0_nop_ack_o }), 69 | .s2i_err_i({ s2_reg_err_o, 1'b0, 1'b0 }), 70 | .s2i_dat_i({ s2_reg_dat_o, 32'b0, 32'b0 }), 71 | .i2s_stb_o({ s2_reg_stb_i, s1_nop_stb_i, s0_nop_stb_i }), 72 | .i2s_cyc_o(slave_cyc_i), 73 | .i2s_adr_o(slave_adr_i), 74 | .i2s_dat_o(slave_dat_i), 75 | .i2s_sel_o(slave_sel_i), 76 | .i2s_we_o(slave_we_i) 77 | ); 78 | 79 | wb_master_nop #( 80 | .INITIAL_DELAY(1), 81 | .WAIT_CYCLES(0) 82 | ) wb_master0_nop_dut ( 83 | .rst_i(rst_o), 84 | .clk_i(clk_o), 85 | .cyc_o(m0_nop_cyc_o), 86 | .stb_o(m0_nop_stb_o), 87 | .ack_i(m0_nop_ack_i) 88 | ); 89 | 90 | wb_master_nop #( 91 | .INITIAL_DELAY(1), 92 | .WAIT_CYCLES(0) 93 | ) wb_master1_nop_dut ( 94 | .rst_i(rst_o), 95 | .clk_i(clk_o), 96 | .cyc_o(m1_nop_cyc_o), 97 | .stb_o(m1_nop_stb_o), 98 | .ack_i(m1_nop_ack_i) 99 | ); 100 | 101 | wb_master_seq_mem_access #( 102 | .ADDR_WIDTH(ADDR_WIDTH), 103 | .DATA_WIDTH(DATA_WIDTH), 104 | .START_ADDR(16'h2000), 105 | .END_ADDR(16'h200f) 106 | ) wb_master2_mem_dut ( 107 | .rst_i(rst_o), 108 | .clk_i(clk_o), 109 | .stb_o(m2_mem_stb_o), 110 | .cyc_o(m2_mem_cyc_o), 111 | .we_o(m2_mem_we_o), 112 | .adr_o(m2_mem_adr_o), 113 | .dat_o(m2_mem_dat_o), 114 | .dat_i(master_dat_i), 115 | .ack_i(m2_mem_ack_i), 116 | .err_i(m2_mem_err_i) 117 | ); 118 | 119 | wb_slave_nop wb_slave0_nop_dut ( 120 | .rst_i(rst_o), 121 | .clk_i(clk_o), 122 | .cyc_i(slave_cyc_i), 123 | .stb_i(s0_nop_stb_i), 124 | .ack_o(s0_nop_ack_o) 125 | ); 126 | 127 | wb_slave_nop wb_slave1_nop_dut ( 128 | .rst_i(rst_o), 129 | .clk_i(clk_o), 130 | .cyc_i(slave_cyc_i), 131 | .stb_i(s1_nop_stb_i), 132 | .ack_o(s1_nop_ack_o) 133 | ); 134 | 135 | wb_slave_register #( 136 | .ADDR_WIDTH(ADDR_WIDTH), 137 | .DATA_WIDTH(DATA_WIDTH), 138 | .GRANULE(GRANULE) 139 | ) wb_slave2_reg_dut ( 140 | .rst_i(rst_o), 141 | .clk_i(clk_o), 142 | .cyc_i(slave_cyc_i), 143 | .stb_i(s2_reg_stb_i), 144 | .ack_o(s2_reg_ack_o), 145 | .adr_i(slave_adr_i), 146 | .dat_i(slave_dat_i), 147 | .dat_o(s2_reg_dat_o), 148 | .sel_i(slave_sel_i), 149 | .we_i(slave_we_i), 150 | .err_o(s2_reg_err_o) 151 | ); 152 | 153 | initial begin 154 | $dumpfile(`WAVE_FILE); 155 | $dumpvars(0); 156 | 157 | rst_o = 0; 158 | clk_o = 0; 159 | 160 | #2000; 161 | 162 | $finish; 163 | end 164 | 165 | always begin 166 | #10 clk_o = ~clk_o; 167 | end 168 | 169 | endmodule -------------------------------------------------------------------------------- /wb_loopback/design.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * General description: 4 | * 5 | * A basic device which implements both a master and a slave Wishbone interface 6 | * 7 | * Wishbone specification used: B4 (https://cdn.opencores.org/downloads/wbspec_b4.pdf) 8 | * 9 | * Copyright (c) Szymon Urbaś All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions are met: 13 | * 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 3. Neither the name of the copyright holder nor the names of its 20 | * contributors may be used to endorse or promote products derived from 21 | * this software without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 | * POSSIBILITY OF SUCH DAMAGE. 34 | * 35 | */ 36 | 37 | `default_nettype none 38 | 39 | package wb_loopback_pkg; 40 | 41 | typedef enum int { 42 | MASTER_STATE_WAIT, 43 | MASTER_STATE_START, 44 | MASTER_STATE_WAIT_FOR_ACK 45 | } master_state_t; 46 | 47 | typedef enum int { 48 | SLAVE_STATE_WAIT, 49 | SLAVE_STATE_RESPOND 50 | } slave_state_t; 51 | 52 | endpackage 53 | 54 | module wb_loopback ( 55 | input wire rst_i, 56 | input wire clk_i, 57 | // master interface 58 | input wire ack_i, 59 | output reg stb_o, 60 | output reg cyc_o, 61 | // slave interface 62 | output reg ack_o, 63 | input wire stb_i, 64 | input wire cyc_i 65 | ); 66 | 67 | parameter INITIAL_DELAY = 2; 68 | parameter WAIT_CYCLES = 4; 69 | parameter SLAVE_RESPONSE_WAIT_CYCLES = 4; 70 | 71 | import wb_loopback_pkg::*; 72 | 73 | master_state_t master_state = MASTER_STATE_WAIT; 74 | slave_state_t slave_state = SLAVE_STATE_WAIT; 75 | int wait_cycles = INITIAL_DELAY; 76 | int slave_response_wait_cycles = SLAVE_RESPONSE_WAIT_CYCLES; 77 | 78 | // slave interface 79 | always @(posedge clk_i) begin 80 | if (rst_i) begin 81 | slave_state <= SLAVE_STATE_WAIT; 82 | ack_o <= 1'b0; 83 | end else begin 84 | case (slave_state) 85 | SLAVE_STATE_WAIT: begin 86 | if (stb_i) begin 87 | slave_state <= SLAVE_STATE_RESPOND; 88 | ack_o <= 1'b1; 89 | end 90 | end 91 | SLAVE_STATE_RESPOND: begin 92 | if (slave_response_wait_cycles == 0) begin 93 | slave_state <= SLAVE_STATE_WAIT; 94 | slave_response_wait_cycles <= SLAVE_RESPONSE_WAIT_CYCLES; 95 | ack_o <= 1'b0; 96 | end else begin 97 | slave_response_wait_cycles <= slave_response_wait_cycles - 1; 98 | end 99 | end 100 | endcase 101 | end 102 | end 103 | 104 | // master interface 105 | always @(posedge clk_i) begin 106 | if (rst_i) begin 107 | master_state <= MASTER_STATE_WAIT; 108 | stb_o <= 0; 109 | cyc_o <= 0; 110 | wait_cycles <= WAIT_CYCLES; 111 | end else begin 112 | case (master_state) 113 | MASTER_STATE_WAIT: begin 114 | if (wait_cycles == 0) begin 115 | master_state <= MASTER_STATE_START; 116 | wait_cycles <= WAIT_CYCLES; 117 | end else begin 118 | wait_cycles <= wait_cycles - 1; 119 | end 120 | end 121 | MASTER_STATE_START: begin 122 | master_state <= MASTER_STATE_WAIT_FOR_ACK; 123 | stb_o <= 1; 124 | cyc_o <= 1; 125 | end 126 | MASTER_STATE_WAIT_FOR_ACK: begin 127 | if (ack_i) begin 128 | master_state <= MASTER_STATE_WAIT; 129 | stb_o <= 0; 130 | cyc_o <= 0; 131 | end 132 | end 133 | endcase 134 | end 135 | end 136 | 137 | endmodule 138 | -------------------------------------------------------------------------------- /wb_master_seq_mem_access/design.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * General description: 4 | * 5 | * A master device, which continuously issues SINGLE WRITE and SINGLE READ 6 | * bus cycles, over a range of memory addresses. 7 | * 8 | * Wishbone specification used: B4 (https://cdn.opencores.org/downloads/wbspec_b4.pdf) 9 | * 10 | * Copyright (c) Szymon Urbaś All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. Neither the name of the copyright holder nor the names of its 21 | * contributors may be used to endorse or promote products derived from 22 | * this software without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 | * POSSIBILITY OF SUCH DAMAGE. 35 | * 36 | */ 37 | 38 | `default_nettype none 39 | 40 | package wb_master_seq_mem_access_pkg; 41 | 42 | typedef enum int { 43 | STATE_INIT, 44 | STATE_START, 45 | STATE_WAIT_FOR_ACK_AFTER_WRITE, 46 | STATE_WAIT_BEFORE_READ, 47 | STATE_WAIT_FOR_ACK_AFTER_READ 48 | } state_t; 49 | 50 | endpackage 51 | 52 | module wb_master_seq_mem_access ( 53 | input wire rst_i, 54 | input wire clk_i, 55 | output wire stb_o, 56 | output wire cyc_o, 57 | output reg we_o, 58 | output reg [ADDR_WIDTH-1:0] adr_o, 59 | output reg [DATA_WIDTH-1:0] dat_o, 60 | input wire [DATA_WIDTH-1:0] dat_i, 61 | input wire ack_i, 62 | input wire err_i 63 | ); 64 | 65 | parameter ADDR_WIDTH = 16; 66 | parameter DATA_WIDTH = 32; 67 | parameter START_ADDR = 0; 68 | parameter END_ADDR = 15; // inclusive 69 | parameter STEP = 1; 70 | 71 | import wb_master_seq_mem_access_pkg::*; 72 | 73 | state_t state = STATE_INIT; 74 | 75 | reg stb = 0; 76 | reg cyc = 0; 77 | 78 | reg [ADDR_WIDTH-1:0] curr_addr = START_ADDR; 79 | reg [DATA_WIDTH-1:0] curr_data; 80 | reg [2:0] init_cycles = 0; 81 | 82 | assign stb_o = stb; 83 | assign cyc_o = cyc; 84 | 85 | always @(posedge clk_i) begin 86 | if (rst_i) begin 87 | state <= STATE_IDLE; 88 | end else begin 89 | case (state) 90 | STATE_INIT: begin 91 | if (init_cycles[2] == 1'b1) 92 | state <= STATE_START; 93 | 94 | init_cycles <= init_cycles + 1; 95 | end 96 | STATE_START: begin 97 | state <= STATE_WAIT_FOR_ACK_AFTER_WRITE; 98 | stb <= 1; 99 | cyc <= 1; 100 | we_o <= 1'b1; 101 | adr_o <= curr_addr; 102 | dat_o <= $urandom_range(16); 103 | curr_data <= dat_o; 104 | end 105 | STATE_WAIT_FOR_ACK_AFTER_WRITE: begin 106 | if (ack_i) begin 107 | state <= STATE_WAIT_BEFORE_READ; 108 | stb <= 0; 109 | we_o <= 1'b0; 110 | end else if (err_i) begin 111 | // essentially retry 112 | state <= STATE_START; 113 | stb <= 0; 114 | cyc <= 0; 115 | we_o <= 1'b0; 116 | end 117 | end 118 | STATE_WAIT_BEFORE_READ: begin 119 | state <= STATE_WAIT_FOR_ACK_AFTER_READ; 120 | stb <= 1; 121 | end 122 | STATE_WAIT_FOR_ACK_AFTER_READ: begin 123 | if (ack_i) begin 124 | state <= STATE_START; 125 | stb <= 0; 126 | cyc <= 0; 127 | 128 | if (curr_addr + STEP > END_ADDR) 129 | curr_addr <= START_ADDR; 130 | else 131 | curr_addr <= curr_addr + STEP; 132 | end 133 | end 134 | endcase 135 | end 136 | end 137 | 138 | endmodule 139 | -------------------------------------------------------------------------------- /wb_slave_register/design.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * General description: 4 | * 5 | * A simple register array device, which contains a number of identical registers. 6 | * Number of registers is controlled by a module parameter. They are then 7 | * addressed using the ADR_I lines (where, ADR_I = 0x0, is first register, 8 | * ADR_I = 0x1 is second register, etc. regardless of their sizes) 9 | * 10 | * Supported cycles: 11 | * 12 | * SLAVE, READ / WRITE 13 | * SLAVE, READ MODIFY WRITE 14 | * SLAVE, PIPELINED READ / WRITE 15 | * 16 | * Data organization: 17 | * 18 | * Port size: 8, 16, 32 or 64 bit (module parameter: DATA_WIDTH) 19 | * Port granularity: 8, 16, 32 or 64 bit (module parameter: GRANULE) 20 | * Port maximum operand size: depends on port size 21 | * Transfer ordering: Big endian 22 | * Transfer sequencing: Undefined 23 | * 24 | * Usage of ERR_O: 25 | * 26 | * ERR_O is asserted (instead of ACK_O) when one of the following occurs: 27 | * 28 | * - an out-of-bounds register is addressed 29 | * 30 | * Wishbone specification used: B4 (https://cdn.opencores.org/downloads/wbspec_b4.pdf) 31 | * 32 | * Copyright (c) Szymon Urbaś All rights reserved. 33 | * 34 | * Redistribution and use in source and binary forms, with or without 35 | * modification, are permitted provided that the following conditions are met: 36 | * 37 | * 1. Redistributions of source code must retain the above copyright 38 | * notice, this list of conditions and the following disclaimer. 39 | * 2. Redistributions in binary form must reproduce the above copyright 40 | * notice, this list of conditions and the following disclaimer in the 41 | * documentation and/or other materials provided with the distribution. 42 | * 3. Neither the name of the copyright holder nor the names of its 43 | * contributors may be used to endorse or promote products derived from 44 | * this software without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 47 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 50 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 51 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 52 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 53 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 54 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 55 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 56 | * POSSIBILITY OF SUCH DAMAGE. 57 | * 58 | */ 59 | 60 | `default_nettype none 61 | 62 | typedef enum { 63 | STATE_IDLE, 64 | STATE_PROCESS, 65 | STATE_WAIT_FOR_PHASE_END 66 | } state_t; 67 | 68 | module wb_slave_register ( 69 | input wire rst_i, 70 | input wire clk_i, 71 | input wire [ADDR_WIDTH-1:0] adr_i, 72 | input wire [DATA_WIDTH-1:0] dat_i, 73 | output reg [DATA_WIDTH-1:0] dat_o, 74 | input wire [SEL_WIDTH-1:0] sel_i, 75 | input wire we_i, 76 | input wire stb_i, 77 | output wire ack_o, 78 | output wire err_o, 79 | input wire cyc_i 80 | ); 81 | 82 | parameter ADDR_WIDTH = 16; 83 | parameter DATA_WIDTH = 32; 84 | parameter GRANULE = 8; 85 | parameter REGISTER_NUM = 16; 86 | localparam SEL_WIDTH = DATA_WIDTH / GRANULE; 87 | 88 | reg [DATA_WIDTH-1:0] register_value [0:REGISTER_NUM-1]; 89 | reg [ADDR_WIDTH-1:0] r_adr_i; 90 | reg [DATA_WIDTH-1:0] r_dat_i; 91 | reg [SEL_WIDTH-1:0] r_sel_i; 92 | reg r_we_i; 93 | reg ack = 1'h0; 94 | reg err = 1'h0; 95 | state_t state = STATE_IDLE; 96 | int i; 97 | 98 | always @(posedge clk_i) begin 99 | if (rst_i) begin 100 | state <= STATE_IDLE; 101 | ack <= 1'h0; 102 | err <= 1'h0; 103 | 104 | for (i = 0; i < REGISTER_NUM; i++) begin 105 | register_value[i] <= {DATA_WIDTH{1'h0}}; 106 | end 107 | end else begin 108 | case (state) 109 | STATE_IDLE: begin 110 | if (stb_i) begin 111 | state <= STATE_PROCESS; 112 | r_sel_i <= sel_i; 113 | r_adr_i <= adr_i; 114 | r_we_i <= we_i; 115 | ack <= 1'h0; 116 | err <= 1'h0; 117 | 118 | if (we_i) begin 119 | r_dat_i <= dat_i; 120 | end 121 | end 122 | end 123 | STATE_PROCESS: begin 124 | if (r_adr_i > REGISTER_NUM) begin 125 | err <= 1'h1; 126 | ack <= 1'h0; 127 | end else begin 128 | for (i = 0; i < SEL_WIDTH; i++) begin 129 | if (r_sel_i[i]) begin 130 | if (r_we_i) begin 131 | register_value[r_adr_i][i*GRANULE+:GRANULE] <= r_dat_i[i*GRANULE+:GRANULE]; 132 | end else begin 133 | dat_o[i*GRANULE+:GRANULE] <= register_value[r_adr_i][i*GRANULE+:GRANULE]; 134 | end 135 | end 136 | end 137 | 138 | ack <= 1'h1; 139 | err <= 1'h0; 140 | end 141 | 142 | state <= STATE_WAIT_FOR_PHASE_END; 143 | end 144 | STATE_WAIT_FOR_PHASE_END: begin 145 | if (~stb_i) begin 146 | state <= STATE_IDLE; 147 | ack <= 1'h0; 148 | err <= 1'h0; 149 | end 150 | end 151 | endcase 152 | end 153 | end 154 | 155 | assign ack_o = ack; 156 | assign err_o = err; 157 | 158 | endmodule 159 | -------------------------------------------------------------------------------- /wb_intercon/design.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * General description: 4 | * 5 | * A simple general Wishbone multiplexed interconnect. 6 | * It's using a simple round robin way of selecting which master gets to go. 7 | * 8 | * Wishbone specification used: B4 (https://cdn.opencores.org/downloads/wbspec_b4.pdf) 9 | * 10 | * Copyright (c) Szymon Urbaś All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. Neither the name of the copyright holder nor the names of its 21 | * contributors may be used to endorse or promote products derived from 22 | * this software without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 | * POSSIBILITY OF SUCH DAMAGE. 35 | * 36 | */ 37 | 38 | package wb_intercon_pkg; 39 | 40 | typedef enum { 41 | STATE_WAIT_FOR_BUS_CLAIM, 42 | STATE_WAIT_FOR_CYCLE_END 43 | } state_t; 44 | 45 | endpackage 46 | 47 | module wb_intercon ( 48 | input wire rst_i, 49 | input wire clk_i, 50 | 51 | // 52 | // master -> intercon 53 | // 54 | input wire [MASTERS_NUM-1:0] m2i_cyc_i, 55 | input wire [MASTERS_NUM-1:0] m2i_stb_i, 56 | input wire [MASTERS_NUM-1:0] m2i_we_i, 57 | input wire [MASTERS_NUM*ADDR_WIDTH-1:0] m2i_adr_i, 58 | input wire [MASTERS_NUM*DATA_WIDTH-1:0] m2i_dat_i, 59 | input wire [MASTERS_NUM*SEL_WIDTH-1:0] m2i_sel_i, 60 | // 61 | // intercon -> master 62 | // 63 | output wire [MASTERS_NUM-1:0] i2m_ack_o, 64 | output wire [MASTERS_NUM-1:0] i2m_err_o, 65 | // shared between all masters 66 | output wire [DATA_WIDTH-1:0] i2m_dat_o, 67 | // 68 | // slave -> intercon 69 | // 70 | input wire [SLAVES_NUM-1:0] s2i_ack_i, 71 | input wire [SLAVES_NUM-1:0] s2i_err_i, 72 | input wire [SLAVES_NUM*DATA_WIDTH-1:0] s2i_dat_i, 73 | // 74 | // intercon -> slave 75 | // 76 | // each slave gets it's own stb signal 77 | output wire [SLAVES_NUM-1:0] i2s_stb_o, 78 | // and these are all shared across all slaves 79 | output wire i2s_cyc_o, 80 | output wire [ADDR_WIDTH-1:0] i2s_adr_o, 81 | output wire [DATA_WIDTH-1:0] i2s_dat_o, 82 | output wire [SEL_WIDTH-1:0] i2s_sel_o, 83 | output wire i2s_we_o, 84 | 85 | // so we don't have to care about the ',' 86 | output wire nc 87 | ); 88 | 89 | parameter MASTERS_NUM = 2; 90 | parameter SLAVES_NUM = 2; 91 | parameter ADDR_WIDTH = 16; 92 | parameter DATA_WIDTH = 32; 93 | localparam SEL_WIDTH = 8; 94 | 95 | import wb_intercon_pkg::*; 96 | 97 | state_t state = STATE_WAIT_FOR_BUS_CLAIM; 98 | reg [$clog2(MASTERS_NUM)-1:0] grant = 0; 99 | 100 | wire [$clog2(SLAVES_NUM)-1:0] selected_slave; 101 | 102 | // upper 4 bits of granted master's adr_o select the slave 103 | assign selected_slave = m2i_adr_i[ADDR_WIDTH*grant+ADDR_WIDTH-4+:4]; 104 | 105 | // distribute the stb_o signal only to the one slave 106 | assign i2s_stb_o = m2i_stb_i[grant] << selected_slave; 107 | // distribute the rest of signals, which are shared across all slaves 108 | assign i2s_cyc_o = {SLAVES_NUM{m2i_cyc_i[grant]}}; 109 | assign i2s_adr_o = m2i_adr_i[ADDR_WIDTH*grant+:ADDR_WIDTH] & 12'hfff; 110 | assign i2s_dat_o = m2i_dat_i[DATA_WIDTH*grant+:DATA_WIDTH]; 111 | assign i2s_sel_o = m2i_sel_i[SEL_WIDTH*grant+:SEL_WIDTH]; 112 | assign i2s_we_o = m2i_we_i[grant]; 113 | 114 | // distribute the ack and err signals coming back from the slave to the blessed master 115 | assign i2m_ack_o = s2i_ack_i[selected_slave] << grant; 116 | assign i2m_err_o = s2i_err_i[selected_slave] << grant; 117 | // distribute the output data of the selected slave to all masters 118 | assign i2m_dat_o = s2i_dat_i[DATA_WIDTH*selected_slave+:DATA_WIDTH]; 119 | 120 | int n, i; 121 | bit found_next_master; 122 | 123 | always @(posedge clk_i) begin 124 | if (rst_i) begin 125 | state <= STATE_WAIT_FOR_BUS_CLAIM; 126 | grant <= 0; 127 | end else begin 128 | case (state) 129 | STATE_WAIT_FOR_BUS_CLAIM: begin 130 | // reduction OR - check if at least one bit is set 131 | if (|m2i_cyc_i) begin 132 | found_next_master = 0; 133 | // find the next right-most bit, starting from 'grant' bit 134 | i = grant; 135 | for (n = 0; n < MASTERS_NUM && !found_next_master; n++) begin 136 | if (m2i_cyc_i[i]) begin 137 | found_next_master = 1; 138 | state <= STATE_WAIT_FOR_CYCLE_END; 139 | grant <= i; 140 | end 141 | 142 | i = (i + 1) % MASTERS_NUM; 143 | end 144 | end 145 | end 146 | STATE_WAIT_FOR_CYCLE_END: begin 147 | if (~m2i_cyc_i[grant]) begin 148 | state <= STATE_WAIT_FOR_BUS_CLAIM; 149 | grant <= (grant + 1) % MASTERS_NUM; 150 | end 151 | end 152 | endcase 153 | end 154 | end 155 | 156 | endmodule -------------------------------------------------------------------------------- /wb_slave_register/testbench.sv: -------------------------------------------------------------------------------- 1 | typedef enum { 2 | OP_CLASSIC_SINGLE_READ, 3 | OP_CLASSIC_SINGLE_WRITE, 4 | OP_READ_MODIFY_WRITE, 5 | OP_PIPELINED_SINGLE_READ, 6 | OP_PIPELINED_SINGLE_WRITE 7 | } op_t; 8 | 9 | typedef enum { 10 | RETURN_ACK, 11 | RETURN_ERR 12 | } ret_t; 13 | 14 | module wb_slave_register_tb (); 15 | localparam ADDR_WIDTH = 16; 16 | localparam DATA_WIDTH = 32; 17 | localparam GRANULE = 8; 18 | localparam SEL_WIDTH = DATA_WIDTH / GRANULE; 19 | 20 | reg rst_o; 21 | reg clk_i; 22 | reg ack_i; 23 | reg err_i; 24 | reg stb_o; 25 | reg [ADDR_WIDTH-1:0] adr_o; 26 | reg [DATA_WIDTH-1:0] dat_i; 27 | reg [DATA_WIDTH-1:0] dat_o; 28 | reg [SEL_WIDTH-1:0] sel_o; 29 | reg we_o; 30 | reg cyc_o; 31 | 32 | reg [DATA_WIDTH-1:0] read_data; 33 | reg [3:0] return_type; 34 | 35 | reg [4+SEL_WIDTH+ADDR_WIDTH+DATA_WIDTH*2+4-1:0] testvector [31:0]; 36 | reg [3:0] tv_op; 37 | reg [SEL_WIDTH-1:0] tv_sel; 38 | reg [ADDR_WIDTH-1:0] tv_addr; 39 | reg [DATA_WIDTH-1:0] tv_write_data; 40 | reg [DATA_WIDTH-1:0] tv_expected_data; 41 | reg [3:0] tv_return_type; 42 | int current_test_num = 0; 43 | int errors = 0; 44 | int i = 0; 45 | 46 | wb_slave_register #( 47 | .ADDR_WIDTH(ADDR_WIDTH), 48 | .DATA_WIDTH(DATA_WIDTH), 49 | .GRANULE(GRANULE) 50 | ) slave_tb ( 51 | .rst_i(rst_o), 52 | .clk_i(clk_i), 53 | .adr_i(adr_o), 54 | .dat_o(dat_i), 55 | .dat_i(dat_o), 56 | .we_i(we_o), 57 | .cyc_i(cyc_o), 58 | .ack_o(ack_i), 59 | .err_o(err_i), 60 | .stb_i(stb_o), 61 | .sel_i(sel_o) 62 | ); 63 | 64 | task single_read; 65 | input [ADDR_WIDTH-1:0] addr; 66 | input [7:0] selection; 67 | output [DATA_WIDTH-1:0] data; 68 | output [3:0] return_type; 69 | 70 | @(posedge clk_i); 71 | 72 | $display(".. %03g: Starting a cycle (adr_o -> 0x%x, sel_o -> 0x%x, we_o -> 0, cyc_o -> 1, stb_o -> 1)", 73 | $time, addr, selection); 74 | 75 | adr_o = addr; 76 | sel_o = selection; 77 | we_o = 1'h0; 78 | cyc_o = 1'h1; 79 | stb_o = 1'h1; 80 | 81 | while (ack_i != 1'h1 && err_i != 1'h1) begin 82 | $display(".. %03g: Waiting for ACK or ERR...", $time); 83 | @(posedge clk_i); 84 | end 85 | 86 | if (err_i == 1'h1) begin 87 | $display(".. %03g: Got ERR", $time); 88 | return_type = RETURN_ERR; 89 | end else if (ack_i == 1'h1) begin 90 | $display(".. %03g: Got ACK", $time); 91 | data = dat_i; 92 | $display(".. %03g: Received data: 0x%x", $time, data); 93 | return_type = RETURN_ACK; 94 | end 95 | 96 | $display(".. %03g: Ending cycle (cyc_o -> 0, stb_o -> 0)", $time); 97 | 98 | stb_o = 1'h0; 99 | cyc_o = 1'h0; 100 | 101 | #1; 102 | endtask 103 | 104 | task single_write; 105 | input [ADDR_WIDTH-1:0] addr; 106 | input [7:0] selection; 107 | input [DATA_WIDTH-1:0] data; 108 | output [3:0] return_type; 109 | 110 | @(posedge clk_i); 111 | 112 | $display(".. %03g: Starting a cycle (adr_o -> 0x%x, sel_o -> 0x%x, dat_o -> 0x%x, we_o -> 0, cyc_o -> 1, stb_o -> 1)", 113 | $time, addr, selection, data); 114 | 115 | adr_o = addr; 116 | sel_o = selection; 117 | dat_o = data; 118 | we_o = 1'h1; 119 | cyc_o = 1'h1; 120 | stb_o = 1'h1; 121 | 122 | while (ack_i != 1'h1 && err_i != 1'h1) begin 123 | $display(".. %03g: Waiting for ACK or ERR...", $time); 124 | @(posedge clk_i); 125 | end 126 | 127 | if (err_i == 1'h1) begin 128 | $display(".. %03g: Got ERR", $time); 129 | return_type = RETURN_ERR; 130 | end else if (ack_i == 1'h1) begin 131 | $display(".. %03g: Got ACK", $time); 132 | return_type = RETURN_ACK; 133 | end 134 | 135 | $display(".. %03g: Ending cycle (cyc_o -> 0, stb_o -> 0, we_o -> 0)", $time); 136 | 137 | stb_o = 1'h0; 138 | cyc_o = 1'h0; 139 | we_o = 1'h0; 140 | 141 | #1; 142 | endtask 143 | 144 | task read_modify_write; 145 | input [ADDR_WIDTH-1:0] addr; 146 | input [7:0] selection; 147 | input [DATA_WIDTH-1:0] write_data; 148 | output [DATA_WIDTH-1:0] read_data; 149 | output [3:0] return_type; 150 | 151 | @(posedge clk_i); 152 | 153 | $display(".. %03g: Starting a cycle (adr_o -> 0x%x, sel_o -> 0x%x, we_o -> 0, cyc_o -> 1, stb_o -> 1)", 154 | $time, addr, selection); 155 | $display(".. %03g: Read phase (stb_o -> 1)", $time); 156 | 157 | adr_o = addr; 158 | sel_o = selection; 159 | we_o = 1'h0; 160 | cyc_o = 1'h1; 161 | stb_o = 1'h1; 162 | 163 | @(posedge clk_i); 164 | 165 | stb_o = 1'h0; 166 | 167 | while (ack_i != 1'h1 && err_i != 1'h1) begin 168 | $display(".. %03g: Waiting for ACK or ERR...", $time); 169 | @(posedge clk_i); 170 | end 171 | 172 | if (err_i == 1'h1) begin 173 | $display(".. %03g: Got ERR", $time); 174 | return_type = RETURN_ERR; 175 | end else if (ack_i == 1'h1) begin 176 | $display(".. %03g: Got ACK", $time); 177 | return_type = RETURN_ACK; 178 | end 179 | 180 | read_data = dat_i; 181 | 182 | $display(".. %03g: Received data: 0x%x", $time, read_data); 183 | $display(".. %03g: Ending phase (stb_o -> 0)", $time); 184 | 185 | // set the data up before the next posedge 186 | @(negedge clk_i); 187 | 188 | $display(".. %03g: Write phase (dat_o -> 0x%x, stb_o -> 1)", $time, write_data); 189 | 190 | dat_o = write_data; 191 | we_o = 1'h1; 192 | stb_o = 1'h1; 193 | 194 | // wait two posedges so the slave has time to latch the data in 195 | @(posedge clk_i); 196 | @(posedge clk_i); 197 | 198 | stb_o = 1'h0; 199 | we_o = 1'h0; 200 | 201 | i = 0; 202 | while (ack_i != 1'h1 && err_i != 1'h1 && i < 10) begin 203 | $display(".. %03g: Waiting for ACK or ERR...", $time); 204 | @(posedge clk_i); 205 | i = i+1; 206 | end 207 | 208 | if (err_i == 1'h1) begin 209 | $display(".. %03g: Got ERR", $time); 210 | return_type = RETURN_ERR; 211 | end else if (ack_i == 1'h1) begin 212 | $display(".. %03g: Got ACK", $time); 213 | return_type = RETURN_ACK; 214 | end 215 | 216 | $display(".. %03g: Ending cycle (cyc_o -> 0, stb_o -> 0, we_o -> 0)", $time); 217 | 218 | stb_o = 1'h0; 219 | cyc_o = 1'h0; 220 | we_o = 1'h0; 221 | 222 | #1; 223 | endtask 224 | 225 | task pipelined_single_read; 226 | input [ADDR_WIDTH-1:0] addr; 227 | input [7:0] selection; 228 | output [DATA_WIDTH-1:0] data; 229 | output [3:0] return_type; 230 | 231 | @(posedge clk_i); 232 | 233 | $display(".. %03g: Starting a cycle (adr_o -> 0x%x, sel_o -> 0x%x, we_o -> 0, cyc_o -> 1, stb_o -> 1)", 234 | $time, addr, selection); 235 | 236 | adr_o = addr; 237 | sel_o = selection; 238 | we_o = 1'h0; 239 | cyc_o = 1'h1; 240 | stb_o = 1'h1; 241 | 242 | @(posedge clk_i); 243 | 244 | adr_o = {ADDR_WIDTH{1'bx}}; 245 | sel_o = {SEL_WIDTH{1'bx}}; 246 | stb_o = 1'h0; 247 | i = 0; 248 | 249 | while (ack_i != 1'h1 && err_i != 1'h1 && i < 10) begin 250 | $display(".. %03g: Waiting for ACK or ERR...", $time); 251 | @(posedge clk_i); 252 | i = i+1; 253 | end 254 | 255 | if (err_i == 1'h1) begin 256 | $display(".. %03g: Got ERR", $time); 257 | return_type = RETURN_ERR; 258 | end else if (ack_i == 1'h1) begin 259 | $display(".. %03g: Got ACK", $time); 260 | data = dat_i; 261 | $display(".. %03g: Received data: 0x%x", $time, data); 262 | return_type = RETURN_ACK; 263 | end 264 | 265 | $display(".. %03g: Ending cycle (cyc_o -> 0, stb_o -> 0)", $time); 266 | 267 | cyc_o = 1'h0; 268 | 269 | #1; 270 | endtask 271 | 272 | task pipelined_single_write; 273 | input [ADDR_WIDTH-1:0] addr; 274 | input [7:0] selection; 275 | input [DATA_WIDTH-1:0] data; 276 | output [3:0] return_type; 277 | 278 | @(posedge clk_i); 279 | 280 | $display(".. %03g: Starting a cycle (adr_o -> 0x%x, sel_o -> 0x%x, dat_o -> 0x%x, we_o -> 0, cyc_o -> 1, stb_o -> 1)", 281 | $time, addr, selection, data); 282 | 283 | adr_o = addr; 284 | sel_o = selection; 285 | dat_o = data; 286 | we_o = 1'h1; 287 | cyc_o = 1'h1; 288 | stb_o = 1'h1; 289 | 290 | @(posedge clk_i); 291 | 292 | adr_o = {ADDR_WIDTH{1'bx}}; 293 | dat_o = {DATA_WIDTH{1'bx}}; 294 | sel_o = {SEL_WIDTH{1'bx}}; 295 | we_o = 1'h0; 296 | stb_o = 1'h0; 297 | 298 | while (ack_i != 1'h1 && err_i != 1'h1) begin 299 | $display(".. %03g: Waiting for ACK or ERR...", $time); 300 | @(posedge clk_i); 301 | end 302 | 303 | if (err_i == 1'h1) begin 304 | $display(".. %03g: Got ERR", $time); 305 | return_type = RETURN_ERR; 306 | end else if (ack_i == 1'h1) begin 307 | $display(".. %03g: Got ACK", $time); 308 | return_type = RETURN_ACK; 309 | end 310 | 311 | $display(".. %03g: Ending cycle (cyc_o -> 0)", $time); 312 | 313 | cyc_o = 1'h0; 314 | 315 | #1; 316 | endtask 317 | 318 | initial begin 319 | $dumpfile(`WAVE_FILE); 320 | $dumpvars(0, slave_tb); 321 | 322 | $readmemh("testvector.tv", testvector); 323 | 324 | clk_i = 0; 325 | cyc_o = 0; 326 | stb_o = 0; 327 | we_o = 0; 328 | adr_o = 0; 329 | dat_o = 0; 330 | 331 | // reset the slave 332 | #1; 333 | rst_o = 1; 334 | #1; 335 | rst_o = 0; 336 | 337 | #10; 338 | 339 | for (int i = 0; i < 32; i++) begin 340 | { tv_op, tv_sel, tv_addr, tv_write_data, tv_expected_data, tv_return_type } = testvector[i]; 341 | 342 | if (tv_op === 4'hx) begin 343 | $display(""); 344 | $display("Completed %1d tests, %1d failed, %.2f%% success ratio", 345 | current_test_num, errors, (current_test_num - errors) * 100 / current_test_num); 346 | $finish; 347 | end 348 | 349 | current_test_num = current_test_num + 1; 350 | 351 | case (tv_op) 352 | OP_CLASSIC_SINGLE_READ: begin 353 | $display("## Test %1d: Classic Single Read", current_test_num); 354 | $display("-- Address: 0x%x", tv_addr); 355 | $display("-- Selection: 0x%x", tv_sel); 356 | $display("-- Expected output data: 0x%x", tv_expected_data); 357 | 358 | single_read(tv_addr, tv_sel, read_data, return_type); 359 | 360 | if (tv_expected_data != read_data) begin 361 | $display("!! Mismatch!"); 362 | $display("!! Expected 0x%x, got 0x%x (xor: 0x%x)", 363 | tv_expected_data, read_data, tv_expected_data ^ read_data); 364 | $display("!! NOK!"); 365 | errors = errors + 1; 366 | end else if (tv_return_type != return_type) begin 367 | $display("!! Mismatch!"); 368 | $display("!! Expected return with %1d, got %1d", tv_return_type, return_type); 369 | $display("!! (ACK is %1d, ERR is %1d)", RETURN_ACK, RETURN_ERR); 370 | $display("!! NOK!"); 371 | errors = errors + 1; 372 | end else begin 373 | $display("## Test %1d: OK", current_test_num); 374 | end 375 | end 376 | OP_CLASSIC_SINGLE_WRITE: begin 377 | $display("## Test %1d: Classic Single Write", current_test_num); 378 | $display("-- Address: 0x%x", tv_addr); 379 | $display("-- Input data: 0x%x", tv_write_data); 380 | $display("-- Selection: 0x%x", tv_sel); 381 | 382 | single_write(tv_addr, tv_sel, tv_write_data, return_type); 383 | 384 | if (tv_return_type != return_type) begin 385 | $display("!! Mismatch!"); 386 | $display("!! Expected return with %1d, got %1d", tv_return_type, return_type); 387 | $display("!! (ACK is %1d, ERR is %1d)", RETURN_ACK, RETURN_ERR); 388 | $display("!! NOK!"); 389 | errors = errors + 1; 390 | end else begin 391 | $display("## Test %1d: OK", current_test_num); 392 | end 393 | end 394 | OP_READ_MODIFY_WRITE: begin 395 | $display("## Test %1d: Read Modify Write", current_test_num); 396 | $display("-- Address: 0x%x", tv_addr); 397 | $display("-- Selection: 0x%x", tv_sel); 398 | $display("-- Input data: 0x%x", tv_write_data); 399 | $display("-- Expected read: 0x%x", tv_expected_data); 400 | 401 | read_modify_write(tv_addr, tv_sel, tv_write_data, read_data, return_type); 402 | 403 | if (tv_expected_data != read_data) begin 404 | $display("!! Mismatch!"); 405 | $display("!! Expected 0x%x, got 0x%x (xor: 0x%x)", 406 | tv_expected_data, read_data, tv_expected_data ^ read_data); 407 | $display("!! NOK!"); 408 | errors = errors + 1; 409 | end else if (tv_return_type != return_type) begin 410 | $display("!! Mismatch!"); 411 | $display("!! Expected return with %1d, got %1d", tv_return_type, return_type); 412 | $display("!! (ACK is %1d, ERR is %1d)", RETURN_ACK, RETURN_ERR); 413 | $display("!! NOK!"); 414 | errors = errors + 1; 415 | end else begin 416 | $display("## Test %1d: OK", current_test_num); 417 | end 418 | end 419 | OP_PIPELINED_SINGLE_READ: begin 420 | $display("## Test %1d: Pipelined Single Read", current_test_num); 421 | $display("-- Address: 0x%x", tv_addr); 422 | $display("-- Selection: 0x%x", tv_sel); 423 | $display("-- Expected output data: 0x%x", tv_expected_data); 424 | 425 | pipelined_single_read(tv_addr, tv_sel, read_data, return_type); 426 | 427 | if (tv_expected_data != read_data) begin 428 | $display("!! Mismatch!"); 429 | $display("!! Expected 0x%x, got 0x%x (xor: 0x%x)", 430 | tv_expected_data, read_data, tv_expected_data ^ read_data); 431 | $display("!! NOK!"); 432 | errors = errors + 1; 433 | end else if (tv_return_type != return_type) begin 434 | $display("!! Mismatch!"); 435 | $display("!! Expected return with %1d, got %1d", tv_return_type, return_type); 436 | $display("!! (ACK is %1d, ERR is %1d)", RETURN_ACK, RETURN_ERR); 437 | $display("!! NOK!"); 438 | errors = errors + 1; 439 | end else begin 440 | $display("## Test %1d: OK", current_test_num); 441 | end 442 | end 443 | OP_PIPELINED_SINGLE_WRITE: begin 444 | $display("## Test %1d: Pipelined Single Write", current_test_num); 445 | $display("-- Address: 0x%x", tv_addr); 446 | $display("-- Input data: 0x%x", tv_write_data); 447 | $display("-- Selection: 0x%x", tv_sel); 448 | 449 | pipelined_single_write(tv_addr, tv_sel, tv_write_data, return_type); 450 | 451 | if (tv_return_type != return_type) begin 452 | $display("!! Mismatch!"); 453 | $display("!! Expected return with %1d, got %1d", tv_return_type, return_type); 454 | $display("!! (ACK is %1d, ERR is %1d)", RETURN_ACK, RETURN_ERR); 455 | $display("!! NOK!"); 456 | errors = errors + 1; 457 | end else begin 458 | $display("## Test %1d: OK", current_test_num); 459 | end 460 | end 461 | default: begin 462 | $error("# test %2d: Unknown op: %x", 463 | current_test_num, tv_op); 464 | 465 | errors = errors + 1; 466 | end 467 | endcase 468 | end 469 | end 470 | 471 | always begin 472 | #1 clk_i = ~clk_i; 473 | end 474 | endmodule 475 | --------------------------------------------------------------------------------