EDA Playground lets you type in and run HDL code (using a selection of free and commercial simulators and synthesizers).
It's great for learning HDLs, it's great for testing out unfamiliar things and it's great for sharing code.
You can start typing straight away. But to run your code, you'll need to sign or log in. Logging in with a Google account gives you access to all non-commercial simulators and some commercial simulators:
To run commercial simulators, you need to register and log in with a username and password. Registration is free, and only pre-approved email's will have access to the commercial simulators.
* ModelSim 10.1d not available.
208
// or browse Examples
// or browse Examples
`timescale 1ns/1ns
`include "slv_pci.v"
`include "slv_pci_shell.sv"
`include "pci_bus_if.sv"
//`include "test_uvm.sv"
//`timescale 1ns/1ns
// use parameter to allow changes by higher design module
parameter IO_Address = 32'h0000_0200;
parameter ADDRMASK = 32'hFFFF_FFF0; // remove A<3:0>
parameter IO_Read_CMD = 4'h2;
parameter IO_Write_CMD = 4'h3;
parameter AREG_WIDTH = 2; // 2 address bits for 4 data registers
parameter DREG_DEPTH = 4; // 4 data register
parameter WAIT_WIDTH = 3; // wait 2^3 -1 = 7
module test_uvm (interface.port_test bus);
integer wr_data;
integer rd_data;
integer address, data;
logic write;
initial begin
wr_data = 12;
single_reset ();
fork
begin
single_write_drv_uvm (.address (32'h0000_0204),.data (wr_data));
single_read_drv_uvm (.address (32'h0000_0204),.data (rd_data));
end
begin
get_item_mon_uvm (.address (address), .write (write),.data (data));
if (address == 32'h0000_0204) $display ("Correct address\n");
else $display ("Incorrect address\n");
if (write == 1) $display ("Correct type\n");
else $display ("Incorrect type\n");
if (data == wr_data) $display ("Correct write data\n");
else $display ("Incorrect write data\n");
$display ("Expect data: time=%t address = %0h, write mode = %s, data = %d\n", $time, 32'h0000_0204, "true", wr_data);
$display ("Mon: time=%t address = %0h, write mode = %s, data = %d\n", $time, address, ((write) ? "true" : "false"), data);
get_item_mon_uvm (.address (address), .write (write),.data (data));
if (address == 32'h0000_0204) $display ("Correct address\n");
else $display ("Incorrect address\n");
if (write == 0) $display ("Correct type\n");
else $display ("Incorrect type\n");
if (data == wr_data) $display ("Correct write data\n");
else $display ("Incorrect write data\n");
$display ("Expect data: time=%t address = %0h, write mode = %s, data = %d\n", $time, 32'h0000_0204, "false", wr_data);
$display ("Mon: time=%t address = %0h, write mode = %s, data = %d\n", $time, address, ((write) ? "true" : "false"), data);
end
join
$100;
if (rd_data == wr_data)
$display ("Pass matched: wr_data = %d, rd_data = %d\n",wr_data, rd_data, wr_data);
else
$display ("Fail mismatched: wr_data = %d, rd_data = %d\n",wr_data, rd_data, wr_data);
#10 $finish;
end
// `include"single_reset.sv"
task single_reset;
//input integer address;
//output integer data;
// Comment: Test pass case for Single Read Cycle for all assertion checks
// Comment: PCI waveform signal changes at the falling clock edge.
// CLK :_/~\_/~\_/~\
// RSTn :________~~~~
// FRAMEn :~~~~~~~~~~~~
// ADm :< 0>< 0>< 0>
// OE_ADm :~~~~~~~~~~~~
// CBEn :< 0>< 0>< 0>
// IRDYn :~~~~~~~~~~~~
// TRDYn :~~~~~~~~~~~~
// DEVSELn :~~~~~~~~~~~~
// waitdelay :< 0>< 0>< 0>
@(bus.DRVCLK); // Cycle 0
bus.DRVCLK.RSTn <= 1'b0;
bus.DRVCLK.FRAMEn <= 1'b1;
bus.DRVCLK.AD <= 32'h0000_0000;
//ADm <= 32'h0000_0000;
//OE_ADm <= 1'b1;
bus.DRVCLK.CBEn <= 4'h0;
bus.DRVCLK.IRDYn <= 1'b1;
bus.DRVCLK.waitdelay <= 4'h0;
@(bus.DRVCLK); // Cycle 0
bus.DRVCLK.RSTn <= 1'b0;
bus.DRVCLK.FRAMEn <= 1'b1;
bus.DRVCLK.AD <= 32'h0000_0000;
//ADm <= 32'h0000_0000;
//OE_ADm <= 1'b1;
bus.DRVCLK.CBEn <= 4'h0;
bus.DRVCLK.IRDYn <= 1'b1;
bus.DRVCLK.waitdelay <= 4'h0;
@(bus.DRVCLK); // Cycle 0
bus.DRVCLK.RSTn <= 1'b1;
bus.DRVCLK.FRAMEn <= 1'b1;
bus.DRVCLK.AD <= 32'h0000_0000;
//ADm <= 32'h0000_0000;
//OE_ADm <= 1'b1;
bus.DRVCLK.CBEn <= 4'h0;
bus.DRVCLK.IRDYn <= 1'b1;
bus.DRVCLK.waitdelay <= 4'h0;
endtask
`include"single_write_drv_uvm.sv"
`include"single_read_drv_uvm.sv"
`include"get_item_mon_uvm.sv"
`include"get_write_mon_uvm.sv"
`include"get_read_mon_uvm.sv"
endmodule
module testbench;
// signal declaration //
bit CLK;
// Module declaration //
pci_bus_if bus (CLK);
slv_pci_shell dut (bus.port_dut);
test_uvm test (bus.port_test);
// clock generation //
initial forever #(10/2) CLK = ~CLK;
//initial $dumpvars(0, testbench);
initial $dumpvars(0, testbench.bus);
initial $dumpvars(0, testbench.test);
initial $dumpvars(0, testbench.dut.dut);
endmodule
xxxxxxxxxx
// Code your design here
xxxxxxxxxx
task get_item_mon_uvm(output integer address, output bit write, output integer data);
integer address1,address2,data1,data2;
bit write1,write2,status1,status2;
begin
fork
get_read_mon_uvm(address1,write1,data1, status1);
get_write_mon_uvm(address2,write2,data2, status2);
join
$display ("get time = %t\n", $time);
`ifdef DEBUG_WRITE
$display ("get address2 = %0h\n", address2);
$display ("get pci_write2 = %s\n", (write2) ? "true" : "false");
$display ("get data2 = %0d\n", data2);
$display ("get status2 = %0d\n", status2);
`endif
if (status1) begin
address = address1;
write = write1;
data = data1;
end else if (status2) begin
$display ("get status2 is true.\n");
address = address2;
write = write2;
data = data2;
end else begin
address = 0;
write = 0;
data = 0;
end
$display ("get address = %0h\n", address);
$display ("get pci_write = %s\n", (write) ? "true" : "false");
$display ("get data = %0d\n", data);
end
endtask
xxxxxxxxxx
task get_read_mon_uvm (output integer address, output bit write, output integer data, output bit status);
// Comment: Test pass case for Single Write Cycle for all assertion checks
// Comment: PCI waveform signal changes at the falling clock edge.
// CLK :_/~\_/~\_/~\
// FRAMEn :____~~~~~~~~
// AD :< A>< 0>< D>
// CBEn :< C>< F>< F>
@(negedge bus.MONCLK.FRAMEn);
//@(bus.MONCLK);
address = bus.MONCLK.AD;
if (bus.MONCLK.CBEn == IO_Read_CMD) begin
write = 0; // false
@(bus.MONCLK);
@(bus.MONCLK);
data = bus.MONCLK.AD;
status = 1'b1; // success
end else begin
status = 1'b0; // not success
end
`ifdef DEBUG_READ
$display ("read time = %t\n", $time);
$display ("read address = %0h\n", address);
$display ("read pci_write = %s\n", (write) ? "true" : "false");
$display ("read data = %0d\n", data);
$display ("read status = %0d\n", status);
`endif
endtask
xxxxxxxxxx
task get_write_mon_uvm (output integer address, output bit write, output integer data, output bit status);
// Comment: Test pass case for Single Write Cycle for all assertion checks
// Comment: PCI waveform signal changes at the falling clock edge.
// CLK :_/~\_/~\
// FRAMEn :____~~~~
// AD :< A>< D>
// CBEn :< C>< F>
@(negedge bus.MONCLK.FRAMEn);
//@(bus.MONCLK); // removed for correct capture
address = bus.MONCLK.AD;
if (bus.MONCLK.CBEn == IO_Write_CMD) begin
//tran_type = PCI_WRITE;
write = 1; // true
@(bus.MONCLK);
data = bus.MONCLK.AD;
status = 1'b1; // success
end else begin
status = 1'b0; // not success
end
`ifdef DEBUG_WRITE
$display ("write time = %t\n", $time);
$display ("write address = %0h\n", address);
$display ("write pci_write = %s\n", (write) ? "true" : "false");
$display ("write data = %0d\n", data);
$display ("write status = %0d\n", status);
`endif
endtask
xxxxxxxxxx
interface pci_bus_if (input bit CLK);
// use parameter to allow changes by higher design module
parameter IO_Address = 32'h0000_0200;
parameter ADDRMASK = 32'hFFFF_FFF0; // remove A<3:0>
parameter IO_Read_CMD = 4'h2;
parameter IO_Write_CMD = 4'h3;
parameter AREG_WIDTH = 2; // 2 address bits for 4 data registers
parameter DREG_DEPTH = 4; // 4 data register
parameter WAIT_WIDTH = 3; // wait 2^3 -1 = 7
logic RSTn;
logic FRAMEn;
wire [31:0] AD;
logic [ 3:0] CBEn;
logic IRDYn;
logic TRDYn;
logic DEVSELn;
logic [WAIT_WIDTH-1:0] waitdelay;
// DRVCLK is for driving output signal changes at negative clock edge
clocking DRVCLK @(negedge CLK);
input TRDYn, DEVSELn;
output RSTn, FRAMEn, CBEn, IRDYn, waitdelay;
inout AD;
endclocking
// DRVCLK_IN is for detecting input signals at positive clock edge
// allowing single clock operation
clocking DRVCLK_IN @(posedge CLK);
input TRDYn, DEVSELn;
endclocking
clocking MONCLK @(negedge CLK);
input TRDYn, DEVSELn;
input RSTn, FRAMEn, CBEn, IRDYn, waitdelay;
input AD;
endclocking
modport port_dut (
input CLK,
input RSTn,
input FRAMEn,
inout AD,
input CBEn,
input IRDYn,
output TRDYn,
output DEVSELn,
input waitdelay);
modport port_test (clocking DRVCLK, clocking MONCLK);
endinterface:pci_bus_if
// 12-15 version
task single_read_drv_uvm;
input integer address;
output integer data;
// Comment: Test pass case for Single Read Cycle for all assertion checks
// Comment: PCI waveform signal changes at the falling clock edge.
// CLK :_/~\_/~\_/~\_/~\_/~\
// FRAMEn :~~~~____~~~~~~~~~~~~
// AD :< 0>< A>< z>< z>< D>
// CBEn :< 0>< C>< F>< F>< 0>
// IRDYn :~~~~~~~~________~~~~
// TRDYn :~~~~~~~~~~~~____~~~~
// DEVSELn :~~~~~~~~________~~~~
@(bus.DRVCLK); // Cycle 0
bus.DRVCLK.FRAMEn <= 1'b1;
bus.DRVCLK.AD <= 32'h0000_0000;
bus.DRVCLK.CBEn <= 4'h0;
bus.DRVCLK.IRDYn <= 1'b1;
@(bus.DRVCLK); // Cycle 1
bus.DRVCLK.FRAMEn <= 1'b0;
//bus.DRVCLK.AD <= req.address + IO_Address;
//bus.DRVCLK.AD <= address + IO_Address;
bus.DRVCLK.AD <= address;
bus.DRVCLK.CBEn <= IO_Read_CMD;
bus.DRVCLK.IRDYn <= 1'b1;
@(bus.DRVCLK); // Cycle 2
bus.DRVCLK.FRAMEn <= 1'b1;
bus.DRVCLK.AD <= 'hz;
bus.DRVCLK.CBEn <= 4'hF;
bus.DRVCLK.IRDYn <= 1'b0;
@(bus.DRVCLK); // Cycle 3
bus.DRVCLK.FRAMEn <= 1'b1;
bus.DRVCLK.AD <= 'hz;
bus.DRVCLK.CBEn <= 4'hF;
bus.DRVCLK.IRDYn <= 1'b0;
@(bus.DRVCLK); // Cycle 4
bus.DRVCLK.FRAMEn <= 1'b1;
//req.data = bus.DRVCLK.AD;
data = bus.DRVCLK.AD;
bus.DRVCLK.CBEn <= 4'h0;
bus.DRVCLK.IRDYn <= 1'b1;
endtask
xxxxxxxxxx
// 12-15 version
task single_write_drv_uvm;
input integer address;
input integer data;
// Comment: Test pass case for Single Write Cycle for all assertion checks
// Comment: PCI waveform signal changes at the falling clock edge.
// CLK :_/~\_/~\_/~\_/~\
// FRAMEn :~~~~____~~~~~~~~
// AD :< 0>< A>< D>< 0>
// CBEn :< 0>< C>< F>< 0>
// IRDYn :~~~~~~~~____~~~~
// TRDYn :~~~~~~~~____~~~~
// DEVSELn :~~~~~~~~____~~~~
@(bus.DRVCLK); // Cycle 0
bus.DRVCLK.FRAMEn <= 1'b1;
bus.DRVCLK.AD <= 32'h0000_0000;
bus.DRVCLK.CBEn <= 4'h0;
bus.DRVCLK.IRDYn <= 1'b1;
@(bus.DRVCLK); // Cycle 1
bus.DRVCLK.FRAMEn <= 1'b0;
//bus.DRVCLK.AD <= req.address + IO_Address;
//bus.DRVCLK.AD <= address + IO_Address;
bus.DRVCLK.AD <= address;
bus.DRVCLK.CBEn <= IO_Write_CMD;
bus.DRVCLK.IRDYn <= 1'b1;
@(bus.DRVCLK); // Cycle 2
bus.DRVCLK.FRAMEn <= 1'b1;
//bus.DRVCLK.AD <= req.data;
bus.DRVCLK.AD <= data;
bus.DRVCLK.CBEn <= 4'hF;
bus.DRVCLK.IRDYn <= 1'b0;
@(bus.DRVCLK); // Cycle 3
bus.DRVCLK.FRAMEn <= 1'b1;
bus.DRVCLK.AD <= 32'h0000_0000;
bus.DRVCLK.CBEn <= 4'h0;
bus.DRVCLK.IRDYn <= 1'b1;
endtask
xxxxxxxxxx
module slv_pci_shell (interface.port_dut bus);
slv_pci dut (
.CLK (bus.CLK),
.RSTn (bus.RSTn),
.FRAMEn (bus.FRAMEn),
.AD (bus.AD),
.CBEn (bus.CBEn),
.IRDYn (bus.IRDYn),
.TRDYn (bus.TRDYn),
.DEVSELn (bus.DEVSELn),
.waitdelay (bus.waitdelay)
);
endmodule
xxxxxxxxxx
///////////////////////////////////////////////////////////////////////////////
// //
// File name: slv.pci.v //
// Author : Michael Li //
// Date : 10/10/2014 //
// Description : Implementation of PCI slave device for these features //
// //
// 1. single cycle or burst (multiple cycles) operations. //
// 2. support for read (02h) and write (03h) commands //
// 3. support to handle wait from master. //
// 4. programmable slave wait duration. //
// 5. random address access within the valid address range. //
// 6. auto addresss increment in burst read or write //
// //
///////////////////////////////////////////////////////////////////////////////
// //
// rev 1c : add check for master delay wait insertion (IRDYn==1)
// rev 1d : use enum type for state type variables in FSM
// add wait state to inject TRDY wait states.
// rev 1e : testing
// rev 1f : fix read data out needs to wait for TRDYn low.
// rev 1g : change DEVSELn to register to eliminate glitch issue
// (10/10/15 ML) rev 1h : allow start address to be 200,204,208,20c
// add time scale for this module. //
// rev 1j : optimized register size (waitdelay, address) //
// //
///////////////////////////////////////////////////////////////////////////////
`timescale 1ns/1ns
`define WDELAY 1 // mininum number is 1
typedef enum {ST_IDLE, ST_TURNAROUND, ST_WAIT, ST_DATA, ST_END} state_t;
module slv_pci (CLK,RSTn,FRAMEn,AD,CBEn,IRDYn,TRDYn,DEVSELn,waitdelay);
// use parameter to allow changes by higher design module
parameter IO_Address = 32'h0000_0200;
parameter ADDRMASK = 32'hFFFF_FFF0; // remove A<3:0>
parameter IO_Read_CMD = 4'h2;
parameter IO_Write_CMD = 4'h3;
input CLK; // clock (system)
input RSTn; // reset (master)
input FRAMEn; // frame to start new transaction (master)
inout [31:0] AD; // address/data bus (master or slave)
//input [31:0] AD; // address/data bus (master or slave)
input [3:0] CBEn; // command or Byte enable (master)
input IRDYn; // Initiator (master) ready
output TRDYn; // Target (slave) ready
output DEVSELn; // Device select (slave)
reg DEVSELn; // make a register for it
//////////////////////////////////////////////////////////////////////
// Local varaiables //
//////////////////////////////////////////////////////////////////////
parameter AREG_WIDTH = 2; // 2 address bits for 4 data registers
parameter DREG_DEPTH = 4; // 4 data register
parameter WAIT_WIDTH = 3; // wait 2^3 -1 = 7
input[WAIT_WIDTH-1:0] waitdelay; // wait delay (up to 7 delay)
state_t current_state, next_state; // Finite State machine state
reg [AREG_WIDTH-1:0] address; // address register
reg rnw_mode; // read not write mode register
reg dev_oe; // enable to drive AD bus during read
wire [31:0] data_out; // output of data mux
reg [31:0] data [DREG_DEPTH-1:0]; // Data registers
reg [WAIT_WIDTH-1:0] waitcount; // wait state duration in clock cycles
reg waiten; // Wait enable
wire addrmatch; // valid address match
wire wrcmdmatch;
wire rdcmdmatch;
//////////////////////////////////////////////////////////////////////
// local compare logic //
//////////////////////////////////////////////////////////////////////
assign addrmatch = ((AD & ADDRMASK) == IO_Address);
assign wrcmdmatch = addrmatch & CBEn == IO_Write_CMD;
assign rdcmdmatch = addrmatch & CBEn == IO_Read_CMD;
//////////////////////////////////////////////////////////////////////
// Register Sets //
//////////////////////////////////////////////////////////////////////
// wait enable bit register
//always @ (negedge RSTn) begin
always @ (negedge CLK or negedge RSTn) begin
//if (!RSTn)
waiten <= (waitdelay > 0);
end
// address register
always @ (negedge CLK or negedge RSTn) begin
if (!RSTn)
address <= 0;
else if (current_state == ST_IDLE)
address <= AD[2+AREG_WIDTH-1:2];
else if (current_state == ST_DATA && ~IRDYn && ~TRDYn) // data transfer condition
address <= address + 1;
end
// data register (for write mode)
always @ (negedge CLK or negedge RSTn) begin
if (!RSTn) begin
data[0] <= 0;
data[1] <= 0;
data[2] <= 0;
data[3] <= 0;
end else if (current_state == ST_DATA && rnw_mode == 0 && ~IRDYn && ~TRDYn) // data transfer condition
data[address] <= AD;
end
// read/write mode bit register
always @ (negedge CLK or negedge RSTn) begin
if (!RSTn)
rnw_mode <= 1'b1;
else if (~FRAMEn && wrcmdmatch)
rnw_mode <= 0;
else if (~FRAMEn && rdcmdmatch)
rnw_mode <= 1'b1;
end
// device output enable register (for read mode)
always @ (negedge CLK or negedge RSTn) begin
if (!RSTn)
dev_oe <= 1'b0;
else if (current_state == ST_IDLE)
dev_oe <= 1'b0;
else if (current_state == ST_TURNAROUND)
dev_oe <= 1'b1;
end
// device output enable register (for read mode)
always @ (negedge CLK or negedge RSTn) begin
if (!RSTn)
waitcount <= 'h1;
else if (current_state != ST_WAIT)
waitcount <= 'h1;
else if (waiten == 1'b1 && waitcount < waitdelay)
waitcount <= waitcount + 1;
end
// device selection output register
always @ (negedge CLK or negedge RSTn) begin
if (!RSTn)
DEVSELn <= 1'b1;
else if (~FRAMEn && (wrcmdmatch || rdcmdmatch)) // address/command
DEVSELn <= 1'b0;
else if (~IRDYn && ~TRDYn & FRAMEn) // last data transfer
DEVSELn <= 1'b1;
end
//////////////////////////////////////////////////////////////////////
// FSM //
//////////////////////////////////////////////////////////////////////
// sequential logic only
always @ (negedge CLK or negedge RSTn) begin
if (!RSTn)
current_state <= ST_IDLE;
else
current_state <= next_state;
end
// combination logic only
always @(*) begin
case (current_state)
ST_IDLE : begin
if (~FRAMEn && wrcmdmatch && waiten == 1)
next_state <= ST_WAIT;
else if (~FRAMEn && wrcmdmatch && waiten == 0)
next_state <= ST_DATA;
else if (~FRAMEn && rdcmdmatch)
next_state <= ST_TURNAROUND;
else
next_state <= ST_IDLE; // for initialization
end
ST_TURNAROUND : begin
if (waiten)
next_state <= ST_WAIT;
else
next_state <= ST_DATA;
end
ST_WAIT : begin
if (waitcount == waitdelay)
next_state <= ST_DATA;
else
next_state <= ST_WAIT; // need to specify all condition for comblogic
end
ST_DATA : begin
if (~IRDYn && ~TRDYn & FRAMEn)
next_state <= ST_END;
else if (~IRDYn && ~TRDYn & ~FRAMEn && waiten == 1)
next_state <= ST_WAIT;
else if (~IRDYn && ~TRDYn & ~FRAMEn && waiten == 0)
next_state <= ST_DATA;
else
next_state <= ST_DATA;
end
ST_END : begin
if (IRDYn && TRDYn && FRAMEn)
next_state <= ST_IDLE;
else
next_state <= ST_END;
end
endcase
end
//assign DEVSELn = !(current_state == ST_DATA || current_state == ST_WAIT || current_state == ST_TURNAROUND ) // glitch problem
assign TRDYn = !(current_state == ST_DATA);
assign data_out = (current_state == ST_DATA) ? data[address] : 'hx; // delay data out
assign AD = (dev_oe & ~DEVSELn) ? data_out : 'hz ;
endmodule
Your account is not validated. If you wish to use commercial simulators, you need a validated account.
If you have already registered (or have recently changed your email address), but have not clicked on the link in the email we sent you, please do so. If you cannot find the email, please check your spam/junk folder. Or click here to resend the email.
If you have not already registered for a full account, you can do so by clicking below. You will then need to provide us with some identification information. You may wish to save your code first.
Creating, deleting, and renaming files is not supported during Collaboration. To encourage development of these features for Collaboration, tweet to @EDAPlayground
This playground may have been modified. Please save or copy before starting collaboration.
Your exercise has been submitted.