Wednesday, July 29, 2020

System verilog assertion - If b is asserted in the current cycle, a must have been present anywhere between 1 - 3 cycles earlier than b.

Problem Statement:
1. A and B are 2 pulses.
If B is asserted, A must have been asserted anywhere between 1 and 3 cycles in the past.

Solution :
We cannot use $past, as the problem requires the check to be range bound.

One way around is to use an intermediate signal ( vector).

Let us try using an vector to accommodate the length of duration to be under check.
In our case, it is between 1 and 3.
Therefore , let us take an intermediate signal arr, ranging from 3:0.
Each bit position corresponds to 1 cycle.

Code snippet will be something like this:

always @(posedge clk) arr = {[arr[2:0],a};

Code for assertion :

  property check;
    @(posedge clk) (b==1) |-> $countones(arr[3:1])>=1; // omit arr[0] as this is represents the time at which 'b' is set to 1
  endproperty: check

  a_check: assert property (check);

One more way to do it is the use of sequence.triggered.
As per LRM, triggered is a method, which checks if the operand sequence has reached its end point at that point in time.

Using this, we can write a sequence and check whether it reached its endpoint before $rose(b).

sequence s_1;
  @(posedge clk) $rose(a) ##[1:3]  1;
endsequence: s_1

property test_1;
  @(posedge clk) $rose(b) |-> s_1.triggered;
endproperty: test_1

Notes:
Now the sequence s_1, checks for $rose(a) between 1 and 3 cycles.
property test_1 checks if the s_1.triggered is reached to its endpoint at $rose(a).

Code with stimulus :
module top;
  bit a;
  bit b;
  bit [3:0] arr;

  bit clk;

  initial  begin
    $timeformat(-9,3,"ns",8);
    clk <= 0;
    forever #5 clk = !clk;
  end

  initial
    $monitor("%0t - A -%0d B -%0d Arr:%0b",$time,a,b,arr);

  initial begin
    repeat(1) @(posedge clk);
    a = 1;
    repeat(1) @(posedge clk);
    a = 0;

    repeat(2) @(posedge clk); // Check should pass, as 'a' is asserted 3 cycles before 'b'.
    b = 1;
    repeat(1) @(posedge clk);
    b = 0;
  
    repeat(3) @(posedge clk); // Check should fail, as 'a' is not present in the previous 3 cycles
    b = 1;
    repeat(1) @(posedge clk);
    b = 0;
   
    repeat(1) @(posedge clk); // Check should fail, as 'a' and 'b' are asserted in the same cycle.
    a = 1; b = 1;
    repeat(1) @(posedge clk);
    a = 0; b = 0;
    repeat(4) @(posedge clk);
    $finish;
  end

  always @(posedge clk) begin
    arr <= { arr[2:0], a };
  end

  property check;
    @(posedge clk) (b==1) |-> $countones(arr[3:1])>=1; // omit arr[0] as this is represents the time at which 'b' is set to 1
  endproperty: check

  a_check: assert property (check);
endmodule

Result :

Compiler version L-2016.06; Runtime version L-2016.06;  Jul 29 04:18 2020
0ns - A -0 B -0 Arr:0
5ns - A -1 B -0 Arr:1
15ns - A -0 B -0 Arr:10
25ns - A -0 B -0 Arr:100
35ns - A -0 B -1 Arr:1000
45ns - A -0 B -0 Arr:0
75ns - A -0 B -1 Arr:0
"assertion_past_value.sv", 51: top.a_check: started at 85000ps failed at 85000ps
        Offending '($countones(arr[3:1]) >= 1)'
85ns - A -0 B -0 Arr:0
95ns - A -1 B -1 Arr:1
"assertion_past_value.sv", 51: top.a_check: started at 105000ps failed at 105000ps
        Offending '($countones(arr[3:1]) >= 1)'
105ns - A -0 B -0 Arr:10
115ns - A -0 B -0 Arr:100
125ns - A -0 B -0 Arr:1000
135ns - A -0 B -0 Arr:0
$finish called from file "assertion_past_value.sv", line 40.
$finish at simulation time    145ns

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

Thursday, July 23, 2020

Telephone dialer code in system verilog

Problem Statement :
Write a sequence item for telephone dialer with the following data
1. RECEPTION             - 0
2. EMERGENCY          - 911
3. LOCAL                     - 8 Digit Number
4. INTERNATIONAL  - 11 Digit number starting with 1. < 1-10Digits >

With the above code we can derive the constraints for each dial type.
RECEPTION - Just 0
EMERGENCY - Just 911
LOCAL - 8 Digit number must not start with 0 or have 911 as its first few numbers
INTERNATIONAL - 11 digit telephone number must start with 1.


CODE

typedef enum { RECEPTION, EMERGENCY, LOCAL, INTERNATIONAL } dial_type;
class telephone;
  rand bit [3:0] tele[];
  rand dial_type d;

  constraint c_tele {
    d dist { RECEPTION:= 1, EMERGENCY:= 1, LOCAL:= 1, INTERNATIONAL:= 1};
    if(d == RECEPTION) {
      tele.size() == 1;
      tele[0] == 'd0;
    }
    if(d == EMERGENCY) {
      tele.size() == 3;
      tele[0] == 'd9;
      tele[1] == 'd1;
      tele[2] == 'd1;
    }
    if(d == LOCAL) {
      tele.size() == 8;
      foreach(tele[i]) {
        if(i==0) { tele[i] inside {[2:9]}; }
        else     { tele[i] inside {[0:9]}; }
    }
     {tele[0],tele[1],tele[2]} != {4'h9,4'h1,4'h1}; }
    if(d == INTERNATIONAL) {
      tele.size() == 11;
      foreach(tele[i]) {
        if(i==0) { tele[i] == 'd1; }
        else     { tele[i] inside {[0:9]}; }
      } 
    }

  }

  function void display();
    $display("DIAL_TYPE:%s NUM:%p",d,tele);
  endfunction: display
endclass

module top;
 telephone t;

 initial begin
   t = new;
   repeat(20) begin
   void'(t.randomize());
   t.display();
   end
 end

endmodule: top

Wednesday, July 22, 2020

Write a system verilog assertion to check for lock when '110' is observed on the input bit stream and lock is de-asserted when '111' is observed.

`timescale 1ns / 100ps
module top;
 bit a;
 bit [2:0] bin;
 bit lock;

 bit clk;

 initial begin
   $timeformat(-9,0,"ns",8);
   clk <= 0;
   forever #5 clk = !clk;
 end

 initial begin
   repeat(100) begin
     @(posedge clk);
     std::randomize(a);
   end
   $finish;
 end
  

 always @ (posedge clk) begin
   bin <= { bin[1:0], a };
   if(bin == 'b110) lock <= 1;
   if(bin == 'b111) lock <= 0;
 end


 property check_lock;
   @(posedge clk) (bin == 'b110) |=> lock throughout (bin == 'b111)[->1];
 endproperty

 property check_lock_deassertion;
   @(posedge clk) (bin == 'b111) && lock |=> $fell(lock);
 endproperty


 check_lock_assertion    : assert property (check_lock);
 check_lock_de_assertion : assert property (check_lock_deassertion);



 initial
   $monitor("%0t - Lock:%0d A:%0d B:%0b",$time,lock,a,bin);

  endmodule: top

Monday, July 20, 2020

System Verilog Assertion to check if no more than 3 ACK are generated in a 10 cycle window

The above problem statement gives us 2 conditions.
  1. Window of check should be 10 cycles
  2. Number of ACK should be no more than 3.
Since the both end at the same time we will use INTERSECT operator.

Assertion :
  property check_ack;
    @(posedge clk) ack[->3] intersect 1[*10];
  endproperty

ack[->3] or ack[=3] satisfies point 2.
Since we need to check it in 10 cycles (i.e., 10 posedge clk's) we used 1[*10] --> 10 consecutive clock edges.


Code :

// Generate whatever pattern you want in the test class
class test;
   rand bit ack_b;
endclass: test

module top;
  test t;
 
  bit clk;
  bit ack;
 
  initial begin
    $timeformat(-9,0,"ns",8);
    clk <= 0;
    forever #5 clk = !clk;
   
  end
 
  initial begin
    t = new;
    repeat(20) begin //{
      @(posedge clk);
      void'(t.randomize());
      ack = t.ack_b;  
    end //}
    $finish;
  end
 
  property check_ack;
    @(posedge clk) ack[->3] intersect 1[*10];
  endproperty

 

  abc: assert property (check_ack) $display("@%0t ACK is through",$time); else
      $error("Check failed at %0t",$time);


 
  initial
    begin //{
    forever begin //{
      @(posedge clk);
      $display("Time:%0t ACK:%0d",$time,ack);
    end //}
    end //}
endmodule: top


Result :
# //
# Loading sv_std.std
# Loading work.testbench_sv_unit(fast)
# Loading work.top(fast)
#
# vsim -voptargs=+acc=npr
# run -all
# Time:5ns ACK:0
# Time:15ns ACK:1
# Time:25ns ACK:1
# Time:35ns ACK:0
# Time:45ns ACK:1
# Time:55ns ACK:0
# ** Error: Check failed at 55ns
# Time: 55 ns Started: 25 ns Scope: top.abc File: testbench.sv Line: 54
# ** Error: Check failed at 55ns
# Time: 55 ns Started: 15 ns Scope: top.abc File: testbench.sv Line: 54
# ** Error: Check failed at 55ns
# Time: 55 ns Started: 5 ns Scope: top.abc File: testbench.sv Line: 54
# Time:65ns ACK:1
# Time:75ns ACK:1
# ** Error: Check failed at 75ns
# Time: 75 ns Started: 35 ns Scope: top.abc File: testbench.sv Line: 54
# Time:85ns ACK:0
# ** Error: Check failed at 85ns
# Time: 85 ns Started: 55 ns Scope: top.abc File: testbench.sv Line: 54
# ** Error: Check failed at 85ns
# Time: 85 ns Started: 45 ns Scope: top.abc File: testbench.sv Line: 54
# Time:95ns ACK:0
# Time:105ns ACK:1
# Time:115ns ACK:0
# ** Error: Check failed at 115ns
# Time: 115 ns Started: 75 ns Scope: top.abc File: testbench.sv Line: 54
# ** Error: Check failed at 115ns
# Time: 115 ns Started: 65 ns Scope: top.abc File: testbench.sv Line: 54
# Time:125ns ACK:1
# Time:135ns ACK:0
# ** Error: Check failed at 135ns
# Time: 135 ns Started: 85 ns Scope: top.abc File: testbench.sv Line: 54
# Time:145ns ACK:0
# Time:155ns ACK:0
# Time:165ns ACK:0
# Time:175ns ACK:0
# Time:185ns ACK:0
# ** Error: Check failed at 185ns
# Time: 185 ns Started: 95 ns Scope: top.abc File: testbench.sv Line: 54
# ** Note: $finish : testbench.sv(45)
# Time: 195 ns Iteration: 1 Instance: /top
# End time: 11:23:36 on Jul 20,2020, Elapsed time: 0:00:00
# Errors: 20, Warnings: 1

Saturday, July 18, 2020

Generating RANDC without using the keyword

In many interviews people ask this question,
how can we reproduce functionality of RANDC without using the keyword in the variable declaration.


About the code:

Here we used a variable 'v' which ranges from 3:0 covering 0-15 values.
Let us say we need to limit the range to 10.
We used a queue to place the value generated by 'v' in post_randomize().
Since the constraint unique { v,v_q } ensures unique values in v and v_q, v will not generate the same value again, therefore matching the behavior of randc.
Once queue reaches size of 10, we clear it.

Here is the piece of code which does the work.

CODE:

class test;
  rand bit [3:0] v;
  bit [3:0] v_q[$];

  constraint c_v { unique {v,v_q};
                            v inside {[1:10]};
                 }

  function void post_randomize();
    v_q.push_back(v);
    if(v_q.size() == 10) v_q.delete();
  endfunction: post_randomize

  function void display();
    $display("V:%0d",v);
  endfunction: display

endclass

module top;
  test t;

  initial begin
    t = new;
    repeat(20) begin
      void'(t.randomize());
      t.display();
    end
  end
endmodule: top


Results :
CPU time: .234 seconds to compile + .310 seconds to elab + .310 seconds to link
Chronologic VCS simulator copyright 1991-2019
Contains Synopsys proprietary information.
Compiler version P-2019.06-1; Runtime version P-2019.06-1; Jul 18 23:48 2020
V:3
V:5
V:8
V:9
V:7
V:10
V:4
V:6
V:1
V:2
V:10
V:7
V:6
V:5
V:4
V:8
V:1
V:2
V:9
V:3
V C S S i m u l a t i o n R e p o r t

X propagation in ASIC/FPGA simulations

Ternary operator is used as a program statement.
If-else is a programming block.
Both can achieve similar results when a non 'X' or 'Z' value is used in conditional expression.
But when X is present inside conditional expression, the scenario changes.

Let us look at 3 scenarios.

When conditional expressions has 'bxx, 'bx0, 'bx1 values.

=========================================================================
module top;
  logic [1:0] a;
  logic [1:0] b;
  logic [1:0] c;
  logic [1:0] d;
  logic [1:0] e;
  
  initial begin
    b = 'bxx;
    c = 'b10;
    d = 'b11;
    
    a = b ? c : d;
    if(b) e = c;
    else  e = d;
    $display("Outputs - A:%0b E:%0b  || Condition:%0b || Inputs - C:%0b D:%0b",a,e,b,c,d);

    b = 'bx0;
    a = b ? c : d;
    if(b) e = c;
    else  e = d;
    $display("Outputs - A:%0b E:%0b  || Condition:%0b || Inputs - C:%0b D:%0b",a,e,b,c,d);

    b = 'bx1;
    a = b ? c : d;
    if(b) e = c;
    else  e = d;
    $display("Outputs - A:%0b E:%0b  || Condition:%0b || Inputs - C:%0b D:%0b",a,e,b,c,d);
  end
endmodule: top

===========================================================
Compiler version P-2019.06-1; Runtime version P-2019.06-1; Jul 18 06:15 2020

Outputs - A:1x E:11 || Condition:xx || Inputs - C:10 D:11
Outputs - A:1x E:11 || Condition:x0 || Inputs - C:10 D:11
Outputs - A:10 E:10 || Condition:x1 || Inputs - C:10 D:11

If you replace 'X' with 'Z' the result is the same.

Outputs - A:1x E:11 || Condition:zz || Inputs - C:10 D:11
Outputs - A:1x E:11 || Condition:z0 || Inputs - C:10 D:11
Outputs - A:10 E:10 || Condition:z1 || Inputs - C:10 D:11

Thursday, July 16, 2020

Solving queen puzzle using system verilog constraints

 Problem statement :
  • 8 queens should be placed on a chess board such that no queen can kill each other.
Notes :
  • To solve this we need to know how queen moves on the chess board.
  • Queen can move through entire ROW, COLUMN and across the DIAGONAL.
  • Therefore, we should have only 1 queen across each row, column and diagonal.
  • Queen in the 2-d matrix used is represented by 1 and the rest are 0's in the matrix(2-D).
  • We have 2 set of constraints for the problem.
    • diag_c : for controlling the diagonals ( same direction and anti diagonals )
    • Transpose_c : for using a transpose matrix for application of sum on the columns.
Constraints :
  • diag_c :
    • For this, use 2 matrices, one for normal directional diagonals and one for the other direction.
    • Map the elements of the diagonal to the main matrix board.
    • Number of row equal number of diagonals present. ( 2*N -1 ).
    • The number of colums for each row depends on the length of the diagonal.
    • For example, if we take a 3x3 matrix, we have 3 diagonals on each side.
    • [00].[0,1] [1,0] , [0,2] [1,1] [2,0]. [1,2] [2,1], [3,3]
    • Mapping of these will be
      • diag - board
      • [0,0] - [0,0]
      • [1,0] - [0,1] , [1,1] - [1,0]
      • [2,0] - [0,2] , [2,1] - [1,1], [2,2] - [2,0]
      • [3,0] - [1,2] , [3,1] - [2,1]
      • [4,0] - [3,3]
  • transpose_c :
    • 3 constraints
      • board_t transpose map to board
      • sum on each row for board
      • sum on each row for board_t, in effect it would be a sum on each row of board.
  • And we are done. :)
//======================================================================//
class queen#(parameter N=3);
  rand bit board[N][N];
  rand bit board_t[N][N];
  rand bit diag[2*N-1][];
  rand bit anti_diag[2*N-1][];

  constraint diag_c {
    foreach(diag[i,j]) {
      if(i < N) diag[i][j] == board[j][i-j];
      else      diag[i][j] == board
[(N-1)-j][i+j-N+1];
    }
    foreach(anti_diag[i,j]) {
      if(i < N) anti_diag[i][j] == board[j][N-1-i+j];
      else      anti_diag[i][j] == board[i-(N-1)+j][j];
    }
    foreach (diag[i]     ) {
      diag[i].sum() with (int'(item)) inside {0,1};
    }
    foreach (anti_diag[i]) {
      anti_diag[i].sum() with (int'(item)) inside {0,1};
    }
  }
 
 
  constraint transpose_c {
    foreach(board[i,j])  { board[i][j] == board_t[j][i];  }
    foreach (board[i])   { board[i].sum(item)   with (int'(item))== 1;  }
    foreach (board_t[i]) { board_t[i].sum(item) with (int'(item))== 1;  }
  }
 

  function void pre_randomize();
    int unsigned n;
    foreach(diag[i]) begin //{
      n = (i < N) ? i+1 : 2*N -(i+1);
      diag[i]      = new[n];
      anti_diag[i] = new[n];
    end //}
  endfunction: pre_randomize


  function void display();
    foreach(board[i,j]) begin //{
      $write("%0b ",board[i][j]);
      if(j== N-1) $write("\n");
    end //}
/*
    foreach(diag[i,j]) begin
      if(i < N)  $display(" DIAG %0d %0d BOARD %0d %0d",i,j,j,i-j);
      else       $display(" DIAG %0d %0d BOARD %0d %0d",i,j,((N-1)-j),(i+j-N+1));
    end
    foreach(anti_diag[i,j]) begin
      if(i < N) $display(" DIAG %0d %0d BOARD %0d %0d",i,j,j,(N-1-i+j));
      else      $display(" DIAG %0d %0d BOARD %0d %0d",i,j,(i-(N-1)+j),j);
    end
    */
  endfunction: display
   
endclass: queen

module top;
  queen#(8) q;

  initial begin //{
    q = new;
    void'(q.randomize());
    q.display();
  end //}
endmodule: top

Generating Sudoko using System verilog constraints


Constraints:
  • c_values : Constraint on minimum and maximum values any element in the matrix can hold
  • c_row_unique :
    • We need to have unique value (from 1 to 9) in each row, for this we run 2 loops
    • Loop - 1 [i,j] iterates through all elements in 2d-matrix
    • Loop - 2 [ ,l] iterates only through each column element
    • If condition is used for not picking up the same element for comparison
  • Constraint c_row_unique and c_col_unique employs similar strategy to generate unique elements in each row and column
  • c_subs_unique :
    • since each sub matrix 3x3 too should have unique values, we can simply divide the i,j and k,l with 3 to pick each 3x3 matrix and apply unique condition for them as well.
    •   !(i==l && j==k) is used to skip same element for comparision.
    • matrix[i][j] != matrix[k][l] , compares one element against all the other elements to avoid replication. 

//------------------------------------------------------------------------------------------------------------------------//

class sudoku;
  rand bit [3:0] matrix[9][9];

  constraint c_values     { foreach (matrix[i,j]) { matrix[i][j] inside {[1:9]}; } }
  constraint c_row_unique { foreach (matrix[i,j]) { foreach (matrix[,l]) { if(j!=l) matrix[i][j] != matrix[i][l]; } } }                    
  constraint c_col_unique { foreach (matrix[i,j]) { foreach (matrix[k,]) { if(i!=k) matrix[i][j] != matrix[k][j]; } } }  

constraint c_sub_unique { foreach (matrix[i,j]) { foreach (matrix[k,l]){ if(i/3 == k/3 && j/3 == l/3 && !(i==k && j==l)) matrix[i][j] != matrix[k][l]; } } } 


  function void display();
    foreach(matrix[i,j]) begin //{
      $write("%0d ",matrix[i][j]);
      if(j == 8) $write("\n");
    end //}
  endfunction: display

endclass: sudoku

module top;
  sudoku s;

  initial begin
    s = new;
    void'(s.randomize());
    s.display();
  end
endmodule:top

Wednesday, July 14, 2010

VHDL examples

============
single port ram
============

library ieee;
use ieee.std_logic_1164.all;

entity single_port_ram is
port
(
data : in std_logic_vector(7 downto 0);
addr : in natural range 0 to 63;
we : in std_logic := '1';
clk : in std_logic;
q : out std_logic_vector(7 downto 0)
);

end entity;

architecture rtl of single_port_ram is

-- Build a 2-D array type for the RAM
subtype word_t is std_logic_vector(7 downto 0);
type memory_t is array(63 downto 0) of word_t;

-- Declare the RAM signal.
signal ram : memory_t;

-- Register to hold the address
signal addr_reg : natural range 0 to 63;

begin

process(clk)
begin
if(rising_edge(clk)) then
if(we = '1') then
ram(addr) <= data;
end if;

-- Register the address for reading
addr_reg <= addr;
end if;

end process;

q <= ram(addr_reg);

end rtl;

=====================
FSM : moore -> BCD counter
=====================

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;

entity bcd is
port (
clk : in std_logic;
rst : in std_logic;
count: out std_logic_vector);
end bcd;

architecture beh_bcd of bcd is

-- enumeration of states
type state is (zero,one,two,three,four,five,six,seven,eight,nine);
signal pr_state,nxt_state: state;

--coding starts here
begin

-- sequential part
process(clk,rst)
begin
if(rst = '1') then
pr_state <= zero;
elsif rising_edge(clk) then
pr_state <= nxt_state;
end if;
end process;

-- combinational part
process(pr_state)
begin
case pr_state is
when zero =>
count <= "0000";
nxt_state <= one;
when one =>
count <= "0001";
nxt_state <= two;
when two =>
count <= "0010";
nxt_state <= three;
when three =>
count <= "0011";
nxt_state <= four;
when four =>
count <= "0100";
nxt_state <= five;
when five =>
count <= "0101";
nxt_state <= six;
when six =>
count <= "0110";
nxt_state <= seven;
when seven =>
count <= "0111";
nxt_state <= eight;
when eight =>
count <= "1000";
nxt_state <= nine;
when nine =>
count <= "1001";
nxt_state <= zero;
end case;

end process;

end beh_bcd;

============
2-bit grey code:
============

library IEEE;
use IEEE.Std_logic_1164.all;



entity grey is
port(
x: in std_logic_vector(1 downto 0);
y: out std_logic_vector(1 downto 0)
);
end entity;

architecture beh of grey is
begin
y(1) <= x(1);
y(0) <= x(0) xor x(1);
end beh;

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...