Saturday, July 25, 2020

Pipeline driver logic in System Verilog

 For pipeline protocols such as AHB, the driver should support the parallel access of Address and Data.

In the example below, I tried to show one of the ways to achieve this.

In the following code, there are 3 possible burst traffic supported.
1. Single   - only 1 cycle of data for a given address
2. Double - 2 back-to-back cycles of data for a given address
3. Quad    - 4 cycles of data for a given address.

Let us take a scenario

You have the following sequence of burst traffic generated from your sequence.
SINGLE - DOUBLE - QUAD
@100ns Burst - Signle   Addr - 'h1 Data - 'h100
@200ns Burst - Double Addr - 'h2 Data - 'h200, 'h400
@400ns Burst - Quad    Addr - 'h3 Data - 'h600, 'h800,'hA00,'hC00

What should be driven to the interface is as follows
@100ns Addr: 'h1 Data: 'h100

@200ns Addr: 'h2 Data: 'h200
@300ns Addr: 'h2 Data: 'h400

@400ns Addr: 'h3 Data: 'h600
@500ns Addr: 'h3 Data: 'h800
@600ns Addr: 'h3 Data: 'hA00
@700ns Addr: 'h3 Data: 'hC00

There are only 2 things to take care of.
1. Whenever you get the seq_item, fork 2 process using join_any
    a.    process -1 will drive address
    b.    process -2 will drive data
    Why join-any?, reason is, when we get the sequence item, address ( process - 1) will be consumed in a single cycle, whereas the data (process - 2) can take multiple cycles. Since we may need to wait for multiple cycles for the process 2 to complete, we can unblock the wait state on process and proceed to receive to another sequence item.
2. We need to to make sure that the process-2 generated early ( say on 100ns ) should be completed first before driving the later version of the task (200ns). To achieve this we need to lock down the process , therefore we used semaphore to hold on to the process until it is done.

I highlighted the code in RED and GREEN.

Note: If you are using UVM, make sure you use seq_item_port.get(seq_item) instead of get_next_item(seq_item). This is required to return the control back to the sequencer once the cycle is completed.

CODE

typedef enum { SINGLE, DOUBLE, QUAD } BURST_TYPE;
class seq_item;
  static int trans_id;
  rand bit [31:0] addr;
  rand bit [31:0] data[];
  rand BURST_TYPE burst;

  constraint c_burst {
    if( burst == SINGLE ) { data.size() == 1; }
    if( burst == DOUBLE ) { data.size() == 2; }
    if( burst == QUAD   ) { data.size() == 4; }
  }

  constraint c_addr { addr inside { [1:100] }; }
 
  function void print();
    $display("@%0t - SEQ_ITEM :%0d ADDR:%0h BURST:%0s DATA:%p",$time,trans_id,addr,burst,data);
  endfunction

endclass


class driver;
  mailbox #(seq_item) drv;
  semaphore sem = new(1);


  task run_phase();
    seq_item item;

    $display("%0t DRIVER::RUN_PHASE",$time);
    forever begin
      drv.get(item);
      fork
        drv_addr(item);
        drv_data(item);
      join_any

    end
  endtask

  task drv_addr( seq_item s);
    $display("@%0t - DRV_ADDR :%0d ADDR:%0h BURST:%0s DATA:%p",$time,s.trans_id,s.addr,s.burst,s.data);
    #100;
  endtask

  task drv_data( seq_item s);
    sem.get(1);
    foreach(s.data[i]) begin
      $display("@%0t - DRV_DATA :%0d ADDR:%0h BURST:%0s DATA:%0h",$time,s.trans_id,s.addr,s.burst,s.data[i]);
      #100;
    end
    sem.put(1);
  endtask

endclass: driver


class generator;
  seq_item s;
  mailbox #(seq_item) gen;

  task run_phase ();
    $display("%0t GENERATOR::RUN_PHASE",$time);
    repeat(5) begin
      s = new;
      void'(s.randomize());
      #100;
      s.print();
      gen.put(s);
    end
  endtask
endclass: generator

module top;
  driver    d;
  generator g;
  mailbox #(seq_item) gen2drv;

  initial begin
    d = new;
    g = new;
    gen2drv = new(1);

    d.drv = gen2drv;
    g.gen = gen2drv;

    fork
      d.run_phase();
      g.run_phase();
    join
  end
endmodule: top

Command to run : vcs -sverilog -R <filename.sv>

Result:
Chronologic VCS simulator copyright 1991-2016
Contains Synopsys proprietary information.
Compiler version L-2016.06; Runtime version L-2016.06;  Jul 25 08:18 2020
0 DRIVER::RUN_PHASE
0 GENERATOR::RUN_PHASE
@100 - SEQ_ITEM :0 ADDR:59 BURST:SINGLE DATA:'{'h79b40674}
@100 - DRV_ADDR :0 ADDR:59 BURST:SINGLE DATA:'{'h79b40674}
@100 - DRV_DATA :0 ADDR:59 BURST:SINGLE DATA:79b40674
@200 - SEQ_ITEM :0 ADDR:42 BURST:DOUBLE DATA:'{'h51c5e838, 'ha3239b2d}
@200 - DRV_ADDR :0 ADDR:42 BURST:DOUBLE DATA:'{'h51c5e838, 'ha3239b2d}
@200 - DRV_DATA :0 ADDR:42 BURST:DOUBLE DATA:51c5e838
@300 - SEQ_ITEM :0 ADDR:18 BURST:QUAD DATA:'{'hf160aa62, 'h40498f74, 'h2446ea44, 'h4c0e692b}
@300 - DRV_DATA :0 ADDR:42 BURST:DOUBLE DATA:a3239b2d
@300 - DRV_ADDR :0 ADDR:18 BURST:QUAD DATA:'{'hf160aa62, 'h40498f74, 'h2446ea44, 'h4c0e692b}
@400 - SEQ_ITEM :0 ADDR:9 BURST:QUAD DATA:'{'h1e8bda74, 'h651da1c0, 'h477d65b1, 'hbf79aff8}
@400 - DRV_DATA :0 ADDR:18 BURST:QUAD DATA:f160aa62
@400 - DRV_ADDR :0 ADDR:9 BURST:QUAD DATA:'{'h1e8bda74, 'h651da1c0, 'h477d65b1, 'hbf79aff8}
@500 - SEQ_ITEM :0 ADDR:1f BURST:DOUBLE DATA:'{'ha4d5d480, 'h7aa3e09}
@500 - DRV_DATA :0 ADDR:18 BURST:QUAD DATA:40498f74
@500 - DRV_ADDR :0 ADDR:1f BURST:DOUBLE DATA:'{'ha4d5d480, 'h7aa3e09}
@600 - DRV_DATA :0 ADDR:18 BURST:QUAD DATA:2446ea44
@700 - DRV_DATA :0 ADDR:18 BURST:QUAD DATA:4c0e692b
@800 - DRV_DATA :0 ADDR:9 BURST:QUAD DATA:1e8bda74
@900 - DRV_DATA :0 ADDR:9 BURST:QUAD DATA:651da1c0
@1000 - DRV_DATA :0 ADDR:9 BURST:QUAD DATA:477d65b1
@1100 - DRV_DATA :0 ADDR:9 BURST:QUAD DATA:bf79aff8
@1200 - DRV_DATA :0 ADDR:1f BURST:DOUBLE DATA:a4d5d480
@1300 - DRV_DATA :0 ADDR:1f BURST:DOUBLE DATA:7aa3e09
           V C S   S i m u l a t i o n   R e p o r t

No comments:

Post a Comment

Constraint to have N elements distributed in M bins

Code to distribute N elements into M bins, you add unique keyword to have each bin will have unique number of elements. class test; param...