Top Banner
Sequence, Sequence on the Wall, Who’s the Fairest of Them All? Using SystemVerilog UVM Sequences for Fun and Profit by Rich Edelman and Raghu Ardeishar Verification Technologists Mentor Graphics Questa Verification Platform
26

Sequence, Sequence on the Wall, Who’s the Fairest of Them All? Using SystemVerilog UVM Sequences for Fun and Profit by Rich Edelman and Raghu Ardeishar.

Dec 14, 2015

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
  • Slide 1

Sequence, Sequence on the Wall, Whos the Fairest of Them All? Using SystemVerilog UVM Sequences for Fun and Profit by Rich Edelman and Raghu Ardeishar Verification Technologists Mentor Graphics Questa Verification Platform Slide 2 Sponsored By: 2 thefreedictionary.com/fairest Whos the fairest? fair 1 (fr)adj. fairer, fairest 1. Of pleasing appearance, especially because of a pure or fresh quality; comely. 2. a. Light in color, especially blond: fair hair. b. Of light complexion: fair skin. 3. Free of clouds or storms; clear and sunny: fair skies. 4. Free of blemishes or stains; clean and pure: one's fair name. 5. Promising; likely: We're in a fair way to succeed. 6. a. Having or exhibiting a disposition that is free of favoritism or bias; impartial: a fair mediator. b. Just to all parties; equitable: a compromise that is fair to both factions. 7. Being in accordance with relative merit or significance: She wanted to receive her fair share of the proceeds. 8. Consistent with rules, logic, or ethics: a fair tactic. 9. Moderately good; acceptable or satisfactory: gave only a fair performance of the play; in fair health. 10. Superficially true or appealing; specious: Don't trust his fair promises. 11. Lawful to hunt or attack: fair game. 12. Archaic Free of all obstacles. Slide 3 Sponsored By: 3 Overview - Smorgasbord UVM Review Agents Transactions Sequences Drivers Sequence API start_item finish_item start grab priority Hierarchy/Constraints Dice/roll Words/Sentence Special Sequences Task interface Command line (+SEQ=seqA) Reading from a file C code Out-of-Order Slide 4 Sponsored By: 4 Agent manages an interface Driver wiggles the pins Monitor monitors pin wiggles Sequencer arbitrates access to the driver Sequence generates transactions and sends them to the driver AGENT Agents DRVR MON SQR trans SEQ Interface: Pins & Pin Wiggles Slide 5 Sponsored By: 5 Fun Sequence/Sequencer/Driver The sequence, sequencer and driver communicate one transaction at a time with each other. 1.The sequence creates (constructs) a transaction and sends it to the driver. 2.The sequencer arbitrates amongst multiple sequences 3.Finally the driver gets the transaction and acts on it AGENT DRVR SQR transA SEQA SEQC SEQB 1 2 3 Slide 6 Sponsored By: 6 Transactions heres three Transaction as a payload class trans_c extends uvm_sequence_item; `uvm_object_utils(trans_c) rand bit rw; rand bit[31:0] addr; rand bit[31:0] data; endclass class trans_c extends uvm_sequence_item; `uvm_object_utils(trans_c) rand bit rw; rand bit[31:0] addr; rand bit[31:0] data; endclass typedef enum { DICE1 = 1, DICE2, DICE3, DICE4, DICE5, DICE6 } dice_t; class dice_item extends uvm_sequence_item; `uvm_object_utils(dice_item) rand dice_t value;... endclass typedef enum { DICE1 = 1, DICE2, DICE3, DICE4, DICE5, DICE6 } dice_t; class dice_item extends uvm_sequence_item; `uvm_object_utils(dice_item) rand dice_t value;... endclass class packet extends uvm_sequence_item; `uvm_object_utils(packet) rand bit [7:0] som; rand bit [7:0] addr; rand bit [7:0] payload [8]; bit [7:0] checksum; rand bit [7:0] eom; constraint val { som == '0; eom == '1; foreach (payload[i]) payload[i] inside {[0:100]}; } function void post_randomize(); checksum = 0; foreach (payload[i]) checksum = f(checksum, payload[i]); endfunction endclass class packet extends uvm_sequence_item; `uvm_object_utils(packet) rand bit [7:0] som; rand bit [7:0] addr; rand bit [7:0] payload [8]; bit [7:0] checksum; rand bit [7:0] eom; constraint val { som == '0; eom == '1; foreach (payload[i]) payload[i] inside {[0:100]}; } function void post_randomize(); checksum = 0; foreach (payload[i]) checksum = f(checksum, payload[i]); endfunction endclass Slide 7 Sponsored By: 7 Sequences Sequences are functors a class wrapper around a body() task A sequence can have two jobs Generate a sequence of transactions Start other sequences class dice_item extends uvm_sequence_item; rand dice_t value;... endclass class dice_item extends uvm_sequence_item; rand dice_t value;... endclass class roll_sequence extends uvm_sequence#(dice_item); rand int how_many; task body(); dice_item t; for(int i = 0; i < how_many; i++) begin t = dice_item::type_id::create(...); if (!t.randomize()) begin `uvm_fatal("SEQ", "Randomize failed") end start_item(t); finish_item(t); end endtask endclass class roll_sequence extends uvm_sequence#(dice_item); rand int how_many; task body(); dice_item t; for(int i = 0; i < how_many; i++) begin t = dice_item::type_id::create(...); if (!t.randomize()) begin `uvm_fatal("SEQ", "Randomize failed") end start_item(t); finish_item(t); end endtask endclass AGENT DRVR SQR SEQA SEQC SEQB create randomize start_item finish_item create randomize start_item finish_item Slide 8 Sponsored By: 8 Sequences virtual sequences Start other sequences class axx_basic_sequence extends uvm_sequence_base; `uvm_object_utils(axx_basic_sequence) axx_env env; task body(); abc_sequence seq1; xyz_sequence seq2, seq3; seq1 = abc_sequence::type_id::create("seq1"); seq2 = xyz_sequence::type_id::create("seq2"); seq3 = xyz_sequence::type_id::create("seq3"); fork seq1.start(env.agent1.sequencer); seq2.start(env.agent2.sequencer); seq3.start(env.agent3.sequencer); join endtask endclass class axx_basic_sequence extends uvm_sequence_base; `uvm_object_utils(axx_basic_sequence) axx_env env; task body(); abc_sequence seq1; xyz_sequence seq2, seq3; seq1 = abc_sequence::type_id::create("seq1"); seq2 = xyz_sequence::type_id::create("seq2"); seq3 = xyz_sequence::type_id::create("seq3"); fork seq1.start(env.agent1.sequencer); seq2.start(env.agent2.sequencer); seq3.start(env.agent3.sequencer); join endtask endclass Slide 970; how_many < 100; } task body(); dice_item t; grab(); for(int i = 0; i < how_many; i++) begin t = dice_item::type_id::create($sformatf("t%0d", i)); if (!t.randomize()) begin `uvm_fatal("SEQ", "Randomize failed") end start_item(t); finish_item(t); end ungrab(); endtask endclass AGENT DRVR SQR SEQA SEQC SEQB"> Sponsored By: 9 Sequences with grab Get exclusive use of the sequencer class roll_sequence extends uvm_sequence#(dice_item); `uvm_object_utils(roll_sequence) rand int how_many; constraint val { how_many > 70; how_many < 100; } task body(); dice_item t; grab(); for(int i = 0; i < how_many; i++) begin t = dice_item::type_id::create($sformatf("t%0d", i)); if (!t.randomize()) begin `uvm_fatal("SEQ", "Randomize failed") end start_item(t); finish_item(t); end ungrab(); endtask endclass class roll_sequence extends uvm_sequence#(dice_item); `uvm_object_utils(roll_sequence) rand int how_many; constraint val { how_many > 70; how_many < 100; } task body(); dice_item t; grab(); for(int i = 0; i < how_many; i++) begin t = dice_item::type_id::create($sformatf("t%0d", i)); if (!t.randomize()) begin `uvm_fatal("SEQ", "Randomize failed") end start_item(t); finish_item(t); end ungrab(); endtask endclass AGENT DRVR SQR SEQA SEQC SEQB Slide 1070; how_many < 100; } task body(); dice_item t; for(int i = 0; i < how_many; i++) begin t = dice_item::type_id::create($sformatf("t%0d", i)); if (!t.randomize()) begin `uvm_fatal("SEQ", "Randomize failed") end start_item(t, 1000); finish_item(t); end endtask endclass AGENT DRVR SQR SEQA SEQC SEQB"> Sponsored By: 10 Transactions with priority Default priority is 100. Higher numbers are better. Dont forget to change the sequencer mode sqr.set_arbitration(SEQ_ARB_STRICT_FIFO); class roll_sequence extends uvm_sequence#(dice_item); `uvm_object_utils(roll_sequence) rand int how_many; constraint val { how_many > 70; how_many < 100; } task body(); dice_item t; for(int i = 0; i < how_many; i++) begin t = dice_item::type_id::create($sformatf("t%0d", i)); if (!t.randomize()) begin `uvm_fatal("SEQ", "Randomize failed") end start_item(t, 1000); finish_item(t); end endtask endclass class roll_sequence extends uvm_sequence#(dice_item); `uvm_object_utils(roll_sequence) rand int how_many; constraint val { how_many > 70; how_many < 100; } task body(); dice_item t; for(int i = 0; i < how_many; i++) begin t = dice_item::type_id::create($sformatf("t%0d", i)); if (!t.randomize()) begin `uvm_fatal("SEQ", "Randomize failed") end start_item(t, 1000); finish_item(t); end endtask endclass AGENT DRVR SQR SEQA SEQC SEQB Slide 11 Sponsored By: 11 Driver Driver handshake with the sequence class driver extends uvm_driver#(dice_item); `uvm_component_utils(driver) // Simple counter for each face seen int distribution[dice_t]; task run_phase(uvm_phase phase); forever begin dice_item t; seq_item_port.get_next_item(t); distribution[t.value]++; `uvm_info("DRVR", $sformatf(" Got %s [%p]", t.convert2string(), distribution), UVM_MEDIUM) // Send to BUS... seq_item_port.item_done(); end endtask endclass class driver extends uvm_driver#(dice_item); `uvm_component_utils(driver) // Simple counter for each face seen int distribution[dice_t]; task run_phase(uvm_phase phase); forever begin dice_item t; seq_item_port.get_next_item(t); distribution[t.value]++; `uvm_info("DRVR", $sformatf(" Got %s [%p]", t.convert2string(), distribution), UVM_MEDIUM) // Send to BUS... seq_item_port.item_done(); end endtask endclass AGENT DRVR SQR SEQA SEQC SEQB Slide 12 Sponsored By: 12 Tasks Wrapping Sequences Sequence wrapped with a simple task Task does seq.start(sequencer) task read(input bit [7:0] addr, output bit [7:0] data); read_seq seq; seq = read_seq::type_id::create("read",, get_full_name()); seq.addr = addr; seq.start(seqr); data = seq.data; endtask task read(input bit [7:0] addr, output bit [7:0] data); read_seq seq; seq = read_seq::type_id::create("read",, get_full_name()); seq.addr = addr; seq.start(seqr); data = seq.data; endtask class trans extends uvm_sequence_item; `uvm_object_utils(trans) rand bit rw; rand bit [7:0] addr; rand bit [7:0] data;... endclass class trans extends uvm_sequence_item; `uvm_object_utils(trans) rand bit rw; rand bit [7:0] addr; rand bit [7:0] data;... endclass class read_seq extends uvm_sequence#(trans); `uvm_object_utils(read_seq) rand bit [7:0] addr; // Input bit [7:0] data; // Output task body(); trans t; t = trans::type_id::create("t",, get_full_name()); t.rw = 1; t.addr = addr; start_item(t); finish_item(t); data = t.data; endtask endclass class read_seq extends uvm_sequence#(trans); `uvm_object_utils(read_seq) rand bit [7:0] addr; // Input bit [7:0] data; // Output task body(); trans t; t = trans::type_id::create("t",, get_full_name()); t.rw = 1; t.addr = addr; start_item(t); finish_item(t); data = t.data; endtask endclass Slide 13 Sponsored By: 13 Command line - +SEQ= task run_phase(uvm_phase phase); string sequence_name; uvm_object obj; simple_value_base_class seq; string list_of_sequences[$]; uvm_cmdline_processor clp; clp = uvm_cmdline_processor::get_inst(); clp.get_arg_values("+SEQ=", list_of_sequences) foreach (list_of_sequences[n]) begin sequence_name = list_of_sequences[n]; phase.raise_objection(this); obj = factory.create_object_by_name(sequence_name); if (obj == null) /* Handle Error */ if (!$cast(seq, obj)) /* Handle Error */ seq.env = env; seq.start(null); phase.drop_objection(this); end endtask task run_phase(uvm_phase phase); string sequence_name; uvm_object obj; simple_value_base_class seq; string list_of_sequences[$]; uvm_cmdline_processor clp; clp = uvm_cmdline_processor::get_inst(); clp.get_arg_values("+SEQ=", list_of_sequences) foreach (list_of_sequences[n]) begin sequence_name = list_of_sequences[n]; phase.raise_objection(this); obj = factory.create_object_by_name(sequence_name); if (obj == null) /* Handle Error */ if (!$cast(seq, obj)) /* Handle Error */ seq.env = env; seq.start(null); phase.drop_objection(this); end endtask +SEQ=seqA +SEQ=seqB Slide 14 Sponsored By: 14 Reading from a file - +FILE= class read_sequence_from_file extends uvm_sequence#(value_item); `uvm_object_utils(read_sequence_from_file) task body(); int fd, count; string filenames[$], sequence_name; uvm_object obj; simple_value_base_class seq; uvm_cmdline_processor clp; clp = uvm_cmdline_processor::get_inst(); clp.get_arg_values("+FILE=", filenames) foreach (filenames[n]) begin fd = $fopen(filenames[n], "r"); while(!$feof(fd)) begin ret = $fscanf(fd, "%s %d", sequence_name, count); obj = factory.create_object_by_name(sequence_name); if (obj == null) /* Handle Error */ if (!$cast(seq, obj)) /* Handle Error */ if (!seq.randomize() with {seq.how_many == count;}) /* Handle Error */ seq.start(m_sequencer); end // while end // foreach endtask endclass class read_sequence_from_file extends uvm_sequence#(value_item); `uvm_object_utils(read_sequence_from_file) task body(); int fd, count; string filenames[$], sequence_name; uvm_object obj; simple_value_base_class seq; uvm_cmdline_processor clp; clp = uvm_cmdline_processor::get_inst(); clp.get_arg_values("+FILE=", filenames) foreach (filenames[n]) begin fd = $fopen(filenames[n], "r"); while(!$feof(fd)) begin ret = $fscanf(fd, "%s %d", sequence_name, count); obj = factory.create_object_by_name(sequence_name); if (obj == null) /* Handle Error */ if (!$cast(seq, obj)) /* Handle Error */ if (!seq.randomize() with {seq.how_many == count;}) /* Handle Error */ seq.start(m_sequencer); end // while end // foreach endtask endclass sequences.txt: fibonacci_sequence 10 triangle_sequence 20 sequences.txt: fibonacci_sequence 10 triangle_sequence 20 +FILE=sequences.txt +FILE=sequences2.txt Slide 15 Sponsored By: 15 DPI-C (bound) Use C code to Get stimulus input Get expected output Scoreboard (checker) interface my_interface(); import "DPI-C" context task c_calc(output int x); export "DPI-C" task intf_calling_back; seq my_class_handle; function void init(seq s); s.vif = interface::self(); my_class_handle = s; endfunction task intf_calling_back(output int x); my_class_handle.class_calling_back(x); endtask endinterface interface my_interface(); import "DPI-C" context task c_calc(output int x); export "DPI-C" task intf_calling_back; seq my_class_handle; function void init(seq s); s.vif = interface::self(); my_class_handle = s; endfunction task intf_calling_back(output int x); my_class_handle.class_calling_back(x); endtask endinterface class seq; virtual my_interface vif; task class_calling_back(output int x); #10 x = id; endtask task body(); int x; for(int i = 0; i < 5; i++) vif.c_calc(x); endtask endclass class seq; virtual my_interface vif; task class_calling_back(output int x); #10 x = id; endtask task body(); int x; for(int i = 0; i < 5; i++) vif.c_calc(x); endtask endclass C Code int c_calc(int *val) { int id; intf_calling_back(&id); printf("c_calc() Scope = %s\n", svGetNameFromScope(svGetScope())); *val = id++; return 0; } C Code int c_calc(int *val) { int id; intf_calling_back(&id); printf("c_calc() Scope = %s\n", svGetNameFromScope(svGetScope())); *val = id++; return 0; } 1 2 3 4 Slide 16 Sponsored By: 16 DRIVER Out-of-Order sequence/driver SEQUENCE forever begin get_next_item(t); work_list.push(t); item_done(); end forever begin get_next_item(t); work_list.push(t); item_done(); end forever begin work_list.pop(t); t.item_really_started(); lookup[tag] = t; send t to BUS end forever begin work_list.pop(t); t.item_really_started(); lookup[tag] = t; send t to BUS end Execute forever begin @(interrupt); t = lookup[tag]; t.resp = BUS.resp; resp_list.push(t); end forever begin @(interrupt); t = lookup[tag]; t.resp = BUS.resp; resp_list.push(t); end ISR forever begin resp_list.pop(t); t.item_really_done(); end forever begin resp_list.pop(t); t.item_really_done(); end RSP trans t; t = new(t); start_item(t); finish_item(t); trans t; t = new(t); start_item(t); finish_item(t); Run DUT t Slide 17 Sponsored By: 17 Out-of-Order item_really_done SEQ trans t; t = new(t); start_item(t); finish_item(t); trans t; t = new(t); start_item(t); finish_item(t); class trans... bit item_really_done_e; function item_really_done(); item_really_done_e = 1; endfunction... endclass class trans... bit item_really_done_e; function item_really_done(); item_really_done_e = 1; endfunction... endclass t DRIVER forever begin get_next_item(t); work_list.push(t); item_done(); end forever begin get_next_item(t); work_list.push(t); item_done(); end forever begin resp_list.pop(t); t.item_really_done(); end forever begin resp_list.pop(t); t.item_really_done(); end RSP Run class my_sequence_base... function finish_item(trans t); super.finish_item(t); wait(t.item_really_done_e == 1); endfunction class my_sequence_base... function finish_item(trans t); super.finish_item(t); wait(t.item_really_done_e == 1); endfunction Slide 18 Sponsored By: 18 Summary Sequences are the way to write tests. Just code that... Starts other sequences Sends transactions Sequences have an API Randomized tests constraints, layering Directed tests, C code, files, command line Building collections of sequences is a good idea Glad to share source code. Some of it is in the paper. Questions? rich_edelman@mentor.com Slide 19 Sponsored By: 19 BACKUP SLIDES Slide 20 Sponsored By: 20 Fun with Words Encryption hardware one word at a time Job of the Stimulus Generating words Generating four-letter-words Sentences, Paragraphs, Chapters, Use Constraints Unique combinations Distribution of letters Really Fun with Constraints SV LRM Chapter 18 only(!) 50 pages out of 1315 DUT word mode encrypted word Hold the Presses! News Flash Just released Slide 21 Sponsored By: 21 Transaction/Sequence Design Transaction: a word (data), an encryption mode and the result (secret_data) Sequence: create a word and send it. virtual class my_sequence extends uvm_sequence#(transaction); `uvm_object_utils(my_sequence) rand byte data[]; task body(); transaction t; t = transaction::type_id::create("t"); start_item(t); if (!t.randomize()) `uvm_fatal("MSG", "Randomization failed") t.data = data; finish_item(t); `uvm_info("MSG", $sformatf("secret=%s", t.secret_data), UVM_MEDIUM) endtask endclass virtual class my_sequence extends uvm_sequence#(transaction); `uvm_object_utils(my_sequence) rand byte data[]; task body(); transaction t; t = transaction::type_id::create("t"); start_item(t); if (!t.randomize()) `uvm_fatal("MSG", "Randomization failed") t.data = data; finish_item(t); `uvm_info("MSG", $sformatf("secret=%s", t.secret_data), UVM_MEDIUM) endtask endclass class transaction extends uvm_sequence_item;... rand mode_t mode; // CLR or ROT13 rand byte data[]; string secret_data; endclass class transaction extends uvm_sequence_item;... rand mode_t mode; // CLR or ROT13 rand byte data[]; string secret_data; endclass Slide 22 Sponsored By: 22 Four Letter Words - constraints Inheritance Sequence: Extends my_sequence. IS-A Randc data from the gadget r. pre_randomize() post_randomize() What is r? class four_letter_words extends my_sequence; `uvm_object_utils(four_letter_words) four_letter_words_randc r; function new(string name = ..."); super.new(name); r = new(); endfunction function void pre_randomize(); if (!(r.randomize())) `uvm_fatal(...) endfunction function void post_randomize(); data = r.sdata; endfunction endclass class four_letter_words extends my_sequence; `uvm_object_utils(four_letter_words) four_letter_words_randc r; function new(string name = ..."); super.new(name); r = new(); endfunction function void pre_randomize(); if (!(r.randomize())) `uvm_fatal(...) endfunction function void post_randomize(); data = r.sdata; endfunction endclass Slide 23 Sponsored By: 23 The Gadget r Just a container which allows for randc to be used. How to generate all the possible four letter words with no repeats? Randomize value Convert value to string sdata Modulo 26 operations class four_letter_words_randc; string sdata; randc int value; constraint val { value >= 0; value < 456976; } function void post_randomize(); int v; sdata = " "; v = value; for(int i = 0; i < 4; i++) begin sdata[i] = (v%26) + "a"; v = v/26; end endfunction class four_letter_words_randc; string sdata; randc int value; constraint val { value >= 0; value < 456976; } function void post_randomize(); int v; sdata = " "; v = value; for(int i = 0; i < 4; i++) begin sdata[i] = (v%26) + "a"; v = v/26; end endfunction Note to math people 26**4 = 456976 Slide 24 = 3; length0; how_many < 200;} task body(); uvm_sequence_base seq; for(int i = 0; i < how_many; i++) begin if (use_four_letter_word) seq = four_letter_words::type_id::create(..."> Sponsored By: 25 Sentence Seq Sentence HAS-A seq it generates sequences and starts them. 4 letter Short word Paragraph Chapter Book class sentence_seq extends uvm_sequence#(transaction); `uvm_object_utils(sentence_seq) rand int how_many; rand bit use_four_letter_word = 0; constraint val_how_many {how_many > 0; how_many < 200;} task body(); uvm_sequence_base seq; for(int i = 0; i < how_many; i++) begin if (use_four_letter_word) seq = four_letter_words::type_id::create(..."); else seq = short_word_seq::type_id::create(..."); if (!seq.randomize()) `uvm_fatal("SEQ", "Randomize failed") seq.start(m_sequencer); end endtask class sentence_seq extends uvm_sequence#(transaction); `uvm_object_utils(sentence_seq) rand int how_many; rand bit use_four_letter_word = 0; constraint val_how_many {how_many > 0; how_many < 200;} task body(); uvm_sequence_base seq; for(int i = 0; i < how_many; i++) begin if (use_four_letter_word) seq = four_letter_words::type_id::create(..."); else seq = short_word_seq::type_id::create(..."); if (!seq.randomize()) `uvm_fatal("SEQ", "Randomize failed") seq.start(m_sequencer); end endtask Slide 26 Sponsored By: 26 Factory - Overrides Type based override Instance based override class test extends uvm_test; `uvm_component_utils(test) task run_phase(uvm_phase phase); n_packets seq1, seq2; phase.raise_objection(this); packet::type_id::set_type_override( packet_with_randc_addr::get_type); packet::type_id::set_inst_override( big_packet::get_type(), "uvm_test_top.e1.sequencer.seq1.packet"); seq1=n_packets::type_id::create("seq1",,get_full_name()); seq2=n_packets::type_id::create("seq2",,get_full_name()); factory.print();... class test extends uvm_test; `uvm_component_utils(test) task run_phase(uvm_phase phase); n_packets seq1, seq2; phase.raise_objection(this); packet::type_id::set_type_override( packet_with_randc_addr::get_type); packet::type_id::set_inst_override( big_packet::get_type(), "uvm_test_top.e1.sequencer.seq1.packet"); seq1=n_packets::type_id::create("seq1",,get_full_name()); seq2=n_packets::type_id::create("seq2",,get_full_name()); factory.print();...