Wishbone

Wishbone is an open source standard bus that connects slave peripherals to a master CPU. Instant SoC V1.2 supports Wishbone and you can easily add your own VHDL or Verilog peripherals to the Instant SoC RISC-V system. Instant SoC supports the B4 version of Wishbone.

Wishbone Bus
Wishbone Bus

To add a Wishbone component you simply creates a FC_Wishbone object in C++ with a file path to the component and Instant SoC adds the component and maps all Wishbone bus signals to the system. The file could be a Verilog (*.v) or VHDL (*.vhd) source file. You can add any number of the component to the system.

The following example shows the C++ code to add two PWM modules and two encoders to the system.

#include "FC_System.h"
#indlude "FC_IO.h"

void main()
{
 //% hw_begin
    FC_IO_Clk clk(100);         // 100 MHz        
    FC_Wishbone pwm_1("PWM_HiLo.v");
    FC_Wishbone pwm_2("PWM_HiLo.v");
    FC_Wishbone enc_1("QEncoder.vhd");
    FC_Wishbone enc_2("QEncoder.vhd");
//% hw_end

    // Reset enc_1
    enc_1.Reset();

    // Write 1000 to pwm_1 addr 2
    pwm_1.Write(1000, 2);    
    ...
    // Read addr 0 from enc_1
    int pos = enc_1.Read(0);
    ...
}

The Wishbone signals are automatically mapped inside the SoC system. Non Wishbone signals are exposed out from the generated system component. The name of the exposed signals are the same as the component signals names with the C++ object name added. In the example above the generated system port will look like the following.

entity wishbone is
    port(
        clk            : in std_logic;    --  100 MHz        
        pwm_1_pulse_hi : out std_logic;
        pwm_1_pulse_lo : out std_logic;
        pwm_2_pulse_hi : out std_logic;
        pwm_2_pulse_lo : out std_logic;
        enc_1_A        : in std_logic;
        enc_1_B        : in std_logic;
        enc_2_A        : in std_logic;
        enc_2_B        : in std_logic
    );
end entity;

The PWM component in the example is written in Verilog. The address width is two, i.e. four registers. The read/write data width is 16. The port looks like following.

module PWM_HiLo
(
    // --- Example external signals ---
    output reg pulse_hi,
    output reg pulse_lo,
    
    // --- Wishbone Signals ---
    input  wire CLK_I,
    input  wire RST_I,
    input  wire [1:0] ADR_I,
    output reg  [15:0] DAT_O,
    input  wire [15:0] DAT_I,
    input  wire WE_I,
    input  wire STB_I,
    output reg  ACK_O,
    input  wire CYC_I
);

The quadrature encoder component in the example is written in VHDL. It has only one read register that is 32 bits wide. The port looks like the following.

entity QEncoder is
port (
    --- Example external signals ---
    A : in std_logic;
    B : in std_logic;
    
    --- Wishbone Signals ---
    CLK_I : in std_logic;
    RST_I : in std_logic;
    DAT_O : out std_logic_vector(31 downto 0);
    STB_I : in std_logic;
    ACK_O : out std_logic;
    CYC_I : in std_logic
);
end entity;

Instant SoC parses the input source file signals and optimizes the system regarding to the component’s address and data width with minimal overhead.

Wishbone Slave Signals

Instant SoC supports the following Wishbone signals.

CLK_IInClock input. Mandatory. This is the same clock
as the system clock, FC_IO_Clk
RST_IInReset input. Active high. Reset is active when
system starts or called by FC_Wishbone::Reset()
ADR_IInAddress input for read and write cycles. Optional.
Width from 1 to 32.
DAT_OOutData out from component. Optional. Width from 1
to 32.
DAT_IInData in to component. Optional. Width from 1
to 32.
WE_IInWrite Enable. Indicates a write cycle. Optional.
STB_IInIndicates a valid data transfer
ACK_OOutAcknowledge output. Terminates a normal bus
cycle.
CYC_IInIndicates a valid bus cycle. Typically this is same as
STB_I signal.
Wishbone Slave SIgnals

Note that the signal names must be spelled exactly like the signal names in the table above.

As a minimum, the SLAVE interface MUST include the following signals: [ACK_O] , [CLK_I], [CYC_I], [STB_I], and [RST_I].

Create a Wishbone Slave Template

Instant SoC can generate a template that is a good starting point for your peripheral. Use the FC_Wishbone C++ constructor with a file name and address/data width arguments. If the file doesn’t exists Instant SoC will create the file and write a very simple component. Both Verilog and VHDL temple creation are supported. If the file name is (*.v) a Verilog source file is created. If the file name is (*.vhd) or (*.vhdl) a VHDL source file is created.

Expose the Wishbone Master Signals

It is also possible to expose the Master Wishbone signals if you want to map the signals outside the generated system. This is done by creating a FC_Wishbone object without a source file. You specify data and adress width.

In the following example a 16 x 32 bits register component is created.

#include "fc_io.h"
#include "fc_system.h"

int main()
{
//% hw_begin
    FC_IO_Clk clk(100);         // 100 MHz        
    FC_Wishbone wb(4,32,32);
//% hw_end

    wb.Write(0x1234,0); // Write 0x1234 to addr 0

    int read = wb.Read(1); // Read addr 1
    
    for(;;)
    {
    // Do something...        
    }
}

When building the C++ example code above a system is generated with the following VHDL port.

entity wishbone_example2 is
    port(
        clk      : in  std_logic;    --  100 MHz        
        wb_RST_O : out std_logic;
        wb_ADR_O : out std_logic_vector(3 downto 0);
        wb_DAT_I : in  std_logic_vector(31 downto 0);
        wb_DAT_O : out std_logic_vector(31 downto 0);
        wb_WE_O  : out std_logic;
        wb_STB_O : out std_logic;
        wb_ACK_I : in  std_logic;
        wb_CYC_O : out std_logic
    );
end entity;

Connect your FPGA