610 likes | 919 Views
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
E N D
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 World module M(); initial $display(“Hello world”); endmodule
SystemVerilog simple program module M(); logic a,b; logic [7:0] c; assign b = ~a; initial begin a <= 0; #20ns; repeat(40) #5ns a <= ~a; #20ns $display(c); $finish(); end initial c <= 0; always @(posedge a) c <= c + 1; endmodule
SystemVerilog syntax • Case sensitive • C-style comments: // or /*comment*/ • Code blocks delimited by “begin” “end”. If a single-line, can be omitted
Modules • Let’s 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 <= 54; // automatically extended to the length of a with 0 padding • a <= ‘d54; • a <= 12’d54; // specifies that a is 12-bits wide • Unspecified length: • ‘1, ‘0, ‘x, ‘z // fills with all 1s, 0s, xs, zs • binary literal • 12’b1000_1100_1110 // underscores can be put anywhere except the beginning of a literal • ‘b11011 // automatically resized with zeroes if fed to something bigger • hexadecimal literal: • 12’hc; // “000000001100” • ‘hcd: // ”….0000011001101”
Packed array access • Single element access: • bit [7:0] a • a[5] <= a[6]; • bit [9:0][7:0] b: • b[5] <= 15; • Packed arrays can be sliced: • bit [7:0] a; • a[3:2] <= 2’b10; • a[3:0] <= a[7:4]; • bit [2047:0][7:0] a; bit [1:0][7:0] b; • a[2047:2046] <= b
packed structures • equivalent to a packed array subdivided into named fields: • example: 48 bit packed array • can be accessed as pack1[15:0] <= ‘b0; • can access pack1[9:4] <= 15; • can be accessed as pack1.d <= ‘b0; • the whole struct can be resetted with pack1 <= ‘b0; • unpacked struct (no “packed” keyword) allow only acces through the named fields (pack1.d <=‘b0); struct packed { int a; bit [7:0] c; bit [7:0] d; } pack1;
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 <= 1’b1; #20ns; a <= 1’b0; end
Processes • Always - no sensitivity list: triggers as soon as it finishes executing always begin #10ns; a <= 1’b1; #20ns; a <= 1’b0; end
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 <= 1’b1; #20ns; a <= 1’b0; end • posedge: positive edge • negedge: negative edge • signal name: any toggle
Always block, combinational process • The sensitivity list must contain all elements in the left-hand side always @(a,b) begin c <= a+b; end • SystemVerilog allows using always_comb instead • the sensitivity list is automatically compiled always_comb begin c <= a+b; end
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 <= 0; • else // posedge clk, rst==1 • q <= d; • end • always_ff @(posedge clk, negedge rst) begin • if (rst==0) • q <= 0; • else // posedge clk, rst==1 • q <= d; • end
Procedural code • if (a==1) begin • //code • end • if (a) begin // 1 counts as true • //code • end • while (a==1) begin • //code • end • repeat (3) begin • //code • end • forever begin // loops forever • //code • end • for (i=0; i<3; i++) begin // loops three times • //code • end
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 <= ~a • Do a bit-wise OR between two bit/logic arrays: • c <= a | b
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<=!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 • “<=“ • takes place after a delta delay • Blocking assignment • “=“ • takes place immediately • The two can be mixed – but probably not a good idea
Procedural assignments • blocking assignments correspond to the VHDL variable assignment “:=“ • non-blocking assignments correspond to the VHDL signals assignment “<=“ • BUT: • In VHDL := is reserved for variables, <= for signals • In Verilog, both can be used for variables • Possible to mix them - but probably not a good idea • A better idea is to use some objects as VHDL variables and only assign them with “=“, others as VHDL signals and only assign them with “<=“
Procedural assignments • always @(posedge clk) begin • a <= b; • b <= a; • end • always @(posedge clk) begin • a = b; • b = a; • end
Procedural assignments • initial begin • a = 1; • $display(a); • end • initial begin • a <= 1; • $display(a); • end • initial begin • a <= 1; • #10ns; • $display(a); • end
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
Event-driven simulation • The simulator executes in a random order any of the operations scheduled for a given timestamp. It continues until the timestamp 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 condition • Race condition: at 10 ns there are two events that are scheduled, which one is executed first is random. • The value of a at 20 ns is unknown • No error is signalled • initial begin • #10ns; • a = 1; • end • initial begin • #10 ns; • a = 0; • end • initial begin • #20 ns; • $display(a); • end
Race condition • Race condition: at 10 ns+delta there are two events that are scheduled, which one is executed first is random. • The value of a at 20 ns is unknown • No error is signalled • initial begin • #10ns; • a <= 1; • end • initial begin • #10 ns; • a <= 0; • end • initial begin • #20 ns; • $display(a); • end
Race condition • No Race condition: at 10 ns a is assigned 0, at 10ns+delta it is assigned 1 • The value of a at 20 ns is 1 • initial begin • #10ns; • a <= 1; • end • initial begin • #10 ns; • a = 0; • end • initial begin • #20 ns; • $display(a); • end
Race condition • No race condition: at 10 ns a is assigned to 1, then to 0. • The value of a at 20 ns is 0 • initial 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: • don’t write the same signal in different processes, unless you really know what you do (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; • 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 • 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 • That’s it
How variables work initial #10ns a <= 1; initial #20ns a <= 0; • a variable keeps the newest value that is written to it • VARIABLES HAVE NOTHING TO DO WITH VHDL VARIABLES
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
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 (inout are read at the beginning and 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 don’t delay the function execution function logic myfunc3(input int a, output int b); b = a + 1; return (a==1000); endfunction
Tasks task 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
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 integers: • declared as logic [7:0] a [*]; • Acts exactly as a vector of 2^32 bytes: • a[4102345432] <= 8’b10000110 is legal • Memory space is allocated only when used • Slow to access the elements in terms of simulation time • If we would try to write to all locations we would crash everything or generate an error • Ideal to model big memories used only sparsely
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