diff --git a/sv-parser/Cargo.toml b/sv-parser/Cargo.toml index 07c16ce..398d668 100644 --- a/sv-parser/Cargo.toml +++ b/sv-parser/Cargo.toml @@ -23,3 +23,8 @@ sv-parser-syntaxtree = {version = "0.1.0", path = "../sv-parser-syntaxtree"} [dev-dependencies] structopt = "0.3.2" +criterion = "0.3" + +[[bench]] +name = "parse_sv" +harness = false diff --git a/sv-parser/benches/parse_sv.rs b/sv-parser/benches/parse_sv.rs new file mode 100644 index 0000000..f15fd2f --- /dev/null +++ b/sv-parser/benches/parse_sv.rs @@ -0,0 +1,52 @@ +use criterion::{criterion_group, criterion_main, Criterion, Throughput}; +use std::collections::HashMap; +use std::path::{Path, PathBuf}; +use std::time::Duration; +use std::{env, fs}; +use sv_parser::parse_sv; + +fn get_path(s: &str) -> PathBuf { + PathBuf::from(format!( + "{}/testcases/{}", + env::var("CARGO_MANIFEST_DIR").unwrap(), + s + )) +} + +fn get_size(p: &Path) -> u64 { + let metadata = fs::metadata(p).unwrap(); + metadata.len() +} + +fn gen_benchmark_group(c: &mut Criterion, s: &str) { + let defines = HashMap::new(); + let includes: Vec = Vec::new(); + let path = get_path(s); + let size = get_size(&path); + let mut group = c.benchmark_group(s); + group.throughput(Throughput::Bytes(size)); + group.bench_function(s, |b| { + b.iter_with_large_drop(|| parse_sv(&path, &defines, &includes)) + }); + group.finish(); +} + +fn config() -> Criterion { + Criterion::default() + .sample_size(30) + .measurement_time(Duration::new(30, 0)) + //Criterion::default().measurement_time(Duration::new(90, 0)) +} + +fn criterion_benchmark(c: &mut Criterion) { + gen_benchmark_group(c, "test1.sv"); + gen_benchmark_group(c, "test2.sv"); +} + +criterion_group! { + name = benches; + config = config(); + targets = criterion_benchmark +} + +criterion_main!(benches); diff --git a/sv-parser/testcases/test1.sv b/sv-parser/testcases/test1.sv new file mode 100644 index 0000000..af662c9 --- /dev/null +++ b/sv-parser/testcases/test1.sv @@ -0,0 +1,64 @@ +module dimm(addr, ba, rasx, casx, csx, wex, cke, clk, dqm, data, dev_id); + parameter [31:0] MEM_WIDTH = 16, MEM_SIZE = 8; // in mbytes + input [10:0] addr; + input ba, rasx, casx, csx, wex, cke, clk; + input [ 7:0] dqm; + inout [63:0] data; + input [ 4:0] dev_id; + genvar i; + + case ({MEM_SIZE, MEM_WIDTH}) + {32'd8, 32'd16}: // 8Meg x 16 bits wide + begin: memory + for (i=0; i<4; i=i+1) begin:word16 + sms_08b216t0 p(.clk(clk), .csb(csx), .cke(cke),.ba(ba), + .addr(addr), .rasb(rasx), .casb(casx), + .web(wex), .udqm(dqm[2*i+1]), .ldqm(dqm[2*i]), + .dqi(data[15+16*i:16*i]), .dev_id(dev_id)); + // The hierarchical instance names are: + // memory.word16[3].p, memory.word16[2].p, + // memory.word16[1].p, memory.word16[0].p, + // and the task memory.read_mem + end + task read_mem; + input [31:0] address; + output [63:0] data; + begin // call read_mem in sms module + word16[3].p.read_mem(address, data[63:48]); + word16[2].p.read_mem(address, data[47:32]); + word16[1].p.read_mem(address, data[31:16]); + word16[0].p.read_mem(address, data[15: 0]); + end + endtask + end + {32'd16, 32'd8}: // 16Meg x 8 bits wide + begin: memory + for (i=0; i<8; i=i+1) begin:word8 + sms_16b208t0 p(.clk(clk), .csb(csx), .cke(cke),.ba(ba), + .addr(addr), .rasb(rasx), .casb(casx), + .web(wex), .dqm(dqm[i]), + .dqi(data[7+8*i:8*i]), .dev_id(dev_id)); + // The hierarchical instance names are + // memory.word8[7].p, memory.word8[6].p, + // ... + // memory.word8[1].p, memory.word8[0].p, + // and the task memory.read_mem + end + task read_mem; + input [31:0] address; + output [63:0] data; + begin // call read_mem in sms module + word8[7].p.read_mem(address, data[63:56]); + word8[6].p.read_mem(address, data[55:48]); + word8[5].p.read_mem(address, data[47:40]); + word8[4].p.read_mem(address, data[39:32]); + word8[3].p.read_mem(address, data[31:24]); + word8[2].p.read_mem(address, data[23:16]); + word8[1].p.read_mem(address, data[15: 8]); + word8[0].p.read_mem(address, data[ 7: 0]); + end + endtask + end + // Other memory cases ... + endcase +endmodule diff --git a/sv-parser/testcases/test2.sv b/sv-parser/testcases/test2.sv new file mode 100644 index 0000000..fab9c6f --- /dev/null +++ b/sv-parser/testcases/test2.sv @@ -0,0 +1,104 @@ +interface simple_bus (input logic clk); // Define the interface + logic req, gnt; + logic [7:0] addr, data; + logic [1:0] mode; + logic start, rdy; + int slaves = 0; + + // tasks executed concurrently as a fork-join block + extern forkjoin task countSlaves(); + extern forkjoin task Read (input logic [7:0] raddr); + extern forkjoin task Write (input logic [7:0] waddr); + + modport slave (input req,addr, mode, start, clk, + output gnt, rdy, + ref data, slaves, + export Read, Write, countSlaves); + // export from module that uses the modport + + modport master ( input gnt, rdy, clk, + output req, addr, mode, start, + ref data, + import task Read(input logic [7:0] raddr), + task Write(input logic [7:0] waddr)); + // import requires the full task prototype + + initial begin + slaves = 0; + countSlaves; + $display ("number of slaves = %d", slaves); + end +endinterface: simple_bus + +module memMod #(parameter int minaddr=0, maxaddr=0) (interface a); + logic avail = 1; + logic [7:0] mem[255:0]; + + task a.countSlaves(); + a.slaves++; + endtask + + task a.Read(input logic [7:0] raddr); // Read method + if (raddr >= minaddr && raddr <= maxaddr) begin + avail = 0; + #10 a.data = mem[raddr]; + avail = 1; + end + endtask + + task a.Write(input logic [7:0] waddr); // Write method + if (waddr >= minaddr && waddr <= maxaddr) begin + avail = 0; + #10 mem[waddr] = a.data; + avail = 1; + end + endtask +endmodule + +module cpuMod(interface b); + typedef enum {read, write} instr; + instr inst; + logic [7:0] raddr; + integer seed; + + always @(posedge b.clk) begin + inst = instr'($dist_uniform(seed, 0, 1)); + raddr = $dist_uniform(seed, 0, 3); + if (inst == read) begin + $display("%t begin read %h @ %h", $time, b.data, raddr); + callr:b.Read(raddr); + $display("%t end read %h @ %h", $time, b.data, raddr); + end + else begin + $display("%t begin write %h @ %h", $time, b.data, raddr); + b.data = raddr; + callw:b.Write(raddr); + $display("%t end write %h @ %h", $time, b.data, raddr); + end + end +endmodule + +module top; + logic clk = 0; + + function void interrupt(); + disable mem1.a.Read; // task via module instance + disable sb_intf.Write; // task via interface instance + if (mem1.avail == 0) $display ("mem1 was interrupted"); + if (mem2.avail == 0) $display ("mem2 was interrupted"); + endfunction + + always #5 clk++; + + initial begin + #28 interrupt(); + #10 interrupt(); + #100 $finish; + end + + simple_bus sb_intf(clk); + + memMod #(0, 127) mem1(sb_intf.slave); + memMod #(128, 255) mem2(sb_intf.slave); + cpuMod cpu(sb_intf.master); +endmodule