// // Testbench for demonstrating the capabilities of the // ScriptSim PCI Bus Functional Model // It demonstrates master, target, monitor, and arbiter capabilities // This is a PCI 64-bit 66Mhz testbench // But has one 32-bit agent to show compatibility // `timescale 1ps / 1ps module demo; parameter agents = 4; // testbench allows up to 16 agents parameter half_clock_period = 7576; // ps for 66Mhz parameter PCI_MR = 6, PCI_MW = 7; // this is a standard and_reduce except // if all drivers are 'z', result is '1' function and_reduce; input [agents-1:0] inval; integer i; begin and_reduce = 1'b1; for (i = 0; i < agents; i = i + 1) begin if (inval[i] !== 1'bz) begin and_reduce = and_reduce & inval[i]; end end end endfunction // The ScriptSim PCI model outputs to verilog registers // Resolution of multiple drivers is done here in the verilog code reg clock; reg reset_l; reg [agents-1:0] req_l, gnt_l, frame_rl, irdy_rl, trdy_rl, stop_rl, lock_rl, devsel_rl, par_r, perr_rl, serr_rl, req64_rl, ack64_rl, par64_r; reg frame_l, irdy_l, trdy_l, stop_l, lock_l, devsel_l, par, perr_l, serr_l, req64_l, ack64_l, par64; wire clk; wire [15:0] idsel; // 16 devices allowed reg [63:0] ad0, ad1, ad2; // must define for all agents reg [31:0] ad3; // for 32-bit agent reg [7:0] cbe0_l, cbe1_l, cbe2_l; // must define for all agents reg [3:0] cbe3_l; // for 32-bit agent wire [63:0] ad; wire [31:0] ad32; // for 32-bit agent wire [7:0] cbe_l; wire [3:0] cbe_l32; // for 32-bit agent // signals used for scriptsim task calls integer ss_id0, ss_id1, ss_id2, ss_id3; assign ad = ad0; // must assign for all agents. assign ad = ad1; assign ad = ad2; assign ad[31:0] = ad3; assign ad32 = ad[31:0]; // for 32-bit agent assign cbe_l = cbe0_l; // must assign for all agents assign cbe_l = cbe1_l; assign cbe_l = cbe2_l; assign cbe_l[3:0] = cbe3_l; assign cbe_l32 = cbe_l[3:0]; // for 32-bit agent assign clk = clock; // This special and_reduce returns a '1' if all drivers are 'z' // This simulates pci signals with pullups always @(frame_rl) begin frame_l = and_reduce(frame_rl); end always @(irdy_rl) begin irdy_l = and_reduce(irdy_rl); end always @(trdy_rl) begin trdy_l = and_reduce(trdy_rl); end always @(stop_rl) begin stop_l = and_reduce(stop_rl); end always @(lock_rl) begin lock_l = and_reduce(lock_rl); end always @(devsel_rl) begin devsel_l = and_reduce(devsel_rl); end always @(par_r) begin par = and_reduce(par_r); end always @(perr_rl) begin perr_l = and_reduce(perr_rl); end always @(serr_rl) begin serr_l = and_reduce(serr_rl); end always @(req64_rl) begin req64_l = and_reduce(req64_rl); end always @(ack64_rl) begin ack64_l = and_reduce(ack64_rl); end always @(par64_r) begin par64 = and_reduce(par64_r); end assign idsel = ad[31:16]; // here is the 'guts' of the model // simply instantiate all the ScriptSim PCI agents, monitor, arbiter initial begin: main_block $timeformat(-9, 0, "ns", 10); clock <= 1'b0; reset_l <= 1'b0; // agent names: leftmost uses req_l[0] and devsel_rl[0] // i.e. if "cpu, scsi", cpu is agent0, scsi is agent 1 ... // here is the monitor $scriptsim("../../pci/mon_pci.py", "cpu, scsi, lan, lan32", clk, reset_l, req_l, gnt_l, frame_l, irdy_l, trdy_l, stop_l, lock_l, idsel, devsel_l, devsel_rl, ad, cbe_l, par, perr_l, serr_l, req64_l, ack64_l, par64); // 3 64-bit agents $scriptsim("../../pci/agent.py", ss_id0, "../../pci/pci_cmds0", clk, reset_l, req_l[0], gnt_l[0], frame_l, frame_rl[0], irdy_l, irdy_rl[0], trdy_l, trdy_rl[0], stop_l, stop_rl[0], lock_l, lock_rl[0], idsel[0], devsel_l, devsel_rl[0], ad, ad0, cbe_l, cbe0_l, par, par_r[0], perr_l, perr_rl[0], serr_l, serr_rl[0], req64_l, req64_rl[0], ack64_l, ack64_rl[0], par64, par64_r[0]); $scriptsim("../../pci/agent.py", ss_id1, "../../pci/pci_cmds1", clk, reset_l, req_l[1], gnt_l[1], frame_l, frame_rl[1], irdy_l, irdy_rl[1], trdy_l, trdy_rl[1], stop_l, stop_rl[1], lock_l, lock_rl[1], idsel[1], devsel_l, devsel_rl[1], ad, ad1, cbe_l, cbe1_l, par, par_r[1], perr_l, perr_rl[1], serr_l, serr_rl[1], req64_l, req64_rl[1], ack64_l, ack64_rl[1], par64, par64_r[1]); $scriptsim("../../pci/agent.py", ss_id2, "../../pci/pci_cmds2", clk, reset_l, req_l[2], gnt_l[2], frame_l, frame_rl[2], irdy_l, irdy_rl[2], trdy_l, trdy_rl[2], stop_l, stop_rl[2], lock_l, lock_rl[2], idsel[2], devsel_l, devsel_rl[2], ad, ad2, cbe_l, cbe2_l, par, par_r[2], perr_l, perr_rl[2], serr_l, serr_rl[2], req64_l, req64_rl[2], ack64_l, ack64_rl[2], par64, par64_r[2]); // here we mix in a 32-bit agent $scriptsim("../../pci/agent.py", ss_id3, "../../pci/pci_cmds3", clk, reset_l, req_l[3], gnt_l[3], frame_l, frame_rl[3], irdy_l, irdy_rl[3], trdy_l, trdy_rl[3], stop_l, stop_rl[3], lock_l, lock_rl[3], idsel[3], devsel_l, devsel_rl[3], ad32, ad3, cbe_l32, cbe3_l, par, par_r[3], perr_l, perr_rl[3], serr_l, serr_rl[3]); // here is the arbiter $scriptsim("../../pci/arb.py", clk, reset_l, req_l, gnt_l, frame_l, irdy_l); # 100000 reset_l <= 1'b1; // headers for the crude printed output $display(" r g f i t"); $display(" e n r r r"); $display(" time q t m d d"); end // block: main_block // simple clock generation always begin: clock_gen #half_clock_period clock <= 1'b1; #half_clock_period clock <= 1'b0; end // block: clock_gen // produce a very crude printed output - not very useful... always @(posedge clock) begin if (reset_l == 1'b1) begin $display("%t %h %h %h %h %h", $time, ~req_l, ~gnt_l, ~frame_l, ~irdy_l, ~trdy_l); end end // here we demonstrate a verilog scriptsim call to generate a PCI bus cycle initial begin: PCI_Do_Tranfer reg [31:0] data; reg [255:0] options, results; reg done; #1 // must wait until the scriptsim programs are running data = 32'h55667788; options = 256'b1; $scriptsim(ss_id2, PCI_MW, 'h300, 4, options, data, results, done); @(posedge done); // results should be checked here $scriptsim(ss_id2, PCI_MR, 'h300, 4, options, data, results, done); @(posedge done); // results should be checked here end // block: PCI_Initiate // Here we call a task to initiate the pci operations initial begin: Task_call reg [31:0] data; reg [255:0] options, results; #1 // must wait until the scriptsim programs are running data = 32'h11223344; options = 256'b1; pci_initiate_task(ss_id2, PCI_MW, 'h304, 4, options, data, results); // results should be checked here pci_initiate_task(ss_id2, PCI_MR, 'h304, 4, options, data, results); // results should be checked here end // block: Task_call initial begin: Stop_Sim $dumpvars; // create a VCD file for possible debug purposes //#1000000 $stop; #7000000 $finish; end // Here we demonstrate that tasks can make $scriptsim calls // BUT, since task variables are static, therefore shared, // **concurrent** calls to this task are not allowed, // and will result in a $scriptsim error message task pci_initiate_task; input id, command, address, bytes; input [255:0] options; inout [31:0] data; inout [255:0] results; integer id, command, address, bytes; reg done; begin $scriptsim(id, command, address, bytes, options, data, results, done); @(posedge done); end endtask endmodule // demo