Full digital flow with Cadence tools and NCSU standard library

 

The intention of this post is to show all the steps required to successfully fabricate a chip with Cadence environment using NCSU 0.5um standard digital library. It is important to highlight that this tutorial will show a lot of details that can be adapted to other CAD tools or technologies, it can also be used to implement mixed-signal projects by including the digital layout inside Virtuoso. I find it helpful since it is difficult to find such content on the internet. Likewise, I am not going to go deep on the tools capabilities, but explore the basic steps to have a final product. With the exception of the Cadence tools, you can get a totally free chip using the NCSU design kit and the MOSIS service (if you are attached to a university). The process steps may differ depending on the system is being used.

The beginning of the digital flow starts with a Verilog/VHDL code specified by the desired project. For the sake of simplicity, let’s use a Verilog code which implements a 8-bit counter:

module up_counter(
  out,
  enable,
  clk,
  reset
);

output [7:0] out;
input enable, clk, reset;
reg [7:0] out;

always @(posedge clk)
if (reset) begin
  out <= 8'b0 ;
end else if (enable) begin
  out <= out + 1;
end

endmodule

And its testbench:


`include "up_counter.v"

module up_counter_tb;

wire [7:0] out;
reg enable, clk, reset;

up_counter U0(
  .out (out),
  .enable (enable),
  .clk (clk),
  .reset (reset)
);

initial begin

  $monitor("out=%8b enable=%b clk=%b reset=%b",
            out,enable,clk,reset);
  enable=1;
  reset=0;
  clk=0;
  #1
  reset=1;
  #1
  clk=1;
  #1
  reset=0;
  clk=0;
  #1
  repeat(300) #20 clk = ~clk;

end

endmodule

The simulation can be performed with the NCSim tool “irun”, running on a graphical window or the terminal. To run on a graphical window (SimVision):

irun -gui -access rwc up_counter_tb.v

After the window pops-up, click on the instance “up_counter_tb” and after “Send To: Waveform”. Press “Run” and the simulation results can be seen:

SimVision

With the successful verification of the Verilog functionality, it’s time to synthesize it! The “Encounter RTL Compiler” is used to translate the produced Verilog code into the combination of digital cells from a standard library, NCSU in our case. The file containing the information of the digital cells usually has a “.lib” suffix, the name of the NCSU file for the 0.5um technology is “osu05_stdcells.lib”, make sure to include this file in the same directory you are working. Next, run the compiler:

"path_to_RC"/bin/rc

When the RC terminal opens, insert the following commands:

  1. set_attribute library osu05_stdcells.lib
  2. set interconnect_mode wireload
  3. read_hdl up_counter.v
  4. elaborate
  5. synthesize -to_mapped
  6. report area (optional)
  7. report gates (optional)
  8. report timing (optional)
  9. write_hdl > up_counter_synth.v
  10. exit

If you want to know about those commands better, please refer to the user manual inside the tool package. After following the last steps, the tool returns the synthesized Verilog file:

module up_counter(out, enable, clk, reset);
  input enable, clk, reset;
  output [7:0] out;
  wire enable, clk, reset;
  wire [7:0] out;
  wire n_0, n_1, n_2, n_3, n_4, n_5, n_6, n_7;
  wire n_10, n_11, n_12, n_14, n_15, n_16, n_17, n_18;
  wire n_19, n_20, n_21, n_22, n_23, n_24, n_25, n_26;
  wire n_27, n_28, n_29, n_30, n_31, n_32, n_33, n_34;
  wire n_35, n_36, n_37, n_38, n_39, n_40, n_52;
  DFFPOSX1 \out_reg[7] (.CLK (clk), .D (n_40), .Q (out[7]));
  NOR2X1 g129(.A (reset), .B (n_38), .Y (n_40));
  DFFPOSX1 \out_reg[6] (.CLK (clk), .D (n_39), .Q (out[6]));
  NOR2X1 g132(.A (reset), .B (n_36), .Y (n_39));
  DFFPOSX1 \out_reg[5] (.CLK (clk), .D (n_37), .Q (out[5]));
  AOI22X1 g131(.A (enable), .B (n_34), .C (n_35), .D (out[7]), .Y
       (n_38));
  NOR2X1 g137(.A (reset), .B (n_32), .Y (n_37));
  DFFPOSX1 \out_reg[4] (.CLK (clk), .D (n_33), .Q (out[4]));
  AOI22X1 g134(.A (enable), .B (n_29), .C (n_35), .D (out[6]), .Y
       (n_36));
  OAI21X1 g133(.A (out[7]), .B (n_30), .C (n_31), .Y (n_34));
  NOR2X1 g143(.A (reset), .B (n_28), .Y (n_33));
  DFFPOSX1 \out_reg[3] (.CLK (clk), .D (n_27), .Q (out[3]));
  AOI22X1 g139(.A (enable), .B (n_26), .C (n_35), .D (out[5]), .Y
       (n_32));
  NAND2X1 g136(.A (out[7]), .B (n_30), .Y (n_31));
  DFFPOSX1 \out_reg[2] (.CLK (clk), .D (n_25), .Q (out[2]));
  OAI21X1 g138(.A (out[6]), .B (n_23), .C (n_24), .Y (n_29));
  AOI22X1 g145(.A (enable), .B (n_19), .C (n_35), .D (out[4]), .Y
       (n_28));
  NOR2X1 g149(.A (reset), .B (n_22), .Y (n_27));
  OAI21X1 g144(.A (out[5]), .B (n_21), .C (n_20), .Y (n_26));
  NOR2X1 g155(.A (reset), .B (n_18), .Y (n_25));
  NAND2X1 g141(.A (out[6]), .B (n_23), .Y (n_24));
  OR2X2 g142(.A (n_23), .B (n_0), .Y (n_30));
  AOI22X1 g151(.A (enable), .B (n_15), .C (n_35), .D (out[3]), .Y
       (n_22));
  OR2X2 g147(.A (n_21), .B (n_3), .Y (n_23));
  NAND2X1 g148(.A (out[5]), .B (n_21), .Y (n_20));
  OAI21X1 g150(.A (out[4]), .B (n_16), .C (n_17), .Y (n_19));
  AOI22X1 g157(.A (enable), .B (n_52), .C (n_35), .D (out[2]), .Y
       (n_18));
  DFFPOSX1 \out_reg[1] (.CLK (clk), .D (n_14), .Q (out[1]));
  NAND2X1 g153(.A (out[4]), .B (n_16), .Y (n_17));
  OR2X2 g154(.A (n_16), .B (n_2), .Y (n_21));
  OAI21X1 g156(.A (out[3]), .B (n_11), .C (n_12), .Y (n_15));
  NOR2X1 g161(.A (reset), .B (n_10), .Y (n_14));
  NAND2X1 g159(.A (out[3]), .B (n_11), .Y (n_12));
  OR2X2 g160(.A (n_11), .B (n_1), .Y (n_16));
  DFFPOSX1 \out_reg[0] (.CLK (clk), .D (n_7), .Q (out[0]));
  AOI22X1 g163(.A (enable), .B (n_4), .C (n_35), .D (out[1]), .Y
       (n_10));
  NAND2X1 g165(.A (out[2]), .B (n_6), .Y (n_11));
  NOR2X1 g167(.A (reset), .B (n_5), .Y (n_7));
  MUX2X1 g170(.A (n_35), .B (enable), .S (out[0]), .Y (n_5));
  HAX1 g169(.A (out[1]), .B (out[0]), .YC (n_6), .YS (n_4));
  INVX1 g174(.A (out[5]), .Y (n_3));
  INVX1 g173(.A (out[4]), .Y (n_2));
  INVX1 g171(.A (out[3]), .Y (n_1));
  INVX1 g175(.A (enable), .Y (n_35));
  INVX1 g172(.A (out[6]), .Y (n_0));
  XOR2X1 g2(.A (out[2]), .B (n_6), .Y (n_52));
endmodule

The above code illustrates the synthesis result, from a behavioral Verilog it is possible to get a structural code compatible with the provided standard library cells.

Now, it is time to perform another verification after the synthesis process. The Verilog file “osu05_stdcells.v” containing the digital characteristics is required. After including it in your working directory, change the include file from the previously created testbench as:

`include "osu05_stdcells.v"
`include "up_counter_synth.v"

Then, just run the simulation again with the “irun” tool. Double-check the results and correct the project if they are wrong.

The next step is encapsulating the created Verilog instance to the chip pads. The NCSU pads orientation which is compatible with Cadence placement tool is described in the file “ex_encounter.io” inside the NCSU package. To encapsulate, create another instance inside the synthesized Verilog file, and connect the wires of the circuit to the pads as:

module up_counter_synth_pads(out_pad,enable_pad,clk_pad,reset_pad);

  input enable_pad, clk_pad, reset_pad;
  output [7:0] out_pad;
  wire enable, clk, reset;
  wire [7:0] out;

  up_counter CORE(
    .out(out),
    .enable(enable),
    .clk(clk),
    .reset(reset)
  );

   PADOUT p00 (.YPAD(out_pad[0]),
	.DO(out[0]));
   PADOUT p01 (.YPAD(out_pad[1]),
	.DO(out[1]));
   PADOUT p02 (.YPAD(out_pad[2]),
	.DO(out[2]));
   PADOUT p03 (.YPAD(out_pad[3]),
	.DO(out[3]));
   PADOUT p04 (.YPAD(out_pad[4]),
	.DO(out[4]));
   PADOUT p05 (.YPAD(out_pad[5]),
	.DO(out[5]));
   PADOUT p06 (.YPAD(out_pad[6]),
	.DO(out[6]));
   PADOUT p07 (.YPAD(out_pad[7]),
	.DO(out[7]));
   PADINC p08 (.YPAD(enable_pad),
	.DI(enable));
   PADINC p09 (.YPAD(clk_pad),
	.DI(clk));
   PADINC p10 (.YPAD(reset_pad),
	.DI(reset));
   PADGND p11 ();
   PADVDD p12 ();
   PADGND p20 ();
   PADVDD p21 ();
   PADGND p30 ();
   PADVDD p31 ();

   PADNC p13 ();
   PADNC p14 ();
   PADNC p15 ();
   PADNC p16 ();
   PADNC p17 ();
   PADNC p18 ();
   PADNC p19 ();

   PADNC p22 ();
   PADNC p23 ();
   PADNC p24 ();
   PADNC p25 ();
   PADNC p26 ();
   PADNC p27 ();
   PADNC p28 ();
   PADNC p29 ();

   PADNC p32 ();
   PADNC p33 ();
   PADNC p34 ();
   PADNC p35 ();
   PADNC p36 ();
   PADNC p37 ();
   PADNC p38 ();
   PADNC p39 ();

   PADFC c01 ();
   PADFC c02 ();
   PADFC c03 ();
   PADFC c04 ();
endmodule

The “PADOUT” and “PADINC” stands for the I/O pads, “PADNC” for dummy, “PADVDD” and “PADGND” for power supply, and “PADFC” for corner pads.

The Verilog is ready for layout placement by Cadence Encounter tool, but before that, make sure you include “ex_encounter.io”, “osu05_stdcells.stacks.lef” and “osu05_stdcells.lef” inside your directory, the “.lef” files contains the layout information of the digital cells, such as it’s area and which coordinates are it’s ports, it acts as a symbol from a Virtuoso schematic for example. Open the Encounter:

"path_to_Encounter"/bin/encounter

And open File->Import Design…

  1. Files: up_counter_synth.v
  2. By User: up_counter_synth_pads
  3. LEF Files: osu05_stdcells.lef osu05_stdcells.stacks.lef
  4. IO Assignment File: ex_encounter.io
  5. Power Nets: vdd!
  6. Power Nets: gnd!
  7. OK

import_design

Result:

pads_placed

Moving foward, let’s add some space for power management and nets routing. Open Floorplan->Specify Floorplan…->Die/IO/Core Coordinates->subtract 100 units of space from width and height (Core LL->UR):

core_margins

You should also change the orientation of the pads since they are 180 degrees shifted from the right position (with exception to the corners, that will be adjusted later). Floorplan->Specify Floorplan…->Advanced->Bottom IO Pad Orientation->R180

IO_orientation

Result:

core_space

Then, let’s insert the rings and stripes. Open Power->Connect Global Nets…

  1. Tie High->Pin name:vdd->Apply All->To Global Net:vdd!->Add to List
  2. Tie Low->Pin name:gnd->Apply All->To Global Net:gnd!->Add to List
  3. Apply

global_nets

Power->Power Planning->Add Ring…

  1. Net(s): vdd! gnd!
  2. Width Top/Bottom/Left/Right: 15
  3. Spacing Top/Bottom/Left/Right: 10
  4. Center in channel
  5. OK

rings

Result:

rings_fig

Power->Power Planning->Add Stripes

  1. Net(s): vdd! gnd!
  2. Width: 15
  3. Spacing: 10
  4. Number of sets: 1
  5. Relative from core or selected area->X from left 350 ||(1100-400)/2
  6. OK

stripes.png

Result:

stripes_fig

Route->Special Route->Net(s): vdd! gnd!->OK

special_r

After the power supply configuration, it is time to place the standard cells in the layout, as well as the filler cells to meet design constraints. Do Place->Standard Cell->Run Full Placement->Include Pre-Place Optimization->OK

placement

Place->Physicall Cell->Add Filler->Cell Name->Select->FILL->Add

fill_menu

Result:

fill_fig

Route the placed instances: Route->NanoRoute->Route->OK

nano_route

Finally, finish the Encounter work by saving your design. File->Save->Netlist | File->Save->DEF. The Netlist file will be used to import the schematic on Cadence Virtuoso, and the DEF to import the layout.

Now, it is time to check if the produced layout meet the project specifications, as well as the technology Design Rule Check (DRC). Open the Virtuoso software:

virtuoso

Create a new library to import the design in the library manager, “counter_import” for example and attach it to the “NCSU_TechLib_ami06”. Then go to the main window and do File->Import->Verilog

  1. Target Library Name: counter_import
  2. Reference Libraries: OSU_stdcells_ami05 NCSU_Analog_Parts
  3. Verilog Files To Import: “path_to_encounter_file”/up_counter_encounter.v
  4. OK

verilog_import

Futhermore, import the layout: File->Import->DEF

  1. DEFIn File Name: “path_to_def_file”/up_counter_encounter.def
  2. Target Library Name: counter_import
  3. Ref. Technology Libraries: *leave it blank*
  4. Target Cell Name: up_counter_synth_pads
  5. Target View Name: layout
  6. OK

def_in

After importing both Verilog and DEF files, you will be able to see the schematics created and the layout instances placed gracefully. However, the layout layers can’t be seen yet because it is needed to map the views of the cells to layout.

pre_layer

Shift+s->Search for “inst” in “current cellView”->Replace “view name”->layout->Apply->Replace All:

layers_nois

The corners seem to be 180 degrees rotated, to fix that, just right click on the top of the instance and choose a rotation property that makes the corner go on on the right position:

corner_prop

Result:

corner_good

Some remarks: for some reason that I didn’t figure out yet, the virtuoso could not import the layout with the power supply vias from the stripes and the pads, so the project manager has to manually include those vias in order to fix this power supply issue. Also, take care if there are some unconnected nets on the pads port.

no_vias
net_crazy

Before sending to fabrication, the chip needs to be verified with the schematic and with the DRC rules (DRC and LVS), other post-layout analysis will not be made in this post. The pads rules are not the same as the standard rules for the technology, for this reason, it is required to remove the pads in order to successfully run the DRC and LVS to check if the core is functional. To do so, create a clone of the hole library, and remove the pads from the layout and schematic of the clone.

The next image shows the final layout of an FPGA Configurable Logic Block from a research project:

chip_clb word.png

The above layout were sent to fabrication (MOSIS) after adjusting the DRC errors such as tiling, and the LVS too. I will make a post with the testing of the physical chip soon!

Overcoming Writer’s Block with Automatic Transcription

Hi everyone! I would like to share this article by Descript, which seems to be suitable for a variety of applications and needs:

descript

If you’re a writer — of books, essays, scripts, blog posts, whatever — you’re familiar with the phenomenon: the blank screen, a looming deadline, and a sinking feeling in your gut that pairs poorly with the jug of coffee you drank earlier.

If you know that rumble all too well: this post is for you. Maybe it’ll help you get out of a rut; at the very least, it’s good for a few minutes of procrastination.

Here’s the core idea: thinking out loud is often less arduous than writing. And it’s now easier than ever to combine the two, thanks to recent advances in speech recognition technology.

Of course, dictation is nothing new — and plenty of writers have taken advantage of it. Carl Sagan’s voluminous output was facilitated by his process of speaking into an audio recorder, to be transcribed later by an assistant (you can listen to some of his dictations in the Library of Congress!) And software like Dragon’s Naturally Speaking has offered automated transcription for people with the patience and budget to pursue it.

But it’s only in the last couple of years that automated transcription has reached a sweet spot — of convenience, affordability and accuracy—that makes it practical to use it more casually. And I’ve found it increasingly useful for generating a sort of proto-first draft: an alternative approach to the painful process of converting the nebulous wisps inside your head into something you can actually work with.

I call this process idea extraction (though these ideas may be more accurately dubbed brain droppings).

Continue reading

Digital Image Processing Class: First Unit Exercises

This post is dedicated to the Digital Image Processing exercises with professor Agostinho, which is happening during the second semester of this year. Here, the exercises related to the first unit of the class are going to be listed, to be a part of the class final grade. The OpenCV is going to be the main library used in this course, with the C++ programming language. A simple tutorial can be found on my friend’s website.

All the codes can be accessed by clicking the titles of each exercise.
The root directory can be accessed here.

2.2.1: Negative of a region

The first exercise is to create the negative of an image inside a given rectangle. The following image illustrates the concept:

negative_img

For implementation simplicity, the images were converted to gray-scale. The trick is inverting the values of the pixels inside the selected region. If we consider the range of the gray-scale to be from 0 to 255, as the following code does:

for(int i=x0;i<y0;i++){
  for(int j=x1;j<y1;j++){
    image.at(i,j)= 255 - image.at(i,j);
  }
}

The user is asked to give the rectangle points at the beginning of execution.

Continue reading

My experience at Gwangju Institute of Science and Technology Global Internship program

gip_participants.jpg

My research opportunity starts with the announcement of an internship program at the city of Gwangju, located in South Korea. My advisor Diomadson saw the GIP flier and noticed me about it. Then, I thought that it could be a great opportunity to enhance my curriculum. With the chance, I started to provide the necessary documents and essays about myself, including academic achievements, personal experiences, and grades. The program details can be found here. The biggest challenge encountered in the registration process was obtaining an English certificate, since many proficiency certificates may take a long time to be got depending on the exam type, and I needed the result fast because I noticed the opportunity late. Luckily, the TOEIC exam is well accepted in a lot of Korean universities as I heard, and it is relatively fast and cheap to obtain its certificate. I recommend new participants to try to do a proficiency exam as soon as possible to avoid deadline issues, but if you are tight on time, TOEIC is a good option to meet this constraint.

I have found many reasons to apply for this program, among them, Korea is a well-developed country in the technology industry which is very interesting for my major. I thought that it could bring me new opportunities and develop my network. The other main reason is to visit my Korean girlfriend, which I had the happiness to meet during an exchange program in the USA.

In the application process, it is required to choose a laboratory where you will be developing your work for two months. From there, I tried to search the laboratory that best fitted with my academic experiences. The ICSL lab seemed to be the best choice, the fields of study are very related to my laboratory in Brazil. So I decided to email the lab professor to assure that it would be a good option. The following paragraph illustrates the email sent and its response.

Continue reading

A way to remove special characters from a text file

Hi everyone! I have been busy for the last months with various duties related to my university classes and research. But now I have separated a little time to write another post! Soon I will bring more contents related to my university environment.

Last month, the campus party happened in my city. So my friends and I decided to participate in two hackathons that happened simultaneously during the event just for fun, which later showed to be a great challenge. The first hackathon involved data science directed to the Brazilian health, and the second one was intended to accelerate the national overall judgment process. In the picture below I am presenting my groups work related to the data science hackathon, the TV shows a correlation matrix made from various databases data.

word

Jumping now to this post purpose!

While trying to develop a solution for one of the hackathons, we had to process the text of pdf files.  To do so, we used the PDFMiner package. The next line illustrates its usage:

pdf2txt.py -o 'output file' 'pdf file'

The application seemed to extract the pdf text pretty well, with just one little peculiarity: There were special/control characters (“Ctrl+l”) inserted whenever there was a new page at the original pdf. The picture below illustrates the character with the VIM text editor:

word2

This character got in our way to process the file for our final purpose. At first, we tried to just remove it with ordinary python functions and with different inputs representing the character, without success at the beginning. So we found a pretty interesting solution!


text_file = open('text.txt','r')
text_file = text_file.read()
text_file = repr(text_file)
text_file = text_file.replace("\\x0c","")
text_file = literal_eval(text_file)

The trick consists of using the “repr()” function which returns the completely “raw” string. From there, the special character can be easily identified an removed. In the end, just return the string to the original form with the “literal_eval()” function! The relation of “\x0c” and “Ctrl+l” was found by analyzing the raw text file with the “repr()” function.

I believe this approach can be used to similarly solve other issues involving different characters and programming languages.

Robot path generation from a Genetic Algorithm

The project presented in this post was accomplished during the Artificial Intelligence class given by professor Caroline. It consisted of using the Genetic Algorithm (GA) to make a robot (from the iRobot Matlab toolbox) navigate from a start point to an end point without hitting any obstacles (walls).

A GA flowchart is shown below to quickly resume the method. At the beginning, a new population of possible solutions is created, each individual of this population can be the solution for a given problem. The population size is strictly fixed to a selected size. Next, an evaluation (or fitness) is applied to each individual of the population, to know how well their solution fits into the problem solution. From there, the process of “evolution” begins, a new generation is created by selecting the best individuals, reproducing them (crossover) and applying a chance of mutation for each individual. At the end, this new generation is evaluated and the process of creating a new generation starts again. The algorithm stops when the evaluation of the population is good enough or the number of generations specified is reached.

flow

source: http://techeffigytutorials.blogspot.com.br/2015/02/the-genetic-algorithm-explained.html

The robot path generation was adapted based on the explanation given of the GA. A brief summary of the developed code in this post is shown:

  1. The start population is created from the possible paths that the robot can follow. Each path (individual) is composed of a sequence of cartesian coordinates (x,y), the path is constructed from the interconnection of those coordinates. It is important to check if the path is valid (no obstacles in the way).
  2. The evaluation (fitness) of the population is retrieved based on the success of the path to reach the destination and the distance traveled from the start point to the finish point.
  3. A new generation is started by selecting the new individuals randomly (Roulette selection) until a selected percentage of the population size. The individuals with the best evaluation have more chances to be selected (Elitism).
  4. The last empty spots of the new population are filled with the reproduction (crossover) of two individuals selected the same way as step 3. The reproduction generates a single child which has one part of the first selected individual and another part of the second individual from a common intersection of both.
  5. With the new population filled, a chance of mutation is applied to each individual. Each Cartesian coordinate have a really small chance of being replaced by another random one. It is also important to check if this new random point is valid to create a path. Mutation is applied to avoid the global minimum solution to the problem.
  6. The population is evaluated again, and the algorithm repeats from step 2 until the requirements are matched.
population_size = 100;
path_size = 10;
%Start point coordinates
start_x = 3;
start_y = 3;
%End point
desired_x = -3;
desired_y = -3;
%survive rate for next generation
keep_alive = 90;
%Number of generations
epoch = 10;
%Mutation chance for each node
mutation_chance = 0.0005; %For each point in the path

Continue reading

A simple chat with Sockets using Python

The following work was developed during the Computer Network class given by professor Carlos Viegas at the Federal University of Rio Grande do Norte. The group was composed of Lenildo and me.

The assignment consisted of implementing a simple chat with Sockets based on a client/server communication. We also needed to insert some functionalities into the application, like changing the name of the user, listing the active clients connected to the chat and even to start a private chat with a specific user. There is no direct communication between clients, all messages need to pass through the server to reach the other end.

Now let’s start to talk about the code!

The strategies to create the system involves using threads to communicate the clients and server parallelly with the help of sockets:


# import libraries
from socket import *
from threading import Thread # thread

Beginning with the server, the following lines were used for the main configuration. It is needed to describe the server IP, port and operating protocol (TCP in our case):


# Server IP
serverName = ''
# Server port to connect
serverPort = 12000
# TCP protocol
serverSocket = socket(AF_INET,SOCK_STREAM)
# Bind the Server IP with its port
serverSocket.bind((serverName,serverPort))
# Ready to receive connections
serverSocket.listen(1) 

Continue reading