Archive for the ‘ Verilog ’ Category

ipxact2systemverilog

Registers in an ASIC are described in many different places, for example in:

  • Actual physical registers
  • Block level test benches
  • Top level test benches
  • Block level models
  • System architectural model
  • Software
  • Software help files
  • Block documentation
  • Chip documentation
  • Chip datasheet

The register descriptions in the datasheet many times covers many hundreds of pages. Imagine if the registers are described independently in these +10 places: how many incompatible descriptions of the same thing will there be?

Clearly there is a need to describe the registers once, and generate all the other descriptions or views from the same source. Luckily the the fellows at http://www.accellera.org/activities/committees/ip-xact/ has set an industry standard to describe registers.

I had a little time over and took the opportunity to write a few registers description generators:

https://github.com/oddball/ipxact2systemverilog

The package contain these generators

ipxact2systemverilog
ipxaxct2vhdl
ipxact2rst

Through the reStructuredText (rst) file there are implicitly 2 other generators

ipxact2pdf
ipxact2html

Through .rst files it is also possible to generate .odt or .doc files, but writing documentation in those formats is an engineering sin.

In order to generate UVM or OVM packages, there are other generators available.
One nice tutorial can be found here

http://www.doulos.com/knowhow/sysverilog/ovm/tutorial_rgm_1/

Embed Python for use with HDL

Wanted to show how easy it is to use Python together with Verilog or VHDL. With just a few lines the Python interpreter can be embedded and call tasks or functions in SystemVerilog. I am using the proprietary simulator Questasim in this example.

The SystemVerilog code looks like this

`timescale 1 ns/1 ns
module top;
      import "DPI-C" context task startPython();
      export "DPI-C" task sv_write;

   // Exported SV task.  Can be called by C,SV or Python using c_write
   task sv_write(input int data,address);
      begin
	 $display("sv_write(data = %d, address = %d)",data,address);
      end
   endtask

   initial
     begin
	startPython();
	$display("DONE!!");
     end

endmodule

The C code looks like this

#include
#include "vpi_user.h"
#include "pythonEmbedded.h"

static PyObject * c_write(PyObject *self, PyObject *args) {
  int address,data;
  if(!PyArg_ParseTuple(args, "ii", &data, &address))
    return NULL;
  sv_write(address,data);
  return Py_BuildValue("");
}

static PyMethodDef EmbMethods[] = {
  {"c_write",c_write, METH_VARARGS,"c_write(data,address)"},
  {NULL, NULL, 0, NULL}
};

DPI_DLLESPEC
int startPython(){
    Py_Initialize();
    Py_InitModule("emb", EmbMethods);
    PyRun_SimpleString("import emb\n"
		       "emb.c_write(0,1)\n");
    Py_Finalize();
    return 0;
}

Easiest way to try it out:

git clone http://github.com/oddball/embedPythonInVerilogExample.git
cd embedPythonInVerilogExample
make

Can also view the code online at https://github.com/oddball/embedPythonInVerilogExample

Synthesizable Generic Memory

Synthesizable Generic Memory

A Verilog module that can be specialised from a simulation model to a vendor memory, without manually changing a line of RTL!

In an ASIC project a lot a time is needlessly consumed by they way memories are handled . Time is wasted, waiting for new models, instantiating the new models, changing code to fit new vendor memories. Over and over again.  A lot of time is also wasted developing a design, using the real size of a memory, when its faster in the development face to use a smaller memory. This extrapolates very well. No matter the design, if it is not generic, you are not doing it correctly!!

There are also significant SCM and reuse, advantages to using a generic memory.

The general principle is simple

Instantiate a module that depending on parameters (generics) instantiates different memory models.

  • If you have no vendor models, instantiate a generic memory model.
  • If you have vendor models, have a simple switch statement that instantiates the memory of the correct size.

Generate the switch statement with a script that goes through your memory models. Include the switch statement in your code.

Voila! A generic memory that is synthesizable.

So lets show how its done in code

Assume that you have a bunch of memories in a directory.

ls -1 vendorMemModels/
someOnePortVendorMem_2048_8_16.v
someOnePortVendorMem_256_8_16.v

With the naming convention of {vendorName}_{numberOfAddresses}_{width}_{muxfactor}.v
The muxfactor is, as all know, only interesting from a layout point of view.

Traverse your vendor memory models with a script in your favourite language (which of course is Python) and generate some code that looks somewhat like this:

//Automaticly generated file!!!! Do not edit!!!
//fileName : scriptGeneratedListOfVendorOnePortMems.vh
else if((addresses==256)&&(width==8))
  begin
     someOnePortVendorMem_256_8_16 mem(.A (address),
				 .CLK (clk),
				 .CEN (~(readEnable|writeEnable)),
				 .D   (writeData),
				 .WEN (~writeEnable),
				 .OEN (1'b0),
				 .Q   (readData) );
  end
else if((addresses==2048)&&(width==8))
  begin
     someOnePortVendorMem_2048_8_16 mem(.A (address),
				 .CLK (clk),
				 .CEN (~(readEnable|writeEnable)),
				 .D   (writeData),
				 .WEN (~writeEnable),
				 .OEN (1'b0),
				 .Q   (readData) );
  end

That was the automaticly generated part of the switch statement. Lets have a look at the rest.
We need a module to instantiate.

module onePortMem(readData,
		  readEnable,
		  address,
		  clk,
		  writeEnable,
		  writeData);
   //user defined
   parameter               addresses   = 32;
   parameter		   width       = 8;
   parameter 		   muxFactor   = 0;

   //Auto-calculated, user dont touch
   localparam		   addressWidth =clogb2(addresses);

   generate
      if((addresses==0)&&(width==0))
	begin
	   initial
	     begin
		$display("FAIL!! :%m:Parameters, addresses and width can not be set to 0");
		$stop;
	     end
        end
`include "scriptGeneratedListOfVendorOnePortMems.vh"
      else
	begin
	   onePortSimMem   #(.addresses  (addresses),
                             .width      (width),
                             .muxFactor (muxFactor)
			     ) mem (.readData(readData),
				    .readEnable(readEnable),
				    .address(address),
				    .clk(clk),
				    .writeEnable(writeEnable),
				    .writeData(writeData));
	end
   endgenerate
endmodule // onePortMem

Since I am a firm believer on version control, I put some executable example code on github.com. There I have also made some code for two port memories. The Makefile requires that you have a proprietary simulation tool (Modelsim/Questasim) in your path. If you don’t have it, feel free to update the Makefile for other tools and commit it.
In order to check it out and run it :

git clone http://github.com/oddball/genMem.git
cd genMem
make

Also possible to view the code online at  https://github.com/oddball/autoDependMakefileExample

In my example code there is a lot of issues that I have not touched. I have not touched them because I don’t want to cloud the general idea. But they are as well overcomeable. The main issue is BIST. BIST’s come in wide variety of forms. If they are parameterised, which they seldom are, it would be possible to solve the problem with including them in the Module “onePortMem”. Most likely they are not. Then it is possible to specialise them in the same manor as the memories. Can be nicely done with putting an BIST interface in a SystemVerilog interface and then specialise that interface in each project (when the specifics of the BIST interface is known). But there are other ways to handle it. It is also possible to handle write-masks etc, but again I have not put it here, because it clouds the concept.

The concept of “active-low” is a menace (except for reset which is generally accepted). It has caused numerous bugs, so I don’t use it in the module “onePortMem”.

PS: Most companies require the http_proxy environment variable to be set to something useful. And of unknown reason its not set per default. It should be done something like this in BASH:

export http_proxy="http://host:port/"

Scan coverage estimate

Scan coverage estimate

Have you ever been trying to figure out why you don’t get the desired 100% coverage when you are synthesizing your design, just to find yourself waiting for the project synthesis script to finish.

I have many times. So I have written a minimal script that does nothing, but reporting the scan coverage estimate. Since it does nothing but the thing you want, it is very very fast.

Make a file scan_estimate.tcl

#Read your HDL files
read_file -format vhdl{ /path/to/design-e.vhd \
            /path/to/design-a.vhd}

# Sadly you need a technology, the default tech does not have test models
set search_path     { /path/to/your/tech/lib }; #most likely, last dirname is synopsys
set target_library   { some_vendor_name_and_techname.db };

create_clock clk -period 5.0; #We dont care about freq, but need a clock
compile -exact_map -scan
create_port -direction in scan_en; #We need a scan enable port
set_dft_signal -view existing_dft -type Reset -port rstn -active_state 0
set_dft_signal -view existing_dft -type ScanClock -timing [list 40 60] -port clk
set_dft_signal -view existing_dft -type ScanEnable -active_state 1 -port scan_en
set_scan_configuration
create_test_protocol
insert_dft

#report the scan coverage estimate
dft_drc -coverage_estimate

Start your DesignCompiler in a shell

dc_shell -gui

In your dc-shell type

source scan_estimate.tcl

Many times the project synthesis script takes hours and hours. But reporting just a small design typically takes a minute or less. Thus cutting down turnaround times, and freeing up the very expensive DesignCompiler license for actual work.