System Verilog Basics

download System Verilog Basics

of 82

description

System Verilog Basics

Transcript of System Verilog Basics

  • SystemVerilog basicsJean-Michel Chabloz

  • How we study SystemVerilogHuge language:last LRM has 1315 pagesNot possible to cover everything, we cover maybe 5% of the constructsYou can succeed in the course using only the subset of the language that is treated in these slidesIf you want you are free to use other constructs, research them by yourself

  • SystemVerilog Hello Worldmodule M(); initial $display(Hello world); endmodule

  • SystemVerilog simple programmodule M(); logic a,b; logic [7:0] c; assign b = ~a;

    initial begin a

  • SystemVerilog syntaxCase sensitiveC-style comments: // or /*comment*/Code blocks delimited by begin end. If a single-line, can be omitted

  • ModulesLets start to consider systems without hierarchy (no submodules)A module contains objects declarations and concurrent processes that operate in parallel.Initial blocksAlways blocksContinuous assignments(instantiations of submodules)

  • SystemVerilog basic data typesData types:logic 4 valued data type:0, 1, X, Zinitialized to Xcan also be called reg // deprecated verilog legacy namebit 2 valued data type:0, 1initialized to 0Defining a data type:bit a;logic b;bit c, d;

  • Packed arrays of logic and bitsbit [5:0] a;logic [2:0] b;logic [0:2047] [7:0] c; //array of 2048 bytesinteger: equivalent to logic [31:0]int, byte: equivalents to bit [31:0] and bit [7:0]arrays of bits and logics default to unsigned, can be overriden with the keyword signedex: bit signed [7:0] a;

  • LiteralsDecimal literal:a
  • Packed array accessSingle element access:bit [7:0] aa[5]
  • packed structuresequivalent to a packed array subdivided into named fields:example: 48 bit packed array

    can be accessed as pack1[15:0]

  • Other data typesEnumerated data type:enum bit [1:0] {idle, writing, reading} stateIf skipping the type an int type is assumedCan be typedeffed (like all other data types):typedef enum {red, green, blue, yellow, white, black} Colors;Colors [2:0] setOfColors; // array of 3 elements of type colors

  • Types in SVSystemVerilog is a weakly-typed languageadvantages: simpler and shorter codedisadvantages: easy to do mistakesMany assignment-compatible typesa bit and a logic are assignment-compatible, we can assign one to the othera longer array can be assigned to a shorter one or viceversa (truncation or extension will happen automatically)arrays can be indexed by logic arrays, bit arraysa packed struct has the same properties as an arraystruct packed {bit[3:0] a, b;} can be assigned a bit array, a logic array, etc.ifs, whiles, etc. can take as condition bits, logic, arrays, etc.non-zero values count as TRUE, all-zero values count as falseif a is a bit or logic, then we can write if (a==1) or if (a), they do the same thing

  • ProcessesModules contain processes (initial, always) code inside processes is called procedural codeInitial: executed only once, at the beginning of the simulation

    initial begin #10ns; a

  • ProcessesAlways - no sensitivity list: triggers as soon as it finishes executing

    always begin #10ns; a

  • ProcessesAlways - with sensitivity list: triggers when it has finished executing and one of the events in the sensitivity list happens

    always @(posedge b, negedge c) begin #10ns; a

  • Always block, combinational processThe sensitivity list must contain all elements in the right-hand side always @(a,b) begin c
  • Always block, flip-flopD flip-flop with async reset:

    Possible to specify always_ff to declare intentwe declare to the compiler we want to do a FF (in the sense of edge-triggered logic, can also be an FSM), if it is not an FF we get an error

    always @(posedge clk, negedge rst) begin if (rst==0) q

  • Procedural codeif (a==1) begin //codeendwhile (a==1) begin //codeendforever begin // loops forever //codeendfor (i=0; i
  • if treesif (condition) begin endelse begin end

  • if treesif (condition1) begin endelse if (condition2) begin endelse if (condition3) begin endelse begin end

    No elsif construct, but this is equivalent

  • Bitwise logic operatorsBitwise logic operators return a number of bits equal to the length of the inputs:&: and| : or^ : xor~ : notNegate one bit/logic array:a
  • logic operatorslogic operators return one bit only, treat as one everything that is non-zero:&&: and| |: or! : notfor one-bit elements if (!a) is equal to if (~a)for a 4-bit elements, if a=1100if(!a) will not execute (!a returns 0)if(~a) will execute (~a returns 0011 which is not all-zeros)

  • comparisonsequality: == diseguality: !=greather than: >lower than: =lower or equal than:
  • arithmetic+ and can be used with logic arrays, bit arrays, automatically wrap around:up counter:.111011111011111000000000100010.

  • Timing Control in Processes#10ns: waits for 10 ns#10: wait for 10 time units time unit specified during elaboration or with a `timescale directive in the code#(a): wait for a number of time units equal to the value of variable a#(a*1ps): wait for a number of picoseconds equal to the value of a

    @(posedge a): waits for the positive edge of a@(b): wait until b toggles

    wait(expr): waits until expr is truewait(b): wait until b is one

    Timing checks can be bundled with the next instr: #10ns a

  • fork joinSpawn concurrent processes from a single process: A is printed at 30ns; B at 20ns; join waits until both subprocesses have finished, the last display takes place at 40ns

    initial begin #10ns; fork begin #20ns; $display( A\n" ); end begin #10ns; $display( B\n" ); #20ns; end join $display(both finished);end

  • Procedural assignmentsNon-blocking assignment
  • Procedural assignmentsblocking assignments correspond to the VHDL variable assignment :=non-blocking assignments correspond to the VHDL signals assignment
  • Procedural assignmentsalways @(posedge clk) begin a
  • Procedural assignmentsinitial begin a = 1; $display(a);endinitial begin a
  • Default assignmentsdefault values to avoid latches and to avoid writing long if else treesworks like in VHDL (the last write is kept)

    always_comb a

  • Console/control commandsintroduced with the $ keyword$display used to display information to the consoleex:$display(hello); // displays hello$display(a); // displays the value of a, depending on its data type$stop(), $finish(): stop (break) and finish (terminate) the simulation

  • Direct generation of random numbers$urandom returns a 32-bit random unsigned number every time it is calledCan be automatically assigned to shorter values, automatic clipping will take place:bit a; a
  • Direct generation of random numbers$urandom_range(10,0) returns a random number between 10 and 0Note: if not seeded, every time the testbench is run we get the same valuesthis behavior is required for being able to repeat tests

  • Event-driven simulationThe simulator executes in a random order any of the operations scheduled for a given timestep.It continues until the event queue for the timestep is empty, then advances time to the next non-empty timestamp

    This might create race conditions:What happens is not defined by the rules of SystemVerilogNo error is signaledThe behavior of the system might be simulator-dependent or even change from run to run

  • Race conditioninitial begin #10ns; a = 1;end

    initial begin #10 ns; a = 0;end

    initial begin #20 ns; $display(a);end

  • Race conditioninitial begin #10ns; a
  • Race conditioninitial begin #10ns; a
  • Race conditioninitial begin #10ns; a = 1; a = 0;end

    initial begin #20 ns; $display(a);end

  • Race conditionsHappen when two different processes try to write the same signal during the same time stepWays to avoid:dont write the same signal in different processes, unless you really know what you do (you know that the two processes will never write the signal in the same time step)

  • Continuous assignmentscontinuously performs an assignmentoutside procedural codeex: assign a = b+c;Note: module input/output ports count as continuous assignmentscan be done on variables or netsnets can be driven by multiple continuous assignments, variables no

  • Variables vs NetsVariables:Are defined as: var type nameExample: var logic a (logic is default, can be omitted)The keyword var is the default, it can be omittedSo when we define something likelogic a;bit [7:0] b;we are actually defining variables

  • Variables vs NetsVariables can be assigned:in a procedural assignment (blocking or non-blocking assignment inside an initial or always process)By a single continuous assignment

  • How variables workinitial #10ns a
  • Variables vs NetsNets:Different types: wire, wand, wor, etc. We consider only wireAre defined as: wire type nameExamples: wire logic a, wire logic [2:0] clogic is the default and can be omittedA wire cannot be a 2-valued data typeA net can be assigned only by one or more continuous assignments, cannot be assigned into procedural code

  • Variables vs NetsSo there is only one thing in SV that nets can do and that variables cannot: be driven by multiple continuous assignmentsNets should be used when modeling tri-state buffers and busesThe value is determined by a resolution function

  • Objects scopeobjects declared inside modules/programs:local to that module/programobjects declared inside blocks (ifs, loops, etc.) between a begin and an end:local to that block of code

  • SubroutinesFunctions: return a value, cannot consume timeTasks: no return, can consume time

  • Functionsinput/ouput/inout ports (inouts are read at the beginning and written at the end)the keyword input is the default, no need to specify it.cannot consume timea function can return void (no return value)It is allowed to have non-blocking assignments, writes to clocking drivers and other constructs that schedule assignments for the future but dont delay the function execution

    function logic myfunc3(input int a, output int b); b = a + 1; return (a==1000);endfunction

  • Taskstask light (output color, input [31:0] tics); repeat (tics) @ (posedge clock); color = off; // turn light off.endtask: light

    Tasks can consume time, they do not return values

  • Packagestype definitions, functions, etc. can be defined in packages

    package ComplexPkg; typedef struct { shortreal i, r; } Complex; function Complex add(Complex a, b); add.r = a.r + b.r; add.i = a.i + b.i; endfunction function Complex mul(Complex a, b); mul.r = (a.r * b.r) - (a.i * b.i); mul.i = (a.r * b.i) + (a.i * b.r); endfunctionendpackage

  • PackagesStuff that is in package can be called as:c
  • Unpacked arraysbit a [5:0];Arrays can have multiple unpacked dimensions or can even mix packed and unpacked dimensions:logic [7:0] c [0:2047]; // array of 2048 bytesUnpacked dimensions cannot be sliced, only single elements can be accessedThey do not reside in memory in contiguous locations they can be bigger than a packed array because of this reason

  • dynamic arraysarrays with an unpacked dimension that is not specified in the code:logic [7:0] b [];Can only be used after having been initialized with the keyword newb = new[100];Can be resized with: b = new[200](b);After having been initialized it can be used like any other array with unpacked dimension

  • associative arraysassociative array of bytes:declared as logic [7:0] a [*];Acts exactly as a vector of 2^32 bytes:a[4102345432]
  • queueslogic [7:0] q[$];Supports all operations that can be done on unpacked arraysq.push_front(a); // pushes element to the frontq.push_back(a); // pushes element to the backb=q.pop_back(); // pops element from backb=q.pop_front(); // pops element from frontq.insert(3,a) // inserts element at position 3q.delete(3) // deletes the third elementq.delete() // delete all the queueq.size() // returns size of queue

  • queuesCan also be accessed using slicing and $:q = { q, 6 }; // q.push_back(6)q = { e, q }; // q.push_front(e)q = q[1:$]; // q.pop_front() or q.delete(0)q = q[0:$-1]; // q.pop_back() or q.delete(q.size-1)q = { q[0:pos-1], e, q[pos:$] }; // q.insert(pos, e)q = { q[0:pos], e, q[pos+1:$] }; // q.insert(pos+1, e)q = {}; // q.delete()

  • StructureHierarchy is encapsulated and hidden in modules module dut ( output bit c, input bit [7:0] a, input bit [7:0] b);

    // module code (processes, continuos assignments, instantiations of submodules)endmodule

    There exists legacy verilog port declaration methods

  • StructureVerilog legacy port declarations

    module test(a,b,c);input logic [7:0] a;input b; //unspecified type: logicoutput bit [7:0] c;endmodule

  • StructureModule declaration with ports

    module simple_fifo ( input bit clk, input bit rst, input bit [7:0] a, output bit [7:0] b);

    // module code (processes, continuous assignments, instantiations of submodules)

    endmodule

  • StructureModule instantiation in a top-level testbench module tb (); // top-level testbench has no inputs/outputs bit clk, reset; bit [7:0] av, bv;

    simple_fifo dut(.clk(clk), // module instantiation .rst(reset), .b(bv), .a(av));

    always #5ns clk

  • Module instantiationModule instantiation in a top-level testbenchPorts can be named out of order module tb (); bit clk, reset; bit [7:0] av, bv;

    simple_fifo dut(.clk(clk), // module instantiation .rst(reset), .a(av), .b(bv));

    always #5ns clk

  • Module InstantiationIf signals have the same names in the including and the included modules we can use the syntax (.*) for port connection.

    module tb (); bit clk, rst; bit [7:0] a, b;

    simple_fifo dut(.*); // a->a; b->b; clk->clk; rst-> rst

    always #5ns clk

  • Module Instantiationpositional connection, each signal is connected to the port in the same position easy to make errors

    module tb (); // top-level testbench has no inputs/outputs bit clk, reset; bit [7:0] av, bv;

    simple_fifo dut(clk,reset,av,bv);

    always #5ns clk

  • Module instantiation module tb (); bit clk, reset; bit [7:0] av, bv;

    simple_fifo dut(.*, // ports are connected to signals with the same name .a(av), // except the ones named later .b()); // b is left open

    always #5ns clk

  • Parametersused to express configurabilitymodule tb (); // top-level testbench has no inputs/outputs bit clk, rst; bit [7:0] a, b;

    simple_fifo #( .DEPTH(64), .WIDTH(8)) dut ( .clk(clk), .rst(rst), .a(a), .b(b));

    endmodulemodule #( parameter DEPTH=64, parameter WIDTH=8 ) simple_fifo ( input logic clk, input logic rst, input logic [WIDTH-1:0] a, output logic [WIDTH-1:0] b );

    localparam internal_param_name;

    endmodule

  • Parametersused to express configurabilitymodule tb (); // top-level testbench has no inputs/outputs bit clk, rst; bit [7:0] a, b;

    simple_fifo #( .DEPTH(64), .WIDTH(8)) dut ( .clk(clk), .rst(rst), .a(a), .b(b));

    endmodulemodule #( parameter DEPTH=64, parameter WIDTH=8 ) simple_fifo ( input logic clk, input logic rst, input logic [WIDTH-1:0] a, output logic [WIDTH-1:0] b );

    localparam internal_param_name;

    endmodule

  • ParametersPositional instantiationmodule tb (); // top-level testbench has no inputs/outputs bit clk, rst; bit [7:0] a, b;

    simple_fifo #(64,8) dut ( .clk(clk), .rst(rst), .a(a), .b(b));

    endmodulemodule #( parameter DEPTH=64, parameter WIDTH=8 ) simple_fifo ( input logic clk, input logic rst, input logic [WIDTH-1:0] a, output logic [WIDTH-1:0] b );

    localparam internal_param_name;

    endmodule

  • ParametersOther notationmodule tb (); // top-level testbench has no inputs/outputs bit clk, rst; bit [7:0] a, b;

    simple_fifo #( .DEPTH(64), .WIDTH(8)) dut ( .clk(clk), .rst(rst), .a(a), .b(b));

    endmodulemodule simple_fifo ( input logic clk, input logic rst, input logic [WIDTH-1:0] a, output logic [WIDTH-1:0] b );parameter DEPTH=64parameter WIDTH=8localparam internal_param_name;endmodule

  • ParametersIf not overwritten, they keep their default valueCan have a type:parameter logic [7:0] DEPTH = 64;localparam: like parameters, but cannot be modified hierarchically during the instantiationUsed to indicate a parameter that there is not any sense for it to be modified by some higher block in the hierarchy

  • Hierarchical accessFrom anywhere, it is possible to access any object in the hierarchy by accessing through its full path starting from the top module name:

    a

  • SystemVerilog ProgramsPrograms are and look like modules, but:They cannot contain always blocksThey cannot include modulesSimulation finishes automatically when all initial have been completedAlways blocks are the basic building block of RTL code, not needed by the testbenchesPrograms can do everything that is needed for verification

  • Clocking blockdefault clocking ck1 @(posedge clk); default input #1ns output #1ns; // reading and writing skew input a; // a, b, objects visible from this scope output b; // input: can read; output: can write output negedge rst; // overwrite the default skew to the negedge // of the clock inout c; // inout: can both read and write input d = top.dut.internal_dut_signal_name;endclocking

    Inside a module/program, we access signals for read/write inside processes in this way:ck1.a

  • Clocking blockThe clocking block makes the timing relation (positive-edge of the clock or other explicit)Since we only verify synchronous systems with a single clock, we need a single clocking blockWe add only one and specify it as defaultIt gives a input and output skew to read/write to the signalsThe input/output skew can also be omitted

  • Clocking blocks and programsThe rules of SV say that if we access signals from a program through a clocking block, there will be no race condition between testbench and DUTEven if no timing skew is specifiedWhen there is a default clocking block in a program/module we can use the ##n timing construct: wait n cycles as specified by the default clocking blockexamples:##3; // wait 3 cycles##(2*a); //wait a number of cycles equal to the double of the value of variable ainitial begin##3 reset
  • generateUsed to generate processes and continuous assignmentsNo need of generate endgenerate statementsDefine a variable of type genvarWe can then do a generate using a loop or if with with the genvar

    Example:genvar i;

    initial ##20 b

  • named blocksafter every begin there can be an optional nameAllows hierarchical access to local variables and to find the variables in the simulator window

    ex:initial begin : inputController if (a==10) begin : terminationHandler

    endend

  • Good Testbench StructureWrite all your testbenches in this wayThe testbench program must use access all DUT signals in read and write through the default clocking blockOnly timing construct allowed in the testbench program: ##

    top modulegeneration of clocktestbenchprogram

    driveDUT inputs,

    checkDUT outputsDUTclk

  • Good Testbench StructureAlternative: several programs are allowedall use clocking block in links to the DUT

    top modulegeneration of clocktestbenchprogram

    drive inputsDUTclktestbenchprogram

    check outputs

  • Good testbench structureYou can use any structure you like, everything is allowedThe one below is more UVM-liketop modulegeneration of clocktestbenchprogramdrive some inputsDUTclktestbenchprogramcollect outputstranslate them intoa higher levelmodeltestbenchprogramdrive other inputsprogramcheck outputs

  • Good testbench structureYou can use multiple programs, but given the size of the testbenches used in this course, one program that does everything is a good choiceAll inputs/outputs to the DUT through the default clocking blockOnly timing construct allowed: ## (no need for other levels of granularity)Try to keep separated the different functions (input generation, output checking) using several initial blocks