2. Add and edit components

There are two ways to add a new component

  • Joining components for create “macro components”.
  • Adding all from scratch, IO definitions, python code, vhd code, verilog code, svg icon.

2.1. Joining components

You can create components joining another components, we call this union as “maco component”, you can create macro components joining components with components and macro components.

For add a macro component, you must select the components that are part of the macro component and press in the bottom site the button “Add macro component”, and this will create a white box that contains the components inside, you can expand or contract this box clicking the “+” icon or the “-” icon.

This box initially not have inputs and outputs, you can add them double click the white box, and a modal window will appear, there are two tables, you can add the inputs and outputs separated, define the ID, bus size and if is input, a default value (if this no has default value, put “-1” in the field), for delete a I/O, leave blank the ID field.

You can save this macro component, going to second tab of the macro component properties, put a name and press the save button, now this schematic circuit will save in your directory.

If you select a macro component and press “supr” key, the macro is removed but the internal components are conserved, for delete all complete, just right click and press delete all.

The macro components schematic is saved in JSON format in the SintelDir/components_macros, yo can share this file to another people.

2.2. Adding components from scratch

This action is realized in the “add components view”, for show this section you must press the “Add component” button in the menu of simulation view.

This view has 3 main sections

  • Left panel: there is a form with the basic data of the component.
  • Right panel: there is a view of the configuration component file, and a resume of the entered data in JSON format.
  • Center: there are tabs for add the component data

2.2.1. Left Panel:

Warning

Take care, if there is a component with the name that you putted, the old component will be replaced.

Danger

Don’t use a reserved python, vhdl or verilog word for name the component.

Warning

There are two fields that are for define if the component is an input or output of all the system, for example a clock generator, don’t select them if your component isn’t a general IO of the system, since if you select it, the component can consume more computing resources and will not work in the best way.

2.2.2. Tabs of data

2.2.2.1. I/O Definition

  • Variables are created for change define the bus size, you can assign them to Inputs and outputs, and when the user change the size of a connector, all connectors that are associated to this variable will change, this is useful when you have outputs that depends of inputs for example a OR gate, the output or 8 bits is realized by 2 inputs of 8 bits.
  • Inputs, define the input ID, the variable for change the connector size in the simulation, and if this is a normal input, a clock input (If you will connect a clock to this connector, for example the register clock input), or a reset input (If you will connect a reset signal, for example the reset input of a state machine).
  • Outputs, define the output ID, the variable for change the connector size in the simulation, and if this is a clock generator, select “Yes” in “is clock generator” field.

2.2.2.2. Properties

You can add two types of properties, checking the “Show Inline?” value

  • Inline: are visible in the workspace under the component, use them only for characteristics that can be changed in execution time, it should be noted that the processor usage increments when a property is changed in execution time, this can be used for change system inputs in real time. Those properties won’t be exported to HDL.
  • Hide: these properties are shown when you double click on a component in workspace, those properties will be exported to HDL.

Regardless of the type of property, you can select different types of user interaction, for example a number input, or a list. These types of input have their own fields for fill.

  • Select list: add the list of values separated by colon, if you select the “Is Binary?” option, the values that you can add are “1” and “0”.
  • Number: you can add a default value, the min value and the max value, if you prefer, you can limit the maximum value to a variable size, then, when the user changes the bus size, this maximum value will change.
  • Bit: Only allows select “1” or “0”.

For delete a property, press the “Delete button”.

2.2.2.3. Icons

There is a workspace where you can drag and drop the Inputs or Outputs added previous, select the SVG icon clocking the button, and you cand adjust the size with the “range inputs”.

Note

When you create the svg file, try to take the measurements respect “25px”, for example: Width (50px) height (75px).

2.2.2.4. Python code

The basic structure for the python file of a component is

#!/usr/bin/env python
from common import Component

class component(Component):
        def setup(self, properties):
                {{IO Declarations}}
                self.userSetup(properties)

        def userSetup(self, properties):
                {{your setup code}}

        def update(self):
                {{ your update code }}
  • “IO Declarations”, these lines are added automatically, and defines the inputs and outputs of the component.
  • “your update code”, you must add the update code, this code is executed when a Signal writes a value in this connector
  • “setup user code” is executed in the constructor, in this method you can assign the properties, these properties are sent on a dictionary like (this example applies if you add two properties called “reset” and “myProperty”)
properties = {"reset_pos" : "0", "myProperty" : "100"}
self._resetPos = int(properties["reset_pos"])

Next you will see two examples, one of an OR, and another of a register

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python
# OR example by sintel
from common import Component

class OR1(Component):
        def setup(self, properties):
                self._addInput("pIn1")
                self._addInput("pIn2")
                self._addOutput("pOut")
                self.userSetup(properties)

        def userSetup(self, properties):
                pass

        def update(self):
                # Read the input values
                value1 = self.read("pIn1", base = 2)
                value2 = self.read("pIn2", base = 2)

                # Checks if the size are equal
                if len(value1) == len(value2):

                        # Realize the OR operation
                        write = ['1' if value1[i] == '1' or value2[i] == '1' else '0' for i in range(len(value1))]

                        # Write the result
                        self.write("pOut", write, base = 2)
                else:
                        # Writes an unknown value
                        self.write("pOut", 'U')
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/env python
# Register example by sintel
from common import Component

class Register2(Component):
        def setup(self, properties):
                self._addInput("inD")
                self._addInput("ena")
                self._addInput("rst")
                self._addInput("clk")
                self._addOutput("outQ")
                self.userSetup(properties)

        def userSetup(self, properties):
                self._resetPos = int(properties["reset"])
                self._firstTime = True
                self._lastValue = None

        def update(self):
                # Read the inputs
                resetVal = self.read("rst")
                ena = self.read("ena")

                if resetVal == self._resetPos:

                        # As this component updates with clock, this line prevents that the component writes the same value and reduce the processor usage.
                        if self._lastValue != 0:

                                # Writes 0 to output
                                self.write("outQ", 0)
                                self._lastValue = 0

                elif ena == 1:
                        value = self.read("inD")

                        # As this component updates with clock, this line prevents that the component writes the same value and reduce the processor usage.
                        if self._lastValue != value:

                                # Writes the input value to output
                                self.write("outQ", value)
                                self._lastValue = value

The methods that you can use in the python code are:

a = self.read(“pInput”, base = 10):
 Reads the input value, this value is in 10 base by default, if you want read in another base, just pass the “base” parameter with the base that you want, if this is base=2, the returned value is a list with strings of “1” or “0”, for example [“0”, “0”, “1”, “0”] (this is the number 2).
self.write(“pOutput”, value, base = 10):
 Writes a value in the signal connected to this output, base 10 is by default, if you want to write a value in another base, pass the “base” parameter, for base 2, you have to write a list with strings like [“1”, “0”, “1”, “0”] (this is the number 10)

2.2.2.5. VHDL code

If the component has clock, you have to add two different codes, one for falling edge and another for rising edge, Sintel assign the property of select the clock flank for work, and you must have this present in the vhdl code.

The inputs and generics will be created by default, and you must add the architecture code.

There are two examples for two components in VHDL, an OR gate and a register.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
--- OR gate example for sintel

library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;

entity OR01 is
        generic(
                Bus_LEN:natural := 1
        );
        port(
                pIn1: in std_logic_vector(Bus_LEN - 1 downto 0);
                pIn2: in std_logic_vector(Bus_LEN - 1 downto 0);
                pOut: out std_logic_vector(Bus_LEN - 1 downto 0)
        );
end entity;
architecture rtl of OR01 is
begin
-- Put the code here
        pOut <= pIn1 or pIn2;
end architecture;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
--- Register example for sintel

library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;

entity Register2 is
        generics(
                buses_LEN:natural := 1;
                reset_PAR:std_logic := '0'
        );
        port(
                inD: in std_logic_vector(buses_LEN - 1 downto 0);
                ena: in std_logic;
                rst: in std_logic;
                clk: in std_logic;
                outQ: out std_logic_vector(buses_LEN - 1 downto 0)
        );
end entity;

--- This code is executed if the component is configured with the rising edge flank
architecture rising_edge_arch of Register2 is
begin
        outQ <= (others => '0') when rst = reset_PAR else inD when falling_Edge(clk) and ena='1';
end architecture;

--- This code is executed if the component is configured with the falling edge flank
architecture falling_edge_arch of Register2 is
begin
        outQ <= (others => '0') when rst = reset_PAR else inD when rising_Edge(clk) and ena='1';
end architecture;

As you can see in the register example, there is two architectures that are executed separated depending the component configuration made by user.

2.2.2.6. Verilog

The verilog code addition is equal to vhdl edition, please read the prev item for understand all steps, next, there are two examples of an OR gate and a Register in verilog.