Commit dd9214be authored by Grzegorz Daniluk's avatar Grzegorz Daniluk

adding simulation models

parent d3482f06
//
// 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
This diff is collapsed.
`ifndef __IF_WISHBONE_SLAVE_SVH
`define __IF_WISHBONE_SLAVE_SVH
`timescale 1ns/1ps
`include "if_wishbone_types.svh"
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;
int stall_min_duration;
int stall_max_duration;
real stall_prob;
} settings;
function automatic int _poll(); return poll(); endfunction
task automatic _get(ref wb_cycle_t xfer); get(xfer); endtask
class CIWBSlaveAccessor extends CWishboneAccessor;
function automatic int poll();
return _poll();
endfunction
task get(ref 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(ref 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();
static int stall_remaining = 0;
static int seed = 0;
// $display("stallr: %d\n", stall_remaining);
if(settings.gen_random_stalls && (probability_hit(settings.stall_prob) || stall_remaining > 0))
begin
if(stall_remaining == 0)
stall_remaining = $dist_uniform(seed,
settings.stall_min_duration,
settings.stall_max_duration);
if(stall_remaining)
stall_remaining--;
stall <= 1;
end else
stall <= 0;
endtask // gen_random_stalls
function automatic int count_ones(int x, int n_bits);
int i, cnt;
cnt = 0;
for(i=0;i<n_bits;i++) if(x & (1<<i)) cnt ++;
return cnt;
endfunction
function automatic int count_leading_zeroes(int x, int n_bits);
int i;
for(i=0;i<n_bits && !(x & (1<<i)); i++);
return i;
endfunction // count_leading_zeroes
function automatic int count_trailing_zeroes(int x, int n_bits);
int i;
for(i=n_bits-1;i>=0 && !(x & (1<<i)); i--);
return (n_bits-1-i);
endfunction
task pipelined_fsm();
if(settings.gen_random_stalls)
gen_random_stalls();
else
stall <= 0;
/* -----\/----- EXCLUDED -----\/-----
if(cyc) begin
end else
stall <= 0;
-----/\----- EXCLUDED -----/\----- */
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 && !stall && cyc) begin
int oc, lzc, tzc;
wb_xfer_t d;
oc = count_ones(sel, g_data_width/8);
lzc = count_leading_zeroes(sel, g_data_width/8);
tzc = count_trailing_zeroes(sel, g_data_width/8);
d.a = adr * (g_data_width / 8);
d.size = oc;
d.d = (dat_i>>(8*lzc)) & ((1<<(oc*8)) -1);
if(lzc + tzc + oc != g_data_width/8)
$error("IWishboneSlave [write a %x d %x sel %x]: non-contiguous sel", adr, dat_i, sel);
d.sel [g_data_width/8-1:0] = sel;
current_cycle.data.push_back(d);
// $display("ifWb:[%d] write a %x d %x sel %x",current_cycle.data.size(), adr, dat_i, sel);
ack <= 1;
end else if(stb && !we && !stall) 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;
settings.stall_min_duration = 1;
settings.stall_max_duration = 2;
end
endinterface // IWishboneSlave
`endif
\ No newline at end of file
`ifndef IF_WISHBONE_ACCESSOR_SV
`define IF_WISHBONE_ACCESSOR_SV
`include "if_wishbone_types.svh"
virtual class CWishboneAccessor extends CBusAccessor;
static int _null = 0;
protected wb_cycle_type_t m_cycle_type;
function new();
m_cycle_type = CLASSIC;
endfunction // new
virtual task set_mode(wb_cycle_type_t mode);
m_cycle_type = mode;
endtask // set_mode
// [slave only] checks if there are any transactions in the queue
virtual function automatic int poll();
return 0;
endfunction // poll
// [slave only] adds a simulation event (e.g. a forced STALL, RETRY, ERROR)
// evt = event type (STALL, ERROR, RETRY)
// behv = event behavior: DELAYED - event occurs after a predefined delay (dly_start)
// RANDOM - event occurs randomly with probability (prob)
// These two can be combined (random events occuring after a certain initial delay)
// DELAYED events can be repeated (rep_rate parameter)
virtual task add_event(wba_sim_event_t evt, wba_sim_behavior_t behv, int dly_start, real prob, int rep_rate);
endtask // add_event
// [slave only] gets a cycle from the queue
virtual task get(ref wb_cycle_t xfer);
endtask // get
// [master only] executes a cycle and returns its result
virtual task put(ref wb_cycle_t xfer);
endtask // put
virtual function int idle();
return 1;
endfunction // idle
// [master only] generic write(s), blocking
virtual task writem(uint64_t addr[], uint64_t data[], int size = 4, ref int result = _null);
wb_cycle_t cycle;
int i;
cycle.ctype = m_cycle_type;
cycle.rw = 1'b1;
for(i=0;i < addr.size(); i++)
begin
wb_xfer_t xfer;
xfer.a = addr[i];
xfer.d = data[i];
xfer.size = size;
cycle.data.push_back(xfer);
end
// $display("DS: %d", cycle.data.size());
put(cycle);
get(cycle);
result = cycle.result;
endtask // write
// [master only] generic read(s), blocking
virtual task readm(uint64_t addr[], ref uint64_t data[],input int size = 4, ref int result = _null);
wb_cycle_t cycle;
int i;
cycle.ctype = m_cycle_type;
cycle.rw = 1'b0;
for(i=0;i < addr.size(); i++)
begin
wb_xfer_t xfer;
xfer.a = addr[i];
xfer.size = size;
cycle.data.push_back(xfer);
end
put(cycle);
get(cycle);
for(i=0;i < addr.size(); i++)
data[i] = cycle.data[i].d;
result = cycle.result;
endtask // readm
virtual task read(uint64_t addr, ref uint64_t data, input int size = 4, ref int result = _null);
uint64_t aa[], da[];
aa = new[1];
da = new[1];
aa[0] = addr;
readm(aa, da, size, result);
data = da[0];
endtask
virtual task write(uint64_t addr, uint64_t data, int size = 4, ref int result = _null);
uint64_t aa[], da[];
aa = new[1];
da = new[1];
aa[0] = addr;
da[0] = data;
writem(aa, da, size, result);
endtask
endclass // CWishboneAccessor
static 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_WISHBONE_ACCESSOR_SV
//
// 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
//
// Title : Pipelined Wishbone BFM - type definitions
//
// File : if_wishbone_types.sv
// Author : Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
// Created : Tue Mar 23 12:19:36 2010
// Standard : Verilog 2001
//
`ifndef __IF_WB_TYPES_SVH
`define __IF_WB_TYPES_SVH
`include "simdrv_defs.svh"
typedef enum
{
R_OK = 0,
R_ERROR,
R_RETRY
} wb_cycle_result_t;
typedef enum
{
CLASSIC = 0,
PIPELINED = 1
} wb_cycle_type_t;
typedef enum {
WORD = 0,
BYTE = 1
} wb_address_granularity_t;
typedef struct {
uint64_t a;
uint64_t d;
int size;
bit [7:0] sel;
} wb_xfer_t;
typedef struct {
int rw;
wb_cycle_type_t ctype;
wb_xfer_t data[$];
wb_cycle_result_t result;
} wb_cycle_t;
typedef enum
{
RETRY = 0,
STALL,
ERROR
} wba_sim_event_t;
typedef enum
{
RANDOM = (1<<0),
DELAYED = (1<<1)
} wba_sim_behavior_t;
`endif // `ifndef __IF_WB_TYPES_SVH
`ifndef SIMDRV_DEFS_SV
`define SIMDRV_DEFS_SV 1
typedef longint unsigned uint64_t;
typedef int unsigned uint32_t;
typedef shortint unsigned uint16_t;
typedef uint64_t u64_array_t[];
typedef byte byte_array_t[];
virtual class CBusAccessor;
static int _null = 0;
pure virtual task writem(uint64_t addr[], uint64_t data[], input int size, ref int result);
pure virtual task readm(uint64_t addr[], ref uint64_t data[], input int size, ref int result);
virtual task read(uint64_t addr, ref uint64_t data, input int size = 4, ref int result = _null);
int res;
uint64_t aa[1], da[];
da= new[1];
aa[0] = addr;
readm(aa, da, size, res);
data = da[0];
endtask
virtual task write(uint64_t addr, uint64_t data, input int size = 4, ref int result = _null);
uint64_t aa[1], da[1];
aa[0] = addr;
da[0] = data;
writem(aa, da, size, result);
endtask
endclass // CBusAccessor
class CSimUtils;
static function automatic u64_array_t pack(byte x[], int size, int big_endian = 1);
u64_array_t tmp;
int i, j;
int nwords, nbytes;
nwords = (x.size() + size - 1) / size;
tmp = new [nwords];
for(i=0;i<nwords;i++)
begin
uint64_t d;
d =0;
nbytes = (x.size() - i * nbytes > size ? size : x.size() - i*nbytes);
for(j=0;j<nbytes;j++)
begin
if(big_endian)
d = d | ((x[i*size+j] << (8*(size-1-j))));
else
d = d | ((x[i*size+j] << (8*j)));
end
tmp[i] = d;
end
return tmp;
endfunction // pack
static function automatic byte_array_t unpack(u64_array_t x, int entry_size, int size, int big_endian = 1);
byte_array_t tmp;
int i, n;
tmp = new[size];
n = 0;
i = 0;
while(n < size)
begin
tmp[n] = x[i] >> (8*(entry_size-1 - (n % entry_size)));
n++;
if(n % entry_size == 0)
i++;
end
return tmp;
endfunction // unpack
endclass // CSimUtils
static CSimUtils SimUtils;
`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
`ifndef __WB_FABRIC_DEFS_SVH
`define __WB_FABRIC_DEFS_SVH
const bit [2:0] WRF_STATUS = 3'b100;
const bit [2:0] WRF_DATA = 3'b000;
const bit [2:0] WRF_OOB = 3'b010;
const bit [2:0] WRF_USER = 3'b110;
const bit [3:0] WRF_OOB_TX_FID = 4'b0001;
const bit [3:0] WRF_OOB_RX_TIMESTAMP = 4'b0000;
`endif // `ifndef __WB_FABRIC_DEFS_SVH
`ifndef __WB_PACKET_SINK_SVH
`define __WB_PACKET_SINK_SVH
`include "simdrv_defs.svh"
`include "eth_packet.svh"
`include "if_wishbone_accessor.svh"
`include "wb_fabric_defs.svh"
class WBPacketSink extends EthPacketSink;
protected CWishboneAccessor m_acc;
function new(CWishboneAccessor acc);
m_acc = acc;
endfunction // new
function int poll();
return m_acc.poll();
endfunction // poll
protected task decode_status(uint64_t stat, ref EthPacket pkt);
if(stat & 'h2)
pkt.error = 1'b1;
else begin
pkt.has_smac = (stat & 'h4 ? 1'b1 : 1'b0);
pkt.has_crc = (stat & 'h8 ? 1'b1 : 1'b0);
pkt.pclass = (stat>>8) & 'hff;
end
endtask // decode_status
protected task decode_oob(uint64_t oob, int size, ref EthPacket pkt);
if(!size)
return;
else if(size == 2 && (oob >> 28) == WRF_OOB_TX_FID)
begin
// $display("GotTxOOB");
pkt.oob_type = TX_FID;
pkt.ts.frame_id = oob & 'hffff;
end
else if (size == 3 && (oob >> 46) == WRF_OOB_RX_TIMESTAMP)
begin
$display("GotRXOOB");
end else begin
$error("Invalid OOB!");
$stop;
end
endtask // decode_oob
task recv(ref EthPacket pkt, ref int result = _null);
uint64_t oob = 0;
byte tmp[];
wb_cycle_t cyc;
int i, size = 0, n = 0, n_oob = 0;
int oob_size = 0;
pkt = new;
m_acc.get(cyc);
for(i=0;i<cyc.data.size(); i++)
if (cyc.data[i].a == WRF_DATA)
size = size + cyc.data[i].size;
tmp = new[size];
// $display("CDS %d size: %d\n", cyc.data.size(), size);
for(i=0;i<cyc.data.size(); i++)
begin
wb_xfer_t xf = cyc.data[i];
case(xf.a)
WRF_STATUS:
begin
decode_status(xf.d, pkt);
if(pkt.error)
break;
end
WRF_DATA:
begin
if(xf.size == 1)
tmp[n++] = (xf.d & 'hff);
else if(xf.size == 2)begin
tmp[n++] = ((xf.d >> 8) & 'hff);
tmp[n++] = (xf.d & 'hff);
end
end
WRF_OOB:
begin
oob = (oob << 16) | xf.d;
oob_size ++;
end
endcase // case (xf.a)
end
pkt.deserialize(tmp);
decode_oob(oob, oob_size, pkt);
endtask // recv
endclass // WBPacketSink
`endif
`ifndef __WB_PACKET_SOURCE_SVH
`define __WB_PACKET_SOURCE_SVH
`include "simdrv_defs.svh"
`include "eth_packet.svh"
`include "if_wishbone_accessor.svh"
`include "wb_fabric_defs.svh"
class WBPacketSource extends EthPacketSource;
protected CWishboneAccessor m_acc;
function new(CWishboneAccessor acc);
m_acc = acc;
endfunction // new
function bit[15:0] pack_status(ref EthPacket pkt, input bit error = 0);
bit [15:0] st;
st[0] = (pkt.is_hp ? 1'b1: 1'b0);
st[1] = 1'b0;
st[2] = (pkt.has_smac ? 1'b1: 1'b0);
st[3] = error;
st[15:8] = pkt.pclass; // FIXME: add packet classes
st[7:4]= 0;
return st;
endfunction // pack_status
task unpack_status(bit[15:0] status, ref EthPacket pkt);
endtask // unpack_status
typedef bit[15:0] oob_array16[];
function u64_array_t pack_oob(ref EthPacket pkt);
u64_array_t oob;
case(pkt.oob_type)
TX_FID: begin
oob = new[2];
oob[0] = {WRF_OOB_TX_FID, 12'b0};
oob[1] = pkt.ts.frame_id;
end
endcase // case (pkt.oob_type)
return oob;
endfunction // pack_oob
task send(ref EthPacket pkt, ref int result = _null);
byte pdata[]; // FIXME: dynamic allocation would be better...
u64_array_t pdata_p;
u64_array_t oob_p;
int i, len;
wb_cycle_t cyc;
wb_xfer_t xf;
cyc.ctype = PIPELINED;
cyc.rw = 1;
/* First, the status register */
xf.a = WRF_STATUS;
xf.d = pack_status(pkt);
xf.size = 2;
cyc.data.push_back(xf);
pkt.serialize(pdata);
pdata_p = SimUtils.pack(pdata, 2, 1);
len = pdata_p.size();
for(i=0; i < len; i++)
begin
xf.a = WRF_DATA;
if(i==len-1 && (pdata.size()&1))
begin
xf.size = 1;
xf.d = pdata_p[i] >> 8;
end else begin
xf.size = 2;
xf.d = pdata_p[i];
end
cyc.data.push_back(xf);
end
if(pkt.error)
begin
xf.a = WRF_STATUS;
xf.d = pack_status(pkt, 1);
xf.size = 2;
cyc.data.push_back(xf);
end else begin
// $display("WBPacketSource::send(): DataSize: %d\n", cyc.data.size());
oob_p = pack_oob(pkt);
for (i=0;i<oob_p.size(); i++)
begin
xf.a = WRF_OOB;
xf.d = oob_p[i] & 'hffff;
xf.size = 2;
cyc.data.push_back(xf);
end
end // else: !if(pkt.error)
m_acc.put(cyc);
m_acc.get(cyc);
result = cyc.result;
endtask // send
endclass // WBPacketSource
`endif
//
// 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