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. .. code-block:: python 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. .. code-block:: python 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: .. code-block:: python 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. .. code-block:: python 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. .. code-block:: python //adder.c void adder(){ while(1){ output_z(input_a() + input_b()); } } .. code-block:: python 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`. .. code-block:: python 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. .. code-block:: python 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. .. code-block:: python 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. .. code-block:: python mychip.compile_iverilog(True)