Python API

The C language provides the ability to define components. The Python API provides the ability to build systems from C components.

To use the Python API, you must import it.

from chips.api.api import *

Chip

Once you have imported the Python API, you can define a chip. A chip is a canvas to which you can add inputs outputs, components and wires. When you create a chips all you need to give it is a name.

mychip = Chip("mychip")

Wire

You can create Input, Output and Wires objects. A Wire is a point to point connection, a stream, that connects an output from one component to the input of another. A Wire can only have one source of data, and one data sink. When you create a Wire, you must tell it which Chip it belongs to:

wire_a = Wire(mychip)
wire_b = Wire(mychip)

Input

An Input takes data from outside the Chip, and feeds it into the input of a Component. When you create an Input, you need to specify the Chip it belongs to, and the name it will be given.

input_a = Input(mychip, "A")
input_b = Input(mychip, "B")
input_c = Input(mychip, "C")
input_d = Input(mychip, "D")

Output

An Output takes data from a Component output, and sends it outside the Chip. When you create an Output you must tell it which Chip it belongs to, and the name it will be given.

Component

From Python, you can import a C component by specifying the file where it is defined. When you import a C component it will be compiled.

The C file adder.c defines a two input adder.

//adder.c

void adder(){
    while(1){
        output_z(input_a() + input_b());
    }
}
adder = Component("source/adder.c")

Instances

You can make many instances of a component by “calling” the component. Each time you make an instance, you must specify the Chip it belongs to, and connect up the inputs and outputs of the Component.

adder(mychip,
    inputs = {"a" : input_a, "b" : input_b},
    outputs = {"z" : wire_a})

adder(mychip,
    inputs = {"a" : input_c, "b" : input_d},
    outputs = {"z" : wire_b})

adder(mychip,
    inputs = {"a" : wire_a, "b" : wire_b},
    outputs = {"z" : output_z})

A diagrammatic representation of the Chip is shown below.

       +-------+       +-------+
       | adder |       | adder |
A =====>       >=======>       >=====> Z
B =====>       |       |       |
       +-------+       |       |
                       |       |
       +-------+       |       |
       | adder |       |       |
C =====>       >=======>       |
D =====>       |       |       |
       +-------+       +-------+

Code Generation

You can generate synthesisable Verilog code for your chip using the generate_verilog method.

mychip.generate_verilog()

You can also generate a matching testbench using the generate_testbench method. You can also specify the simulation run time in clock cycles.

mychip.generate_testbench(1000) #1000 clocks

To compile the design in Icarus Verilog, use the compile_iverilog method. You can also run the code directly if you pass True to the compile_iverilog function.

mychip.compile_iverilog(True)

Table Of Contents

Previous topic

C Libraries

Next topic

Physical Interface

This Page