// // QA Testbench for pci task calls // `timescale 1ps / 1ps module demo; parameter agents = 2; // 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; // must define for all 64-bit agents reg [31:0] ad1; // for 32-bit agent reg [7:0] cbe0_l; // must define for all agents reg [3:0] cbe1_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; assign ad = ad0; // must assign for all agents. assign ad[31:0] = ad1; assign ad32 = ad[31:0]; // for 32-bit agent assign cbe_l = cbe0_l; // must assign for all agents assign cbe_l[3:0] = cbe1_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", 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); // a 64-bit agent $scriptsim("../../pci/agent.py", ss_id0, "../pci_qa/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]); // a 32-bit agent $scriptsim("../../pci/agent.py", ss_id1, "../pci_qa/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], ad32, ad1, cbe_l32, cbe1_l, par, par_r[1], perr_l, perr_rl[1], serr_l, serr_rl[1]); // 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 call a task to initiate the pci operations initial begin: Task_call #1; // must wait until the scriptsim programs are running // perform the tests with all combinations of 64-bit and 32-bit // masters and targets fork begin // ss_id* is which PCI agent should execute the commands // the 2nd parameter is an offset address, which determines the target test_writes(ss_id0, 0); test_writes(ss_id0, 'h10000); test_writes(ss_id1, 'h100); test_writes(ss_id1, 'h10100); end join end // Task_call // ss_id* is which PCI agent should execute the commands // the 2nd parameter is an offset address, which determines the target task test_writes; input id, base_adr; integer id, base_adr; integer adr, i; reg [31:0] data32; reg [63:0] data64; reg [127:0] data128; reg [135:0] data136; reg [255:0] options, results; reg done; begin options = 256'b1; // 1 byte write to various addresses: adr = 'h304 + base_adr; data32 = 32'h04; $scriptsim(id, PCI_MW, adr, 1, 256'b1, data32, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end adr = 32'h305 + base_adr; data32 = 32'h05; $scriptsim(id, PCI_MW, adr, 1, 256'b1, data32, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end adr = 32'h306 + base_adr; data32 = 32'h06; $scriptsim(id, PCI_MW, adr, 1, 256'b1, data32, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end adr = 32'h307 + base_adr; data32 = 32'h07; $scriptsim(id, PCI_MW, adr, 1, 256'b1, data32, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end // 2 byte transfer on even boundary adr = 32'h308 + base_adr; data32 = 32'hffff0908; $scriptsim(id, PCI_MW, adr, 2, 256'b1, data32, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end // 2 byte transfer on odd boundary adr = 32'h30b + base_adr; data32 = 32'hffff0c0b; $scriptsim(id, PCI_MW, adr, 2, 256'b1, data32, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end // 4 byte transfer on even boundary adr = 32'h310 + base_adr; data32 = 32'h13121110; $scriptsim(id, PCI_MW, adr, 4, 256'b1, data32, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end // 4 byte transfer on odd boundary adr = 32'h315 + base_adr; data32 = 32'h18171615; $scriptsim(id, PCI_MW, adr, 4, 256'b1, data32, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end // 4 byte transfer on odd boundary adr = 32'h31b + base_adr; data32 = 32'h1e1d1c1b; $scriptsim(id, PCI_MW, adr, 4, 256'b1, data32, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end // 8 byte transfer on even boundary adr = 32'h320 + base_adr; data64 = 64'h2726252423222120; $scriptsim(id, PCI_MW, adr, 0, 256'b1, data64, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end // 8 byte transfer on odd boundary adr = 32'h329 + base_adr; data64 = 64'h302f2e2d2c2b2a29; $scriptsim(id, PCI_MW, adr, 0, 256'b1, data64, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end // 8 byte transfer on odd boundary adr = 32'h337 + base_adr; data64 = 64'h3e3d3c3b3a393837; $scriptsim(id, PCI_MW, adr, 0, 256'b1, data64, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end // 16 byte transfer on even boundary to pci64 device adr = 32'h340 + base_adr; data128 = 128'h4f4e4d4c4b4a49484746454443424140; $scriptsim(id, PCI_MW, adr, 0, 256'b1, data128, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end // 17 byte transfer on even boundary adr = 32'h350 + base_adr; data136 = 136'h605f5e5d5c5b5a59585756555453525150; $scriptsim(id, PCI_MW, adr, 0, 256'b1, data136, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MW, adr, results); end // read back data to check adr = 32'h300 + base_adr; //data32 = 32'h07060504; $scriptsim(id, PCI_MR, adr, 0, 256'b1, 512'h003e3d3c3b3a393837000000000000302f2e2d2c2b2a29002726252423222120001e1d1c1b00001817161500131211100000000c0b0009080706050400000000, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MR, adr, results); end // read back data to check adr = 32'h340 + base_adr; //data32 = 32'h07060504; $scriptsim(id, PCI_MR, adr, 0, 256'b1, 272'h00605f5e5d5c5b5a595857565554535251504f4e4d4c4b4a49484746454443424140, results, done); @(posedge done) if (results & 256'b1) begin error_msg(PCI_MR, adr, results); end end endtask // test_writes initial begin: Stop_Sim $dumpvars; // create a VCD file for possible debug purposes //#1000000 $stop; #10000000 $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 // NOT USED AT THE MOMENT task pci_initiate_task0; input id, command; input [31:0] address; input bytes; input [255:0] options; inout [31:0] data; inout [255:0] results; integer id, command, bytes; reg done; begin $scriptsim(id, command, address, bytes, options, data, results, done); @(posedge done); end endtask // simply display a basic error message // will be enhanced later to describe the error in more detail task error_msg; input command; input [31:0] address; input [255:0] results; integer command; begin $display("%t Error: Cmd=%0h Adr=%0h Result=%0h", $time, command, address, results); end endtask endmodule // demo