system verilog lecture

Upload: khanhle

Post on 09-Oct-2015

59 views

Category:

Documents


6 download

DESCRIPTION

This lecture helps to understand the system verilog language

TRANSCRIPT

  • SystemVerilog basics

    Jean-Michel Chabloz

  • How we study SystemVerilog

    Huge language: last LRM has 1315 pages Not possible to cover everything, we cover

    maybe 5% of the constructs You can succeed in the course using only the

    subset of the language that is treated in these slides

    If 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 syntax

    Case sensitive C-style comments: // or /*comment*/ Code blocks delimited by begin end. If

    a single-line, can be omitted

  • Modules

    Lets start to consider systems without hierarchy (no submodules)

    A module contains objects declarations and concurrent processes that operate in parallel. Initial blocks Always blocks Continuous assignments (instantiations of submodules)

  • SystemVerilog basic data types Data types:

    logic 4 valued data type: 0, 1, X, Z initialized to X can also be called reg // deprecated verilog legacy name

    bit 2 valued data type: 0, 1 initialized to 0

    Defining a data type: bit a; logic b; bit c, d;

  • Packed arrays of logic and bits bit [5:0] a; logic [2:0] b; logic [0:2047] [7:0] c; //array of 2048 bytes integer: 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 signed ex: bit signed [7:0] a;

  • Literals Decimal literal:

    a

  • Packed array access Single element access:

    bit [7:0] a a[5]

  • packed structures equivalent to a packed array subdivided into named

    fields: example: 48 bit packed array

    can be accessed as pack1[15:0]

  • Other data types

    Enumerated data type: enum bit [1:0] {idle, writing, reading} state If skipping the type an int type is assumed Can 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 SV SystemVerilog is a weakly-typed language

    advantages: simpler and shorter code disadvantages: easy to do mistakes

    Many assignment-compatible types a bit and a logic are assignment-compatible, we can assign one

    to the other a 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 arrays a packed struct has the same properties as an array

    struct 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 false if a is a bit or logic, then we can write if (a==1) or if (a), they do

    the same thing

  • Processes Modules contain processes (initial, always)

    code inside processes is called procedural code Initial: executed only once, at the beginning of the

    simulation

    initial begin #10ns; a

  • Processes Always - no sensitivity list: triggers as soon as

    it finishes executing

    always begin #10ns; a

  • Processes Always - 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 process

    The sensitivity list must contain all elements in the right-hand side

    always @(a,b) begin c

  • Always block, flip-flop D flip-flop with async reset:

    Possible to specify always_ff to declare intent we 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 code

    if (a==1) begin //codeend

    while (a==1) begin //codeend

    forever begin // loops forever //codeend

    for (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 operators Bitwise logic operators return a number of bits

    equal to the length of the inputs: &: and | : or ^ : xor ~ : not

    Negate one bit/logic array: a

  • logic operators logic operators return one bit only, treat as one

    everything that is non-zero: &&: and | |: or ! : not

    for one-bit elements if (!a) is equal to if (~a) for a 4-bit elements, if a=1100

    if(!a) will not execute (!a returns 0) if(~a) will execute (~a returns 0011 which is not all-

    zeros)

  • comparisons

    equality: == diseguality: != greather than: > lower than: < greater or equal than: >= lower or equal than:

  • arithmetic + and can be used with logic arrays, bit arrays,

    automatically wrap around: up counter:

    . 11101 11110 11111 00000 00001 00010 .

  • 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 true wait(b): wait until b is one

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

  • fork join Spawn 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 assignments

    Non-blocking assignment

  • Procedural assignments blocking assignments correspond to the VHDL

    variable assignment := non-blocking assignments correspond to the

    VHDL signals assignment

  • Procedural assignments

    always @(posedge clk) begin a

  • Procedural assignments

    initial begin a = 1; $display(a);end

    initial begin a

  • Default assignments default values to avoid latches and to avoid writing long if

    else trees works like in VHDL (the last write is kept)

    always_comb a

  • Console/control commands

    introduced with the $ keyword $display used to display information to the

    console ex:

    $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 called

    Can 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 0

    Note: if not seeded, every time the testbench is run we get the same values this behavior is required for being able to

    repeat tests

  • Event-driven simulation The 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

    SystemVerilog No error is signaled The 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 conditions

    Happen when two different processes try to write the same signal during the same time step

    Ways 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 assignments

    continuously performs an assignment outside procedural code ex: assign a = b+c; Note: module input/output ports count as

    continuous assignments can be done on variables or nets nets can be driven by multiple continuous

    assignments, variables no

  • Variables vs Nets Variables:

    Are defined as: var type name Example: var logic a (logic is default, can be

    omitted) The keyword var is the default, it can be

    omitted So when we define something like

    logic a; bit [7:0] b;

    we are actually defining variables

  • Variables vs Nets

    Variables 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 Nets Nets:

    Different types: wire, wand, wor, etc. We consider only wire

    Are defined as: wire type name Examples: wire logic a, wire logic [2:0] c logic is the default and can be omitted A wire cannot be a 2-valued data type

    A net can be assigned only by one or more continuous assignments, cannot be assigned into procedural code

  • Variables vs Nets So there is only one thing

    in SV that nets can do and that variables cannot: be driven by multiple continuous assignments

    Nets should be used when modeling tri-state buffers and buses

    The value is determined by a resolution function

    0 1 X Z

    0 0 X X 0

    1 X 1 X 1

    X X X X X

    Z 0 1 X Z

  • Objects scope

    objects declared inside modules/programs: local to that module/program

    objects declared inside blocks (ifs, loops, etc.) between a begin and an end: local to that block of code

  • Subroutines

    Functions: return a value, cannot consume time

    Tasks: no return, can consume time

  • Functions input/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 time a 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

  • Packages type 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

  • Packages Stuff that is in package can be called as:

    c

  • Unpacked arrays bit 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 bytes Unpacked dimensions cannot be sliced, only

    single elements can be accessed They do not reside in memory in contiguous

    locations they can be bigger than a packed array because of this reason

  • dynamic arrays arrays 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 new b = 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 arrays associative array of bytes:

    declared as logic [7:0] a [*]; Acts exactly as a vector of 2^32 bytes:

    a[4102345432]

  • queues logic [7:0] q[$];

    Supports all operations that can be done on unpacked arrays

    q.push_front(a); // pushes element to the front q.push_back(a); // pushes element to the back b=q.pop_back(); // pops element from back b=q.pop_front(); // pops element from front q.insert(3,a) // inserts element at position 3 q.delete(3) // deletes the third element q.delete() // delete all the queue q.size() // returns size of queue

  • queues

    Can 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()

  • Structure Hierarchy 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

  • Structure

    Verilog legacy port declarations

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

  • Structure Module 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

  • Structure Module 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 instantiation Module instantiation in a top-level testbench Ports 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 Instantiation If 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 Instantiation positional 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

  • Parameters

    used 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));

    endmodule

    module #( 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

  • Parameters

    used 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));

    endmodule

    module #( 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

  • Parameters

    Positional 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));

    endmodule

    module #( 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

  • Parameters

    Other 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));

    endmodule

    module 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

  • Parameters If not overwritten, they keep their default value Can have a type:

    parameter logic [7:0] DEPTH = 64; localparam: like parameters, but cannot be

    modified hierarchically during the instantiation Used to indicate a parameter that there is not

    any sense for it to be modified by some higher block in the hierarchy

  • Hierarchical access From 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 Programs Programs are and look like modules, but:

    They cannot contain always blocks They cannot include modules Simulation finishes automatically when all

    initial have been completed Always blocks are the basic building block

    of RTL code, not needed by the testbenches

    Programs 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 block The 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 block We add only one and specify it as default

    It gives a input and output skew to read/write to the signals

    The input/output skew can also be omitted

  • Clocking blocks and programs The 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 DUT Even if no timing skew is specified

    When 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 block examples:

    ##3; // wait 3 cycles ##(2*a); //wait a number of cycles equal to the double of the value of variable

    ainitial begin

    ##3 reset

  • generate Used to generate processes and continuous assignments No need of generate endgenerate statements Define a variable of type genvar We can then do a generate using a loop or if with with the genvar

    Example:genvar i;

    initial ##20 b

  • named blocks after every begin there can be an optional name Allows 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 Structure Write all your

    testbenches in this way

    The testbench program must use access all DUT signals in read and write through the default clocking block

    Only timing construct allowed in the testbench program: ##

    top modulegeneration of clock

    testbenchprogram

    driveDUT inputs,

    checkDUT outputs

    DUT

    clk

  • Good Testbench Structure Alternative: several programs are allowed all use clocking block in links to the DUT

    top modulegeneration of clock

    testbenchprogram

    drive inputs

    DUT

    clk

    testbenchprogram

    check outputs

  • Good testbench structure You can use any structure you like, everything is allowed

    The one below is more UVM-like

    top modulegeneration of clock

    testbenchprogram

    drive some inputs

    DUT

    clk

    testbenchprogram

    collect outputstranslate them into

    a higher levelmodel

    testbenchprogram

    drive other inputs

    programcheck outputs

  • Good testbench structure You can use multiple programs, but given the

    size of the testbenches used in this course, one program that does everything is a good choice

    All inputs/outputs to the DUT through the default clocking block

    Only 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

    SystemVerilog basicsHow we study SystemVerilogSystemVerilog Hello WorldSystemVerilog simple programSystemVerilog syntaxModulesSystemVerilog basic data typesPacked arrays of logic and bitsLiteralsPacked array accesspacked structuresOther data typesTypes in SVProcessesSlide 15Slide 16Always block, combinational processAlways block, flip-flopProcedural codeif treesSlide 21Bitwise logic operatorslogic operatorscomparisonsarithmeticTiming Control in Processesfork joinProcedural assignmentsSlide 29Slide 30Slide 31Default assignmentsConsole/control commandsDirect generation of random numbersSlide 35Event-driven simulationRace conditionSlide 38Slide 39Slide 40Race conditionsContinuous assignmentsVariables vs NetsSlide 44How variables workSlide 46Slide 47Objects scopeSubroutinesFunctionsTasksPackagesSlide 53Unpacked arraysdynamic arraysassociative arraysqueuesSlide 58StructureSlide 60Slide 61Slide 62Module instantiationModule InstantiationSlide 65Slide 66ParametersSlide 68Slide 69Slide 70Slide 71Hierarchical accessSystemVerilog ProgramsClocking blockSlide 75Clocking blocks and programsgeneratenamed blocksGood Testbench StructureSlide 80Good testbench structureSlide 82