Commit 408c7ef8 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

Added simulation models

parent 89ba64fb
`define ADDR_MDIO_MCR 7'h0
`define MDIO_MCR_RESV_OFFSET 0
`define MDIO_MCR_RESV 32'h0000001f
`define MDIO_MCR_UNI_EN_OFFSET 5
`define MDIO_MCR_UNI_EN 32'h00000020
`define MDIO_MCR_SPEED1000_OFFSET 6
`define MDIO_MCR_SPEED1000 32'h00000040
`define MDIO_MCR_CTST_OFFSET 7
`define MDIO_MCR_CTST 32'h00000080
`define MDIO_MCR_FULLDPLX_OFFSET 8
`define MDIO_MCR_FULLDPLX 32'h00000100
`define MDIO_MCR_ANRESTART_OFFSET 9
`define MDIO_MCR_ANRESTART 32'h00000200
`define MDIO_MCR_ISOLATE_OFFSET 10
`define MDIO_MCR_ISOLATE 32'h00000400
`define MDIO_MCR_PDOWN_OFFSET 11
`define MDIO_MCR_PDOWN 32'h00000800
`define MDIO_MCR_ANENABLE_OFFSET 12
`define MDIO_MCR_ANENABLE 32'h00001000
`define MDIO_MCR_SPEED100_OFFSET 13
`define MDIO_MCR_SPEED100 32'h00002000
`define MDIO_MCR_LOOPBACK_OFFSET 14
`define MDIO_MCR_LOOPBACK 32'h00004000
`define MDIO_MCR_RESET_OFFSET 15
`define MDIO_MCR_RESET 32'h00008000
`define ADDR_MDIO_MSR 7'h4
`define MDIO_MSR_ERCAP_OFFSET 0
`define MDIO_MSR_ERCAP 32'h00000001
`define MDIO_MSR_JCD_OFFSET 1
`define MDIO_MSR_JCD 32'h00000002
`define MDIO_MSR_LSTATUS_OFFSET 2
`define MDIO_MSR_LSTATUS 32'h00000004
`define MDIO_MSR_ANEGCAPABLE_OFFSET 3
`define MDIO_MSR_ANEGCAPABLE 32'h00000008
`define MDIO_MSR_RFAULT_OFFSET 4
`define MDIO_MSR_RFAULT 32'h00000010
`define MDIO_MSR_ANEGCOMPLETE_OFFSET 5
`define MDIO_MSR_ANEGCOMPLETE 32'h00000020
`define MDIO_MSR_MFSUPPRESS_OFFSET 6
`define MDIO_MSR_MFSUPPRESS 32'h00000040
`define MDIO_MSR_UNIDIRABLE_OFFSET 7
`define MDIO_MSR_UNIDIRABLE 32'h00000080
`define MDIO_MSR_ESTATEN_OFFSET 8
`define MDIO_MSR_ESTATEN 32'h00000100
`define MDIO_MSR_100HALF2_OFFSET 9
`define MDIO_MSR_100HALF2 32'h00000200
`define MDIO_MSR_100FULL2_OFFSET 10
`define MDIO_MSR_100FULL2 32'h00000400
`define MDIO_MSR_10HALF_OFFSET 11
`define MDIO_MSR_10HALF 32'h00000800
`define MDIO_MSR_10FULL_OFFSET 12
`define MDIO_MSR_10FULL 32'h00001000
`define MDIO_MSR_100HALF_OFFSET 13
`define MDIO_MSR_100HALF 32'h00002000
`define MDIO_MSR_100FULL_OFFSET 14
`define MDIO_MSR_100FULL 32'h00004000
`define MDIO_MSR_100BASE4_OFFSET 15
`define MDIO_MSR_100BASE4 32'h00008000
`define ADDR_MDIO_PHYSID1 7'h8
`define MDIO_PHYSID1_OUI_OFFSET 0
`define MDIO_PHYSID1_OUI 32'h0000ffff
`define ADDR_MDIO_PHYSID2 7'hc
`define MDIO_PHYSID2_REV_NUM_OFFSET 0
`define MDIO_PHYSID2_REV_NUM 32'h0000000f
`define MDIO_PHYSID2_MMNUM_OFFSET 4
`define MDIO_PHYSID2_MMNUM 32'h000003f0
`define MDIO_PHYSID2_OUI_OFFSET 10
`define MDIO_PHYSID2_OUI 32'h0000fc00
`define ADDR_MDIO_ADVERTISE 7'h10
`define MDIO_ADVERTISE_RSVD3_OFFSET 0
`define MDIO_ADVERTISE_RSVD3 32'h0000001f
`define MDIO_ADVERTISE_FULL_OFFSET 5
`define MDIO_ADVERTISE_FULL 32'h00000020
`define MDIO_ADVERTISE_HALF_OFFSET 6
`define MDIO_ADVERTISE_HALF 32'h00000040
`define MDIO_ADVERTISE_PAUSE_OFFSET 7
`define MDIO_ADVERTISE_PAUSE 32'h00000180
`define MDIO_ADVERTISE_RSVD2_OFFSET 9
`define MDIO_ADVERTISE_RSVD2 32'h00000e00
`define MDIO_ADVERTISE_RFAULT_OFFSET 12
`define MDIO_ADVERTISE_RFAULT 32'h00003000
`define MDIO_ADVERTISE_RSVD1_OFFSET 14
`define MDIO_ADVERTISE_RSVD1 32'h00004000
`define MDIO_ADVERTISE_NPAGE_OFFSET 15
`define MDIO_ADVERTISE_NPAGE 32'h00008000
`define ADDR_MDIO_LPA 7'h14
`define MDIO_LPA_RSVD3_OFFSET 0
`define MDIO_LPA_RSVD3 32'h0000001f
`define MDIO_LPA_FULL_OFFSET 5
`define MDIO_LPA_FULL 32'h00000020
`define MDIO_LPA_HALF_OFFSET 6
`define MDIO_LPA_HALF 32'h00000040
`define MDIO_LPA_PAUSE_OFFSET 7
`define MDIO_LPA_PAUSE 32'h00000180
`define MDIO_LPA_RSVD2_OFFSET 9
`define MDIO_LPA_RSVD2 32'h00000e00
`define MDIO_LPA_RFAULT_OFFSET 12
`define MDIO_LPA_RFAULT 32'h00003000
`define MDIO_LPA_LPACK_OFFSET 14
`define MDIO_LPA_LPACK 32'h00004000
`define MDIO_LPA_NPAGE_OFFSET 15
`define MDIO_LPA_NPAGE 32'h00008000
`define ADDR_MDIO_EXPANSION 7'h18
`define MDIO_EXPANSION_RSVD1_OFFSET 0
`define MDIO_EXPANSION_RSVD1 32'h00000001
`define MDIO_EXPANSION_LWCP_OFFSET 1
`define MDIO_EXPANSION_LWCP 32'h00000002
`define MDIO_EXPANSION_ENABLENPAGE_OFFSET 2
`define MDIO_EXPANSION_ENABLENPAGE 32'h00000004
`define MDIO_EXPANSION_RSVD2_OFFSET 3
`define MDIO_EXPANSION_RSVD2 32'h0000fff8
`define ADDR_MDIO_ESTATUS 7'h3c
`define MDIO_ESTATUS_RSVD1_OFFSET 0
`define MDIO_ESTATUS_RSVD1 32'h00000fff
`define MDIO_ESTATUS_1000_THALF_OFFSET 12
`define MDIO_ESTATUS_1000_THALF 32'h00001000
`define MDIO_ESTATUS_1000_TFULL_OFFSET 13
`define MDIO_ESTATUS_1000_TFULL 32'h00002000
`define MDIO_ESTATUS_1000_XHALF_OFFSET 14
`define MDIO_ESTATUS_1000_XHALF 32'h00004000
`define MDIO_ESTATUS_1000_XFULL_OFFSET 15
`define MDIO_ESTATUS_1000_XFULL 32'h00008000
`define ADDR_MDIO_WR_SPEC 7'h40
`define MDIO_WR_SPEC_TX_CAL_OFFSET 0
`define MDIO_WR_SPEC_TX_CAL 32'h00000001
`define MDIO_WR_SPEC_RX_CAL_STAT_OFFSET 1
`define MDIO_WR_SPEC_RX_CAL_STAT 32'h00000002
`define MDIO_WR_SPEC_CAL_CRST_OFFSET 2
`define MDIO_WR_SPEC_CAL_CRST 32'h00000004
`define MDIO_WR_SPEC_BSLIDE_OFFSET 4
`define MDIO_WR_SPEC_BSLIDE 32'h000000f0
`define ADDR_EP_ECR 8'h0
`define EP_ECR_PORTID_OFFSET 0
`define EP_ECR_PORTID 32'h0000001f
`define EP_ECR_RST_CNT_OFFSET 5
`define EP_ECR_RST_CNT 32'h00000020
`define EP_ECR_TX_EN_FRA_OFFSET 6
`define EP_ECR_TX_EN_FRA 32'h00000040
`define EP_ECR_RX_EN_FRA_OFFSET 7
`define EP_ECR_RX_EN_FRA 32'h00000080
`define ADDR_EP_TSCR 8'h4
`define EP_TSCR_EN_TXTS_OFFSET 0
`define EP_TSCR_EN_TXTS 32'h00000001
`define EP_TSCR_EN_RXTS_OFFSET 1
`define EP_TSCR_EN_RXTS 32'h00000002
`define EP_TSCR_CS_START_OFFSET 2
`define EP_TSCR_CS_START 32'h00000004
`define EP_TSCR_CS_DONE_OFFSET 3
`define EP_TSCR_CS_DONE 32'h00000008
`define ADDR_EP_RFCR 8'h8
`define EP_RFCR_A_RUNT_OFFSET 0
`define EP_RFCR_A_RUNT 32'h00000001
`define EP_RFCR_A_GIANT_OFFSET 1
`define EP_RFCR_A_GIANT 32'h00000002
`define EP_RFCR_A_HP_OFFSET 2
`define EP_RFCR_A_HP 32'h00000004
`define EP_RFCR_A_FRAG_OFFSET 3
`define EP_RFCR_A_FRAG 32'h00000008
`define EP_RFCR_QMODE_OFFSET 4
`define EP_RFCR_QMODE 32'h00000030
`define EP_RFCR_FIX_PRIO_OFFSET 6
`define EP_RFCR_FIX_PRIO 32'h00000040
`define EP_RFCR_PRIO_VAL_OFFSET 8
`define EP_RFCR_PRIO_VAL 32'h00000700
`define EP_RFCR_VID_VAL_OFFSET 16
`define EP_RFCR_VID_VAL 32'h0fff0000
`define ADDR_EP_FCR 8'hc
`define EP_FCR_RXPAUSE_OFFSET 0
`define EP_FCR_RXPAUSE 32'h00000001
`define EP_FCR_TXPAUSE_OFFSET 1
`define EP_FCR_TXPAUSE 32'h00000002
`define EP_FCR_TX_THR_OFFSET 8
`define EP_FCR_TX_THR 32'h0000ff00
`define EP_FCR_TX_QUANTA_OFFSET 16
`define EP_FCR_TX_QUANTA 32'hffff0000
`define ADDR_EP_MACH 8'h10
`define ADDR_EP_MACL 8'h14
`define ADDR_EP_DMCR 8'h18
`define EP_DMCR_EN_OFFSET 0
`define EP_DMCR_EN 32'h00000001
`define EP_DMCR_N_AVG_OFFSET 16
`define EP_DMCR_N_AVG 32'h0fff0000
`define ADDR_EP_DMSR 8'h1c
`define EP_DMSR_PS_VAL_OFFSET 0
`define EP_DMSR_PS_VAL 32'h00ffffff
`define EP_DMSR_PS_RDY_OFFSET 24
`define EP_DMSR_PS_RDY 32'h01000000
`define ADDR_EP_MDIO_CR 8'h20
`define EP_MDIO_CR_DATA_OFFSET 0
`define EP_MDIO_CR_DATA 32'h0000ffff
`define EP_MDIO_CR_ADDR_OFFSET 16
`define EP_MDIO_CR_ADDR 32'h00ff0000
`define EP_MDIO_CR_RW_OFFSET 31
`define EP_MDIO_CR_RW 32'h80000000
`define ADDR_EP_MDIO_SR 8'h24
`define EP_MDIO_SR_RDATA_OFFSET 0
`define EP_MDIO_SR_RDATA 32'h0000ffff
`define EP_MDIO_SR_READY_OFFSET 31
`define EP_MDIO_SR_READY 32'h80000000
`define ADDR_EP_IDCODE 8'h28
`define ADDR_EP_DSR 8'h2c
`define EP_DSR_LSTATUS_OFFSET 0
`define EP_DSR_LSTATUS 32'h00000001
`define EP_DSR_LACT_OFFSET 1
`define EP_DSR_LACT 32'h00000002
`define ADDR_EP_AFCR 8'h30
`define EP_AFCR_ENABLE_OFFSET 0
`define EP_AFCR_ENABLE 32'h00000001
`define EP_AFCR_RULE_SEL_OFFSET 1
`define EP_AFCR_RULE_SEL 32'h0000000e
`define EP_AFCR_MATRIX_ADDR_OFFSET 4
`define EP_AFCR_MATRIX_ADDR 32'h00000ff0
`define EP_AFCR_MATRIX_DATA_OFFSET 12
`define EP_AFCR_MATRIX_DATA 32'h000ff000
`define EP_AFCR_MATRIX_WRITE_P_OFFSET 20
`define EP_AFCR_MATRIX_WRITE_P 32'h00100000
`define ADDR_EP_AFR0 8'h34
`define EP_AFR0_DMAC_EN_OFFSET 0
`define EP_AFR0_DMAC_EN 32'h00000001
`define EP_AFR0_VID_EN_OFFSET 1
`define EP_AFR0_VID_EN 32'h00000002
`define EP_AFR0_ETYPE_EN_OFFSET 2
`define EP_AFR0_ETYPE_EN 32'h00000004
`define EP_AFR0_VID_OFFSET 3
`define EP_AFR0_VID 32'h00007ff8
`define ADDR_EP_AFR1 8'h38
`define EP_AFR1_DMAC_LO_OFFSET 0
`define EP_AFR1_DMAC_LO 32'hffffffff
`define ADDR_EP_AFR2 8'h3c
`define EP_AFR2_DMAC_HI_OFFSET 0
`define EP_AFR2_DMAC_HI 32'h0000ffff
`define EP_AFR2_ETYPE_OFFSET 16
`define EP_AFR2_ETYPE 32'hffff0000
`define BASE_EP_RMON_RAM 8'h80
`define SIZE_EP_RMON_RAM 32'h20
// Fabric TAP emulator example.
// usage: (as root)
// tunctl -t tap0
// ifconfig tap0 192.168.100.100
// arping -I tap0 192.168.100.101
// you should see some ARP requests coming
`timescale 1ns / 1ps
`include "fabric_emu.sv"
`include "fabric_emu_tap.sv"
module main;
const int c_clock_period = 8;
reg clk = 0;
reg rst_n = 0;
`WRF_WIRES(from_tap); // Data coming from tap0 interface
`WRF_WIRES(to_tap); // Data going to tap0 interface
// generate clock and reset signals
always #(c_clock_period/2) clk <= ~clk;
initial begin
repeat(3) @(posedge clk);
rst_n = 1;
end
// Two fabric emulators talking to each other
fabric_emu_tap U_tap
(
.clk_sys_i(clk),
.rst_n_i(rst_n),
`WRF_CONNECT_SOURCE(rx, from_tap), // connect fabric source/sinks
`WRF_CONNECT_SINK(tx, to_tap)
);
fabric_emu U_emu
(
.clk_i(clk),
.rst_n_i(rst_n),
`WRF_CONNECT_SOURCE(rx, to_tap),
`WRF_CONNECT_SINK(tx, from_tap)
);
// Check if there's anything received by the TAP emulator
always @(posedge clk) if (U_emu.poll())
begin
ether_frame_t frame;
$display("TAP Emulator received a frame!");
U_emu.receive(frame);
dump_frame_header("EmuB RX: ", frame);
frame.hdr.src = 'h010203040506; // modify the MAC address and send the frame back to tap interface
U_emu.send(frame.hdr, frame.payload, frame.size);
end
endmodule // main
This diff is collapsed.
`ifndef __FABRIC_EMU_DEFS_SV
`define __FABRIC_EMU_DEFS_SV
/* Ethernet frame header extended with WR-compliant OOB signalling */
typedef struct {
bit no_mac; // when 1, there's no valid source MAC present in the frame header and the SRC MAC field must be filled by the endpoint
bit [47:0] dst; // DST MAC
bit [47:0] src; // SRC MAC
bit [15:0] ethertype;
bit is_802_1q; // when 1, the frame has 802.1q header
bit [11:0] vid; // VLAN ID
bit [2:0] prio; // PCP priority tag
int oob_type; // OOB TYPE: OOB_TYPE_TXTS = TX frame ID (for TX timestamping), OOB_TYPE_RXTS = RX timestamp
bit[15:0] oob_fid; //
bit [27:0] timestamp_r;
bit [3:0] timestamp_f;
bit [4:0] port_id;
bit has_timestamp; // when 1, the TX/RX timestamp is valid
} ether_header_t;
/* Full ethernet frame */
typedef struct {
ether_header_t hdr;
int size;
bit[7:0] payload[$];
bit[31:0] fcs;
bit error;
bit has_payload;
} ether_frame_t;
/* WR-compliant TX frame timestamp */
typedef struct {
bit[15:0] fid;
bit [4:0] pid;
bit [27:0] timestamp_r;
bit [3:0] timestamp_f;
} tx_timestamp_t;
`timescale 1ns/1ps
/* Bus widths definition, taken from global_defs.vhd */
`define c_wrsw_ctrl_size 4
`define c_wrsw_oob_frame_id_size 16
`define c_wrsw_timestamp_size_r 28
`define c_wrsw_timestamp_size_f 4
`define c_wrsw_mac_addr_width 48
`define c_wrsw_vid_width 12
`define c_wrsw_prio_width 3
/* ctrl bus codes */
`define c_wrsw_ctrl_none 4'h0
`define c_wrsw_ctrl_dst_mac 4'h1
`define c_wrsw_ctrl_src_mac 4'h2
`define c_wrsw_ctrl_ethertype 4'h3
`define c_wrsw_ctrl_vid_prio 4'h4
`define c_wrsw_ctrl_tx_oob 4'h5
`define c_wrsw_ctrl_rx_oob 4'h6
`define c_wrsw_ctrl_payload 4'h7
/* OOB types */
`define OOB_TYPE_TXTS 1
`define OOB_TYPE_RXTS 2
`define QUEUE_MAX_FRAMES 128
//
// WhiteRabbit Fabric Interface (WRF) Macros
//
// declares basic fabric interface (only the mandatory singals)
// sink port list in a verilog/SV module, prefixed with "prefix":
// for example `WRF_PORTS_SINK(test) will generate the following signals
// test_sof_p1_i, test_eof_p1_i, test_data_i, etc....
`define WRF_PORTS_SINK(prefix) \
input [15:0] prefix``_data_i,\
input [3:0] prefix``_ctrl_i,\
input prefix``_bytesel_i,\
input prefix``_sof_p1_i,\
input prefix``_eof_p1_i,\
output prefix``_dreq_o,\
input prefix``_valid_i,\
input prefix``_rerror_p1_i
// same as above but with all WRF signals
`define WRF_FULL_PORTS_SINK(prefix) \
`WRF_PORTS_SINK(prefix),\
output prefix``_terror_p1_o,\
input prefix``_idle_i,\
input prefix``_tabort_p1_i,\
output prefix``_rabort_p1_o
// like the macro above, but for fabric source, mandatory signals only
`define WRF_PORTS_SOURCE(prefix) \
output [15:0] prefix``_data_o,\
output [3:0] prefix``_ctrl_o,\
output prefix``_bytesel_o,\
output prefix``_sof_p1_o,\
output prefix``_eof_p1_o,\
input prefix``_dreq_i,\
output prefix``_valid_o,\
output prefix``_rerror_p1_o
// same as above, but for full WRF
`define WRF_FULL_PORTS_SOURCE(prefix) \
`WRF_PORTS_SOURCE(prefix), \
input prefix``_terror_p1_i,\
output prefix``_idle_o,\
output prefix``_tabort_p1_o,\
input prefix``_rabort_p1_i
// declares a list of verilog/SV wires for a given fabric name
`define WRF_WIRES(prefix) \
wire [15:0] prefix``_data;\
wire [3 :0] prefix``_ctrl;\
wire prefix``_bytesel;\
wire prefix``_dreq;\
wire prefix``_valid;\
wire prefix``_sof_p1;\
wire prefix``_eof_p1;\
wire prefix``_rerror_p1;
// same as above, but for full WRF
`define WRF_FULL_WIRES(prefix) \
`WRF_WIRES(prefix)\
wire prefix``_terror_p1;\
wire prefix``_idle;\
wire prefix``_tabort_p1;\
wire prefix``_rabort_p1;
// Connects fabric sink ports prefixed with port_pfx to fabric wires prefixed with fab_pfx
`define _WRF_CONNECT_MANDATORY_SINK(port_pfx, fab_pfx) \
.port_pfx``_data_i(fab_pfx``_data),\
.port_pfx``_ctrl_i(fab_pfx``_ctrl),\
.port_pfx``_bytesel_i(fab_pfx``_bytesel),\
.port_pfx``_dreq_o(fab_pfx``_dreq),\
.port_pfx``_valid_i(fab_pfx``_valid),\
.port_pfx``_sof_p1_i(fab_pfx``_sof_p1),\
.port_pfx``_eof_p1_i(fab_pfx``_eof_p1),\
.port_pfx``_rerror_p1_i(fab_pfx``_rerror_p1)
// full fabric I/F version
`define WRF_FULL_CONNECT_SINK(port_pfx, fab_pfx) \
`_WRF_CONNECT_MANDATORY_SINK(port_pfx, fab_pfx), \
.port_pfx``_terror_p1_o(fab_pfx``_terror_p1),\
.port_pfx``_tabort_p1_i(fab_pfx``_tabort_p1),\
.port_pfx``_rabort_p1_o(fab_pfx``_rabort_p1),\
.port_pfx``_idle_i(fab_pfx``_idle)
// Connects fabric sink ports prefixed with port_pfx to fabric wires prefixed with fab_pfx
`define WRF_CONNECT_SINK(port_pfx, fab_pfx) \
`_WRF_CONNECT_MANDATORY_SINK(port_pfx, fab_pfx), \
.port_pfx``_terror_p1_o(),\
.port_pfx``_tabort_p1_i(1'b0),\
.port_pfx``_rabort_p1_o(),\
.port_pfx``_idle_i(1'b0)
`define _WRF_CONNECT_MANDATORY_SOURCE(port_pfx, fab_pfx) \
.port_pfx``_data_o(fab_pfx``_data),\
.port_pfx``_ctrl_o(fab_pfx``_ctrl),\
.port_pfx``_bytesel_o(fab_pfx``_bytesel),\
.port_pfx``_dreq_i(fab_pfx``_dreq),\
.port_pfx``_valid_o(fab_pfx``_valid),\
.port_pfx``_sof_p1_o(fab_pfx``_sof_p1),\
.port_pfx``_eof_p1_o(fab_pfx``_eof_p1),\
.port_pfx``_rerror_p1_o(fab_pfx``_rerror_p1)
// same as above, but for source ports, full WRF version
`define WRF_FULL_CONNECT_SOURCE(port_pfx, fab_pfx) \
`_WRF_CONNECT_MANDATORY_SOURCE(port_pfx, fab_pfx),\
.port_pfx``_terror_p1_i(fab_pfx``_terror_p1),\
.port_pfx``_tabort_p1_o(fab_pfx``_tabort_p1),\
.port_pfx``_rabort_p1_i(fab_pfx``_rabort_p1),\
.port_pfx``_idle_o(fab_pfx``_idle)
// same as above, but for source ports, basic WRF version
`define WRF_CONNECT_SOURCE(port_pfx, fab_pfx) \
`_WRF_CONNECT_MANDATORY_SOURCE(port_pfx, fab_pfx),\
.port_pfx``_terror_p1_i(1'b0),\
.port_pfx``_tabort_p1_o(),\
.port_pfx``_rabort_p1_i(1'b0),\
.port_pfx``_idle_o()
`endif
\ No newline at end of file
// Fabric emulator example, showing 2 fabric emulators connected together and exchanging packets.
`timescale 1ns / 1ps
`include "fabric_emu.sv"
module main;
const int c_clock_period = 8;
reg clk = 0;
reg rst_n = 0;
`WRF_WIRES(ab); // Emu A to B fabric
`WRF_WIRES(ba); // And the other way around
// generate clock and reset signals
always #(c_clock_period/2) clk <= ~clk;
initial begin
repeat(3) @(posedge clk);
rst_n = 1;
end
// Two fabric emulators talking to each other
fabric_emu U_emuA
(
.clk_i(clk),
.rst_n_i(rst_n),
`WRF_CONNECT_SOURCE(rx, ba), // connect fabric source/sinks
`WRF_CONNECT_SINK(tx, ab)
);
fabric_emu U_emuB
(
.clk_i(clk),
.rst_n_i(rst_n),
`WRF_CONNECT_SOURCE(rx, ab),
`WRF_CONNECT_SINK(tx, ba)
);
initial begin
ether_header_t hdr;
int buffer[1024];
int i;
wait(U_emuA.ready); // wait until both emulators are initialized
wait(U_emuB.ready);
hdr.src = 'h123456789abcdef;
hdr.dst = 'hcafeb1badeadbef;
hdr.ethertype = 1234;
hdr.is_802_1q = 0;
hdr.oob_type = `OOB_TYPE_RXTS;
hdr.timestamp_r = 10000;
hdr.timestamp_f = 4;
hdr.port_id = 5;
for(i=0;i<100;i++)
buffer[i] = i;
// simulate some flow throttling
U_emuA.simulate_rx_throttling(1, 50);
U_emuA.send(hdr, buffer, 100);
hdr.src = 'h0f0e0a0b0d00;
U_emuB.send(hdr, buffer, 50);
end
// Check if there's anything received by EMU B
always @(posedge clk) if (U_emuB.poll())
begin
ether_frame_t frame;
$display("Emulator B received a frame!");
U_emuB.receive(frame);
dump_frame_header("EmuB RX: ", frame);
end
// Check if there's anything received by EMU A
always @(posedge clk) if (U_emuA.poll())
begin
ether_frame_t frame;
$display("Emulator A received a frame!");
U_emuA.receive(frame);
dump_frame_header("EmuA RX: ", frame);
end
endmodule // main
`timescale 1ns/1ps
/* Ethernet FCS calculator class */
class CCRC32;
protected bit [31:0] crc;
protected bit [31:0] crc_tab[256];
function new();
reg [31:0] c, poly;
int i, j;
poly = 32'hEDB88320;
for (i = 0; i < 256; i++) begin
c = i;
for (j = 8; j > 0; j--) begin
if (c & 1)
c = (c >> 1) ^ poly;
else
c >>= 1;
end
crc_tab[i] = c;
end
crc = 32'hffffffff;
endfunction // new
function bit[31:0] bitrev(bit[31:0] x, int n);
reg [31:0] y= 0;
int i;
for(i=0;i<n;i++) if(x & (1<<i)) y|= 1<< (n-1-i);
bitrev=y;
endfunction
task update_int(bit[7:0] x);
crc = ((crc >> 8) & 32'h00FFFFFF) ^ crc_tab[(crc ^ bitrev(x,8)) & 32'hFF];
endtask
task update(input [15:0] x, int bytesel);
update_int(x[15:8]);
if(!bytesel)
update_int(x[7:0]);
endtask // update
function bit[31:0] get();
get = bitrev(crc ^ 32'hffffffff, 32);
endfunction // get
endclass
/* Simple packet queue */
class CPacketQueue;
protected int head, tail, count;
protected int size;
protected ether_frame_t d[];
function new (int _size);
size = _size;
head = 0;
tail = 0;
count = 0;
d = new [_size];
endfunction // new
task push(input ether_frame_t frame);
if(count == size) begin
$display("CPacketQueue::push(): queue overflow");
$stop();
end
d[head] = frame;
head++; if(head == size) head = 0;
count++;
endtask // push
task pop (output ether_frame_t frame);
if(count <= 0) begin
$display("CPacketQueue::pop(): queue empty");
$stop();
end
frame = d[tail];
tail++; if(tail == size) tail = 0;
count--;
endtask // pop
function int get_count();
return count;
endfunction // get_count
/* Looks for a packet with matching OOB frame identifier and updates it with the new timestamp value */
function int update_tx_timestamp(input [15:0] oob_fid,
input [4:0] port_id,
input [31:0] ts_value);
int i;
i = tail;
while(i != head)
begin
if(d[i].hdr.oob_type == `OOB_TYPE_TXTS && d[i].hdr.oob_fid == oob_fid) begin
d[i].hdr.timestamp_r = ts_value[27:0];
d[i].hdr.timestamp_f = ts_value[31:28];
d[i].hdr.has_timestamp = 1;
return 1;
end
i++;
if(i == count) i = 0;
end
return 0;
endfunction // update_tx_timestamp
endclass // CPacketQueue
// converts a nbytes-long number (hex) to hexadecimal string
function automatic string hex_2_str(input [47:0] hex, int nbytes);
int i;
string s = "";
string hexchars = "0123456789abcdef";
reg [47:0] t;
t = hex;
for(i=0; i<2*nbytes; i++) begin
s= {hexchars[t&'hf], s};
t=t>>4;
end
return s;
endfunction // hex_2_str
// formats an Ethernet frame header as a nice looking string
function automatic string format_ether_header(input ether_header_t hdr);
string s = {"DST: ", hex_2_str(hdr.dst, 6),
" SRC: ", hex_2_str(hdr.src, 6),
" Type: 0x",hex_2_str(hdr.ethertype, 2) };
if(hdr.is_802_1q) s = {s, " VLAN: 0x", hex_2_str({4'b0,hdr.vid}, 2), " PRIO: ", hex_2_str({5'b0, hdr.prio},1) };
return s;
endfunction // automatic
task dump_frame_header(string s, ether_frame_t frame);
$display("%s %s length = %d %s %s", s, format_ether_header(frame.hdr), frame.size, frame.error?"ERROR":"OK", frame.hdr.has_timestamp?"TS":"NoTS");
endtask // dump_frame_header
\ No newline at end of file
/* Linux TAP driver interface to WR fabric */
`timescale 1ns/1ps
`include "fabric_emu_defs.sv"
// module uses Linux TAP interface as a packet source/sink for the fabric simulator.
// link with VPI tap.sl
/* TODO:
- add CTRL code generation
*/
class CPacketFIFO;
int m_size, m_wrptr, m_rdptr, m_count, m_pktcnt;
bit[8:0] m_buffer[];
function new(int size);
m_size = size;
m_buffer = new [size];
m_rdptr = 0;
m_wrptr = 0;
m_count = 0;
m_pktcnt = 0;
endfunction // new
task _push(bit[8:0] val);
if(m_count >= m_size)
$error("FIFO overflow");
m_buffer[m_wrptr++] = val;
m_count++;
endtask // _push
function bit[8:0] get();
return m_buffer[m_rdptr];
endfunction // _get
function bit[8:0] pop();
bit [8:0] rval;
rval = m_buffer[m_rdptr++];
m_count--;
return rval;
endfunction
function int empty();
return (m_count == 0);
endfunction // _empty
task write(bit [7:0] val, bit eop);
// $display("fwrite: %x %x", val, eop);
_push({eop,val});
endtask // write
function int got_packet();
return (m_pktcnt != 0 );
endfunction // got_packets
function int end_of_packet();
bit[8:0] rval;
rval = get();
return rval[8];
endfunction // end_of_packet
endclass // packet_fifo
module fabric_emu_tap
(
input clk_sys_i,
input rst_n_i,
`WRF_FULL_PORTS_SINK(tx),
`WRF_FULL_PORTS_SOURCE(rx)
);
reg [7:0] tap_rx;
reg tap_dvalid_rx;
reg [7:0] tap_tx = 0;
reg tap_dvalid_tx = 0;
CPacketFIFO rx_fifo;
CPacketFIFO tx_fifo;
const int c_FIFO_SIZE = 32768;
const int c_INTERFRAME_GAP = 32768;
assign tx_drop_o = 0;
initial begin
rx_fifo = new(c_FIFO_SIZE);
tx_fifo = new (c_FIFO_SIZE);
end
reg rx_sof_p_int = 0;
reg rx_eof_p_int = 0;
reg tx_dreq_int = 0;
reg [15:0] rx_data_int = 0;
reg [3:0] rx_ctrl_int = 0;
reg rx_error_p_int = 0;
reg rx_bytesel_int = 0;
reg rx_valid_int = 0;
assign rx_sof_p1_o = rx_sof_p_int;
assign rx_eof_p1_o = rx_eof_p_int;
assign tx_dreq_o = tx_dreq_int;
assign rx_data_o = rx_data_int;
assign rx_ctrl_o = rx_ctrl_int;
assign rx_rerror_p1_o = rx_error_p_int;
assign rx_bytesel_o = rx_bytesel_int;
assign rx_valid_o = rx_valid_int;
assign rx_idle_o = 0;
assign rx_tabort_p1_o = 0;
assign tx_terror_p1_o = 0;
assign tx_rabort_p1_o = 0;
reg tap_dvalid_rx_d0 = 0;
reg [7:0] tap_data_d0;
always@(posedge clk_sys_i or negedge clk_sys_i)
begin
// TAP interface PLI call
$tap_io(tap_tx, tap_dvalid_tx, tap_rx, tap_dvalid_rx);
tap_dvalid_rx_d0 <= tap_dvalid_rx;
// TAP reception
if(tap_dvalid_rx_d0 && !tap_dvalid_rx)
rx_fifo.write(0, 1);
else if (tap_dvalid_rx)
rx_fifo.write(tap_rx, 0);
// TAP transmission
if(!tx_fifo.empty())
begin
bit[7:0] data;
bit eof;
{eof, data} = tx_fifo.pop();
// $display("TX: %x eof %b", data, eof);
tap_data_d0 <= data;
tap_tx <= tap_data_d0;
tap_dvalid_tx = !eof;
end
end
task automatic wait_clks(int howmuch);
while(howmuch--) @(posedge clk_sys_i);
endtask // automatic
const int FRX_NOFRAME = 1;
const int FRX_TX = 2;
const int FRX_EOF = 3;
int fab_rx_state;
int fab_rx_offset;
function bit[3:0] gen_ctrl(int offset);
if(offset >=0 && offset <= 2)
return `c_wrsw_ctrl_dst_mac;
else if(offset >=3 && offset <= 5)
return `c_wrsw_ctrl_src_mac;
else if(offset == 6)
return `c_wrsw_ctrl_ethertype;
else
return `c_wrsw_ctrl_payload;
endfunction // gen_ctrl
task automatic fabric_do_rx();
// $display("FabDoRX");
case (fab_rx_state)
FRX_NOFRAME:begin
rx_eof_p_int <= 0;
if(!rx_fifo.empty()) begin
rx_sof_p_int <= 1;
fab_rx_state = FRX_TX;
fab_rx_offset = 0;
return;
end
end
FRX_TX:begin
bit [8:0] lsb, msb;
rx_sof_p_int <= 0;
if(rx_fifo.end_of_packet()) begin
rx_fifo.pop();
fab_rx_state <= FRX_EOF;
rx_valid_int <= 0;
return;
end
msb = rx_fifo.pop();
if(rx_fifo.end_of_packet()) begin
rx_fifo.pop();
fab_rx_state <= FRX_EOF;
rx_valid_int <= 1;
rx_data_int [15:8] <= msb[7:0];
rx_ctrl_int <= gen_ctrl(fab_rx_offset++);
rx_bytesel_int <= 1;
end else begin
lsb = rx_fifo.pop();
rx_valid_int <= 1;
rx_bytesel_int <= 0;
rx_data_int = {msb[7:0], lsb[7:0] };
rx_ctrl_int <= gen_ctrl(fab_rx_offset++);
end
end
FRX_EOF: begin
rx_eof_p_int <= 1;
wait_clks(1);
rx_eof_p_int <= 0;
fab_rx_state <= FRX_NOFRAME;
wait_clks(c_INTERFRAME_GAP);
end
endcase // case (fab_rx_state)
endtask // automatic
task fabric_do_tx();
bit[7:0] buffer[2048];
int i, len ;
i = 0;
while(1) begin
if(tx_valid_i) begin
// ignore OOB
if(tx_ctrl_i == `c_wrsw_ctrl_tx_oob || tx_ctrl_i == `c_wrsw_ctrl_rx_oob)
continue;
buffer[i++] = tx_data_i[15:8];
if(!tx_bytesel_i)
buffer[i++] = tx_data_i[7:0];
end
if(tx_eof_p1_i)
break;
wait_clks(1);
end
// $display("FabTX: %d bytes", i);
len = i;
for(i=0;i<len;i++)
tx_fifo.write(buffer[i], 0);
tx_fifo.write(0, 1);
endtask // fabric_do_tx
initial fab_rx_state = FRX_NOFRAME;
initial forever begin
wait_clks(1);
if(rx_dreq_i)
fabric_do_rx();
else
rx_valid_int <= 0;
end
initial forever begin
tx_dreq_int <= 1;
wait_clks(1);
if(tx_sof_p1_i)
fabric_do_tx();
end
endmodule // tap_if
\ No newline at end of file
//
// Title : Software Wishbone master unit for testbenches
//
// File : if_wishbone.sv
// Author : Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
// Created : Tue Mar 23 12:19:36 2010
// Standard : SystemVerilog
//
// Default values of certain WB parameters.
`include "simdrv_defs.sv"
interface IWishboneClassicMaster
(
input clk_i,
input rst_n_i
);
parameter g_data_width = 32;
parameter g_addr_width = 32;
/* Interface signals */
logic [g_addr_width - 1 : 0] adr;
logic [g_data_width - 1 : 0] dat_o;
logic [3 : 0] sel; // FIXME: 32-bit only
wire [g_data_width - 1 : 0] dat_i;
wire ack;
logic cyc;
logic stb;
logic we;
wire stall;
initial begin
adr = 0;
dat_o = 0;
sel = 0;
cyc = 0;
stb = 0;
we = 0;
end
time last_access_t = 0;
reg [g_data_width-1:0] dummy;
// enables/disables displaying information about each read/write operation.
int tb_verbose = 0;
task verbose(int onoff);
tb_verbose = onoff;
endtask // wb_verbose
task classic_single_rw_generic;
input [g_addr_width - 1 : 0] trans_addr;
input [g_data_width - 1 : 0] trans_wdata;
output [g_data_width - 1 : 0] trans_rdata;
input rw;
input [3:0] size;
begin : rw_generic_main
if(tb_verbose && rw)
$display("WB write %s: addr %x, data %x",
(size==1?"byte":((size==2)?"short":"int")),
trans_addr, trans_wdata);
if($time != last_access_t) begin
@(posedge clk_i);
end
stb<=1;
cyc<=1;
adr <= {2'b00, trans_addr[31:2]};
we <= rw;
if(rw) begin
case(size)
4: begin dat_o<=trans_wdata; sel <= 4'b1111; end
2: begin
if(adr[1]) begin
dat_o[31:16] <= trans_wdata[15:0];
sel <= 4'b1100;
end else begin
dat_o[15:0] <= trans_wdata[15:0];
sel <= 4'b0011;
end
end
1: begin
case(adr[1:0])
0: begin dat_o[31:24] <= trans_wdata[7:0]; sel <= 4'b1000; end
1: begin dat_o[23:16] <= trans_wdata[7:0]; sel <= 4'b0100; end
2: begin dat_o[15:8] <= trans_wdata[7:0]; sel <= 4'b0010; end
3: begin dat_o[7:0] <= trans_wdata[7:0]; sel <= 4'b0001; end
endcase // case(addr[1:0])
end
endcase // case(size)
end // if (rw)
@(posedge clk_i);
if(ack == 0) begin
while(ack == 0) begin @(posedge clk_i); end
end
trans_rdata = dat_i;
cyc <= 0;
we<=0;
stb<=0;
if(tb_verbose && !rw)
$display("WB read %s: addr %x, data %x",
(size==1?"byte":((size==2)?"short":"int")),
trans_addr, trans_rdata);
last_access_t = $time;
end
endtask // rw_generic
task write32;
input [g_addr_width - 1 : 0] addr;
input [31 : 0] data_i;
begin
classic_single_rw_generic(addr, data_i, dummy, 1, 4);
end
endtask // write32
task read32;
input [g_addr_width - 1 : 0] addr;
output [31 : 0] data_o;
begin : read32_body
reg [g_data_width - 1 : 0] rval;
classic_single_rw_generic(addr, 0, rval, 0, 4);
data_o = rval[31:0];
end
endtask // write32
modport master
(
output adr,
output dat_o,
output sel,
output cyc,
output stb,
output we,
input ack,
input dat_i,
input stall);
endinterface // IWishbone
interface IWishboneLink;
parameter g_data_width = 32;
parameter g_addr_width = 32;
wire [g_addr_width - 1 : 0] adr;
wire [g_data_width - 1 : 0] dat_o;
wire [g_data_width - 1 : 0] dat_i;
wire [(g_data_width/8)-1 : 0] sel;
wire ack;
wire stall;
wire err;
wire rty;
wire cyc;
wire stb;
wire we;
modport slave
(
output adr,
output dat_o,
input dat_i,
output sel,
output cyc,
output stb,
output we,
input ack,
input stall,
input err,
input rty
);
modport master
(
input adr,
input dat_o,
output dat_i,
input sel,
input cyc,
input stb,
input we,
output ack,
output stall,
output err,
output rty
);
endinterface // IWishboneLink
//
// Title : Software Wishbone master unit for testbenches
//
// File : if_wishbone.sv
// Author : Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
// Created : Tue Mar 23 12:19:36 2010
// Standard : SystemVerilog
//
// Default values of certain WB parameters.
`include "simdrv_defs.sv"
`include "if_wishbone_defs.sv"
interface IWishboneMaster
(
input clk_i,
input rst_n_i
);
parameter g_data_width = 32;
parameter g_addr_width = 32;
logic [g_addr_width - 1 : 0] adr;
logic [g_data_width - 1 : 0] dat_o;
logic [(g_data_width/8)-1 : 0] sel;
wire [g_data_width - 1 : 0] dat_i;
wire ack;
wire stall;
wire err;
wire rty;
logic cyc;
logic stb;
logic we;
wire clk;
wire rst_n;
time last_access_t = 0;
struct {
wb_cycle_type_t mode;
int gen_random_throttling;
real throttle_prob;
} settings;
modport master
(
output adr,
output dat_o,
output sel,
output cyc,
output stb,
output we,
input ack,
input dat_i,
input stall,
input err,
input rty
);
function automatic logic[g_addr_width-1:0] gen_addr(uint64_t addr, int xfer_size);
case(xfer_size)
1: return addr;
2: return addr << 1;
4: return addr << 2;
8: return addr << 3;
default: $error("IWishbone: invalid WB transfer size [%d bytes]\n", xfer_size);
endcase // case (xfer_size)
endfunction
// FIXME: little-endian
function automatic logic[(g_data_width/8)-1:0] gen_sel(uint64_t addr, int xfer_size);
logic [(g_data_width/8)-1:0] sel;
sel = (1<<xfer_size)-1;
return sel << (addr % xfer_size);
endfunction
function automatic logic[(g_data_width/8)-1:0] gen_data(uint64_t addr, int xfer_size);
logic [(g_data_width/8)-1:0] sel;
sel = (1<<xfer_size)-1;
return sel << (addr % xfer_size);
endfunction // gen_data
function automatic uint64_t decode_data(uint64_t addr, int xfer_size, logic[g_data_width-1:0] data);
int rem;
rem = addr % xfer_size;
return (data[rem] >> (8*rem)) & (1<<(xfer_size*8-1));
endfunction // decode_data
task automatic classic_cycle
(
wb_xfer_t xfer[],
bit rw,
int n_xfers,
output wb_cycle_result_t result
);
int i;
if($time != last_access_t)
@(posedge clk_i); /* resynchronize, just in case */
for(i=0;i<n_xfers;i++)
begin
stb <= 1'b1;
cyc <= 1'b1;
adr <= /*gen_addr(*/xfer[i].a;/*, xfer[i].size);*/
we <= rw;
sel <= xfer[i].sel[g_data_width/8-1:0];
//gen_sel(xfer[i].a, xfer[i].size);
dat_o <= gen_data(xfer[i].a, xfer[i].d);
@(posedge clk_i);
if(ack == 0) begin
while(ack == 0) begin @(posedge clk_i); end
end else if(err == 1'b1 || rty == 1'b1)
begin
cyc <= 0;
we <= 0;
stb <= 0;
result = (err ==1'b1 ? R_ERROR: R_RETRY);
break;
end
xfer[i].d = decode_data(xfer[i].a, xfer[i].d, xfer[i].size);
cyc <= 0;
we <= 0;
stb <= 0;
end // if (ack == 0)
@(posedge clk_i);
result = R_OK;
last_access_t = $time;
endtask // automatic
reg xf_idle = 1;
task automatic pipelined_write_cycle
(
wb_xfer_t xfer[],
int n_xfers,
output wb_cycle_result_t result
);
int i;
int ack_count ;
int failure ;
ack_count = 0;
failure = 0;
xf_idle = 0;
if($time != last_access_t)
@(posedge clk_i); /* resynchronize, just in case */
while(stall)
@(posedge clk_i);
cyc <= 1'b1;
i =0;
while(i<n_xfers)
begin
if(stb && !ack)
ack_count++;
else if(!stb && ack)
ack_count--;
if(err) begin
result = R_ERROR;
failure = 1;
break;
end
if(rty) begin
result = R_RETRY;
failure = 1;
break;
end
if (stall || (settings.gen_random_throttling && probability_hit(settings.throttle_prob))) begin
stb <= 1'b0;
@(posedge clk_i);
end else begin
adr <= xfer[i].a;
//gen_addr(xfer[i].a, xfer[i].size);
stb <= 1'b1;
we <= 1'b1;
sel <= xfer[i].sel[g_data_width/8-1:0];
//gen_sel(xfer[i].a, xfer[i].size);
dat_o <= xfer[i].d;
// $display("wbWrite: a %x d %x\n", xfer[i].a, xfer[i].d);
i++;
@(posedge clk_i);
end
end // for (i=0;i<n_xfers;i++)
while((ack_count > 0) && !failure)
begin
if(err) begin
result = R_ERROR;
failure = 1;
break;
end
if(rty) begin
result = R_RETRY;
failure = 1;
break;
end
if(stb && !ack)
ack_count++;
else if(!stb && ack)
ack_count--;
@(posedge clk_i);
end
cyc <= 1'b0;
@(posedge clk_i);
result = R_OK;
xf_idle = 1;
last_access_t = $time;
endtask // automatic
wb_cycle_t request_queue[$];
wb_cycle_t result_queue[$];
class CIWBMasterAccessor extends CWishboneAccessor;
function automatic int poll();
return 0;
endfunction
task get(output wb_cycle_t xfer);
while(!result_queue.size())
@(posedge clk_i);
xfer = result_queue.pop_front();
endtask
task clear();
endtask // clear
task put(input wb_cycle_t xfer);
// $display("wbMasteR: put");
request_queue.push_back(xfer);
endtask // put
function int idle();
return (request_queue.size() == 0) && xf_idle;
endfunction // idle
endclass // CIWBMasterAccessor
function CIWBMasterAccessor get_accessor();
CIWBMasterAccessor tmp;
tmp = new;
return tmp;
endfunction // get_accessoror
always@(posedge clk_i)
if(!rst_n_i)
begin
request_queue = {};
result_queue = {};
xf_idle = 1;
cyc <= 0;
dat_o <= 0;
stb <= 0;
sel <= 0;
adr <= 0;
we <= 0;
end
initial begin
settings.mode = PIPELINED;
settings.gen_random_throttling =1;
settings.throttle_prob = 0.01;
end
initial forever
begin
@(posedge clk_i);
if(request_queue.size() > 0)
begin
wb_cycle_t c;
// $display("wbMaster: got cycle [%d]", c.data.size());
c = request_queue.pop_front();
if(settings.mode == PIPELINED)
begin
wb_cycle_result_t res;
pipelined_write_cycle(c.data, c.data.size(), res);
c.result =res;
c.data = {};
result_queue.push_back(c);
end
end
end
endinterface // IWishbone
`timescale 1ns/1ps
`include "if_wishbone_defs.sv"
interface IWishboneSlave
(
input clk_i,
input rst_n_i
);
parameter g_addr_width = 32;
parameter g_data_width = 32;
wire [g_addr_width - 1: 0] adr;
wire [g_data_width - 1: 0] dat_i;
wire [(g_data_width/8)-1 : 0] sel;
logic [g_data_width - 1 : 0] dat_o;
logic ack;
logic stall;
logic err;
logic rty;
wire cyc;
wire stb;
wire we;
time last_access_t = 0;
modport slave
(
input adr,
input dat_o,
input sel,
input cyc,
input stb,
input we,
output ack,
output dat_i,
output stall,
output err,
output rty
);
wb_cycle_t c_queue[$];
wb_cycle_t current_cycle;
reg cyc_prev;
int trans_index;
int first_transaction;
struct {
wb_cycle_type_t mode;
int gen_random_stalls;
real stall_prob;
} settings;
function automatic int _poll(); return poll(); endfunction
task automatic _get(output wb_cycle_t xfer); get(xfer); endtask
class CIWBSlaveAccessor extends CWishboneAccessor;
function automatic int poll();
return _poll();
endfunction
task get(output wb_cycle_t xfer);
_get(xfer);
endtask
task clear();
endtask // clear
endclass // CIWBSlaveAccessor
function CIWBSlaveAccessor get_accessor();
CIWBSlaveAccessor tmp;
tmp = new;
return tmp;
endfunction // get_accessor
function automatic int poll();
return c_queue.size() != 0;
endfunction // poll
task automatic get(output wb_cycle_t xfer);
while(c_queue.size() <= 0)
@(posedge clk_i);
xfer = c_queue.pop_front();
endtask // pop_cycle
always@(posedge clk_i) cyc_prev <= cyc;
wire cyc_start = !cyc_prev && cyc;
wire cyc_end = cyc_prev && !cyc;
task gen_random_stalls();
if(settings.gen_random_stalls && probability_hit(settings.stall_prob))
stall <= 1;
else
stall <= 0;
endtask // gen_random_stalls
task pipelined_fsm();
if(cyc) begin
if(settings.gen_random_stalls)
gen_random_stalls();
end else
stall <= 0;
if(cyc_start) begin
current_cycle.data = {};
trans_index <= 0;
first_transaction = 1;
end
if(cyc_end) begin
c_queue.push_back(current_cycle);
end
if(stb && we) begin
wb_xfer_t d;
d.a = adr;
d.d = dat_i;
d.sel [g_data_width/8-1:0] = sel;
d.size = g_data_width; /* fixme */
current_cycle.data.push_back(d);
// $display("ifWb: write a %x d %x sel %x", adr, dat_i, sel);
ack <= 1;
end else if(stb && !we) begin
$error("Sorry, no pipelined read for slave yet implemented");
ack <= 0;
end else
ack <= 0;
endtask // pipelined_fsm
always@(posedge clk_i)
begin
if(!rst_n_i)
begin
c_queue = {};
current_cycle.data = {};
trans_index = 0;
ack <= 0;
rty <= 0;
err <= 0;
dat_o <= 0;
stall <= 0;
end else begin
if(settings.mode == PIPELINED)
pipelined_fsm();
end
end
initial begin
settings.mode = PIPELINED;
settings.gen_random_stalls = 1;
settings.stall_prob = 0.1;
end
endinterface // IWishboneSlave
//
// Title : Software Wishbone master unit for testbenches
//
// File : wishbone_master_tb.v
// Author : Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
// Created : Tue Mar 23 12:19:36 2010
// Standard : Verilog 2001
//
`ifndef __IF_WB_DEFS_SV
`define __IF_WB_DEFS_SV
`include "simdrv_defs.sv"
typedef enum
{
R_OK = 0,
R_ERROR,
R_RETRY
} wb_cycle_result_t;
typedef enum
{
CLASSIC = 0,
PIPELINED = 1
} wb_cycle_type_t;
typedef struct {
uint64_t a;
uint64_t d;
bit[7:0] sel;
int size;
} wb_xfer_t;
typedef struct {
int rw;
wb_cycle_type_t ctype;
wb_xfer_t data[$];
wb_cycle_result_t result;
} wb_cycle_t;
virtual class CWishboneAccessor;
virtual function automatic int poll();
return 0;
endfunction // poll
virtual task get(output wb_cycle_t xfer);
endtask // get
virtual task put(input wb_cycle_t xfer);
endtask // put
virtual function int idle();
return 0;
endfunction // idle
virtual task clear(); endtask
endclass // CWishboneAccessor
int seed = 0;
function automatic int probability_hit(real prob);
real rand_val;
rand_val = real'($dist_uniform(seed, 0, 1000)) / 1000.0;
if(rand_val < prob)
return 1;
else
return 0;
endfunction // probability_hit
`endif // `ifndef __IF_WB_DEFS_SV
`ifndef SIMDRV_DEFS_SV
`define SIMDRV_DEFS_SV 1
typedef longint unsigned uint64_t;
virtual class CBusAccessor;
pure virtual task write32(int addr, bit[31:0] data);
pure virtual task read32(int addr, output bit[31:0] rdata);
endclass // CBusAccessor
`endif
\ No newline at end of file
`timescale 1ps/1ps
// Clock/reset generator module for the TBI interface.
module tbi_clock_rst_gen
(
output clk_ref_o,
output clk_sys_o,
output phy_rbclk_o,
output rst_n_o);
parameter g_rbclk_period = 8010;
parameter g_refclk_period = 8000;
parameter g_sysclk_period = 15900;
reg refclk = 0, refclk2 = 0, rbclk = 0, rst_n = 0;
always #(g_rbclk_period/2) rbclk <= ~rbclk;
always #(g_refclk_period/2) refclk <= ~refclk;
always #(g_sysclk_period/2) refclk2 <= ~refclk2;
// always@(posedge refclk) refclk2 <= ~refclk2;
initial begin repeat(10) @(posedge refclk2); rst_n = 1; end
assign clk_ref_o = refclk;
assign clk_sys_o = refclk2;
assign phy_rbclk_o = rbclk;
assign rst_n_o = rst_n;
endmodule // tbi_clock_gen
`timescale 1ns/1ps
// Clock alignment FIFO for looping back the endpoint TX/RX path
module tbi_loopback_fifo
(
input tx_clk_i,
input rx_clk_i,
input [9:0] tx_data_i,
output reg [9:0] rx_data_o
);
parameter g_buf_size = 20000;
parameter g_error_prob = 0;
function automatic int probability_hit(int prob, int max_prob);
int rand_val;
rand_val = $random % (max_prob+1);
if(rand_val < 0) rand_val = -rand_val;
if(rand_val < prob)
return 1;
else
return 0;
endfunction // probability_hit
reg[9:0] buffer[100000];
int write_ptr, read_ptr, count;
initial begin
write_ptr = 0;
read_ptr = 0;
count = 0;
end
always@(posedge tx_clk_i) begin
buffer[write_ptr] <= tx_data_i;
count++;
write_ptr++;
end
always@(posedge rx_clk_i) begin
if(count == 0) begin
$display("loopback FIFO underrun!");
rx_data_o <= 0;
end else begin
if(probability_hit(g_error_prob, 1000))
rx_data_o <= 'hfff;
else
rx_data_o <= buffer[read_ptr];
read_ptr++;
count--;
end
end
endmodule
//
// Title : Software Wishbone master unit for testbenches
//
// File : wishbone_master_tb.v
// Author : Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
// Created : Tue Mar 23 12:19:36 2010
// Standard : Verilog 2001
//
// Default values of certain WB parameters.
`timescale 1ns/1ps
// Bus clock period
`ifndef WB_CLOCK_PERIOD
`define WB_CLOCK_PERIOD 16
`define WB_RESET_DELAY (3*`WB_CLOCK_PERIOD)
`endif
// Widths of wishbone address/data/byte select
`ifndef WB_DATA_BUS_WIDTH
`define WB_DATA_BUS_WIDTH 32
`endif
`ifndef WB_ADDRESS_BUS_WIDTH
`define WB_ADDRESS_BUS_WIDTH 32
`endif
`define WB_BWSEL_WIDTH ((`WB_DATA_BUS_WIDTH + 7) / 8)
module WB_TEST_MASTER (
`ifdef WB_USE_EXTERNAL_CLOCK
input clk_i,
input rst_n_i
`endif
);
// these signals make the WB bus, which can be accessed from outside the module
reg [`WB_ADDRESS_BUS_WIDTH - 1 : 0] wb_addr = 0;
reg [`WB_DATA_BUS_WIDTH - 1 : 0] wb_data_o = 0;
reg [`WB_BWSEL_WIDTH - 1 : 0] wb_bwsel = 0;
wire [`WB_DATA_BUS_WIDTH -1 : 0] wb_data_i;
wire wb_ack;
reg wb_cyc = 0;
reg wb_stb = 0;
reg wb_we = 0;
reg rst_reg = 0;
reg clk_reg = 1;
wire wb_clk, wb_rst;
reg wb_tb_verbose = 1;
reg wb_monitor_bus = 1;
time last_access_t = 0;
reg [`WB_DATA_BUS_WIDTH -1 : 0] dummy;
// ready signal. 1 indicates that WB_TEST unit is initialized and ready for commands
reg ready = 0;
`ifndef WB_USE_EXTERNAL_CLOCK
// generate the WB bus clock
always #(`WB_CLOCK_PERIOD/2) clk_reg <= ~clk_reg;
// generate the reset and ready signals
initial begin
#(`WB_RESET_DELAY) rst_reg <= 1;
#(`WB_CLOCK_PERIOD*2) ready <= 1;
end
assign wb_clk = clk_reg;
assign wb_rst = rst_reg;
`else // !`ifdef WB_USE_OWN_CLOCK
assign wb_clk = clk_i;
assign wb_rst = rst_n_i;
initial begin repeat(3) @(posedge wb_clk); ready = 1; end
`endif // !`ifdef WB_USE_OWN_CLOCK
// enables/disables displaying information about each read/write operation.
task verbose;
input onoff;
begin
wb_tb_verbose = onoff;
end
endtask // wb_verbose
task monitor_bus;
input onoff;
begin
wb_monitor_bus = onoff;
end
endtask // monitor_bus
task rw_generic;
input [`WB_ADDRESS_BUS_WIDTH - 1 : 0] addr;
input [`WB_DATA_BUS_WIDTH - 1 : 0] data_i;
output [`WB_DATA_BUS_WIDTH - 1 : 0] data_o;
input rw;
input [3:0] size;
begin : rw_generic_main
if(wb_tb_verbose && rw)
$display("WB write %s: addr %x, data %x",
(size==1?"byte":((size==2)?"short":"int")),
addr, data_i);
if($time != last_access_t) begin
@(posedge wb_clk);
end
wb_stb<=1;
wb_cyc<=1;
wb_addr <= {2'b00, addr[31:2]};
wb_we <= rw;
if(rw) begin
case(size)
4: begin wb_data_o<=data_i; wb_bwsel <= 4'b1111; end
2: begin
if(addr[1]) begin
wb_data_o[31:16] <= data_i[15:0];
wb_bwsel <= 4'b1100;
end else begin
wb_data_o[15:0] <= data_i[15:0];
wb_bwsel <= 4'b0011;
end
end
1: begin
case(addr[1:0])
0: begin wb_data_o[31:24] <= data_i[7:0]; wb_bwsel <= 4'b1000; end
1: begin wb_data_o[23:16] <= data_i[7:0]; wb_bwsel <= 4'b0100; end
2: begin wb_data_o[15:8] <= data_i[7:0]; wb_bwsel <= 4'b0010; end
3: begin wb_data_o[7:0] <= data_i[7:0]; wb_bwsel <= 4'b0001; end
endcase // case(addr[1:0])
end
endcase // case(size)
end // if (rw)
@(posedge wb_clk);
if(wb_ack == 0) begin
while(wb_ack == 0) begin @(posedge wb_clk); end
end
data_o = wb_data_i;
wb_cyc <= 0;
wb_we<=0;
wb_stb<=0;
if(wb_tb_verbose && !rw)
$display("WB read %s: addr %x, data %x",
(size==1?"byte":((size==2)?"short":"int")),
addr, wb_data_i);
last_access_t = $time;
end
endtask // rw_generic
task write8;
input [`WB_ADDRESS_BUS_WIDTH - 1 : 0] addr;
input [7 : 0] data_i;
begin
rw_generic(addr, data_i, dummy, 1, 1);
end
endtask // write8
task read8;
input [`WB_ADDRESS_BUS_WIDTH - 1 : 0] addr;
output [7 : 0] data_o;
begin : read8_body
reg [`WB_DATA_BUS_WIDTH - 1 : 0] rval;
rw_generic(addr, 0, rval, 0, 1);
data_o = rval[7:0];
end
endtask // write8
task write32;
input [`WB_ADDRESS_BUS_WIDTH - 1 : 0] addr;
input [31 : 0] data_i;
begin
rw_generic(addr, data_i, dummy, 1, 4);
end
endtask // write32
task read32;
input [`WB_ADDRESS_BUS_WIDTH - 1 : 0] addr;
output [31 : 0] data_o;
begin : read32_body
reg [`WB_DATA_BUS_WIDTH - 1 : 0] rval;
rw_generic(addr, 0, rval, 0, 4);
data_o = rval[31:0];
end
endtask // write32
// bus monitor
always@(posedge wb_clk) begin
if(wb_monitor_bus && wb_cyc && wb_stb && wb_ack)begin
if(wb_we) $display("ACK-Write: addr %x wdata %x bwsel %b", wb_addr, wb_data_o, wb_bwsel);
else $display("ACK-Read: addr %x rdata %x", wb_addr, wb_data_i);
end
end
endmodule
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment