mirror of
https://github.com/ehw-fit/ariths-gen.git
synced 2025-04-08 00:02:12 +01:00
Support of PDK in HA and FA
This commit is contained in:
parent
18b44226d8
commit
d641595c3e
58
README.md
58
README.md
@ -1,34 +1,69 @@
|
||||
# ArithsGen – tool for arithmetic circuits generation
|
||||
### FIT BUT bachelor's degree project
|
||||
|
||||
## Description
|
||||
ArithsGen presents an open source tool that enables generation of various arithmetic circuits along with the possibility to export them to various representations which all serve their specific purpose. C language for easy simulation, Verilog for logic synthesis, BLIF for formal verification possibilities and CGP to enable further global optimization.
|
||||
|
||||
### Usage
|
||||
```bash
|
||||
python3 ariths_gen.py
|
||||
python3 generate_test.py
|
||||
cd test_circuits
|
||||
ls
|
||||
```
|
||||
|
||||
### Example of generation
|
||||
```py
|
||||
#Example generation of Verilog representation of 8-bit unsigned dadda multiplier that uses cla to provide the final product
|
||||
a = Bus(N=8, prefix="a_bus")
|
||||
b = Bus(N=8, prefix="b_bus")
|
||||
|
||||
u_dadda = UnsignedDaddaMultiplier(a=a, b=b, prefix="h_u_dadda_cla8", unsigned_adder_class_name=UnsignedCarryLookaheadAdder)
|
||||
u_dadda.get_v_code_hier(open("h_u_dadda_cla8.v", "w"))
|
||||
```
|
||||
|
||||
### Simple arithmetic circuits
|
||||
See ()[rca.py]
|
||||
|
||||
### Complex circuits
|
||||
|
||||
```py
|
||||
from ariths_gen.core.arithmetic_circuits.arithmetic_circuit import ArithmeticCircuit
|
||||
from ariths_gen.core.arithmetic_circuits import GeneralCircuit
|
||||
from ariths_gen.wire_components import Bus, Wire
|
||||
from ariths_gen.multi_bit_circuits.adders import UnsignedRippleCarryAdder
|
||||
from ariths_gen.multi_bit_circuits.multipliers import UnsignedArrayMultiplier, UnsignedDaddaMultiplier
|
||||
import os
|
||||
|
||||
class MAC(GeneralCircuit):
|
||||
def __init__(self, a: Bus, b: Bus, r: Bus, prefix: str = "", name: str = "mac", **kwargs):
|
||||
super().__init__(prefix=prefix, name=name, out_N=2*a.N+1, inputs=[a, b, r], **kwargs)
|
||||
assert a.N == b.N
|
||||
assert r.N == 2 * a.N
|
||||
|
||||
self.mul = self.add_component(UnsignedArrayMultiplier(a=a, b=b, prefix=self.prefix, name=f"u_arrmul{a.N}", inner_component=True))
|
||||
self.add = self.add_component(UnsignedRippleCarryAdder(a=r, b=self.mul.out, prefix=self.prefix, name=f"u_rca{r.N}", inner_component=True))
|
||||
self.out.connect_bus(connecting_bus=self.add.out)
|
||||
|
||||
# usage
|
||||
if __name__ == "__main__":
|
||||
os.makedirs("test_circuits/mac", exist_ok=True)
|
||||
mymac = MAC(Bus("a", 8), Bus("b", 8), Bus("acc", 16))
|
||||
mymac.get_v_code_hier(open("test_circuits/mac/mac_hier.v", "w"))
|
||||
mymac.get_c_code_hier(open("test_circuits/mac/mac_hier.c", "w"))
|
||||
mymac.get_c_code_flat(open("test_circuits/mac/mac_flat.c", "w"))
|
||||
```
|
||||
|
||||
## Documentation
|
||||
Code documentation is provided using **pdoc** documentation generator tool. Source: https://pdoc3.github.io/pdoc/.
|
||||
https://ehw-fit.github.io/ariths-gen/
|
||||
|
||||
### Installation
|
||||
```bash
|
||||
pip3 install pdoc3
|
||||
|
||||
## Supporting various PDK kits
|
||||
When one uses a specific process design kit (PDK), it is not effective to implement half- and full-adders using two-inputs logic gates. These circuits are directly implemented as CMOS modules and are more effective than heuristic optimization by synthesis tool. If you want to use for example FreePDK45 library, you can call a following function before verilog code generating.
|
||||
|
||||
```py
|
||||
from ariths_gen import set_pdk45_library
|
||||
set_pdk45_library()
|
||||
```
|
||||
|
||||
### Usage
|
||||
```bash
|
||||
pdoc --html ariths_gen
|
||||
```
|
||||
You can add a support of arbitrary PDK (see an [example](ariths_gen/pdk.py) ).
|
||||
|
||||
## Formal verification
|
||||
The `yosys_equiv_check.sh` script enables to formally check the equivalence of generated Verilog and BLIF representations of the same circuit.
|
||||
@ -51,7 +86,6 @@ For more detailed description of script's usage, use help.
|
||||
|
||||
## CGP testing
|
||||
The `chr2c.py` script converts the input CGP chromosome generated by ArithsGen to the corresponding C code and prints it to standard output.
|
||||
It is a modified version of a script originally authored by Vojtech Mrazek.
|
||||
|
||||
### Usage
|
||||
```bash
|
||||
|
@ -14,3 +14,5 @@ from .multi_bit_circuits import (
|
||||
approximate_multipliers,
|
||||
dividers
|
||||
)
|
||||
|
||||
from .pdk import *
|
@ -23,6 +23,8 @@ class FullAdder(ThreeInputOneBitCircuit):
|
||||
c (Wire, optional): Carry input wire. Defaults to Wire(name="cin").
|
||||
prefix (str, optional): Prefix name of full adder. Defaults to "fa".
|
||||
"""
|
||||
use_verilog_instance = False
|
||||
|
||||
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), c: Wire = Wire(name="cin"), prefix: str = "fa"):
|
||||
super().__init__(a, b, c, prefix)
|
||||
# 2 wires for component's bus output (sum, cout)
|
||||
@ -50,6 +52,40 @@ class FullAdder(ThreeInputOneBitCircuit):
|
||||
|
||||
self.out.connect(1, obj_or.out)
|
||||
|
||||
def get_init_v_flat(self):
|
||||
""" support of custom PDK """
|
||||
if not self.use_verilog_instance:
|
||||
return super().get_init_v_flat()
|
||||
|
||||
return " " + self.use_verilog_instance.format(
|
||||
**{
|
||||
"unit": self.prefix,
|
||||
"wirea": self.a.prefix,
|
||||
"wireb": self.b.prefix,
|
||||
"wirec": self.c.prefix,
|
||||
"wireys": self.get_sum_wire().prefix,
|
||||
"wireyc": self.get_carry_wire().prefix,
|
||||
}
|
||||
) + "\n"
|
||||
|
||||
|
||||
def get_self_init_v_hier(self):
|
||||
""" support of custom PDK """
|
||||
if not self.use_verilog_instance:
|
||||
return super().get_self_init_v_hier()
|
||||
|
||||
unique_out_wires = []
|
||||
for o in self.out.bus:
|
||||
unique_out_wires.append(o.name+"_outid"+str(self.out.bus.index(o))) if o.is_const() or o.name in [self.a.name, self.b.name] else unique_out_wires.append(o.name)
|
||||
|
||||
return " " + self.use_verilog_instance.format(**{
|
||||
"unit": self.prefix,
|
||||
"wirea": self.a.name,
|
||||
"wireb": self.b.name,
|
||||
"wirec": self.c.name,
|
||||
"wireys": unique_out_wires[0],
|
||||
"wireyc": unique_out_wires[1],
|
||||
}) + "\n"
|
||||
|
||||
class FullAdderPG(ThreeInputOneBitCircuit):
|
||||
"""Class representing modified three input one bit full adder with propagate/generate logic.
|
||||
|
@ -21,6 +21,8 @@ class HalfAdder(TwoInputOneBitCircuit):
|
||||
b (Wire, optional): Second input wire. Defaults to Wire(name="b").
|
||||
prefix (str, optional): Prefix name of half adder. Defaults to "ha".
|
||||
"""
|
||||
use_verilog_instance = False
|
||||
|
||||
def __init__(self, a: Wire = Wire(name="a"), b: Wire = Wire(name="b"), prefix: str = "ha"):
|
||||
super().__init__(a, b, prefix)
|
||||
# 2 wires for component's bus output (sum, cout)
|
||||
@ -38,6 +40,38 @@ class HalfAdder(TwoInputOneBitCircuit):
|
||||
self.add_component(obj_and)
|
||||
self.out.connect(1, obj_and.out)
|
||||
|
||||
def get_init_v_flat(self):
|
||||
""" support of custom PDK """
|
||||
if not self.use_verilog_instance:
|
||||
return super().get_init_v_flat()
|
||||
|
||||
return " " + self.use_verilog_instance.format(
|
||||
**{
|
||||
"unit": self.prefix,
|
||||
"wirea": self.a.prefix,
|
||||
"wireb": self.b.prefix,
|
||||
"wires": self.get_sum_wire().prefix,
|
||||
"wirec": self.get_carry_wire().prefix,
|
||||
}
|
||||
) + "\n"
|
||||
|
||||
|
||||
def get_self_init_v_hier(self):
|
||||
""" support of custom PDK """
|
||||
if not self.use_verilog_instance:
|
||||
return super().get_self_init_v_hier()
|
||||
|
||||
unique_out_wires = []
|
||||
for o in self.out.bus:
|
||||
unique_out_wires.append(o.name+"_outid"+str(self.out.bus.index(o))) if o.is_const() or o.name in [self.a.name, self.b.name] else unique_out_wires.append(o.name)
|
||||
|
||||
return " " + self.use_verilog_instance.format(**{
|
||||
"unit": self.prefix,
|
||||
"wirea": self.a.name,
|
||||
"wireb": self.b.name,
|
||||
"wireys": unique_out_wires[0],
|
||||
"wireyc": unique_out_wires[1],
|
||||
}) + "\n"
|
||||
|
||||
class PGLogicBlock(TwoInputOneBitCircuit):
|
||||
"""Class representing two input one bit propagate/generate logic block.
|
||||
|
18
ariths_gen/pdk.py
Normal file
18
ariths_gen/pdk.py
Normal file
@ -0,0 +1,18 @@
|
||||
"""
|
||||
Support of custom PDK
|
||||
|
||||
This file defines functions for generating of full and half adders
|
||||
directly on the level of CMOS modules.
|
||||
|
||||
You may add your own modules as in example in set_pdk45_library()
|
||||
|
||||
Please call this function before calling get_verilog_code_XXX()
|
||||
"""
|
||||
from .one_bit_circuits import (
|
||||
one_bit_components
|
||||
)
|
||||
|
||||
|
||||
def set_pdk45_library():
|
||||
one_bit_components.FullAdder.use_verilog_instance = "FAX1 {unit} (.A({wirea}), .B({wireb}), .C({wirec}), .YS({wireys}), .YC({wireyc}))"
|
||||
one_bit_components.HalfAdder.use_verilog_instance = "HAX1 {unit} (.A({wirea}), .B({wireb}), .YS({wireys}), .YC({wireyc}))"
|
4
yosys_equiv_check.sh
Normal file → Executable file
4
yosys_equiv_check.sh
Normal file → Executable file
@ -83,6 +83,8 @@ else
|
||||
if [[ "$TOP_MODULE" != $(echo $BLIF_FILE | cut -c1-"$((${#BLIF_FILE}-5))") ]]; then
|
||||
echo "Input files have different names! Do they describe the same circuit design?"
|
||||
echo "For proper equivalence check, both designs should have the same name used for their filenames and also for their top module designs."
|
||||
echo $TOP_MODULE
|
||||
echo $(echo $BLIF_FILE | cut -c1-"$((${#BLIF_FILE}-5))")
|
||||
echo
|
||||
echo "Type -h | --help for more information."
|
||||
exit 2
|
||||
@ -136,4 +138,4 @@ else
|
||||
equiv_simple
|
||||
equiv_status -assert
|
||||
"
|
||||
fi
|
||||
fi
|
||||
|
Loading…
x
Reference in New Issue
Block a user